diff --git a/.coveragerc b/.coveragerc index 35d60239a28..de0c947eecb 100644 --- a/.coveragerc +++ b/.coveragerc @@ -646,6 +646,7 @@ omit = homeassistant/components/modbus/cover.py homeassistant/components/modbus/climate.py homeassistant/components/modbus/modbus.py + homeassistant/components/modbus/sensor.py homeassistant/components/modbus/validators.py homeassistant/components/modem_callerid/sensor.py homeassistant/components/motion_blinds/__init__.py diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index e98a61257c6..0ff3b67c79f 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -65,6 +65,7 @@ from .const import ( CONF_DATA_TYPE, CONF_FANS, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_MAX_TEMP, CONF_MIN_TEMP, CONF_MSG_WAIT, @@ -136,6 +137,7 @@ BASE_COMPONENT_SCHEMA = vol.Schema( vol.Optional( CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL ): cv.positive_int, + vol.Optional(CONF_LAZY_ERROR, default=0): cv.positive_int, } ) diff --git a/homeassistant/components/modbus/base_platform.py b/homeassistant/components/modbus/base_platform.py index 468e61aefa8..1e2f1056db2 100644 --- a/homeassistant/components/modbus/base_platform.py +++ b/homeassistant/components/modbus/base_platform.py @@ -36,6 +36,7 @@ from .const import ( CALL_TYPE_X_REGISTER_HOLDINGS, CONF_DATA_TYPE, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_PRECISION, CONF_SCALE, CONF_STATE_OFF, @@ -76,6 +77,8 @@ class BasePlatform(Entity): self._attr_device_class = entry.get(CONF_DEVICE_CLASS) self._attr_available = True self._attr_unit_of_measurement = None + self._lazy_error_count = entry[CONF_LAZY_ERROR] + self._lazy_errors = self._lazy_error_count @abstractmethod async def async_update(self, now=None): @@ -245,10 +248,15 @@ class BaseSwitch(BasePlatform, ToggleEntity, RestoreEntity): ) self._call_active = False 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.async_write_ha_state() return + self._lazy_errors = self._lazy_error_count self._attr_available = True if self._verify_type == CALL_TYPE_COIL: self._attr_is_on = bool(result.bits[0] & 1) diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index 08ebfc72880..adc5e2d28f1 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -57,10 +57,15 @@ class ModbusBinarySensor(BasePlatform, RestoreEntity, BinarySensorEntity): ) self._call_active = False 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.async_write_ha_state() return + self._lazy_errors = self._lazy_error_count self._attr_is_on = result.bits[0] & 1 self._attr_available = True self.async_write_ha_state() diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 831f3c979cc..0a89610a2f5 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -162,9 +162,14 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): self._slave, register, self._count, register_type ) 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 return -1 + self._lazy_errors = self._lazy_error_count self._value = self.unpack_structure_result(result.registers) self._attr_available = True diff --git a/homeassistant/components/modbus/const.py b/homeassistant/components/modbus/const.py index 01e0fdd5e13..3bcd85053d2 100644 --- a/homeassistant/components/modbus/const.py +++ b/homeassistant/components/modbus/const.py @@ -28,6 +28,7 @@ CONF_FANS = "fans" CONF_HUB = "hub" CONF_INPUTS = "inputs" CONF_INPUT_TYPE = "input_type" +CONF_LAZY_ERROR = "lazy_error_count" CONF_MAX_TEMP = "max_temp" CONF_MIN_TEMP = "min_temp" CONF_MSG_WAIT = "message_wait_milliseconds" diff --git a/homeassistant/components/modbus/cover.py b/homeassistant/components/modbus/cover.py index 64165412d27..5fa77eb1cb8 100644 --- a/homeassistant/components/modbus/cover.py +++ b/homeassistant/components/modbus/cover.py @@ -146,9 +146,14 @@ class ModbusCover(BasePlatform, CoverEntity, RestoreEntity): ) self._call_active = False 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.async_write_ha_state() - return None + return + self._lazy_errors = self._lazy_error_count self._attr_available = True if self._input_type == CALL_TYPE_COIL: self._set_attr_state(bool(result.bits[0] & 1)) diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 3165f416a6e..2041f8974da 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -64,10 +64,15 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreEntity, SensorEntity): self._slave, self._address, self._count, self._input_type ) 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.async_write_ha_state() return self._attr_native_value = self.unpack_structure_result(result.registers) + self._lazy_errors = self._lazy_error_count self._attr_available = True self.async_write_ha_state() diff --git a/tests/components/modbus/test_binary_sensor.py b/tests/components/modbus/test_binary_sensor.py index fb52ea11090..a710a8b0598 100644 --- a/tests/components/modbus/test_binary_sensor.py +++ b/tests/components/modbus/test_binary_sensor.py @@ -6,6 +6,7 @@ from homeassistant.components.modbus.const import ( CALL_TYPE_COIL, CALL_TYPE_DISCRETE, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, ) from homeassistant.const import ( CONF_ADDRESS, @@ -44,6 +45,7 @@ ENTITY_ID = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}" CONF_SLAVE: 10, CONF_INPUT_TYPE: CALL_TYPE_DISCRETE, CONF_DEVICE_CLASS: "door", + CONF_LAZY_ERROR: 10, } ] }, diff --git a/tests/components/modbus/test_climate.py b/tests/components/modbus/test_climate.py index 16ef18a60ac..d7096d91b44 100644 --- a/tests/components/modbus/test_climate.py +++ b/tests/components/modbus/test_climate.py @@ -6,6 +6,7 @@ from homeassistant.components.climate.const import HVAC_MODE_AUTO from homeassistant.components.modbus.const import ( CONF_CLIMATES, CONF_DATA_TYPE, + CONF_LAZY_ERROR, CONF_TARGET_TEMP, DATA_TYPE_FLOAT32, DATA_TYPE_FLOAT64, @@ -49,6 +50,7 @@ ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}" CONF_SLAVE: 10, CONF_SCAN_INTERVAL: 20, CONF_COUNT: 2, + CONF_LAZY_ERROR: 10, } ], }, diff --git a/tests/components/modbus/test_cover.py b/tests/components/modbus/test_cover.py index a315d8176ae..2f502587949 100644 --- a/tests/components/modbus/test_cover.py +++ b/tests/components/modbus/test_cover.py @@ -8,6 +8,7 @@ from homeassistant.components.modbus.const import ( CALL_TYPE_COIL, CALL_TYPE_REGISTER_HOLDING, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_STATE_CLOSED, CONF_STATE_CLOSING, CONF_STATE_OPEN, @@ -54,6 +55,7 @@ ENTITY_ID = f"{COVER_DOMAIN}.{TEST_ENTITY_NAME}" CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_SLAVE: 10, CONF_SCAN_INTERVAL: 20, + CONF_LAZY_ERROR: 10, } ] }, diff --git a/tests/components/modbus/test_fan.py b/tests/components/modbus/test_fan.py index 821a5cace99..a54b2212fd5 100644 --- a/tests/components/modbus/test_fan.py +++ b/tests/components/modbus/test_fan.py @@ -10,6 +10,7 @@ from homeassistant.components.modbus.const import ( CALL_TYPE_REGISTER_INPUT, CONF_FANS, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_STATE_OFF, CONF_STATE_ON, CONF_VERIFY, @@ -73,6 +74,7 @@ ENTITY_ID = f"{FAN_DOMAIN}.{TEST_ENTITY_NAME}" CONF_SLAVE: 1, CONF_COMMAND_OFF: 0x00, CONF_COMMAND_ON: 0x01, + CONF_LAZY_ERROR: 10, CONF_VERIFY: { CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_ADDRESS: 1235, diff --git a/tests/components/modbus/test_light.py b/tests/components/modbus/test_light.py index 486dfdc64f8..bb4bb7b08f9 100644 --- a/tests/components/modbus/test_light.py +++ b/tests/components/modbus/test_light.py @@ -9,6 +9,7 @@ from homeassistant.components.modbus.const import ( CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_STATE_OFF, CONF_STATE_ON, CONF_VERIFY, @@ -62,6 +63,7 @@ ENTITY_ID = f"{LIGHT_DOMAIN}.{TEST_ENTITY_NAME}" CONF_NAME: TEST_ENTITY_NAME, CONF_ADDRESS: 1234, CONF_WRITE_TYPE: CALL_TYPE_COIL, + CONF_LAZY_ERROR: 10, } ] }, diff --git a/tests/components/modbus/test_sensor.py b/tests/components/modbus/test_sensor.py index e69a6be41a4..07fe8ada2d0 100644 --- a/tests/components/modbus/test_sensor.py +++ b/tests/components/modbus/test_sensor.py @@ -6,6 +6,7 @@ from homeassistant.components.modbus.const import ( CALL_TYPE_REGISTER_INPUT, CONF_DATA_TYPE, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_PRECISION, CONF_REGISTERS, CONF_SCALE, @@ -62,6 +63,7 @@ ENTITY_ID = f"{SENSOR_DOMAIN}.{TEST_ENTITY_NAME}" CONF_PRECISION: 0, CONF_SCALE: 1, CONF_OFFSET: 0, + CONF_LAZY_ERROR: 10, CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, CONF_DEVICE_CLASS: "battery", } diff --git a/tests/components/modbus/test_switch.py b/tests/components/modbus/test_switch.py index fb929d26caf..064d9cf7965 100644 --- a/tests/components/modbus/test_switch.py +++ b/tests/components/modbus/test_switch.py @@ -11,6 +11,7 @@ from homeassistant.components.modbus.const import ( CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT, CONF_INPUT_TYPE, + CONF_LAZY_ERROR, CONF_STATE_OFF, CONF_STATE_ON, CONF_VERIFY, @@ -70,6 +71,7 @@ ENTITY_ID = f"{SWITCH_DOMAIN}.{TEST_ENTITY_NAME}" CONF_NAME: TEST_ENTITY_NAME, CONF_ADDRESS: 1234, CONF_WRITE_TYPE: CALL_TYPE_COIL, + CONF_LAZY_ERROR: 10, } ] },