diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index 64a9e71b3fc..d83406a71d5 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -234,8 +234,10 @@ BASE_SWITCH_SCHEMA = BASE_COMPONENT_SCHEMA.extend( CALL_TYPE_X_REGISTER_HOLDINGS, ] ), - vol.Optional(CONF_STATE_OFF): cv.positive_int, - vol.Optional(CONF_STATE_ON): cv.positive_int, + vol.Optional(CONF_STATE_OFF): vol.All( + cv.ensure_list, [cv.positive_int] + ), + vol.Optional(CONF_STATE_ON): vol.All(cv.ensure_list, [cv.positive_int]), vol.Optional(CONF_DELAY, default=0): cv.positive_int, } ), diff --git a/homeassistant/components/modbus/entity.py b/homeassistant/components/modbus/entity.py index 9f0e862f283..90833516e59 100644 --- a/homeassistant/components/modbus/entity.py +++ b/homeassistant/components/modbus/entity.py @@ -297,8 +297,10 @@ class BaseSwitch(BasePlatform, ToggleEntity, RestoreEntity): self._verify_type = convert[ config[CONF_VERIFY].get(CONF_INPUT_TYPE, config[CONF_WRITE_TYPE]) ][0] - self._state_on = config[CONF_VERIFY].get(CONF_STATE_ON, self.command_on) - self._state_off = config[CONF_VERIFY].get(CONF_STATE_OFF, self._command_off) + self._state_on = config[CONF_VERIFY].get(CONF_STATE_ON, [self.command_on]) + self._state_off = config[CONF_VERIFY].get( + CONF_STATE_OFF, [self._command_off] + ) else: self._verify_active = False @@ -363,9 +365,9 @@ class BaseSwitch(BasePlatform, ToggleEntity, RestoreEntity): self._attr_is_on = bool(result.bits[0] & 1) else: value = int(result.registers[0]) - if value == self._state_on: + if value in self._state_on: self._attr_is_on = True - elif value == self._state_off: + elif value in self._state_off: self._attr_is_on = False elif value is not None: _LOGGER.error( diff --git a/tests/components/modbus/test_switch.py b/tests/components/modbus/test_switch.py index bdb95c667c7..999983a5e30 100644 --- a/tests/components/modbus/test_switch.py +++ b/tests/components/modbus/test_switch.py @@ -44,6 +44,7 @@ from tests.common import async_fire_time_changed ENTITY_ID = f"{SWITCH_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") ENTITY_ID2 = f"{ENTITY_ID}_2" +ENTITY_ID3 = f"{ENTITY_ID}_3" @pytest.mark.parametrize( @@ -153,6 +154,42 @@ ENTITY_ID2 = f"{ENTITY_ID}_2" } ] }, + { + CONF_SWITCHES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_ADDRESS: 1234, + CONF_DEVICE_ADDRESS: 10, + CONF_COMMAND_OFF: 0x00, + CONF_COMMAND_ON: 0x01, + CONF_DEVICE_CLASS: "switch", + CONF_VERIFY: { + CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, + CONF_ADDRESS: 1235, + CONF_STATE_OFF: 0, + CONF_STATE_ON: [1, 2, 3], + }, + } + ] + }, + { + CONF_SWITCHES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_ADDRESS: 1236, + CONF_DEVICE_ADDRESS: 10, + CONF_COMMAND_OFF: 0x00, + CONF_COMMAND_ON: 0x01, + CONF_DEVICE_CLASS: "switch", + CONF_VERIFY: { + CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING, + CONF_ADDRESS: 1235, + CONF_STATE_OFF: [0, 5, 6], + CONF_STATE_ON: 1, + }, + } + ] + }, ], ) async def test_config_switch(hass: HomeAssistant, mock_modbus) -> None: @@ -218,6 +255,18 @@ async def test_config_switch(hass: HomeAssistant, mock_modbus) -> None: None, STATE_OFF, ), + ( + [0x03], + False, + {CONF_VERIFY: {CONF_STATE_ON: [1, 3]}}, + STATE_ON, + ), + ( + [0x04], + False, + {CONF_VERIFY: {CONF_STATE_OFF: [0, 4]}}, + STATE_OFF, + ), ], ) async def test_all_switch(hass: HomeAssistant, mock_do_cycle, expected) -> None: @@ -269,6 +318,13 @@ async def test_restore_state_switch( CONF_SCAN_INTERVAL: 0, CONF_VERIFY: {}, }, + { + CONF_NAME: f"{TEST_ENTITY_NAME} 3", + CONF_ADDRESS: 18, + CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING, + CONF_SCAN_INTERVAL: 0, + CONF_VERIFY: {CONF_STATE_ON: [1, 3]}, + }, ], }, ], @@ -306,6 +362,19 @@ async def test_switch_service_turn( ) await hass.async_block_till_done() assert hass.states.get(ENTITY_ID2).state == STATE_OFF + mock_modbus.read_holding_registers.return_value = ReadResult([0x03]) + assert hass.states.get(ENTITY_ID3).state == STATE_OFF + await hass.services.async_call( + "switch", "turn_on", service_data={"entity_id": ENTITY_ID3} + ) + await hass.async_block_till_done() + assert hass.states.get(ENTITY_ID3).state == STATE_ON + mock_modbus.read_holding_registers.return_value = ReadResult([0x00]) + await hass.services.async_call( + "switch", "turn_off", service_data={"entity_id": ENTITY_ID3} + ) + await hass.async_block_till_done() + assert hass.states.get(ENTITY_ID3).state == STATE_OFF mock_modbus.write_register.side_effect = ModbusException("fail write_") await hass.services.async_call( @@ -319,6 +388,12 @@ async def test_switch_service_turn( ) await hass.async_block_till_done() assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE + mock_modbus.write_register.side_effect = ModbusException("fail write_") + await hass.services.async_call( + "switch", "turn_on", service_data={"entity_id": ENTITY_ID3} + ) + await hass.async_block_till_done() + assert hass.states.get(ENTITY_ID3).state == STATE_UNAVAILABLE @pytest.mark.parametrize( @@ -334,6 +409,26 @@ async def test_switch_service_turn( } ] }, + { + CONF_SWITCHES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_ADDRESS: 1236, + CONF_WRITE_TYPE: CALL_TYPE_COIL, + CONF_VERIFY: {CONF_STATE_ON: [1, 3]}, + } + ] + }, + { + CONF_SWITCHES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_ADDRESS: 1235, + CONF_WRITE_TYPE: CALL_TYPE_COIL, + CONF_VERIFY: {CONF_STATE_OFF: [0, 5]}, + } + ] + }, ], ) async def test_service_switch_update(hass: HomeAssistant, mock_modbus_ha) -> None: