Set stateclass on unknown numeric Tasmota sensors (#120650)

This commit is contained in:
Erik Montnemery 2024-06-28 08:42:47 +02:00 committed by GitHub
parent 4e34d02d2d
commit ec069f9084
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 332 additions and 0 deletions

View file

@ -302,6 +302,15 @@ class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, SensorEntity):
self._attr_native_unit_of_measurement = SENSOR_UNIT_MAP.get(
self._tasmota_entity.unit, self._tasmota_entity.unit
)
if (
self._attr_device_class is None
and self._attr_state_class is None
and self._attr_native_unit_of_measurement is None
):
# If the sensor has a numeric value, but we couldn't detect what it is,
# set state class to measurement.
if self._tasmota_entity.discovered_as_numeric:
self._attr_state_class = SensorStateClass.MEASUREMENT
async def async_added_to_hass(self) -> None:
"""Subscribe to MQTT events."""

View file

@ -1712,3 +1712,301 @@
'state': '2300',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR1 Unknown',
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor1_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unavailable',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].1
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.tasmota_sensor1_unknown',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'SENSOR1 Unknown',
'platform': 'tasmota',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00000049A3BC_sensor_sensor_SENSOR1_Unknown',
'unit_of_measurement': None,
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].10
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR3 Unknown',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor3_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20.5',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].11
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR4 Unknown',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor4_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20.5',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].12
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR1 Unknown',
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor1_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].13
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR2 Unknown',
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor2_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].14
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR3 Unknown',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor3_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].15
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR4 Unknown',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor4_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].2
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR2 Unknown',
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor2_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unavailable',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].3
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.tasmota_sensor2_unknown',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'SENSOR2 Unknown',
'platform': 'tasmota',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00000049A3BC_sensor_sensor_SENSOR2_Unknown',
'unit_of_measurement': None,
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].4
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR3 Unknown',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor3_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unavailable',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].5
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.tasmota_sensor3_unknown',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'SENSOR3 Unknown',
'platform': 'tasmota',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00000049A3BC_sensor_sensor_SENSOR3_Unknown',
'unit_of_measurement': None,
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].6
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR4 Unknown',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor4_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unavailable',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].7
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.tasmota_sensor4_unknown',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'SENSOR4 Unknown',
'platform': 'tasmota',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00000049A3BC_sensor_sensor_SENSOR4_Unknown',
'unit_of_measurement': None,
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].8
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR1 Unknown',
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor1_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20.5',
})
# ---
# name: test_controlling_state_via_mqtt[sensor_config9-entity_ids9-messages9].9
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Tasmota SENSOR2 Unknown',
}),
'context': <ANY>,
'entity_id': 'sensor.tasmota_sensor2_unknown',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20.5',
})
# ---

View file

@ -50,6 +50,17 @@ BAD_LIST_SENSOR_CONFIG_3 = {
}
}
# This configuration has sensors which type we can't guess
DEFAULT_SENSOR_CONFIG_UNKNOWN = {
"sn": {
"Time": "2020-09-25T12:47:15",
"SENSOR1": {"Unknown": None},
"SENSOR2": {"Unknown": "123"},
"SENSOR3": {"Unknown": 123},
"SENSOR4": {"Unknown": 123.0},
}
}
# This configuration has some sensors where values are lists
# Home Assistant maps this to one sensor for each list item
LIST_SENSOR_CONFIG = {
@ -281,6 +292,20 @@ TEMPERATURE_SENSOR_CONFIG = {
),
),
),
# Test we automatically set state class to measurement on unknown numerical sensors
(
DEFAULT_SENSOR_CONFIG_UNKNOWN,
[
"sensor.tasmota_sensor1_unknown",
"sensor.tasmota_sensor2_unknown",
"sensor.tasmota_sensor3_unknown",
"sensor.tasmota_sensor4_unknown",
],
(
'{"SENSOR1":{"Unknown":20.5},"SENSOR2":{"Unknown":20.5},"SENSOR3":{"Unknown":20.5},"SENSOR4":{"Unknown":20.5}}',
'{"StatusSNS":{"SENSOR1":{"Unknown":20},"SENSOR2":{"Unknown":20},"SENSOR3":{"Unknown":20},"SENSOR4":{"Unknown":20}}}',
),
),
],
)
async def test_controlling_state_via_mqtt(