Bump hatasmota to 0.0.29 (#43013)

This commit is contained in:
Erik Montnemery 2020-11-11 13:51:09 +01:00 committed by GitHub
parent 621a0a5dd2
commit 8cc7069323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 266 additions and 13 deletions

View File

@ -3,7 +3,7 @@
"name": "Tasmota (beta)",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/tasmota",
"requirements": ["hatasmota==0.0.27"],
"requirements": ["hatasmota==0.0.29"],
"dependencies": ["mqtt"],
"mqtt": ["tasmota/discovery/#"],
"codeowners": ["@emontnemery"]

View File

@ -95,8 +95,7 @@ class TasmotaAvailability(TasmotaEntity):
@callback
def availability_updated(self, available: bool) -> None:
"""Handle updated availability."""
if available and not self._available:
self._tasmota_entity.poll_status()
self._tasmota_entity.poll_status()
self._available = available
self.async_write_ha_state()

View File

@ -3,6 +3,19 @@ from typing import Optional
from hatasmota import status_sensor
from hatasmota.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER as TASMOTA_CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION as TASMOTA_CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION as TASMOTA_CONCENTRATION_PARTS_PER_MILLION,
ELECTRICAL_CURRENT_AMPERE as TASMOTA_ELECTRICAL_CURRENT_AMPERE,
ELECTRICAL_VOLT_AMPERE as TASMOTA_ELECTRICAL_VOLT_AMPERE,
ENERGY_KILO_WATT_HOUR as TASMOTA_ENERGY_KILO_WATT_HOUR,
FREQUENCY_HERTZ as TASMOTA_FREQUENCY_HERTZ,
LENGTH_CENTIMETERS as TASMOTA_LENGTH_CENTIMETERS,
LIGHT_LUX as TASMOTA_LIGHT_LUX,
MASS_KILOGRAMS as TASMOTA_MASS_KILOGRAMS,
PERCENTAGE as TASMOTA_PERCENTAGE,
POWER_WATT as TASMOTA_POWER_WATT,
PRESSURE_HPA as TASMOTA_PRESSURE_HPA,
SENSOR_AMBIENT,
SENSOR_APPARENT_POWERUSAGE,
SENSOR_BATTERY,
@ -35,12 +48,13 @@ from hatasmota.const import (
SENSOR_PROXIMITY,
SENSOR_REACTIVE_POWERUSAGE,
SENSOR_STATUS_IP,
SENSOR_STATUS_LAST_RESTART_TIME,
SENSOR_STATUS_LINK_COUNT,
SENSOR_STATUS_MQTT_COUNT,
SENSOR_STATUS_RESTART,
SENSOR_STATUS_RESTART_REASON,
SENSOR_STATUS_RSSI,
SENSOR_STATUS_SIGNAL,
SENSOR_STATUS_UPTIME,
SENSOR_STATUS_SSID,
SENSOR_TEMPERATURE,
SENSOR_TODAY,
SENSOR_TOTAL,
@ -49,10 +63,21 @@ from hatasmota.const import (
SENSOR_VOLTAGE,
SENSOR_WEIGHT,
SENSOR_YESTERDAY,
SIGNAL_STRENGTH_DECIBELS as TASMOTA_SIGNAL_STRENGTH_DECIBELS,
SPEED_KILOMETERS_PER_HOUR as TASMOTA_SPEED_KILOMETERS_PER_HOUR,
SPEED_METERS_PER_SECOND as TASMOTA_SPEED_METERS_PER_SECOND,
SPEED_MILES_PER_HOUR as TASMOTA_SPEED_MILES_PER_HOUR,
TEMP_CELSIUS as TASMOTA_TEMP_CELSIUS,
TEMP_FAHRENHEIT as TASMOTA_TEMP_FAHRENHEIT,
TEMP_KELVIN as TASMOTA_TEMP_KELVIN,
VOLT as TASMOTA_VOLT,
)
from homeassistant.components import sensor
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
@ -60,6 +85,25 @@ from homeassistant.const import (
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
ELECTRICAL_CURRENT_AMPERE,
ELECTRICAL_VOLT_AMPERE,
ENERGY_KILO_WATT_HOUR,
FREQUENCY_HERTZ,
LENGTH_CENTIMETERS,
LIGHT_LUX,
MASS_KILOGRAMS,
PERCENTAGE,
POWER_WATT,
PRESSURE_HPA,
SIGNAL_STRENGTH_DECIBELS,
SPEED_KILOMETERS_PER_HOUR,
SPEED_METERS_PER_SECOND,
SPEED_MILES_PER_HOUR,
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
TEMP_KELVIN,
VOLT,
)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -108,10 +152,11 @@ SENSOR_DEVICE_CLASS_ICON_MAP = {
SENSOR_PRESSUREATSEALEVEL: {DEVICE_CLASS: DEVICE_CLASS_PRESSURE},
SENSOR_PROXIMITY: {ICON: "mdi:ruler"},
SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER},
SENSOR_STATUS_RESTART: {ICON: "mdi:information-outline"},
SENSOR_STATUS_LAST_RESTART_TIME: {DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP},
SENSOR_STATUS_RESTART_REASON: {ICON: "mdi:information-outline"},
SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH},
SENSOR_STATUS_RSSI: {ICON: "mdi:access-point"},
SENSOR_STATUS_UPTIME: {ICON: "mdi:progress-clock"},
SENSOR_STATUS_SSID: {ICON: "mdi:access-point-network"},
SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE},
SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER},
SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER},
@ -122,6 +167,30 @@ SENSOR_DEVICE_CLASS_ICON_MAP = {
SENSOR_YESTERDAY: {DEVICE_CLASS: DEVICE_CLASS_POWER},
}
SENSOR_UNIT_MAP = {
TASMOTA_CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
TASMOTA_CONCENTRATION_PARTS_PER_BILLION: CONCENTRATION_PARTS_PER_BILLION,
TASMOTA_CONCENTRATION_PARTS_PER_MILLION: CONCENTRATION_PARTS_PER_MILLION,
TASMOTA_ELECTRICAL_CURRENT_AMPERE: ELECTRICAL_CURRENT_AMPERE,
TASMOTA_ELECTRICAL_VOLT_AMPERE: ELECTRICAL_VOLT_AMPERE,
TASMOTA_ENERGY_KILO_WATT_HOUR: ENERGY_KILO_WATT_HOUR,
TASMOTA_FREQUENCY_HERTZ: FREQUENCY_HERTZ,
TASMOTA_LENGTH_CENTIMETERS: LENGTH_CENTIMETERS,
TASMOTA_LIGHT_LUX: LIGHT_LUX,
TASMOTA_MASS_KILOGRAMS: MASS_KILOGRAMS,
TASMOTA_PERCENTAGE: PERCENTAGE,
TASMOTA_POWER_WATT: POWER_WATT,
TASMOTA_PRESSURE_HPA: PRESSURE_HPA,
TASMOTA_SIGNAL_STRENGTH_DECIBELS: SIGNAL_STRENGTH_DECIBELS,
TASMOTA_SPEED_KILOMETERS_PER_HOUR: SPEED_KILOMETERS_PER_HOUR,
TASMOTA_SPEED_METERS_PER_SECOND: SPEED_METERS_PER_SECOND,
TASMOTA_SPEED_MILES_PER_HOUR: SPEED_MILES_PER_HOUR,
TASMOTA_TEMP_CELSIUS: TEMP_CELSIUS,
TASMOTA_TEMP_FAHRENHEIT: TEMP_FAHRENHEIT,
TASMOTA_TEMP_KELVIN: TEMP_KELVIN,
TASMOTA_VOLT: VOLT,
}
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Tasmota sensor dynamically through discovery."""
@ -190,9 +259,11 @@ class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, Entity):
@property
def state(self):
"""Return the state of the entity."""
if self._state and self.device_class == DEVICE_CLASS_TIMESTAMP:
return self._state.isoformat()
return self._state
@property
def unit_of_measurement(self):
"""Return the unit this state is expressed in."""
return self._tasmota_entity.unit
return SENSOR_UNIT_MAP.get(self._tasmota_entity.unit, self._tasmota_entity.unit)

View File

@ -741,7 +741,7 @@ hass-nabucasa==0.37.1
hass_splunk==0.1.1
# homeassistant.components.tasmota
hatasmota==0.0.27
hatasmota==0.0.29
# homeassistant.components.jewish_calendar
hdate==0.9.12

View File

@ -376,7 +376,7 @@ hangups==0.4.11
hass-nabucasa==0.37.1
# homeassistant.components.tasmota
hatasmota==0.0.27
hatasmota==0.0.29
# homeassistant.components.jewish_calendar
hdate==0.9.12

View File

@ -96,6 +96,54 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
assert state.state == STATE_OFF
async def test_pushon_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
"""Test state update via MQTT."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["swc"][0] = 13
mac = config["mac"]
async_fire_mqtt_message(
hass,
f"{DEFAULT_PREFIX}/{mac}/config",
json.dumps(config),
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test")
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("binary_sensor.test")
assert state.state == STATE_OFF
assert not state.attributes.get(ATTR_ASSUMED_STATE)
# Test normal state update
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"OFF"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_OFF
# Test periodic state update is ignored
async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/SENSOR", '{"Switch1":"ON"}')
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_OFF
# Test polled state update is ignored
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Switch1":"ON"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_OFF
async def test_friendly_names(hass, mqtt_mock, setup_tasmota):
"""Test state update via MQTT."""
config = copy.deepcopy(DEFAULT_CONFIG)

View File

@ -1,8 +1,10 @@
"""The tests for the Tasmota sensor platform."""
import copy
import datetime
from datetime import timedelta
import json
import hatasmota
from hatasmota.utils import (
get_topic_stat_status,
get_topic_tele_sensor,
@ -29,7 +31,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions,
)
from tests.async_mock import patch
from tests.async_mock import Mock, patch
from tests.common import async_fire_mqtt_message, async_fire_time_changed
DEFAULT_SENSOR_CONFIG = {
@ -259,6 +261,7 @@ async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
async_fire_mqtt_message(
hass, "tasmota_49A3BC/tele/STATE", '{"Wifi":{"Signal":20.5}}'
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "20.5"
@ -268,10 +271,142 @@ async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
"tasmota_49A3BC/stat/STATUS11",
'{"StatusSTS":{"Wifi":{"Signal":20.0}}}',
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "20.0"
@pytest.mark.parametrize("status_sensor_disabled", [False])
async def test_single_shot_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
"""Test state update via MQTT."""
entity_reg = await hass.helpers.entity_registry.async_get_registry()
# Pre-enable the status sensor
entity_reg.async_get_or_create(
sensor.DOMAIN,
"tasmota",
"00000049A3BC_status_sensor_status_sensor_status_restart_reason",
suggested_object_id="tasmota_status",
disabled_by=None,
)
config = copy.deepcopy(DEFAULT_CONFIG)
mac = config["mac"]
async_fire_mqtt_message(
hass,
f"{DEFAULT_PREFIX}/{mac}/config",
json.dumps(config),
)
await hass.async_block_till_done()
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
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.tasmota_status")
assert state.state == STATE_UNKNOWN
assert not state.attributes.get(ATTR_ASSUMED_STATE)
# Test polled state update
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS1",
'{"StatusPRM":{"RestartReason":"Some reason"}}',
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "Some reason"
# Test polled state update is ignored
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS1",
'{"StatusPRM":{"RestartReason":"Another reason"}}',
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "Some reason"
# Device signals online again
async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online")
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "Some reason"
# Test polled state update
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS1",
'{"StatusPRM":{"RestartReason":"Another reason"}}',
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "Another reason"
# Test polled state update is ignored
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS1",
'{"StatusPRM":{"RestartReason":"Third reason"}}',
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "Another reason"
@pytest.mark.parametrize("status_sensor_disabled", [False])
@patch.object(hatasmota.status_sensor, "datetime", Mock(wraps=datetime.datetime))
async def test_restart_time_status_sensor_state_via_mqtt(
hass, mqtt_mock, setup_tasmota
):
"""Test state update via MQTT."""
entity_reg = await hass.helpers.entity_registry.async_get_registry()
# Pre-enable the status sensor
entity_reg.async_get_or_create(
sensor.DOMAIN,
"tasmota",
"00000049A3BC_status_sensor_status_sensor_last_restart_time",
suggested_object_id="tasmota_status",
disabled_by=None,
)
config = copy.deepcopy(DEFAULT_CONFIG)
mac = config["mac"]
async_fire_mqtt_message(
hass,
f"{DEFAULT_PREFIX}/{mac}/config",
json.dumps(config),
)
await hass.async_block_till_done()
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
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.tasmota_status")
assert state.state == STATE_UNKNOWN
assert not state.attributes.get(ATTR_ASSUMED_STATE)
# Test polled state update
utc_now = datetime.datetime(2020, 11, 11, 8, 0, 0, tzinfo=dt.UTC)
hatasmota.status_sensor.datetime.now.return_value = utc_now
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS11",
'{"StatusSTS":{"UptimeSec":"3600"}}',
)
await hass.async_block_till_done()
state = hass.states.get("sensor.tasmota_status")
assert state.state == "2020-11-11T07:00:00+00:00"
async def test_attributes(hass, mqtt_mock, setup_tasmota):
"""Test correct attributes for sensors."""
config = copy.deepcopy(DEFAULT_CONFIG)
@ -301,7 +436,7 @@ async def test_attributes(hass, mqtt_mock, setup_tasmota):
assert state.attributes.get("device_class") == "temperature"
assert state.attributes.get("friendly_name") == "Tasmota DHT11 Temperature"
assert state.attributes.get("icon") is None
assert state.attributes.get("unit_of_measurement") == "C"
assert state.attributes.get("unit_of_measurement") == "°C"
state = hass.states.get("sensor.tasmota_beer_CarbonDioxide")
assert state.attributes.get("device_class") is None
@ -371,7 +506,7 @@ async def test_indexed_sensor_attributes(hass, mqtt_mock, setup_tasmota):
assert state.attributes.get("device_class") == "temperature"
assert state.attributes.get("friendly_name") == "Tasmota Dummy1 Temperature 0"
assert state.attributes.get("icon") is None
assert state.attributes.get("unit_of_measurement") == "C"
assert state.attributes.get("unit_of_measurement") == "°C"
state = hass.states.get("sensor.tasmota_dummy2_carbondioxide_1")
assert state.attributes.get("device_class") is None