Add Tasmota sensor (#41483)
* Add Tasmota sensor * Remove useless try-except * Bump hatasmota to 0.0.11 * Apply suggestions from code review Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> * Sort dict constants Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
59edb25e4e
commit
84cb00bb4e
7 changed files with 604 additions and 36 deletions
|
@ -11,7 +11,9 @@ from hatasmota.discovery import (
|
||||||
unique_id_from_hash,
|
unique_id_from_hash,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import homeassistant.components.sensor as sensor
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
from homeassistant.helpers.entity_registry import async_entries_for_device
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
@ -117,8 +119,38 @@ async def async_start(
|
||||||
for (tasmota_entity_config, discovery_hash) in tasmota_entities:
|
for (tasmota_entity_config, discovery_hash) in tasmota_entities:
|
||||||
await _discover_entity(tasmota_entity_config, discovery_hash, platform)
|
await _discover_entity(tasmota_entity_config, discovery_hash, platform)
|
||||||
|
|
||||||
|
async def async_sensors_discovered(sensors, mac):
|
||||||
|
"""Handle discovery of (additional) sensors."""
|
||||||
|
platform = sensor.DOMAIN
|
||||||
|
await _load_platform(platform)
|
||||||
|
|
||||||
|
device_registry = await hass.helpers.device_registry.async_get_registry()
|
||||||
|
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
device = device_registry.async_get_device(set(), {("mac", mac)})
|
||||||
|
|
||||||
|
if device is None:
|
||||||
|
_LOGGER.warning("Got sensors for unknown device mac: %s", mac)
|
||||||
|
return
|
||||||
|
|
||||||
|
orphaned_entities = {
|
||||||
|
entry.unique_id
|
||||||
|
for entry in async_entries_for_device(entity_registry, device.id)
|
||||||
|
if entry.domain == sensor.DOMAIN and entry.platform == DOMAIN
|
||||||
|
}
|
||||||
|
for (tasmota_sensor_config, discovery_hash) in sensors:
|
||||||
|
if tasmota_sensor_config:
|
||||||
|
orphaned_entities.discard(tasmota_sensor_config.unique_id)
|
||||||
|
await _discover_entity(tasmota_sensor_config, discovery_hash, platform)
|
||||||
|
for unique_id in orphaned_entities:
|
||||||
|
entity_id = entity_registry.async_get_entity_id(platform, DOMAIN, unique_id)
|
||||||
|
if entity_id:
|
||||||
|
_LOGGER.debug("Removing entity: %s %s", platform, entity_id)
|
||||||
|
entity_registry.async_remove(entity_id)
|
||||||
|
|
||||||
hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock()
|
hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock()
|
||||||
hass.data[CONFIG_ENTRY_IS_SETUP] = set()
|
hass.data[CONFIG_ENTRY_IS_SETUP] = set()
|
||||||
|
|
||||||
tasmota_discovery = TasmotaDiscovery(discovery_topic, tasmota_mqtt)
|
tasmota_discovery = TasmotaDiscovery(discovery_topic, tasmota_mqtt)
|
||||||
await tasmota_discovery.start_discovery(async_device_discovered, None)
|
await tasmota_discovery.start_discovery(
|
||||||
|
async_device_discovered, async_sensors_discovered
|
||||||
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Tasmota (beta)",
|
"name": "Tasmota (beta)",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/tasmota",
|
"documentation": "https://www.home-assistant.io/integrations/tasmota",
|
||||||
"requirements": ["hatasmota==0.0.10"],
|
"requirements": ["hatasmota==0.0.11"],
|
||||||
"dependencies": ["mqtt"],
|
"dependencies": ["mqtt"],
|
||||||
"mqtt": ["tasmota/discovery/#"],
|
"mqtt": ["tasmota/discovery/#"],
|
||||||
"codeowners": ["@emontnemery"]
|
"codeowners": ["@emontnemery"]
|
||||||
|
|
161
homeassistant/components/tasmota/sensor.py
Normal file
161
homeassistant/components/tasmota/sensor.py
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
"""Support for Tasmota sensors."""
|
||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from hatasmota.const import (
|
||||||
|
SENSOR_AMBIENT,
|
||||||
|
SENSOR_APPARENT_POWERUSAGE,
|
||||||
|
SENSOR_BATTERY,
|
||||||
|
SENSOR_CCT,
|
||||||
|
SENSOR_CO2,
|
||||||
|
SENSOR_COLOR_BLUE,
|
||||||
|
SENSOR_COLOR_GREEN,
|
||||||
|
SENSOR_COLOR_RED,
|
||||||
|
SENSOR_CURRENT,
|
||||||
|
SENSOR_DEWPOINT,
|
||||||
|
SENSOR_DISTANCE,
|
||||||
|
SENSOR_ECO2,
|
||||||
|
SENSOR_FREQUENCY,
|
||||||
|
SENSOR_HUMIDITY,
|
||||||
|
SENSOR_ILLUMINANCE,
|
||||||
|
SENSOR_MOISTURE,
|
||||||
|
SENSOR_PB0_3,
|
||||||
|
SENSOR_PB0_5,
|
||||||
|
SENSOR_PB1,
|
||||||
|
SENSOR_PB2_5,
|
||||||
|
SENSOR_PB5,
|
||||||
|
SENSOR_PB10,
|
||||||
|
SENSOR_PM1,
|
||||||
|
SENSOR_PM2_5,
|
||||||
|
SENSOR_PM10,
|
||||||
|
SENSOR_POWERFACTOR,
|
||||||
|
SENSOR_POWERUSAGE,
|
||||||
|
SENSOR_PRESSURE,
|
||||||
|
SENSOR_PRESSUREATSEALEVEL,
|
||||||
|
SENSOR_PROXIMITY,
|
||||||
|
SENSOR_REACTIVE_POWERUSAGE,
|
||||||
|
SENSOR_TEMPERATURE,
|
||||||
|
SENSOR_TODAY,
|
||||||
|
SENSOR_TOTAL,
|
||||||
|
SENSOR_TOTAL_START_TIME,
|
||||||
|
SENSOR_TVOC,
|
||||||
|
SENSOR_VOLTAGE,
|
||||||
|
SENSOR_WEIGHT,
|
||||||
|
SENSOR_YESTERDAY,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components import sensor
|
||||||
|
from homeassistant.const import (
|
||||||
|
DEVICE_CLASS_BATTERY,
|
||||||
|
DEVICE_CLASS_HUMIDITY,
|
||||||
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
|
DEVICE_CLASS_PRESSURE,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from .const import DOMAIN as TASMOTA_DOMAIN
|
||||||
|
from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW
|
||||||
|
from .mixins import TasmotaAvailability, TasmotaDiscoveryUpdate
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SENSOR_DEVICE_CLASS_MAP = {
|
||||||
|
SENSOR_AMBIENT: DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
SENSOR_APPARENT_POWERUSAGE: DEVICE_CLASS_POWER,
|
||||||
|
SENSOR_BATTERY: DEVICE_CLASS_BATTERY,
|
||||||
|
SENSOR_HUMIDITY: DEVICE_CLASS_HUMIDITY,
|
||||||
|
SENSOR_ILLUMINANCE: DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
SENSOR_POWERUSAGE: DEVICE_CLASS_POWER,
|
||||||
|
SENSOR_PRESSURE: DEVICE_CLASS_PRESSURE,
|
||||||
|
SENSOR_PRESSUREATSEALEVEL: DEVICE_CLASS_PRESSURE,
|
||||||
|
SENSOR_REACTIVE_POWERUSAGE: DEVICE_CLASS_POWER,
|
||||||
|
SENSOR_TEMPERATURE: DEVICE_CLASS_TEMPERATURE,
|
||||||
|
SENSOR_TODAY: DEVICE_CLASS_POWER,
|
||||||
|
SENSOR_TOTAL: DEVICE_CLASS_POWER,
|
||||||
|
SENSOR_YESTERDAY: DEVICE_CLASS_POWER,
|
||||||
|
}
|
||||||
|
|
||||||
|
SENSOR_ICON_MAP = {
|
||||||
|
SENSOR_CCT: "mdi:temperature-kelvin",
|
||||||
|
SENSOR_CO2: "mdi:molecule-co2",
|
||||||
|
SENSOR_COLOR_BLUE: "mdi:palette",
|
||||||
|
SENSOR_COLOR_GREEN: "mdi:palette",
|
||||||
|
SENSOR_COLOR_RED: "mdi:palette",
|
||||||
|
SENSOR_CURRENT: "mdi:alpha-a-circle-outline",
|
||||||
|
SENSOR_DEWPOINT: "mdi:weather-rainy",
|
||||||
|
SENSOR_DISTANCE: "mdi:leak",
|
||||||
|
SENSOR_ECO2: "mdi:molecule-co2",
|
||||||
|
SENSOR_FREQUENCY: "mdi:current-ac",
|
||||||
|
SENSOR_MOISTURE: "mdi:cup-water",
|
||||||
|
SENSOR_PB0_3: "mdi:flask",
|
||||||
|
SENSOR_PB0_5: "mdi:flask",
|
||||||
|
SENSOR_PB10: "mdi:flask",
|
||||||
|
SENSOR_PB1: "mdi:flask",
|
||||||
|
SENSOR_PB2_5: "mdi:flask",
|
||||||
|
SENSOR_PB5: "mdi:flask",
|
||||||
|
SENSOR_PM10: "mdi:air-filter",
|
||||||
|
SENSOR_PM1: "mdi:air-filter",
|
||||||
|
SENSOR_PM2_5: "mdi:air-filter",
|
||||||
|
SENSOR_POWERFACTOR: "mdi:alpha-f-circle-outline",
|
||||||
|
SENSOR_PROXIMITY: "mdi:ruler",
|
||||||
|
SENSOR_TOTAL_START_TIME: "mdi:progress-clock",
|
||||||
|
SENSOR_TVOC: "mdi:air-filter",
|
||||||
|
SENSOR_VOLTAGE: "mdi:alpha-v-circle-outline",
|
||||||
|
SENSOR_WEIGHT: "mdi:scale",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
"""Set up Tasmota sensor dynamically through discovery."""
|
||||||
|
|
||||||
|
async def async_discover_sensor(tasmota_entity, discovery_hash):
|
||||||
|
"""Discover and add a Tasmota sensor."""
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
TasmotaSensor(
|
||||||
|
tasmota_entity=tasmota_entity, discovery_hash=discovery_hash
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
async_dispatcher_connect(
|
||||||
|
hass,
|
||||||
|
TASMOTA_DISCOVERY_ENTITY_NEW.format(sensor.DOMAIN, TASMOTA_DOMAIN),
|
||||||
|
async_discover_sensor,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, Entity):
|
||||||
|
"""Representation of a Tasmota sensor."""
|
||||||
|
|
||||||
|
def __init__(self, **kwds):
|
||||||
|
"""Initialize the Tasmota sensor."""
|
||||||
|
self._state = False
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
discovery_update=self.discovery_update,
|
||||||
|
**kwds,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self) -> Optional[str]:
|
||||||
|
"""Return the device class of the sensor."""
|
||||||
|
return SENSOR_DEVICE_CLASS_MAP.get(self._tasmota_entity.quantity)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Return the icon."""
|
||||||
|
return SENSOR_ICON_MAP.get(self._tasmota_entity.quantity)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state of the entity."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return the unit this state is expressed in."""
|
||||||
|
return self._tasmota_entity.unit
|
|
@ -729,7 +729,7 @@ hass-nabucasa==0.37.0
|
||||||
hass_splunk==0.1.1
|
hass_splunk==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.tasmota
|
# homeassistant.components.tasmota
|
||||||
hatasmota==0.0.10
|
hatasmota==0.0.11
|
||||||
|
|
||||||
# homeassistant.components.jewish_calendar
|
# homeassistant.components.jewish_calendar
|
||||||
hdate==0.9.5
|
hdate==0.9.5
|
||||||
|
|
|
@ -361,7 +361,7 @@ hangups==0.4.11
|
||||||
hass-nabucasa==0.37.0
|
hass-nabucasa==0.37.0
|
||||||
|
|
||||||
# homeassistant.components.tasmota
|
# homeassistant.components.tasmota
|
||||||
hatasmota==0.0.10
|
hatasmota==0.0.11
|
||||||
|
|
||||||
# homeassistant.components.jewish_calendar
|
# homeassistant.components.jewish_calendar
|
||||||
hdate==0.9.5
|
hdate==0.9.5
|
||||||
|
|
|
@ -57,7 +57,13 @@ DEFAULT_CONFIG = {
|
||||||
|
|
||||||
|
|
||||||
async def help_test_availability_when_connection_lost(
|
async def help_test_availability_when_connection_lost(
|
||||||
hass, mqtt_client_mock, mqtt_mock, domain, config
|
hass,
|
||||||
|
mqtt_client_mock,
|
||||||
|
mqtt_mock,
|
||||||
|
domain,
|
||||||
|
config,
|
||||||
|
sensor_config=None,
|
||||||
|
entity_id="test",
|
||||||
):
|
):
|
||||||
"""Test availability after MQTT disconnection.
|
"""Test availability after MQTT disconnection.
|
||||||
|
|
||||||
|
@ -69,6 +75,13 @@ async def help_test_availability_when_connection_lost(
|
||||||
json.dumps(config),
|
json.dumps(config),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Device online
|
# Device online
|
||||||
async_fire_mqtt_message(
|
async_fire_mqtt_message(
|
||||||
|
@ -76,7 +89,8 @@ async def help_test_availability_when_connection_lost(
|
||||||
get_topic_tele_will(config),
|
get_topic_tele_will(config),
|
||||||
config_get_state_online(config),
|
config_get_state_online(config),
|
||||||
)
|
)
|
||||||
state = hass.states.get(f"{domain}.test")
|
|
||||||
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Disconnected from MQTT server -> state changed to unavailable
|
# Disconnected from MQTT server -> state changed to unavailable
|
||||||
|
@ -85,7 +99,7 @@ async def help_test_availability_when_connection_lost(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Reconnected to MQTT server -> state still unavailable
|
# Reconnected to MQTT server -> state still unavailable
|
||||||
|
@ -94,7 +108,7 @@ async def help_test_availability_when_connection_lost(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Receive LWT again
|
# Receive LWT again
|
||||||
|
@ -103,7 +117,7 @@ async def help_test_availability_when_connection_lost(
|
||||||
get_topic_tele_will(config),
|
get_topic_tele_will(config),
|
||||||
config_get_state_online(config),
|
config_get_state_online(config),
|
||||||
)
|
)
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,6 +126,8 @@ async def help_test_availability(
|
||||||
mqtt_mock,
|
mqtt_mock,
|
||||||
domain,
|
domain,
|
||||||
config,
|
config,
|
||||||
|
sensor_config=None,
|
||||||
|
entity_id="test",
|
||||||
):
|
):
|
||||||
"""Test availability.
|
"""Test availability.
|
||||||
|
|
||||||
|
@ -123,8 +139,15 @@ async def help_test_availability(
|
||||||
json.dumps(config),
|
json.dumps(config),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
async_fire_mqtt_message(
|
async_fire_mqtt_message(
|
||||||
|
@ -133,7 +156,7 @@ async def help_test_availability(
|
||||||
config_get_state_online(config),
|
config_get_state_online(config),
|
||||||
)
|
)
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
async_fire_mqtt_message(
|
async_fire_mqtt_message(
|
||||||
|
@ -142,7 +165,7 @@ async def help_test_availability(
|
||||||
config_get_state_offline(config),
|
config_get_state_offline(config),
|
||||||
)
|
)
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,6 +174,8 @@ async def help_test_availability_discovery_update(
|
||||||
mqtt_mock,
|
mqtt_mock,
|
||||||
domain,
|
domain,
|
||||||
config,
|
config,
|
||||||
|
sensor_config=None,
|
||||||
|
entity_id="test",
|
||||||
):
|
):
|
||||||
"""Test update of discovered TasmotaAvailability.
|
"""Test update of discovered TasmotaAvailability.
|
||||||
|
|
||||||
|
@ -180,16 +205,23 @@ async def help_test_availability_discovery_update(
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config1[CONF_MAC]}/config", data1)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config1[CONF_MAC]}/config", data1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, availability_topic1, online1)
|
async_fire_mqtt_message(hass, availability_topic1, online1)
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, availability_topic1, offline1)
|
async_fire_mqtt_message(hass, availability_topic1, offline1)
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Change availability settings
|
# Change availability settings
|
||||||
|
@ -200,17 +232,24 @@ async def help_test_availability_discovery_update(
|
||||||
async_fire_mqtt_message(hass, availability_topic1, online1)
|
async_fire_mqtt_message(hass, availability_topic1, online1)
|
||||||
async_fire_mqtt_message(hass, availability_topic1, online2)
|
async_fire_mqtt_message(hass, availability_topic1, online2)
|
||||||
async_fire_mqtt_message(hass, availability_topic2, online1)
|
async_fire_mqtt_message(hass, availability_topic2, online1)
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Verify we are subscribing to the new topic
|
# Verify we are subscribing to the new topic
|
||||||
async_fire_mqtt_message(hass, availability_topic2, online2)
|
async_fire_mqtt_message(hass, availability_topic2, online2)
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
async def help_test_availability_poll_state(
|
async def help_test_availability_poll_state(
|
||||||
hass, mqtt_client_mock, mqtt_mock, domain, config, poll_topic, poll_payload
|
hass,
|
||||||
|
mqtt_client_mock,
|
||||||
|
mqtt_mock,
|
||||||
|
domain,
|
||||||
|
config,
|
||||||
|
poll_topic,
|
||||||
|
poll_payload,
|
||||||
|
sensor_config=None,
|
||||||
):
|
):
|
||||||
"""Test polling of state when device is available.
|
"""Test polling of state when device is available.
|
||||||
|
|
||||||
|
@ -222,6 +261,13 @@ async def help_test_availability_poll_state(
|
||||||
json.dumps(config),
|
json.dumps(config),
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
mqtt_mock.async_publish.reset_mock()
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
|
||||||
# Device online, verify poll for state
|
# Device online, verify poll for state
|
||||||
|
@ -265,7 +311,16 @@ async def help_test_availability_poll_state(
|
||||||
|
|
||||||
|
|
||||||
async def help_test_discovery_removal(
|
async def help_test_discovery_removal(
|
||||||
hass, mqtt_mock, caplog, domain, config1, config2
|
hass,
|
||||||
|
mqtt_mock,
|
||||||
|
caplog,
|
||||||
|
domain,
|
||||||
|
config1,
|
||||||
|
config2,
|
||||||
|
sensor_config1=None,
|
||||||
|
sensor_config2=None,
|
||||||
|
entity_id="test",
|
||||||
|
name="Test",
|
||||||
):
|
):
|
||||||
"""Test removal of discovered entity."""
|
"""Test removal of discovered entity."""
|
||||||
device_reg = await hass.helpers.device_registry.async_get_registry()
|
device_reg = await hass.helpers.device_registry.async_get_registry()
|
||||||
|
@ -277,34 +332,56 @@ async def help_test_discovery_removal(
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config1[CONF_MAC]}/config", data1)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config1[CONF_MAC]}/config", data1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config1:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config1[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config1),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Verify device and entity registry entries are created
|
# Verify device and entity registry entries are created
|
||||||
device_entry = device_reg.async_get_device(set(), {("mac", config1[CONF_MAC])})
|
device_entry = device_reg.async_get_device(set(), {("mac", config1[CONF_MAC])})
|
||||||
assert device_entry is not None
|
assert device_entry is not None
|
||||||
entity_entry = entity_reg.async_get(f"{domain}.test")
|
entity_entry = entity_reg.async_get(f"{domain}.{entity_id}")
|
||||||
assert entity_entry is not None
|
assert entity_entry is not None
|
||||||
|
|
||||||
# Verify state is added
|
# Verify state is added
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.name == "Test"
|
assert state.name == name
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config2[CONF_MAC]}/config", data2)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config2[CONF_MAC]}/config", data2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config1:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config2[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config2),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Verify entity registry entries are cleared
|
# Verify entity registry entries are cleared
|
||||||
device_entry = device_reg.async_get_device(set(), {("mac", config2[CONF_MAC])})
|
device_entry = device_reg.async_get_device(set(), {("mac", config2[CONF_MAC])})
|
||||||
assert device_entry is not None
|
assert device_entry is not None
|
||||||
entity_entry = entity_reg.async_get(f"{domain}.test")
|
entity_entry = entity_reg.async_get(f"{domain}.{entity_id}")
|
||||||
assert entity_entry is None
|
assert entity_entry is None
|
||||||
|
|
||||||
# Verify state is removed
|
# Verify state is removed
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state is None
|
assert state is None
|
||||||
|
|
||||||
|
|
||||||
async def help_test_discovery_update_unchanged(
|
async def help_test_discovery_update_unchanged(
|
||||||
hass, mqtt_mock, caplog, domain, config, discovery_update
|
hass,
|
||||||
|
mqtt_mock,
|
||||||
|
caplog,
|
||||||
|
domain,
|
||||||
|
config,
|
||||||
|
discovery_update,
|
||||||
|
sensor_config=None,
|
||||||
|
entity_id="test",
|
||||||
|
name="Test",
|
||||||
):
|
):
|
||||||
"""Test update of discovered component without changes.
|
"""Test update of discovered component without changes.
|
||||||
|
|
||||||
|
@ -313,18 +390,33 @@ async def help_test_discovery_update_unchanged(
|
||||||
config1 = copy.deepcopy(config)
|
config1 = copy.deepcopy(config)
|
||||||
config2 = copy.deepcopy(config)
|
config2 = copy.deepcopy(config)
|
||||||
config2[CONF_PREFIX][PREFIX_CMND] = "cmnd2"
|
config2[CONF_PREFIX][PREFIX_CMND] = "cmnd2"
|
||||||
|
config2[CONF_PREFIX][PREFIX_TELE] = "tele2"
|
||||||
data1 = json.dumps(config1)
|
data1 = json.dumps(config1)
|
||||||
data2 = json.dumps(config2)
|
data2 = json.dumps(config2)
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data1)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.name == "Test"
|
assert state.name == name
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data1)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert not discovery_update.called
|
assert not discovery_update.called
|
||||||
|
|
||||||
|
@ -334,7 +426,9 @@ async def help_test_discovery_update_unchanged(
|
||||||
assert discovery_update.called
|
assert discovery_update.called
|
||||||
|
|
||||||
|
|
||||||
async def help_test_discovery_device_remove(hass, mqtt_mock, domain, unique_id, config):
|
async def help_test_discovery_device_remove(
|
||||||
|
hass, mqtt_mock, domain, unique_id, config, sensor_config=None
|
||||||
|
):
|
||||||
"""Test domain entity is removed when device is removed."""
|
"""Test domain entity is removed when device is removed."""
|
||||||
device_reg = await hass.helpers.device_registry.async_get_registry()
|
device_reg = await hass.helpers.device_registry.async_get_registry()
|
||||||
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
@ -344,6 +438,13 @@ async def help_test_discovery_device_remove(hass, mqtt_mock, domain, unique_id,
|
||||||
data = json.dumps(config)
|
data = json.dumps(config)
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
device = device_reg.async_get_device(set(), {("mac", config[CONF_MAC])})
|
device = device_reg.async_get_device(set(), {("mac", config[CONF_MAC])})
|
||||||
assert device is not None
|
assert device is not None
|
||||||
|
@ -358,7 +459,7 @@ async def help_test_discovery_device_remove(hass, mqtt_mock, domain, unique_id,
|
||||||
|
|
||||||
|
|
||||||
async def help_test_entity_id_update_subscriptions(
|
async def help_test_entity_id_update_subscriptions(
|
||||||
hass, mqtt_mock, domain, config, topics=None
|
hass, mqtt_mock, domain, config, topics=None, sensor_config=None, entity_id="test"
|
||||||
):
|
):
|
||||||
"""Test MQTT subscriptions are managed when entity_id is updated."""
|
"""Test MQTT subscriptions are managed when entity_id is updated."""
|
||||||
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
@ -370,22 +471,31 @@ async def help_test_entity_id_update_subscriptions(
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
if not topics:
|
if not topics:
|
||||||
topics = [get_topic_tele_state(config), get_topic_tele_will(config)]
|
topics = [get_topic_tele_state(config), get_topic_tele_will(config)]
|
||||||
assert len(topics) > 0
|
assert len(topics) > 0
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert mqtt_mock.async_subscribe.call_count == len(topics)
|
assert mqtt_mock.async_subscribe.call_count == len(topics)
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
mqtt_mock.async_subscribe.assert_any_call(topic, ANY, ANY, ANY)
|
mqtt_mock.async_subscribe.assert_any_call(topic, ANY, ANY, ANY)
|
||||||
mqtt_mock.async_subscribe.reset_mock()
|
mqtt_mock.async_subscribe.reset_mock()
|
||||||
|
|
||||||
entity_reg.async_update_entity(f"{domain}.test", new_entity_id=f"{domain}.milk")
|
entity_reg.async_update_entity(
|
||||||
|
f"{domain}.{entity_id}", new_entity_id=f"{domain}.milk"
|
||||||
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state is None
|
assert state is None
|
||||||
|
|
||||||
state = hass.states.get(f"{domain}.milk")
|
state = hass.states.get(f"{domain}.milk")
|
||||||
|
@ -394,7 +504,9 @@ async def help_test_entity_id_update_subscriptions(
|
||||||
mqtt_mock.async_subscribe.assert_any_call(topic, ANY, ANY, ANY)
|
mqtt_mock.async_subscribe.assert_any_call(topic, ANY, ANY, ANY)
|
||||||
|
|
||||||
|
|
||||||
async def help_test_entity_id_update_discovery_update(hass, mqtt_mock, domain, config):
|
async def help_test_entity_id_update_discovery_update(
|
||||||
|
hass, mqtt_mock, domain, config, sensor_config=None, entity_id="test"
|
||||||
|
):
|
||||||
"""Test MQTT discovery update after entity_id is updated."""
|
"""Test MQTT discovery update after entity_id is updated."""
|
||||||
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
|
||||||
|
@ -405,16 +517,25 @@ async def help_test_entity_id_update_discovery_update(hass, mqtt_mock, domain, c
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data)
|
async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/config", data)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
if sensor_config:
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
f"{DEFAULT_PREFIX}/{config[CONF_MAC]}/sensors",
|
||||||
|
json.dumps(sensor_config),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, topic, config_get_state_online(config))
|
async_fire_mqtt_message(hass, topic, config_get_state_online(config))
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, topic, config_get_state_offline(config))
|
async_fire_mqtt_message(hass, topic, config_get_state_offline(config))
|
||||||
state = hass.states.get(f"{domain}.test")
|
state = hass.states.get(f"{domain}.{entity_id}")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
entity_reg.async_update_entity(f"{domain}.test", new_entity_id=f"{domain}.milk")
|
entity_reg.async_update_entity(
|
||||||
|
f"{domain}.{entity_id}", new_entity_id=f"{domain}.milk"
|
||||||
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(f"{domain}.milk")
|
assert hass.states.get(f"{domain}.milk")
|
||||||
|
|
||||||
|
|
254
tests/components/tasmota/test_sensor.py
Normal file
254
tests/components/tasmota/test_sensor.py
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
"""The tests for the Tasmota sensor platform."""
|
||||||
|
import copy
|
||||||
|
import json
|
||||||
|
|
||||||
|
from hatasmota.utils import (
|
||||||
|
get_topic_stat_status,
|
||||||
|
get_topic_tele_sensor,
|
||||||
|
get_topic_tele_will,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components import sensor
|
||||||
|
from homeassistant.components.tasmota.const import DEFAULT_PREFIX
|
||||||
|
from homeassistant.const import ATTR_ASSUMED_STATE, STATE_UNKNOWN
|
||||||
|
|
||||||
|
from .test_common import (
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
help_test_availability,
|
||||||
|
help_test_availability_discovery_update,
|
||||||
|
help_test_availability_poll_state,
|
||||||
|
help_test_availability_when_connection_lost,
|
||||||
|
help_test_discovery_device_remove,
|
||||||
|
help_test_discovery_removal,
|
||||||
|
help_test_discovery_update_unchanged,
|
||||||
|
help_test_entity_id_update_discovery_update,
|
||||||
|
help_test_entity_id_update_subscriptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.async_mock import patch
|
||||||
|
from tests.common import async_fire_mqtt_message
|
||||||
|
|
||||||
|
DEFAULT_SENSOR_CONFIG = {
|
||||||
|
"sn": {
|
||||||
|
"Time": "2020-09-25T12:47:15",
|
||||||
|
"DHT11": {"Temperature": None},
|
||||||
|
"TempUnit": "C",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test state update via MQTT."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_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.dht11_temperature")
|
||||||
|
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.dht11_temperature")
|
||||||
|
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", '{"DHT11":{"Temperature":20.5}}'
|
||||||
|
)
|
||||||
|
state = hass.states.get("sensor.dht11_temperature")
|
||||||
|
assert state.state == "20.5"
|
||||||
|
|
||||||
|
# Test polled state update
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"tasmota_49A3BC/stat/STATUS8",
|
||||||
|
'{"StatusSNS":{"DHT11":{"Temperature":20.0}}}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("sensor.dht11_temperature")
|
||||||
|
assert state.state == "20.0"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_attributes(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test correct attributes for sensors."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = {
|
||||||
|
"sn": {
|
||||||
|
"DHT11": {"Temperature": None},
|
||||||
|
"Beer": {"CarbonDioxide": 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.dht11_temperature")
|
||||||
|
assert state.attributes.get("device_class") == "temperature"
|
||||||
|
assert state.attributes.get("friendly_name") == "DHT11 Temperature"
|
||||||
|
assert state.attributes.get("icon") is None
|
||||||
|
assert state.attributes.get("unit_of_measurement") == "C"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.beer_CarbonDioxide")
|
||||||
|
assert state.attributes.get("device_class") is None
|
||||||
|
assert state.attributes.get("friendly_name") == "Beer CarbonDioxide"
|
||||||
|
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
|
||||||
|
):
|
||||||
|
"""Test availability after MQTT disconnection."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
await help_test_availability_when_connection_lost(
|
||||||
|
hass,
|
||||||
|
mqtt_client_mock,
|
||||||
|
mqtt_mock,
|
||||||
|
sensor.DOMAIN,
|
||||||
|
config,
|
||||||
|
sensor_config,
|
||||||
|
"dht11_temperature",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_availability(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test availability."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
await help_test_availability(
|
||||||
|
hass, mqtt_mock, sensor.DOMAIN, config, sensor_config, "dht11_temperature"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_availability_discovery_update(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test availability discovery update."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
await help_test_availability_discovery_update(
|
||||||
|
hass, mqtt_mock, sensor.DOMAIN, config, sensor_config, "dht11_temperature"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_availability_poll_state(
|
||||||
|
hass, mqtt_client_mock, mqtt_mock, setup_tasmota
|
||||||
|
):
|
||||||
|
"""Test polling after MQTT connection (re)established."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
poll_topic = "tasmota_49A3BC/cmnd/STATUS"
|
||||||
|
await help_test_availability_poll_state(
|
||||||
|
hass,
|
||||||
|
mqtt_client_mock,
|
||||||
|
mqtt_mock,
|
||||||
|
sensor.DOMAIN,
|
||||||
|
config,
|
||||||
|
poll_topic,
|
||||||
|
"8",
|
||||||
|
sensor_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_removal_sensor(hass, mqtt_mock, caplog, setup_tasmota):
|
||||||
|
"""Test removal of discovered sensor."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config1 = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
|
||||||
|
await help_test_discovery_removal(
|
||||||
|
hass,
|
||||||
|
mqtt_mock,
|
||||||
|
caplog,
|
||||||
|
sensor.DOMAIN,
|
||||||
|
config,
|
||||||
|
config,
|
||||||
|
sensor_config1,
|
||||||
|
{},
|
||||||
|
"dht11_temperature",
|
||||||
|
"DHT11 Temperature",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_update_unchanged_sensor(
|
||||||
|
hass, mqtt_mock, caplog, setup_tasmota
|
||||||
|
):
|
||||||
|
"""Test update of discovered sensor."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.tasmota.sensor.TasmotaSensor.discovery_update"
|
||||||
|
) as discovery_update:
|
||||||
|
await help_test_discovery_update_unchanged(
|
||||||
|
hass,
|
||||||
|
mqtt_mock,
|
||||||
|
caplog,
|
||||||
|
sensor.DOMAIN,
|
||||||
|
config,
|
||||||
|
discovery_update,
|
||||||
|
sensor_config,
|
||||||
|
"dht11_temperature",
|
||||||
|
"DHT11 Temperature",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_device_remove(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test device registry remove."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
unique_id = f"{DEFAULT_CONFIG['mac']}_sensor_sensor_DHT11_Temperature"
|
||||||
|
await help_test_discovery_device_remove(
|
||||||
|
hass, mqtt_mock, sensor.DOMAIN, unique_id, config, sensor_config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_entity_id_update_subscriptions(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test MQTT subscriptions are managed when entity_id is updated."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
topics = [
|
||||||
|
get_topic_tele_sensor(config),
|
||||||
|
get_topic_stat_status(config, 8),
|
||||||
|
get_topic_tele_will(config),
|
||||||
|
]
|
||||||
|
await help_test_entity_id_update_subscriptions(
|
||||||
|
hass,
|
||||||
|
mqtt_mock,
|
||||||
|
sensor.DOMAIN,
|
||||||
|
config,
|
||||||
|
topics,
|
||||||
|
sensor_config,
|
||||||
|
"dht11_temperature",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_entity_id_update_discovery_update(hass, mqtt_mock, setup_tasmota):
|
||||||
|
"""Test MQTT discovery update when entity_id is updated."""
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG)
|
||||||
|
await help_test_entity_id_update_discovery_update(
|
||||||
|
hass, mqtt_mock, sensor.DOMAIN, config, sensor_config, "dht11_temperature"
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue