Merge pull request #50417 from home-assistant/rc

This commit is contained in:
Paulus Schoutsen 2021-05-10 13:58:00 -07:00 committed by GitHub
commit 5aaead54da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 216 additions and 81 deletions

View File

@ -201,11 +201,15 @@ def _monitor_events(hass, name, api, event_codes):
while True: while True:
api.available_flag.wait() api.available_flag.wait()
try: try:
for code, start in api.event_actions("All", retries=5): for code, payload in api.event_actions("All", retries=5):
event_data = {"camera": name, "event": code, "payload": start} event_data = {"camera": name, "event": code, "payload": payload}
hass.bus.fire("amcrest", event_data) hass.bus.fire("amcrest", event_data)
if code in event_codes: if code in event_codes:
signal = service_signal(SERVICE_EVENT, name, code) signal = service_signal(SERVICE_EVENT, name, code)
start = any(
str(key).lower() == "action" and str(val).lower() == "start"
for key, val in payload.items()
)
_LOGGER.debug("Sending signal: '%s': %s", signal, start) _LOGGER.debug("Sending signal: '%s': %s", signal, start)
dispatcher_send(hass, signal, start) dispatcher_send(hass, signal, start)
except AmcrestError as error: except AmcrestError as error:

View File

@ -4,7 +4,7 @@
"documentation": "https://www.home-assistant.io/integrations/androidtv", "documentation": "https://www.home-assistant.io/integrations/androidtv",
"requirements": [ "requirements": [
"adb-shell[async]==0.3.1", "adb-shell[async]==0.3.1",
"androidtv[async]==0.0.58", "androidtv[async]==0.0.59",
"pure-python-adb[async]==0.3.0.dev0" "pure-python-adb[async]==0.3.0.dev0"
], ],
"codeowners": ["@JeffLIrion"], "codeowners": ["@JeffLIrion"],

View File

