Deprecate and remove lazy_error from modbus (#105037)

This commit is contained in:
jan iversen 2023-12-05 13:08:33 +01:00 committed by GitHub
parent 5b59e043fa
commit 0638088aee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 66 additions and 273 deletions

View File

@ -24,10 +24,11 @@ from homeassistant.const import (
STATE_OFF, STATE_OFF,
STATE_ON, STATE_ON,
) )
from homeassistant.core import callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity, ToggleEntity from homeassistant.helpers.entity import Entity, ToggleEntity
from homeassistant.helpers.event import async_call_later, async_track_time_interval from homeassistant.helpers.event import async_call_later, async_track_time_interval
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from .const import ( from .const import (
@ -61,6 +62,7 @@ from .const import (
CONF_VIRTUAL_COUNT, CONF_VIRTUAL_COUNT,
CONF_WRITE_TYPE, CONF_WRITE_TYPE,
CONF_ZERO_SUPPRESS, CONF_ZERO_SUPPRESS,
MODBUS_DOMAIN,
SIGNAL_START_ENTITY, SIGNAL_START_ENTITY,
SIGNAL_STOP_ENTITY, SIGNAL_STOP_ENTITY,
DataType, DataType,
@ -74,8 +76,34 @@ _LOGGER = logging.getLogger(__name__)
class BasePlatform(Entity): class BasePlatform(Entity):
"""Base for readonly platforms.""" """Base for readonly platforms."""
def __init__(self, hub: ModbusHub, entry: dict[str, Any]) -> None: def __init__(
self, hass: HomeAssistant, hub: ModbusHub, entry: dict[str, Any]
) -> None:
"""Initialize the Modbus binary sensor.""" """Initialize the Modbus binary sensor."""
if CONF_LAZY_ERROR in entry:
async_create_issue(
hass,
MODBUS_DOMAIN,
"removed_lazy_error_count",
breaks_in_ha_version="2024.7.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="removed_lazy_error_count",
translation_placeholders={
"config_key": "lazy_error_count",
"integration": MODBUS_DOMAIN,
"url": "https://www.home-assistant.io/integrations/modbus",
},
)
_LOGGER.warning(
"`close_comm_on_error`: is deprecated and will be removed in version 2024.4"
)
_LOGGER.warning(
"`lazy_error_count`: is deprecated and will be removed in version 2024.7"
)
self._hub = hub self._hub = hub
self._slave = entry.get(CONF_SLAVE, None) or entry.get(CONF_DEVICE_ADDRESS, 0) self._slave = entry.get(CONF_SLAVE, None) or entry.get(CONF_DEVICE_ADDRESS, 0)
self._address = int(entry[CONF_ADDRESS]) self._address = int(entry[CONF_ADDRESS])
@ -92,8 +120,6 @@ class BasePlatform(Entity):
self._attr_device_class = entry.get(CONF_DEVICE_CLASS) self._attr_device_class = entry.get(CONF_DEVICE_CLASS)
self._attr_available = True self._attr_available = True
self._attr_unit_of_measurement = None self._attr_unit_of_measurement = None
self._lazy_error_count = entry[CONF_LAZY_ERROR]
self._lazy_errors = self._lazy_error_count
def get_optional_numeric_config(config_name: str) -> int | float | None: def get_optional_numeric_config(config_name: str) -> int | float | None:
if (val := entry.get(config_name)) is None: if (val := entry.get(config_name)) is None:
@ -153,9 +179,9 @@ class BasePlatform(Entity):
class BaseStructPlatform(BasePlatform, RestoreEntity): class BaseStructPlatform(BasePlatform, RestoreEntity):
"""Base class representing a sensor/climate.""" """Base class representing a sensor/climate."""
def __init__(self, hub: ModbusHub, config: dict) -> None: def __init__(self, hass: HomeAssistant, hub: ModbusHub, config: dict) -> None:
"""Initialize the switch.""" """Initialize the switch."""
super().__init__(hub, config) super().__init__(hass, hub, config)
self._swap = config[CONF_SWAP] self._swap = config[CONF_SWAP]
self._data_type = config[CONF_DATA_TYPE] self._data_type = config[CONF_DATA_TYPE]
self._structure: str = config[CONF_STRUCTURE] self._structure: str = config[CONF_STRUCTURE]
@ -247,10 +273,10 @@ class BaseStructPlatform(BasePlatform, RestoreEntity):
class BaseSwitch(BasePlatform, ToggleEntity, RestoreEntity): class BaseSwitch(BasePlatform, ToggleEntity, RestoreEntity):
"""Base class representing a Modbus switch.""" """Base class representing a Modbus switch."""
def __init__(self, hub: ModbusHub, config: dict) -> None: def __init__(self, hass: HomeAssistant, hub: ModbusHub, config: dict) -> None:
"""Initialize the switch.""" """Initialize the switch."""
config[CONF_INPUT_TYPE] = "" config[CONF_INPUT_TYPE] = ""
super().__init__(hub, config) super().__init__(hass, hub, config)
self._attr_is_on = False self._attr_is_on = False
convert = { convert = {
CALL_TYPE_REGISTER_HOLDING: ( CALL_TYPE_REGISTER_HOLDING: (
@ -343,15 +369,10 @@ class BaseSwitch(BasePlatform, ToggleEntity, RestoreEntity):
) )
self._call_active = False self._call_active = False
if result is None: if result is None:
if self._lazy_errors:
self._lazy_errors -= 1
return
self._lazy_errors = self._lazy_error_count
self._attr_available = False self._attr_available = False
self.async_write_ha_state() self.async_write_ha_state()
return return
self._lazy_errors = self._lazy_error_count
self._attr_available = True self._attr_available = True
if self._verify_type in (CALL_TYPE_COIL, CALL_TYPE_DISCRETE): if self._verify_type in (CALL_TYPE_COIL, CALL_TYPE_DISCRETE):
self._attr_is_on = bool(result.bits[0] & 1) self._attr_is_on = bool(result.bits[0] & 1)

View File

@ -54,7 +54,7 @@ async def async_setup_platform(
slave_count = entry.get(CONF_SLAVE_COUNT, None) or entry.get( slave_count = entry.get(CONF_SLAVE_COUNT, None) or entry.get(
CONF_VIRTUAL_COUNT, 0 CONF_VIRTUAL_COUNT, 0
) )
sensor = ModbusBinarySensor(hub, entry, slave_count) sensor = ModbusBinarySensor(hass, hub, entry, slave_count)
if slave_count > 0: if slave_count > 0:
sensors.extend(await sensor.async_setup_slaves(hass, slave_count, entry)) sensors.extend(await sensor.async_setup_slaves(hass, slave_count, entry))
sensors.append(sensor) sensors.append(sensor)
@ -64,12 +64,18 @@ async def async_setup_platform(
class ModbusBinarySensor(BasePlatform, RestoreEntity, BinarySensorEntity): class ModbusBinarySensor(BasePlatform, RestoreEntity, BinarySensorEntity):
"""Modbus binary sensor.""" """Modbus binary sensor."""
def __init__(self, hub: ModbusHub, entry: dict[str, Any], slave_count: int) -> None: def __init__(
self,
hass: HomeAssistant,
hub: ModbusHub,
entry: dict[str, Any],
slave_count: int,
) -> None:
"""Initialize the Modbus binary sensor.""" """Initialize the Modbus binary sensor."""
self._count = slave_count + 1 self._count = slave_count + 1
self._coordinator: DataUpdateCoordinator[list[int] | None] | None = None self._coordinator: DataUpdateCoordinator[list[int] | None] | None = None
self._result: list[int] = [] self._result: list[int] = []
super().__init__(hub, entry) super().__init__(hass, hub, entry)
async def async_setup_slaves( async def async_setup_slaves(
self, hass: HomeAssistant, slave_count: int, entry: dict[str, Any] self, hass: HomeAssistant, slave_count: int, entry: dict[str, Any]
@ -109,14 +115,9 @@ class ModbusBinarySensor(BasePlatform, RestoreEntity, BinarySensorEntity):
) )
self._call_active = False self._call_active = False
if result is None: if result is None:
if self._lazy_errors:
self._lazy_errors -= 1
return
self._lazy_errors = self._lazy_error_count
self._attr_available = False self._attr_available = False
self._result = [] self._result = []
else: else:
self._lazy_errors = self._lazy_error_count
self._attr_available = True self._attr_available = True
if self._input_type in (CALL_TYPE_COIL, CALL_TYPE_DISCRETE): if self._input_type in (CALL_TYPE_COIL, CALL_TYPE_DISCRETE):
self._result = result.bits self._result = result.bits

View File

@ -67,7 +67,7 @@ async def async_setup_platform(
entities = [] entities = []
for entity in discovery_info[CONF_CLIMATES]: for entity in discovery_info[CONF_CLIMATES]:
hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME]) hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME])
entities.append(ModbusThermostat(hub, entity)) entities.append(ModbusThermostat(hass, hub, entity))
async_add_entities(entities) async_add_entities(entities)
@ -79,11 +79,12 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity):
def __init__( def __init__(
self, self,
hass: HomeAssistant,
hub: ModbusHub, hub: ModbusHub,
config: dict[str, Any], config: dict[str, Any],
) -> None: ) -> None:
"""Initialize the modbus thermostat.""" """Initialize the modbus thermostat."""
super().__init__(hub, config) super().__init__(hass, hub, config)
self._target_temperature_register = config[CONF_TARGET_TEMP] self._target_temperature_register = config[CONF_TARGET_TEMP]
self._target_temperature_write_registers = config[ self._target_temperature_write_registers = config[
CONF_TARGET_TEMP_WRITE_REGISTERS CONF_TARGET_TEMP_WRITE_REGISTERS
@ -288,15 +289,9 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity):
self._slave, register, self._count, register_type self._slave, register, self._count, register_type
) )
if result is None: if result is None:
if self._lazy_errors:
self._lazy_errors -= 1
return -1
self._lazy_errors = self._lazy_error_count
self._attr_available = False self._attr_available = False
return -1 return -1
self._lazy_errors = self._lazy_error_count
if raw: if raw:
# Return the raw value read from the register, do not change # Return the raw value read from the register, do not change
# the object's state # the object's state

View File

@ -51,7 +51,7 @@ async def async_setup_platform(
covers = [] covers = []
for cover in discovery_info[CONF_COVERS]: for cover in discovery_info[CONF_COVERS]:
hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME]) hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME])
covers.append(ModbusCover(hub, cover)) covers.append(ModbusCover(hass, hub, cover))
async_add_entities(covers) async_add_entities(covers)
@ -63,11 +63,12 @@ class ModbusCover(BasePlatform, CoverEntity, RestoreEntity):
def __init__( def __init__(
self, self,
hass: HomeAssistant,
hub: ModbusHub, hub: ModbusHub,
config: dict[str, Any], config: dict[str, Any],
) -> None: ) -> None:
"""Initialize the modbus cover.""" """Initialize the modbus cover."""
super().__init__(hub, config) super().__init__(hass, hub, config)
self._state_closed = config[CONF_STATE_CLOSED] self._state_closed = config[CONF_STATE_CLOSED]
self._state_closing = config[CONF_STATE_CLOSING] self._state_closing = config[CONF_STATE_CLOSING]
self._state_open = config[CONF_STATE_OPEN] self._state_open = config[CONF_STATE_OPEN]
@ -142,14 +143,9 @@ class ModbusCover(BasePlatform, CoverEntity, RestoreEntity):
self._slave, self._address, 1, self._input_type self._slave, self._address, 1, self._input_type
) )
if result is None: if result is None:
if self._lazy_errors:
self._lazy_errors -= 1
return
self._lazy_errors = self._lazy_error_count
self._attr_available = False self._attr_available = False
self.async_write_ha_state() self.async_write_ha_state()
return return
self._lazy_errors = self._lazy_error_count
self._attr_available = True self._attr_available = True
if self._input_type == CALL_TYPE_COIL: if self._input_type == CALL_TYPE_COIL:
self._set_attr_state(bool(result.bits[0] & 1)) self._set_attr_state(bool(result.bits[0] & 1))

View File

@ -30,7 +30,7 @@ async def async_setup_platform(
for entry in discovery_info[CONF_FANS]: for entry in discovery_info[CONF_FANS]:
hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME]) hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME])
fans.append(ModbusFan(hub, entry)) fans.append(ModbusFan(hass, hub, entry))
async_add_entities(fans) async_add_entities(fans)

View File

@ -29,7 +29,7 @@ async def async_setup_platform(
lights = [] lights = []
for entry in discovery_info[CONF_LIGHTS]: for entry in discovery_info[CONF_LIGHTS]:
hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME]) hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME])
lights.append(ModbusLight(hub, entry)) lights.append(ModbusLight(hass, hub, entry))
async_add_entities(lights) async_add_entities(lights)

View File

@ -1,7 +1,7 @@
"""Support for Modbus Register sensors.""" """Support for Modbus Register sensors."""
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime
import logging import logging
from typing import Any from typing import Any
@ -19,7 +19,6 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import (
CoordinatorEntity, CoordinatorEntity,
@ -53,7 +52,7 @@ async def async_setup_platform(
slave_count = entry.get(CONF_SLAVE_COUNT, None) or entry.get( slave_count = entry.get(CONF_SLAVE_COUNT, None) or entry.get(
CONF_VIRTUAL_COUNT, 0 CONF_VIRTUAL_COUNT, 0
) )
sensor = ModbusRegisterSensor(hub, entry, slave_count) sensor = ModbusRegisterSensor(hass, hub, entry, slave_count)
if slave_count > 0: if slave_count > 0:
sensors.extend(await sensor.async_setup_slaves(hass, slave_count, entry)) sensors.extend(await sensor.async_setup_slaves(hass, slave_count, entry))
sensors.append(sensor) sensors.append(sensor)
@ -65,12 +64,13 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreSensor, SensorEntity):
def __init__( def __init__(
self, self,
hass: HomeAssistant,
hub: ModbusHub, hub: ModbusHub,
entry: dict[str, Any], entry: dict[str, Any],
slave_count: int, slave_count: int,
) -> None: ) -> None:
"""Initialize the modbus register sensor.""" """Initialize the modbus register sensor."""
super().__init__(hub, entry) super().__init__(hass, hub, entry)
if slave_count: if slave_count:
self._count = self._count * (slave_count + 1) self._count = self._count * (slave_count + 1)
self._coordinator: DataUpdateCoordinator[list[int] | None] | None = None self._coordinator: DataUpdateCoordinator[list[int] | None] | None = None
@ -114,13 +114,6 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreSensor, SensorEntity):
self._slave, self._address, self._count, self._input_type self._slave, self._address, self._count, self._input_type
) )
if raw_result is None: if raw_result is None:
if self._lazy_errors:
self._lazy_errors -= 1
self._cancel_call = async_call_later(
self.hass, timedelta(seconds=1), self.async_update
)
return
self._lazy_errors = self._lazy_error_count
self._attr_available = False self._attr_available = False
self._attr_native_value = None self._attr_native_value = None
if self._coordinator: if self._coordinator:
@ -142,7 +135,6 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreSensor, SensorEntity):
else: else:
self._attr_native_value = result self._attr_native_value = result
self._attr_available = self._attr_native_value is not None self._attr_available = self._attr_native_value is not None
self._lazy_errors = self._lazy_error_count
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -70,9 +70,13 @@
} }
}, },
"issues": { "issues": {
"removed_lazy_error_count": {
"title": "`{config_key}` configuration key is being removed",
"description": "Please remove the `{config_key}` key from the {integration} entry in your configuration.yaml file and restart Home Assistant to fix this issue. All errors will be reported, as lazy_error_count is accepted but ignored"
},
"deprecated_close_comm_config": { "deprecated_close_comm_config": {
"title": "`{config_key}` configuration key is being removed", "title": "`{config_key}` configuration key is being removed",
"description": "Please remove the `{config_key}` key from the {integration} entry in your configuration.yaml file and restart Home Assistant to fix this issue.\n\nCommunication is automatically closed on errors, see [the documentation]({url}) for other error handling parameters." "description": "Please remove the `{config_key}` key from the {integration} entry in your `configuration.yaml` file and restart Home Assistant to fix this issue. All errors will be reported, as `lazy_error_count` is accepted but ignored."
}, },
"deprecated_retry_on_empty": { "deprecated_retry_on_empty": {
"title": "`{config_key}` configuration key is being removed", "title": "`{config_key}` configuration key is being removed",

View File

@ -30,7 +30,7 @@ async def async_setup_platform(
for entry in discovery_info[CONF_SWITCHES]: for entry in discovery_info[CONF_SWITCHES]:
hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME]) hub: ModbusHub = get_hub(hass, discovery_info[CONF_NAME])
switches.append(ModbusSwitch(hub, entry)) switches.append(ModbusSwitch(hass, hub, entry))
async_add_entities(switches) async_add_entities(switches)

View File

@ -1,5 +1,4 @@
"""Thetests for the Modbus sensor component.""" """Thetests for the Modbus sensor component."""
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from homeassistant.components.binary_sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.binary_sensor import DOMAIN as SENSOR_DOMAIN
@ -10,7 +9,6 @@ from homeassistant.components.modbus.const import (
CALL_TYPE_REGISTER_INPUT, CALL_TYPE_REGISTER_INPUT,
CONF_DEVICE_ADDRESS, CONF_DEVICE_ADDRESS,
CONF_INPUT_TYPE, CONF_INPUT_TYPE,
CONF_LAZY_ERROR,
CONF_SLAVE_COUNT, CONF_SLAVE_COUNT,
CONF_VIRTUAL_COUNT, CONF_VIRTUAL_COUNT,
MODBUS_DOMAIN, MODBUS_DOMAIN,
@ -26,13 +24,12 @@ from homeassistant.const import (
STATE_OFF, STATE_OFF,
STATE_ON, STATE_ON,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
STATE_UNKNOWN,
) )
from homeassistant.core import HomeAssistant, State from homeassistant.core import HomeAssistant, State
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle from .conftest import TEST_ENTITY_NAME, ReadResult
ENTITY_ID = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") ENTITY_ID = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_")
SLAVE_UNIQUE_ID = "ground_floor_sensor" SLAVE_UNIQUE_ID = "ground_floor_sensor"
@ -57,7 +54,6 @@ SLAVE_UNIQUE_ID = "ground_floor_sensor"
CONF_SLAVE: 10, CONF_SLAVE: 10,
CONF_INPUT_TYPE: CALL_TYPE_DISCRETE, CONF_INPUT_TYPE: CALL_TYPE_DISCRETE,
CONF_DEVICE_CLASS: "door", CONF_DEVICE_CLASS: "door",
CONF_LAZY_ERROR: 10,
} }
] ]
}, },
@ -69,7 +65,6 @@ SLAVE_UNIQUE_ID = "ground_floor_sensor"
CONF_DEVICE_ADDRESS: 10, CONF_DEVICE_ADDRESS: 10,
CONF_INPUT_TYPE: CALL_TYPE_DISCRETE, CONF_INPUT_TYPE: CALL_TYPE_DISCRETE,
CONF_DEVICE_CLASS: "door", CONF_DEVICE_CLASS: "door",
CONF_LAZY_ERROR: 10,
} }
] ]
}, },
@ -196,44 +191,6 @@ async def test_all_binary_sensor(hass: HomeAssistant, expected, mock_do_cycle) -
assert hass.states.get(ENTITY_ID).state == expected assert hass.states.get(ENTITY_ID).state == expected
@pytest.mark.parametrize(
"do_config",
[
{
CONF_BINARY_SENSORS: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 51,
CONF_INPUT_TYPE: CALL_TYPE_COIL,
CONF_SCAN_INTERVAL: 10,
CONF_LAZY_ERROR: 2,
},
],
},
],
)
@pytest.mark.parametrize(
("register_words", "do_exception", "start_expect", "end_expect"),
[
(
[False * 16],
True,
STATE_UNKNOWN,
STATE_UNAVAILABLE,
),
],
)
async def test_lazy_error_binary_sensor(
hass: HomeAssistant, start_expect, end_expect, mock_do_cycle: FrozenDateTimeFactory
) -> None:
"""Run test for given config."""
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == end_expect
@pytest.mark.parametrize( @pytest.mark.parametrize(
"do_config", "do_config",
[ [

View File

@ -1,5 +1,4 @@
"""The tests for the Modbus climate component.""" """The tests for the Modbus climate component."""
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
@ -22,7 +21,6 @@ from homeassistant.components.modbus.const import (
CONF_HVAC_MODE_REGISTER, CONF_HVAC_MODE_REGISTER,
CONF_HVAC_MODE_VALUES, CONF_HVAC_MODE_VALUES,
CONF_HVAC_ONOFF_REGISTER, CONF_HVAC_ONOFF_REGISTER,
CONF_LAZY_ERROR,
CONF_TARGET_TEMP, CONF_TARGET_TEMP,
CONF_TARGET_TEMP_WRITE_REGISTERS, CONF_TARGET_TEMP_WRITE_REGISTERS,
CONF_WRITE_REGISTERS, CONF_WRITE_REGISTERS,
@ -40,7 +38,7 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, State from homeassistant.core import HomeAssistant, State
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle from .conftest import TEST_ENTITY_NAME, ReadResult
ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_")
@ -77,7 +75,6 @@ ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_")
CONF_SLAVE: 10, CONF_SLAVE: 10,
CONF_SCAN_INTERVAL: 20, CONF_SCAN_INTERVAL: 20,
CONF_DATA_TYPE: DataType.INT32, CONF_DATA_TYPE: DataType.INT32,
CONF_LAZY_ERROR: 10,
} }
], ],
}, },
@ -581,46 +578,6 @@ async def test_restore_state_climate(
assert state.attributes[ATTR_TEMPERATURE] == 37 assert state.attributes[ATTR_TEMPERATURE] == 37
@pytest.mark.parametrize(
"do_config",
[
{
CONF_CLIMATES: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_TARGET_TEMP: 117,
CONF_ADDRESS: 117,
CONF_SLAVE: 10,
CONF_LAZY_ERROR: 1,
}
],
},
],
)
@pytest.mark.parametrize(
("register_words", "do_exception", "start_expect", "end_expect"),
[
(
[0x8000],
True,
"17",
STATE_UNAVAILABLE,
),
],
)
async def test_lazy_error_climate(
hass: HomeAssistant, mock_do_cycle: FrozenDateTimeFactory, start_expect, end_expect
) -> None:
"""Run test for sensor."""
hass.states.async_set(ENTITY_ID, 17)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == end_expect
@pytest.mark.parametrize( @pytest.mark.parametrize(
"do_config", "do_config",
[ [

View File

@ -1,5 +1,4 @@
"""The tests for the Modbus cover component.""" """The tests for the Modbus cover component."""
from freezegun.api import FrozenDateTimeFactory
from pymodbus.exceptions import ModbusException from pymodbus.exceptions import ModbusException
import pytest import pytest
@ -9,7 +8,6 @@ from homeassistant.components.modbus.const import (
CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_HOLDING,
CONF_DEVICE_ADDRESS, CONF_DEVICE_ADDRESS,
CONF_INPUT_TYPE, CONF_INPUT_TYPE,
CONF_LAZY_ERROR,
CONF_STATE_CLOSED, CONF_STATE_CLOSED,
CONF_STATE_CLOSING, CONF_STATE_CLOSING,
CONF_STATE_OPEN, CONF_STATE_OPEN,
@ -33,7 +31,7 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, State from homeassistant.core import HomeAssistant, State
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle from .conftest import TEST_ENTITY_NAME, ReadResult
ENTITY_ID = f"{COVER_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") ENTITY_ID = f"{COVER_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_")
ENTITY_ID2 = f"{ENTITY_ID}_2" ENTITY_ID2 = f"{ENTITY_ID}_2"
@ -59,7 +57,6 @@ ENTITY_ID2 = f"{ENTITY_ID}_2"
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SLAVE: 10, CONF_SLAVE: 10,
CONF_SCAN_INTERVAL: 20, CONF_SCAN_INTERVAL: 20,
CONF_LAZY_ERROR: 10,
} }
] ]
}, },
@ -71,7 +68,6 @@ ENTITY_ID2 = f"{ENTITY_ID}_2"
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_DEVICE_ADDRESS: 10, CONF_DEVICE_ADDRESS: 10,
CONF_SCAN_INTERVAL: 20, CONF_SCAN_INTERVAL: 20,
CONF_LAZY_ERROR: 10,
} }
] ]
}, },
@ -127,45 +123,6 @@ async def test_coil_cover(hass: HomeAssistant, expected, mock_do_cycle) -> None:
assert hass.states.get(ENTITY_ID).state == expected assert hass.states.get(ENTITY_ID).state == expected
@pytest.mark.parametrize(
"do_config",
[
{
CONF_COVERS: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_INPUT_TYPE: CALL_TYPE_COIL,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_SCAN_INTERVAL: 10,
CONF_LAZY_ERROR: 2,
},
],
},
],
)
@pytest.mark.parametrize(
("register_words", "do_exception", "start_expect", "end_expect"),
[
(
[0x00],
True,
STATE_OPEN,
STATE_UNAVAILABLE,
),
],
)
async def test_lazy_error_cover(
hass: HomeAssistant, start_expect, end_expect, mock_do_cycle: FrozenDateTimeFactory
) -> None:
"""Run test for given config."""
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == end_expect
@pytest.mark.parametrize( @pytest.mark.parametrize(
"do_config", "do_config",
[ [

View File

@ -11,7 +11,6 @@ from homeassistant.components.modbus.const import (
CONF_DEVICE_ADDRESS, CONF_DEVICE_ADDRESS,
CONF_FANS, CONF_FANS,
CONF_INPUT_TYPE, CONF_INPUT_TYPE,
CONF_LAZY_ERROR,
CONF_STATE_OFF, CONF_STATE_OFF,
CONF_STATE_ON, CONF_STATE_ON,
CONF_VERIFY, CONF_VERIFY,
@ -66,7 +65,6 @@ ENTITY_ID2 = f"{ENTITY_ID}_2"
CONF_SLAVE: 1, CONF_SLAVE: 1,
CONF_COMMAND_OFF: 0x00, CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01, CONF_COMMAND_ON: 0x01,
CONF_LAZY_ERROR: 10,
CONF_VERIFY: { CONF_VERIFY: {
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_ADDRESS: 1235, CONF_ADDRESS: 1235,
@ -84,7 +82,6 @@ ENTITY_ID2 = f"{ENTITY_ID}_2"
CONF_DEVICE_ADDRESS: 1, CONF_DEVICE_ADDRESS: 1,
CONF_COMMAND_OFF: 0x00, CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01, CONF_COMMAND_ON: 0x01,
CONF_LAZY_ERROR: 10,
CONF_VERIFY: { CONF_VERIFY: {
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_ADDRESS: 1235, CONF_ADDRESS: 1235,

View File

@ -10,7 +10,6 @@ from homeassistant.components.modbus.const import (
CALL_TYPE_REGISTER_INPUT, CALL_TYPE_REGISTER_INPUT,
CONF_DEVICE_ADDRESS, CONF_DEVICE_ADDRESS,
CONF_INPUT_TYPE, CONF_INPUT_TYPE,
CONF_LAZY_ERROR,
CONF_STATE_OFF, CONF_STATE_OFF,
CONF_STATE_ON, CONF_STATE_ON,
CONF_VERIFY, CONF_VERIFY,
@ -55,7 +54,6 @@ ENTITY_ID2 = f"{ENTITY_ID}_2"
CONF_NAME: TEST_ENTITY_NAME, CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234, CONF_ADDRESS: 1234,
CONF_WRITE_TYPE: CALL_TYPE_COIL, CONF_WRITE_TYPE: CALL_TYPE_COIL,
CONF_LAZY_ERROR: 10,
} }
] ]
}, },

View File

@ -1,7 +1,6 @@
"""The tests for the Modbus sensor component.""" """The tests for the Modbus sensor component."""
import struct import struct
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from homeassistant.components.modbus.const import ( from homeassistant.components.modbus.const import (
@ -10,7 +9,6 @@ from homeassistant.components.modbus.const import (
CONF_DATA_TYPE, CONF_DATA_TYPE,
CONF_DEVICE_ADDRESS, CONF_DEVICE_ADDRESS,
CONF_INPUT_TYPE, CONF_INPUT_TYPE,
CONF_LAZY_ERROR,
CONF_MAX_VALUE, CONF_MAX_VALUE,
CONF_MIN_VALUE, CONF_MIN_VALUE,
CONF_NAN_VALUE, CONF_NAN_VALUE,
@ -49,7 +47,7 @@ from homeassistant.core import HomeAssistant, State
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle from .conftest import TEST_ENTITY_NAME, ReadResult
from tests.common import mock_restore_cache_with_extra_data from tests.common import mock_restore_cache_with_extra_data
@ -80,7 +78,6 @@ SLAVE_UNIQUE_ID = "ground_floor_sensor"
CONF_SCALE: 1, CONF_SCALE: 1,
CONF_OFFSET: 0, CONF_OFFSET: 0,
CONF_STATE_CLASS: SensorStateClass.MEASUREMENT, CONF_STATE_CLASS: SensorStateClass.MEASUREMENT,
CONF_LAZY_ERROR: 10,
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_DEVICE_CLASS: "battery", CONF_DEVICE_CLASS: "battery",
} }
@ -97,7 +94,6 @@ SLAVE_UNIQUE_ID = "ground_floor_sensor"
CONF_SCALE: 1, CONF_SCALE: 1,
CONF_OFFSET: 0, CONF_OFFSET: 0,
CONF_STATE_CLASS: SensorStateClass.MEASUREMENT, CONF_STATE_CLASS: SensorStateClass.MEASUREMENT,
CONF_LAZY_ERROR: 10,
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_DEVICE_CLASS: "battery", CONF_DEVICE_CLASS: "battery",
} }
@ -1142,41 +1138,6 @@ async def test_unpack_ok(hass: HomeAssistant, mock_do_cycle, expected) -> None:
assert hass.states.get(ENTITY_ID).state == expected assert hass.states.get(ENTITY_ID).state == expected
@pytest.mark.parametrize(
"do_config",
[
{
CONF_SENSORS: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 51,
CONF_SCAN_INTERVAL: 10,
CONF_LAZY_ERROR: 1,
},
],
},
],
)
@pytest.mark.parametrize(
("register_words", "do_exception"),
[
(
[0x8000],
True,
),
],
)
async def test_lazy_error_sensor(
hass: HomeAssistant, mock_do_cycle: FrozenDateTimeFactory
) -> None:
"""Run test for sensor."""
hass.states.async_set(ENTITY_ID, 17)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == "17"
await do_next_cycle(hass, mock_do_cycle, 5)
assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
@pytest.mark.parametrize( @pytest.mark.parametrize(
"do_config", "do_config",
[ [

View File

@ -2,7 +2,6 @@
from datetime import timedelta from datetime import timedelta
from unittest import mock from unittest import mock
from freezegun.api import FrozenDateTimeFactory
from pymodbus.exceptions import ModbusException from pymodbus.exceptions import ModbusException
import pytest import pytest
@ -13,7 +12,6 @@ from homeassistant.components.modbus.const import (
CALL_TYPE_REGISTER_INPUT, CALL_TYPE_REGISTER_INPUT,
CONF_DEVICE_ADDRESS, CONF_DEVICE_ADDRESS,
CONF_INPUT_TYPE, CONF_INPUT_TYPE,
CONF_LAZY_ERROR,
CONF_STATE_OFF, CONF_STATE_OFF,
CONF_STATE_ON, CONF_STATE_ON,
CONF_VERIFY, CONF_VERIFY,
@ -39,7 +37,7 @@ from homeassistant.core import HomeAssistant, State
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle from .conftest import TEST_ENTITY_NAME, ReadResult
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
@ -64,7 +62,6 @@ ENTITY_ID2 = f"{ENTITY_ID}_2"
CONF_NAME: TEST_ENTITY_NAME, CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234, CONF_ADDRESS: 1234,
CONF_WRITE_TYPE: CALL_TYPE_COIL, CONF_WRITE_TYPE: CALL_TYPE_COIL,
CONF_LAZY_ERROR: 10,
} }
] ]
}, },
@ -227,46 +224,6 @@ async def test_all_switch(hass: HomeAssistant, mock_do_cycle, expected) -> None:
assert hass.states.get(ENTITY_ID).state == expected assert hass.states.get(ENTITY_ID).state == expected
@pytest.mark.parametrize(
"do_config",
[
{
CONF_SWITCHES: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SCAN_INTERVAL: 10,
CONF_LAZY_ERROR: 2,
CONF_VERIFY: {},
},
],
},
],
)
@pytest.mark.parametrize(
("register_words", "do_exception", "start_expect", "end_expect"),
[
(
[0x00],
True,
STATE_OFF,
STATE_UNAVAILABLE,
),
],
)
async def test_lazy_error_switch(
hass: HomeAssistant, start_expect, end_expect, mock_do_cycle: FrozenDateTimeFactory
) -> None:
"""Run test for given config."""
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == start_expect
await do_next_cycle(hass, mock_do_cycle, 11)
assert hass.states.get(ENTITY_ID).state == end_expect
@pytest.mark.parametrize( @pytest.mark.parametrize(
"mock_test_state", "mock_test_state",
[(State(ENTITY_ID, STATE_ON),), (State(ENTITY_ID, STATE_OFF),)], [(State(ENTITY_ID, STATE_ON),), (State(ENTITY_ID, STATE_OFF),)],