diff --git a/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index c53eac41945..aa51a06725b 100644 --- a/homeassistant/components/tasmota/manifest.json +++ b/homeassistant/components/tasmota/manifest.json @@ -3,7 +3,7 @@ "name": "Tasmota (beta)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tasmota", - "requirements": ["hatasmota==0.0.16"], + "requirements": ["hatasmota==0.0.18"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/requirements_all.txt b/requirements_all.txt index c38ad90d02c..b4f774c9b70 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -729,7 +729,7 @@ hass-nabucasa==0.37.1 hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.16 +hatasmota==0.0.18 # homeassistant.components.jewish_calendar hdate==0.9.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4caab6e04eb..d83482115d8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -364,7 +364,7 @@ hangups==0.4.11 hass-nabucasa==0.37.1 # homeassistant.components.tasmota -hatasmota==0.0.16 +hatasmota==0.0.18 # homeassistant.components.jewish_calendar hdate==0.9.5 diff --git a/tests/components/tasmota/test_sensor.py b/tests/components/tasmota/test_sensor.py index 296d9e4878e..40dcbe69201 100644 --- a/tests/components/tasmota/test_sensor.py +++ b/tests/components/tasmota/test_sensor.py @@ -36,6 +36,51 @@ DEFAULT_SENSOR_CONFIG = { } } +INDEXED_SENSOR_CONFIG = { + "sn": { + "Time": "2020-09-25T12:47:15", + "ENERGY": { + "TotalStartTime": "2018-11-23T15:33:47", + "Total": 0.017, + "TotalTariff": [0.000, 0.017], + "Yesterday": 0.000, + "Today": 0.002, + "ExportActive": 0.000, + "ExportTariff": [0.000, 0.000], + "Period": 0.00, + "Power": 0.00, + "ApparentPower": 7.84, + "ReactivePower": -7.21, + "Factor": 0.39, + "Frequency": 50.0, + "Voltage": 234.31, + "Current": 0.039, + "ImportActive": 12.580, + "ImportReactive": 0.002, + "ExportReactive": 39.131, + "PhaseAngle": 290.45, + }, + } +} + + +NESTED_SENSOR_CONFIG = { + "sn": { + "Time": "2020-03-03T00:00:00+00:00", + "TX23": { + "Speed": {"Act": 14.8, "Avg": 8.5, "Min": 12.2, "Max": 14.8}, + "Dir": { + "Card": "WSW", + "Deg": 247.5, + "Avg": 266.1, + "AvgCard": "W", + "Range": 0, + }, + }, + "SpeedUnit": "km/h", + } +} + async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): """Test state update via MQTT.""" @@ -82,6 +127,96 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): assert state.state == "20.0" +async def test_nested_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): + """Test state update via MQTT.""" + config = copy.deepcopy(DEFAULT_CONFIG) + sensor_config = copy.deepcopy(NESTED_SENSOR_CONFIG) + mac = config["mac"] + + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + await hass.async_block_till_done() + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/sensors", + json.dumps(sensor_config), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.tx23_speed_act") + assert state.state == "unavailable" + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") + state = hass.states.get("sensor.tx23_speed_act") + assert state.state == STATE_UNKNOWN + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + # Test periodic state update + async_fire_mqtt_message( + hass, "tasmota_49A3BC/tele/SENSOR", '{"TX23":{"Speed":{"Act":"12.3"}}}' + ) + state = hass.states.get("sensor.tx23_speed_act") + assert state.state == "12.3" + + # Test polled state update + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS8", + '{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"}}}}', + ) + state = hass.states.get("sensor.tx23_speed_act") + assert state.state == "23.4" + + +async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): + """Test state update via MQTT.""" + config = copy.deepcopy(DEFAULT_CONFIG) + sensor_config = copy.deepcopy(INDEXED_SENSOR_CONFIG) + mac = config["mac"] + + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + await hass.async_block_till_done() + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/sensors", + json.dumps(sensor_config), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.energy_totaltariff_1") + assert state.state == "unavailable" + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") + state = hass.states.get("sensor.energy_totaltariff_1") + assert state.state == STATE_UNKNOWN + assert not state.attributes.get(ATTR_ASSUMED_STATE) + + # Test periodic state update + async_fire_mqtt_message( + hass, "tasmota_49A3BC/tele/SENSOR", '{"ENERGY":{"TotalTariff":[1.2,3.4]}}' + ) + state = hass.states.get("sensor.energy_totaltariff_1") + assert state.state == "3.4" + + # Test polled state update + async_fire_mqtt_message( + hass, + "tasmota_49A3BC/stat/STATUS8", + '{"StatusSNS":{"ENERGY":{"TotalTariff":[5.6,7.8]}}}', + ) + state = hass.states.get("sensor.energy_totaltariff_1") + assert state.state == "7.8" + + async def test_attributes(hass, mqtt_mock, setup_tasmota): """Test correct attributes for sensors.""" config = copy.deepcopy(DEFAULT_CONFIG) @@ -120,6 +255,76 @@ async def test_attributes(hass, mqtt_mock, setup_tasmota): assert state.attributes.get("unit_of_measurement") == "ppm" +async def test_nested_sensor_attributes(hass, mqtt_mock, setup_tasmota): + """Test correct attributes for sensors.""" + config = copy.deepcopy(DEFAULT_CONFIG) + sensor_config = copy.deepcopy(NESTED_SENSOR_CONFIG) + mac = config["mac"] + + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + await hass.async_block_till_done() + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/sensors", + json.dumps(sensor_config), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.tx23_speed_act") + assert state.attributes.get("device_class") is None + assert state.attributes.get("friendly_name") == "TX23 Speed Act" + assert state.attributes.get("icon") is None + assert state.attributes.get("unit_of_measurement") == "km/h" + + state = hass.states.get("sensor.tx23_dir_avg") + assert state.attributes.get("device_class") is None + assert state.attributes.get("friendly_name") == "TX23 Dir Avg" + assert state.attributes.get("icon") is None + assert state.attributes.get("unit_of_measurement") == " " + + +async def test_indexed_sensor_attributes(hass, mqtt_mock, setup_tasmota): + """Test correct attributes for sensors.""" + config = copy.deepcopy(DEFAULT_CONFIG) + sensor_config = { + "sn": { + "Dummy1": {"Temperature": [None, None]}, + "Dummy2": {"CarbonDioxide": [None, None]}, + "TempUnit": "C", + } + } + mac = config["mac"] + + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/config", + json.dumps(config), + ) + await hass.async_block_till_done() + async_fire_mqtt_message( + hass, + f"{DEFAULT_PREFIX}/{mac}/sensors", + json.dumps(sensor_config), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.dummy1_temperature_0") + assert state.attributes.get("device_class") == "temperature" + assert state.attributes.get("friendly_name") == "Dummy1 Temperature 0" + assert state.attributes.get("icon") is None + assert state.attributes.get("unit_of_measurement") == "C" + + state = hass.states.get("sensor.dummy2_carbondioxide_1") + assert state.attributes.get("device_class") is None + assert state.attributes.get("friendly_name") == "Dummy2 CarbonDioxide 1" + assert state.attributes.get("icon") == "mdi:molecule-co2" + assert state.attributes.get("unit_of_measurement") == "ppm" + + async def test_availability_when_connection_lost( hass, mqtt_client_mock, mqtt_mock, setup_tasmota ):