@ -3,7 +3,7 @@
"name": "Denon AVR Network Receivers", "name": "Denon AVR Network Receivers",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/denonavr", "documentation": "https://www.home-assistant.io/integrations/denonavr",
"requirements": ["denonavr==0.10.6"], "requirements": ["denonavr==0.10.7"],
"codeowners": ["@scarface-4711", "@starkillerOG"], "codeowners": ["@scarface-4711", "@starkillerOG"],
"ssdp": [ "ssdp": [
{ {

View File

@ -6,10 +6,15 @@ import math
from aioesphomeapi import SensorInfo, SensorState, TextSensorInfo, TextSensorState from aioesphomeapi import SensorInfo, SensorState, TextSensorInfo, TextSensorState
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import DEVICE_CLASSES, SensorEntity from homeassistant.components.sensor import (
DEVICE_CLASS_TIMESTAMP,
DEVICE_CLASSES,
SensorEntity,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util import dt
from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry
@ -74,6 +79,8 @@ class EsphomeSensor(EsphomeEntity, SensorEntity):
return None return None
if self._state.missing_state: if self._state.missing_state:
return None return None
if self.device_class == DEVICE_CLASS_TIMESTAMP:
return dt.utc_from_timestamp(self._state.state).isoformat()
return f"{self._state.state:.{self._static_info.accuracy_decimals}f}" return f"{self._state.state:.{self._static_info.accuracy_decimals}f}"
@property @property

View File

@ -393,26 +393,29 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
router.subscriptions.clear() router.subscriptions.clear()
# Set up device registry # Set up device registry
device_data = {} if router.device_identifiers or router.device_connections:
sw_version = None device_data = {}
if router.data.get(KEY_DEVICE_INFORMATION): sw_version = None
device_info = router.data[KEY_DEVICE_INFORMATION] if router.data.get(KEY_DEVICE_INFORMATION):
sw_version = device_info.get("SoftwareVersion") device_info = router.data[KEY_DEVICE_INFORMATION]
if device_info.get("DeviceName"): sw_version = device_info.get("SoftwareVersion")
device_data["model"] = device_info["DeviceName"] if device_info.get("DeviceName"):
if not sw_version and router.data.get(KEY_DEVICE_BASIC_INFORMATION): device_data["model"] = device_info["DeviceName"]
sw_version = router.data[KEY_DEVICE_BASIC_INFORMATION].get("SoftwareVersion") if not sw_version and router.data.get(KEY_DEVICE_BASIC_INFORMATION):
if sw_version: sw_version = router.data[KEY_DEVICE_BASIC_INFORMATION].get(
device_data["sw_version"] = sw_version "SoftwareVersion"
device_registry = await dr.async_get_registry(hass) )
device_registry.async_get_or_create( if sw_version:
config_entry_id=config_entry.entry_id, device_data["sw_version"] = sw_version
connections=router.device_connections, device_registry = await dr.async_get_registry(hass)
identifiers=router.device_identifiers, device_registry.async_get_or_create(
name=router.device_name, config_entry_id=config_entry.entry_id,
manufacturer="Huawei", connections=router.device_connections,
**device_data, identifiers=router.device_identifiers,
) name=router.device_name,
manufacturer="Huawei",
**device_data,
)
# Forward config entry setup to platforms # Forward config entry setup to platforms
hass.config_entries.async_setup_platforms(config_entry, CONFIG_ENTRY_PLATFORMS) hass.config_entries.async_setup_platforms(config_entry, CONFIG_ENTRY_PLATFORMS)

View File

@ -5,7 +5,6 @@ import threading
from pymodbus.client.sync import ModbusSerialClient, ModbusTcpClient, ModbusUdpClient from pymodbus.client.sync import ModbusSerialClient, ModbusTcpClient, ModbusUdpClient
from pymodbus.constants import Defaults from pymodbus.constants import Defaults
from pymodbus.exceptions import ModbusException from pymodbus.exceptions import ModbusException
from pymodbus.pdu import ExceptionResponse, IllegalFunctionRequest
from pymodbus.transaction import ModbusRtuFramer from pymodbus.transaction import ModbusRtuFramer
from homeassistant.const import ( from homeassistant.const import (
@ -237,8 +236,8 @@ class ModbusHub:
result = self._client.read_coils(address, count, **kwargs) result = self._client.read_coils(address, count, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) self._log_error(exception_error)
return None result = exception_error
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)): if not hasattr(result, "bits"):
self._log_error(result) self._log_error(result)
return None return None
self._in_error = False self._in_error = False
@ -251,9 +250,8 @@ class ModbusHub:
try: try:
result = self._client.read_discrete_inputs(address, count, **kwargs) result = self._client.read_discrete_inputs(address, count, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return None if not hasattr(result, "bits"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return None return None
self._in_error = False self._in_error = False
@ -266,9 +264,8 @@ class ModbusHub:
try: try:
result = self._client.read_input_registers(address, count, **kwargs) result = self._client.read_input_registers(address, count, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return None if not hasattr(result, "registers"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return None return None
self._in_error = False self._in_error = False
@ -281,9 +278,8 @@ class ModbusHub:
try: try:
result = self._client.read_holding_registers(address, count, **kwargs) result = self._client.read_holding_registers(address, count, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return None if not hasattr(result, "registers"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return None return None
self._in_error = False self._in_error = False
@ -296,9 +292,8 @@ class ModbusHub:
try: try:
result = self._client.write_coil(address, value, **kwargs) result = self._client.write_coil(address, value, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return False if not hasattr(result, "value"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return False return False
self._in_error = False self._in_error = False
@ -311,9 +306,8 @@ class ModbusHub:
try: try:
result = self._client.write_coils(address, values, **kwargs) result = self._client.write_coils(address, values, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return False if not hasattr(result, "count"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return False return False
self._in_error = False self._in_error = False
@ -326,9 +320,8 @@ class ModbusHub:
try: try:
result = self._client.write_register(address, value, **kwargs) result = self._client.write_register(address, value, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return False if not hasattr(result, "value"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return False return False
self._in_error = False self._in_error = False
@ -341,9 +334,8 @@ class ModbusHub:
try: try:
result = self._client.write_registers(address, values, **kwargs) result = self._client.write_registers(address, values, **kwargs)
except ModbusException as exception_error: except ModbusException as exception_error:
self._log_error(exception_error) result = exception_error
return False if not hasattr(result, "count"):
if isinstance(result, (ExceptionResponse, IllegalFunctionRequest)):
self._log_error(result) self._log_error(result)
return False return False
self._in_error = False self._in_error = False

View File

@ -3,7 +3,7 @@
"name": "OVO Energy", "name": "OVO Energy",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/ovo_energy", "documentation": "https://www.home-assistant.io/integrations/ovo_energy",
"requirements": ["ovoenergy==1.1.11"], "requirements": ["ovoenergy==1.1.12"],
"codeowners": ["@timmo001"], "codeowners": ["@timmo001"],
"iot_class": "cloud_polling" "iot_class": "cloud_polling"
} }

View File

@ -2,7 +2,7 @@
"domain": "philips_js", "domain": "philips_js",
"name": "Philips TV", "name": "Philips TV",
"documentation": "https://www.home-assistant.io/integrations/philips_js", "documentation": "https://www.home-assistant.io/integrations/philips_js",
"requirements": ["ha-philipsjs==2.7.0"], "requirements": ["ha-philipsjs==2.7.3"],
"codeowners": ["@elupus"], "codeowners": ["@elupus"],
"config_flow": true, "config_flow": true,
"iot_class": "local_polling" "iot_class": "local_polling"

View File

@ -418,9 +418,8 @@ class RachioZone(RachioSwitch):
CONF_MANUAL_RUN_MINS, DEFAULT_MANUAL_RUN_MINS CONF_MANUAL_RUN_MINS, DEFAULT_MANUAL_RUN_MINS
) )
) )
self._controller.rachio.zone.start( # The API limit is 3 hours, and requires an int be passed
self.zone_id, manual_run_time.total_seconds() self._controller.rachio.zone.start(self.zone_id, manual_run_time.seconds)
)
_LOGGER.debug( _LOGGER.debug(
"Watering %s on %s for %s", "Watering %s on %s for %s",
self.name, self.name,

View File

@ -3,7 +3,7 @@
"name": "Sonos", "name": "Sonos",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/sonos", "documentation": "https://www.home-assistant.io/integrations/sonos",
"requirements": ["pysonos==0.0.44"], "requirements": ["pysonos==0.0.45"],
"after_dependencies": ["plex"], "after_dependencies": ["plex"],
"ssdp": [ "ssdp": [
{ {

View File

@ -498,7 +498,9 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
if new_status == "TRANSITIONING": if new_status == "TRANSITIONING":
return return
self._play_mode = event.current_play_mode if event else self.soco.play_mode self._play_mode = (
variables["current_play_mode"] if variables else self.soco.play_mode
)
self._uri = None self._uri = None
self._media_duration = None self._media_duration = None
self._media_image_url = None self._media_image_url = None

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from asyncio import gather from asyncio import gather
import contextlib import contextlib
import datetime import datetime
from functools import partial
import logging import logging
from typing import Any, Callable from typing import Any, Callable
@ -223,7 +224,11 @@ class SonosSpeaker:
return return
self._poll_timer = self.hass.helpers.event.async_track_time_interval( self._poll_timer = self.hass.helpers.event.async_track_time_interval(
async_dispatcher_send(self.hass, f"{SONOS_ENTITY_UPDATE}-{self.soco.uid}"), partial(
async_dispatcher_send,
self.hass,
f"{SONOS_ENTITY_UPDATE}-{self.soco.uid}",
),
SCAN_INTERVAL, SCAN_INTERVAL,
) )

View File

@ -203,7 +203,7 @@ async def async_setup_platform(
) -> None: ) -> None:
"""Set up the system monitor sensors.""" """Set up the system monitor sensors."""
entities = [] entities = []
sensor_registry: dict[str, SensorData] = {} sensor_registry: dict[tuple[str, str], SensorData] = {}
for resource in config[CONF_RESOURCES]: for resource in config[CONF_RESOURCES]:
type_ = resource[CONF_TYPE] type_ = resource[CONF_TYPE]
@ -225,7 +225,9 @@ async def async_setup_platform(
_LOGGER.warning("Cannot read CPU / processor temperature information") _LOGGER.warning("Cannot read CPU / processor temperature information")
continue continue
sensor_registry[type_] = SensorData(argument, None, None, None, None) sensor_registry[(type_, argument)] = SensorData(
argument, None, None, None, None
)
entities.append(SystemMonitorSensor(sensor_registry, type_, argument)) entities.append(SystemMonitorSensor(sensor_registry, type_, argument))
scan_interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) scan_interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
@ -236,7 +238,7 @@ async def async_setup_platform(
async def async_setup_sensor_registry_updates( async def async_setup_sensor_registry_updates(
hass: HomeAssistant, hass: HomeAssistant,
sensor_registry: dict[str, SensorData], sensor_registry: dict[tuple[str, str], SensorData],
scan_interval: datetime.timedelta, scan_interval: datetime.timedelta,
) -> None: ) -> None:
"""Update the registry and create polling.""" """Update the registry and create polling."""
@ -245,11 +247,11 @@ async def async_setup_sensor_registry_updates(
def _update_sensors() -> None: def _update_sensors() -> None:
"""Update sensors and store the result in the registry.""" """Update sensors and store the result in the registry."""
for type_, data in sensor_registry.items(): for (type_, argument), data in sensor_registry.items():
try: try:
state, value, update_time = _update(type_, data) state, value, update_time = _update(type_, data)
except Exception as ex: # pylint: disable=broad-except except Exception as ex: # pylint: disable=broad-except
_LOGGER.exception("Error updating sensor: %s", type_) _LOGGER.exception("Error updating sensor: %s (%s)", type_, argument)
data.last_exception = ex data.last_exception = ex
else: else:
data.state = state data.state = state
@ -295,7 +297,7 @@ class SystemMonitorSensor(SensorEntity):
def __init__( def __init__(
self, self,
sensor_registry: dict[str, SensorData], sensor_registry: dict[tuple[str, str], SensorData],
sensor_type: str, sensor_type: str,
argument: str = "", argument: str = "",
) -> None: ) -> None:
@ -304,6 +306,7 @@ class SystemMonitorSensor(SensorEntity):
self._name: str = f"{self.sensor_type[SENSOR_TYPE_NAME]} {argument}".rstrip() self._name: str = f"{self.sensor_type[SENSOR_TYPE_NAME]} {argument}".rstrip()
self._unique_id: str = slugify(f"{sensor_type}_{argument}") self._unique_id: str = slugify(f"{sensor_type}_{argument}")
self._sensor_registry = sensor_registry self._sensor_registry = sensor_registry
self._argument: str = argument
@property @property
def name(self) -> str: def name(self) -> str:
@ -353,7 +356,7 @@ class SystemMonitorSensor(SensorEntity):
@property @property
def data(self) -> SensorData: def data(self) -> SensorData:
"""Return registry entry for the data.""" """Return registry entry for the data."""
return self._sensor_registry[self._type] return self._sensor_registry[(self._type, self._argument)]
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""When entity is added to hass.""" """When entity is added to hass."""

View File

@ -3,7 +3,7 @@
"name": "Tasmota", "name": "Tasmota",
"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.2.11"], "requirements": ["hatasmota==0.2.12"],
"dependencies": ["mqtt"], "dependencies": ["mqtt"],
"mqtt": ["tasmota/discovery/#"], "mqtt": ["tasmota/discovery/#"],
"codeowners": ["@emontnemery"], "codeowners": ["@emontnemery"],

View File

@ -140,7 +140,7 @@ async def async_setup_entry(hass, config_entry):
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
config = config_entry.data config = config_entry.data
# Because users can have multiple accounts, we always create a new session so they have separate cookies # Because users can have multiple accounts, we always create a new session so they have separate cookies
async_client = httpx.AsyncClient(headers={USER_AGENT: SERVER_SOFTWARE}) async_client = httpx.AsyncClient(headers={USER_AGENT: SERVER_SOFTWARE}, timeout=60)
email = config_entry.title email = config_entry.title
if email in hass.data[DOMAIN] and CONF_SCAN_INTERVAL in hass.data[DOMAIN][email]: if email in hass.data[DOMAIN] and CONF_SCAN_INTERVAL in hass.data[DOMAIN][email]:
scan_interval = hass.data[DOMAIN][email][CONF_SCAN_INTERVAL] scan_interval = hass.data[DOMAIN][email][CONF_SCAN_INTERVAL]

View File

@ -150,7 +150,7 @@ async def validate_input(hass: core.HomeAssistant, data):
""" """
config = {} config = {}
async_client = httpx.AsyncClient(headers={USER_AGENT: SERVER_SOFTWARE}) async_client = httpx.AsyncClient(headers={USER_AGENT: SERVER_SOFTWARE}, timeout=60)
try: try:
controller = TeslaAPI( controller = TeslaAPI(

View File

@ -111,7 +111,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigType):
async def async_unload_entry(hass, entry): async def async_unload_entry(hass, entry):
"""Unload a config entry.""" """Unload a config entry."""
platforms = [platform for platform in PLATFORMS if platform in hass.data[DOMAIN]] platforms = [platform for platform in PLATFORMS if hass.data[DOMAIN].get(platform)]
unload_ok = await hass.config_entries.async_unload_platforms(entry, platforms) unload_ok = await hass.config_entries.async_unload_platforms(entry, platforms)
if unload_ok: if unload_ok:
hass.data[DOMAIN].clear() hass.data[DOMAIN].clear()

View File

@ -1,7 +1,7 @@
"""Constants used by Home Assistant components.""" """Constants used by Home Assistant components."""
MAJOR_VERSION = 2021 MAJOR_VERSION = 2021
MINOR_VERSION = 5 MINOR_VERSION = 5
PATCH_VERSION = "1" PATCH_VERSION = "2"
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__ = f"{__short_version__}.{PATCH_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER = (3, 8, 0) REQUIRED_PYTHON_VER = (3, 8, 0)

View File

@ -254,7 +254,7 @@ ambiclimate==0.2.1
amcrest==1.7.2 amcrest==1.7.2
# homeassistant.components.androidtv # homeassistant.components.androidtv
androidtv[async]==0.0.58 androidtv[async]==0.0.59
# homeassistant.components.anel_pwrctrl # homeassistant.components.anel_pwrctrl
anel_pwrctrl-homeassistant==0.0.1.dev2 anel_pwrctrl-homeassistant==0.0.1.dev2
@ -479,7 +479,7 @@ defusedxml==0.6.0
deluge-client==1.7.1 deluge-client==1.7.1
# homeassistant.components.denonavr # homeassistant.components.denonavr
denonavr==0.10.6 denonavr==0.10.7
# homeassistant.components.devolo_home_control # homeassistant.components.devolo_home_control
devolo-home-control-api==0.17.3 devolo-home-control-api==0.17.3
@ -720,7 +720,7 @@ guppy3==3.1.0
ha-ffmpeg==3.0.2 ha-ffmpeg==3.0.2
# homeassistant.components.philips_js # homeassistant.components.philips_js
ha-philipsjs==2.7.0 ha-philipsjs==2.7.3
# homeassistant.components.habitica # homeassistant.components.habitica
habitipy==0.2.0 habitipy==0.2.0
@ -735,7 +735,7 @@ hass-nabucasa==0.43.0
hass_splunk==0.1.1 hass_splunk==0.1.1
# homeassistant.components.tasmota # homeassistant.components.tasmota
hatasmota==0.2.11 hatasmota==0.2.12
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate==0.10.2 hdate==0.10.2
@ -1088,7 +1088,7 @@ oru==0.1.11
orvibo==1.1.1 orvibo==1.1.1
# homeassistant.components.ovo_energy # homeassistant.components.ovo_energy
ovoenergy==1.1.11 ovoenergy==1.1.12
# homeassistant.components.mqtt # homeassistant.components.mqtt
# homeassistant.components.shiftr # homeassistant.components.shiftr
@ -1741,7 +1741,7 @@ pysnmp==4.4.12
pysoma==0.0.10 pysoma==0.0.10
# homeassistant.components.sonos # homeassistant.components.sonos
pysonos==0.0.44 pysonos==0.0.45
# homeassistant.components.spc # homeassistant.components.spc
pyspcwebgw==0.4.0 pyspcwebgw==0.4.0

View File

@ -167,7 +167,7 @@ airly==1.1.0
ambiclimate==0.2.1 ambiclimate==0.2.1
# homeassistant.components.androidtv # homeassistant.components.androidtv
androidtv[async]==0.0.58 androidtv[async]==0.0.59
# homeassistant.components.apns # homeassistant.components.apns
apns2==0.3.0 apns2==0.3.0
@ -264,7 +264,7 @@ debugpy==1.2.1
defusedxml==0.6.0 defusedxml==0.6.0
# homeassistant.components.denonavr # homeassistant.components.denonavr
denonavr==0.10.6 denonavr==0.10.7
# homeassistant.components.devolo_home_control # homeassistant.components.devolo_home_control
devolo-home-control-api==0.17.3 devolo-home-control-api==0.17.3
@ -393,7 +393,7 @@ guppy3==3.1.0
ha-ffmpeg==3.0.2 ha-ffmpeg==3.0.2
# homeassistant.components.philips_js # homeassistant.components.philips_js
ha-philipsjs==2.7.0 ha-philipsjs==2.7.3
# homeassistant.components.habitica # homeassistant.components.habitica
habitipy==0.2.0 habitipy==0.2.0
@ -405,7 +405,7 @@ hangups==0.4.11
hass-nabucasa==0.43.0 hass-nabucasa==0.43.0
# homeassistant.components.tasmota # homeassistant.components.tasmota
hatasmota==0.2.11 hatasmota==0.2.12
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate==0.10.2 hdate==0.10.2
@ -576,7 +576,7 @@ onvif-zeep-async==1.0.0
openerz-api==0.1.0 openerz-api==0.1.0
# homeassistant.components.ovo_energy # homeassistant.components.ovo_energy
ovoenergy==1.1.11 ovoenergy==1.1.12
# homeassistant.components.mqtt # homeassistant.components.mqtt
# homeassistant.components.shiftr # homeassistant.components.shiftr
@ -959,7 +959,7 @@ pysmartthings==0.7.6
pysoma==0.0.10 pysoma==0.0.10
# homeassistant.components.sonos # homeassistant.components.sonos
pysonos==0.0.44 pysonos==0.0.45
# homeassistant.components.spc # homeassistant.components.spc
pyspcwebgw==0.4.0 pyspcwebgw==0.4.0

View File

@ -43,6 +43,15 @@ DEFAULT_SENSOR_CONFIG = {
} }
} }
BAD_INDEXED_SENSOR_CONFIG_3 = {
"sn": {
"Time": "2020-09-25T12:47:15",
"ENERGY": {
"ApparentPower": [7.84, 1.23, 2.34],
},
}
}
INDEXED_SENSOR_CONFIG = { INDEXED_SENSOR_CONFIG = {
"sn": { "sn": {
"Time": "2020-09-25T12:47:15", "Time": "2020-09-25T12:47:15",
@ -224,6 +233,117 @@ async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
assert state.state == "7.8" assert state.state == "7.8"
async def test_bad_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
"""Test state update via MQTT where sensor is not matching configuration."""
config = copy.deepcopy(DEFAULT_CONFIG)
sensor_config = copy.deepcopy(BAD_INDEXED_SENSOR_CONFIG_3)
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.tasmota_energy_apparentpower_0")
assert state.state == "unavailable"
assert not state.attributes.get(ATTR_ASSUMED_STATE)
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == "unavailable"
assert not state.attributes.get(ATTR_ASSUMED_STATE)
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
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_energy_apparentpower_0")
assert state.state == STATE_UNKNOWN
assert not state.attributes.get(ATTR_ASSUMED_STATE)
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == STATE_UNKNOWN
assert not state.attributes.get(ATTR_ASSUMED_STATE)
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
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":{"ApparentPower":[1.2,3.4,5.6]}}'
)
state = hass.states.get("sensor.tasmota_energy_apparentpower_0")
assert state.state == "1.2"
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == "3.4"
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
assert state.state == "5.6"
# Test periodic state update with too few values
async_fire_mqtt_message(
hass, "tasmota_49A3BC/tele/SENSOR", '{"ENERGY":{"ApparentPower":[7.8,9.0]}}'
)
state = hass.states.get("sensor.tasmota_energy_apparentpower_0")
assert state.state == "7.8"
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == "9.0"
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
assert state.state == STATE_UNKNOWN
async_fire_mqtt_message(
hass, "tasmota_49A3BC/tele/SENSOR", '{"ENERGY":{"ApparentPower":2.3}}'
)
state = hass.states.get("sensor.tasmota_energy_apparentpower_0")
assert state.state == "2.3"
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == STATE_UNKNOWN
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
assert state.state == STATE_UNKNOWN
# Test polled state update
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS10",
'{"StatusSNS":{"ENERGY":{"ApparentPower":[1.2,3.4,5.6]}}}',
)
state = hass.states.get("sensor.tasmota_energy_apparentpower_0")
assert state.state == "1.2"
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == "3.4"
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
assert state.state == "5.6"
# Test polled state update with too few values
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS10",
'{"StatusSNS":{"ENERGY":{"ApparentPower":[7.8,9.0]}}}',
)
state = hass.states.get("sensor.tasmota_energy_apparentpower_0")
assert state.state == "7.8"
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == "9.0"
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
assert state.state == STATE_UNKNOWN
async_fire_mqtt_message(
hass,
"tasmota_49A3BC/stat/STATUS10",
'{"StatusSNS":{"ENERGY":{"ApparentPower":2.3}}}',
)
state = hass.states.get("sensor.tasmota_energy_apparentpower_0")
assert state.state == "2.3"
state = hass.states.get("sensor.tasmota_energy_apparentpower_1")
assert state.state == STATE_UNKNOWN
state = hass.states.get("sensor.tasmota_energy_apparentpower_2")
assert state.state == STATE_UNKNOWN
@pytest.mark.parametrize("status_sensor_disabled", [False]) @pytest.mark.parametrize("status_sensor_disabled", [False])
async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): async def test_status_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
"""Test state update via MQTT.""" """Test state update via MQTT."""