mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 09:47:52 +00:00
Bump hatasmota to 0.0.29 (#43013)
This commit is contained in:
parent
621a0a5dd2
commit
8cc7069323
@ -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"]
|
||||
|
@ -95,7 +95,6 @@ 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._available = available
|
||||
self.async_write_ha_state()
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user