Allow manual scan and add delay in switch verify. (#50974)

This commit is contained in:
jan iversen 2021-05-24 12:59:55 +02:00 committed by GitHub
parent 2583e4bdc9
commit be13a73db8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 26 deletions

View File

@ -140,6 +140,8 @@ def control_scan_interval(config: dict) -> dict:
for entry in hub[conf_key]:
scan_interval = entry.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
if scan_interval < MINIMUM_SCAN_INTERVAL:
if scan_interval == 0:
continue
_LOGGER.warning(
"%s %s scan_interval(%d) is adjusted to minimum(%d)",
component,
@ -236,6 +238,7 @@ SWITCH_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
),
vol.Optional(CONF_STATE_OFF): cv.positive_int,
vol.Optional(CONF_STATE_ON): cv.positive_int,
vol.Optional(CONF_DELAY, default=0): cv.positive_int,
}
),
}

View File

@ -36,7 +36,7 @@ class BasePlatform(Entity):
self._input_type = entry[CONF_INPUT_TYPE]
self._value = None
self._available = True
self._scan_interval = timedelta(seconds=entry[CONF_SCAN_INTERVAL])
self._scan_interval = int(entry[CONF_SCAN_INTERVAL])
@abstractmethod
async def async_update(self, now=None):
@ -44,7 +44,10 @@ class BasePlatform(Entity):
async def async_base_added_to_hass(self):
"""Handle entity which will be added."""
async_track_time_interval(self.hass, self.async_update, self._scan_interval)
if self._scan_interval > 0:
async_track_time_interval(
self.hass, self.async_update, timedelta(seconds=self._scan_interval)
)
@property
def name(self):

View File

@ -8,11 +8,13 @@ from homeassistant.const import (
CONF_ADDRESS,
CONF_COMMAND_OFF,
CONF_COMMAND_ON,
CONF_DELAY,
CONF_NAME,
CONF_SWITCHES,
STATE_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType
@ -64,6 +66,7 @@ class ModbusSwitch(BasePlatform, SwitchEntity, RestoreEntity):
if config[CONF_VERIFY] is None:
config[CONF_VERIFY] = {}
self._verify_active = True
self._verify_delay = config[CONF_VERIFY].get(CONF_DELAY, 0)
self._verify_address = config[CONF_VERIFY].get(
CONF_ADDRESS, config[CONF_ADDRESS]
)
@ -87,38 +90,34 @@ class ModbusSwitch(BasePlatform, SwitchEntity, RestoreEntity):
"""Return true if switch is on."""
return self._is_on
async def async_turn_on(self, **kwargs):
"""Set switch on."""
async def _async_turn(self, command):
"""Evaluate switch result."""
result = await self._hub.async_pymodbus_call(
self._slave, self._address, self._command_on, self._write_type
self._slave, self._address, command, self._write_type
)
if result is None:
self._available = False
self.async_write_ha_state()
return
self._available = True
if not self._verify_active:
self._is_on = command == self._command_on
self.async_write_ha_state()
return
if self._verify_delay:
async_call_later(self.hass, self._verify_delay, self.async_update)
else:
self._available = True
if self._verify_active:
await self.async_update()
else:
self._is_on = True
self.async_write_ha_state()
await self.async_update()
async def async_turn_on(self, **kwargs):
"""Set switch on."""
await self._async_turn(self._command_on)
async def async_turn_off(self, **kwargs):
"""Set switch off."""
result = await self._hub.async_pymodbus_call(
self._slave, self._address, self._command_off, self._write_type
)
if result is None:
self._available = False
self.async_write_ha_state()
else:
self._available = True
if self._verify_active:
await self.async_update()
else:
self._is_on = False
self.async_write_ha_state()
await self._async_turn(self._command_off)
async def async_update(self, now=None):
"""Update the entity state."""

View File

@ -1,4 +1,7 @@
"""The tests for the Modbus switch component."""
from datetime import timedelta
from unittest import mock
from pymodbus.exceptions import ModbusException
import pytest
@ -19,10 +22,12 @@ from homeassistant.const import (
CONF_ADDRESS,
CONF_COMMAND_OFF,
CONF_COMMAND_ON,
CONF_DELAY,
CONF_DEVICE_CLASS,
CONF_HOST,
CONF_NAME,
CONF_PORT,
CONF_SCAN_INTERVAL,
CONF_SLAVE,
CONF_SWITCHES,
CONF_TYPE,
@ -32,10 +37,11 @@ from homeassistant.const import (
)
from homeassistant.core import State
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from .conftest import ReadResult, base_config_test, base_test, prepare_service_update
from tests.common import mock_restore_cache
from tests.common import async_fire_time_changed, mock_restore_cache
@pytest.mark.parametrize(
@ -72,6 +78,7 @@ from tests.common import mock_restore_cache
CONF_ADDRESS: 1235,
CONF_STATE_OFF: 0,
CONF_STATE_ON: 1,
CONF_DELAY: 10,
},
},
{
@ -93,6 +100,7 @@ from tests.common import mock_restore_cache
CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01,
CONF_DEVICE_CLASS: "switch",
CONF_SCAN_INTERVAL: 0,
CONF_VERIFY: None,
},
],
@ -292,3 +300,46 @@ async def test_service_switch_update(hass, mock_pymodbus):
"homeassistant", "update_entity", {"entity_id": entity_id}, blocking=True
)
assert hass.states.get(entity_id).state == STATE_OFF
async def test_delay_switch(hass, mock_pymodbus):
"""Run test for switch verify delay."""
switch_name = "test_switch"
entity_id = f"{SWITCH_DOMAIN}.{switch_name}"
config = {
MODBUS_DOMAIN: [
{
CONF_TYPE: "tcp",
CONF_HOST: "modbusTestHost",
CONF_PORT: 5501,
CONF_SWITCHES: [
{
CONF_NAME: switch_name,
CONF_ADDRESS: 51,
CONF_SCAN_INTERVAL: 0,
CONF_VERIFY: {
CONF_DELAY: 1,
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
},
}
],
}
]
}
mock_pymodbus.read_holding_registers.return_value = ReadResult([0x01])
now = dt_util.utcnow()
with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
assert await async_setup_component(hass, MODBUS_DOMAIN, config) is True
await hass.async_block_till_done()
await hass.services.async_call(
"switch", "turn_on", service_data={"entity_id": entity_id}
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF
now = now + timedelta(seconds=2)
with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
async_fire_time_changed(hass, now)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON