Initial hlk-sw16 relay switch support (#17855)
* Initial hlk-sw16 relay switch support * remove entity_id and validate relay id's * Bump hlk-sw16 library version and cleanup component * refactor hlk-sw16 switch platform loading * Use voluptuous to coerce relay id to string * remove force_update for SW16Switch * Move to callback based hlk-sw16 relay state changes * fix hlk-sw16 default port and cleanup some unused variables * Refactor to allow registration of multiple HLK-SW16 device * Store protocol in instance variable instead of class variable * remove is_connected * flake8 style fix * Move reconnect logic into HLK-SW16 client library * Cleanup and improve logging * Load hlk-sw16 platform entities at same time per device * scope SIGNAL_AVAILABILITY to device_id * Fixes for connection resume * move device_client out of switches loop * Add timeout for commands and keep alive * remove unused variables
This commit is contained in:
parent
5ae65142b8
commit
832fa61477
4 changed files with 223 additions and 0 deletions
|
@ -148,6 +148,9 @@ omit =
|
||||||
homeassistant/components/hive.py
|
homeassistant/components/hive.py
|
||||||
homeassistant/components/*/hive.py
|
homeassistant/components/*/hive.py
|
||||||
|
|
||||||
|
homeassistant/components/hlk_sw16.py
|
||||||
|
homeassistant/components/*/hlk_sw16.py
|
||||||
|
|
||||||
homeassistant/components/homekit_controller/__init__.py
|
homeassistant/components/homekit_controller/__init__.py
|
||||||
homeassistant/components/*/homekit_controller.py
|
homeassistant/components/*/homekit_controller.py
|
||||||
|
|
||||||
|
|
163
homeassistant/components/hlk_sw16.py
Normal file
163
homeassistant/components/hlk_sw16.py
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
"""
|
||||||
|
Support for HLK-SW16 relay switch.
|
||||||
|
|
||||||
|
For more details about this component, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/hlk_sw16/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_HOST, CONF_PORT,
|
||||||
|
EVENT_HOMEASSISTANT_STOP, CONF_SWITCHES, CONF_NAME)
|
||||||
|
from homeassistant.core import callback
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
|
from homeassistant.helpers.dispatcher import (
|
||||||
|
async_dispatcher_send, async_dispatcher_connect)
|
||||||
|
|
||||||
|
REQUIREMENTS = ['hlk-sw16==0.0.6']
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DATA_DEVICE_REGISTER = 'hlk_sw16_device_register'
|
||||||
|
DEFAULT_RECONNECT_INTERVAL = 10
|
||||||
|
CONNECTION_TIMEOUT = 10
|
||||||
|
DEFAULT_PORT = 8080
|
||||||
|
|
||||||
|
DOMAIN = 'hlk_sw16'
|
||||||
|
|
||||||
|
SIGNAL_AVAILABILITY = 'hlk_sw16_device_available_{}'
|
||||||
|
|
||||||
|
SWITCH_SCHEMA = vol.Schema({
|
||||||
|
vol.Optional(CONF_NAME): cv.string,
|
||||||
|
})
|
||||||
|
|
||||||
|
RELAY_ID = vol.All(
|
||||||
|
vol.Any(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'),
|
||||||
|
vol.Coerce(str))
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Schema({
|
||||||
|
cv.string: vol.Schema({
|
||||||
|
vol.Required(CONF_HOST): cv.string,
|
||||||
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||||
|
vol.Required(CONF_SWITCHES): vol.Schema({RELAY_ID: SWITCH_SCHEMA}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass, config):
|
||||||
|
"""Set up the HLK-SW16 switch."""
|
||||||
|
# Allow platform to specify function to register new unknown devices
|
||||||
|
from hlk_sw16 import create_hlk_sw16_connection
|
||||||
|
hass.data[DATA_DEVICE_REGISTER] = {}
|
||||||
|
|
||||||
|
def add_device(device):
|
||||||
|
switches = config[DOMAIN][device][CONF_SWITCHES]
|
||||||
|
|
||||||
|
host = config[DOMAIN][device][CONF_HOST]
|
||||||
|
port = config[DOMAIN][device][CONF_PORT]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def disconnected():
|
||||||
|
"""Schedule reconnect after connection has been lost."""
|
||||||
|
_LOGGER.warning('HLK-SW16 %s disconnected', device)
|
||||||
|
async_dispatcher_send(hass, SIGNAL_AVAILABILITY.format(device),
|
||||||
|
False)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def reconnected():
|
||||||
|
"""Schedule reconnect after connection has been lost."""
|
||||||
|
_LOGGER.warning('HLK-SW16 %s connected', device)
|
||||||
|
async_dispatcher_send(hass, SIGNAL_AVAILABILITY.format(device),
|
||||||
|
True)
|
||||||
|
|
||||||
|
async def connect():
|
||||||
|
"""Set up connection and hook it into HA for reconnect/shutdown."""
|
||||||
|
_LOGGER.info('Initiating HLK-SW16 connection to %s', device)
|
||||||
|
|
||||||
|
client = await create_hlk_sw16_connection(
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
disconnect_callback=disconnected,
|
||||||
|
reconnect_callback=reconnected,
|
||||||
|
loop=hass.loop,
|
||||||
|
timeout=CONNECTION_TIMEOUT,
|
||||||
|
reconnect_interval=DEFAULT_RECONNECT_INTERVAL)
|
||||||
|
|
||||||
|
hass.data[DATA_DEVICE_REGISTER][device] = client
|
||||||
|
|
||||||
|
# Load platforms
|
||||||
|
hass.async_create_task(
|
||||||
|
async_load_platform(hass, 'switch', DOMAIN,
|
||||||
|
(switches, device),
|
||||||
|
config))
|
||||||
|
|
||||||
|
# handle shutdown of HLK-SW16 asyncio transport
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
|
||||||
|
lambda x: client.stop())
|
||||||
|
|
||||||
|
_LOGGER.info('Connected to HLK-SW16 device: %s', device)
|
||||||
|
|
||||||
|
hass.loop.create_task(connect())
|
||||||
|
|
||||||
|
for device in config[DOMAIN]:
|
||||||
|
add_device(device)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class SW16Device(Entity):
|
||||||
|
"""Representation of a HLK-SW16 device.
|
||||||
|
|
||||||
|
Contains the common logic for HLK-SW16 entities.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, relay_name, device_port, device_id, client):
|
||||||
|
"""Initialize the device."""
|
||||||
|
# HLK-SW16 specific attributes for every component type
|
||||||
|
self._device_id = device_id
|
||||||
|
self._device_port = device_port
|
||||||
|
self._is_on = None
|
||||||
|
self._client = client
|
||||||
|
self._name = relay_name
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def handle_event_callback(self, event):
|
||||||
|
"""Propagate changes through ha."""
|
||||||
|
_LOGGER.debug("Relay %s new state callback: %r",
|
||||||
|
self._device_port, event)
|
||||||
|
self._is_on = event
|
||||||
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No polling needed."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return a name for the device."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return True if entity is available."""
|
||||||
|
return bool(self._client.is_connected)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _availability_callback(self, availability):
|
||||||
|
"""Update availability state."""
|
||||||
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Register update callback."""
|
||||||
|
self._client.register_status_callback(self.handle_event_callback,
|
||||||
|
self._device_port)
|
||||||
|
self._is_on = await self._client.status(self._device_port)
|
||||||
|
async_dispatcher_connect(self.hass,
|
||||||
|
SIGNAL_AVAILABILITY.format(self._device_id),
|
||||||
|
self._availability_callback)
|
54
homeassistant/components/switch/hlk_sw16.py
Normal file
54
homeassistant/components/switch/hlk_sw16.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
"""
|
||||||
|
Support for HLK-SW16 switches.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/switch.hlk_sw16/
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.components.hlk_sw16 import (
|
||||||
|
SW16Device, DOMAIN as HLK_SW16,
|
||||||
|
DATA_DEVICE_REGISTER)
|
||||||
|
from homeassistant.components.switch import (
|
||||||
|
ToggleEntity)
|
||||||
|
from homeassistant.const import CONF_NAME
|
||||||
|
|
||||||
|
DEPENDENCIES = [HLK_SW16]
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def devices_from_config(hass, domain_config):
|
||||||
|
"""Parse configuration and add HLK-SW16 switch devices."""
|
||||||
|
switches = domain_config[0]
|
||||||
|
device_id = domain_config[1]
|
||||||
|
device_client = hass.data[DATA_DEVICE_REGISTER][device_id]
|
||||||
|
devices = []
|
||||||
|
for device_port, device_config in switches.items():
|
||||||
|
device_name = device_config.get(CONF_NAME, device_port)
|
||||||
|
device = SW16Switch(device_name, device_port, device_id, device_client)
|
||||||
|
devices.append(device)
|
||||||
|
return devices
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities,
|
||||||
|
discovery_info=None):
|
||||||
|
"""Set up the HLK-SW16 platform."""
|
||||||
|
async_add_entities(devices_from_config(hass, discovery_info))
|
||||||
|
|
||||||
|
|
||||||
|
class SW16Switch(SW16Device, ToggleEntity):
|
||||||
|
"""Representation of a HLK-SW16 switch."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return true if device is on."""
|
||||||
|
return self._is_on
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs):
|
||||||
|
"""Turn the device on."""
|
||||||
|
await self._client.turn_on(self._device_port)
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs):
|
||||||
|
"""Turn the device off."""
|
||||||
|
await self._client.turn_off(self._device_port)
|
|
@ -482,6 +482,9 @@ hikvision==0.4
|
||||||
# homeassistant.components.notify.hipchat
|
# homeassistant.components.notify.hipchat
|
||||||
hipnotify==1.0.8
|
hipnotify==1.0.8
|
||||||
|
|
||||||
|
# homeassistant.components.hlk_sw16
|
||||||
|
hlk-sw16==0.0.6
|
||||||
|
|
||||||
# homeassistant.components.sensor.pi_hole
|
# homeassistant.components.sensor.pi_hole
|
||||||
hole==0.3.0
|
hole==0.3.0
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue