Add separate on/off ids on manual configured IHC lights (#20253)

* Add support for separate on/off ids on manual configured IHC lights.
This makes it easier to support IHC code units thats relies on being
turned on and off through specific inputs.
Also adds a pulse service (ihc.pulse) that supports sending a short on/off pulse to an IHC input.

* Fix

* Lint fix

* Add on/off id support in switch

* Make pulse async

* Code review fixes
This commit is contained in:
msvinth 2019-03-01 08:17:59 +01:00 committed by Martin Hjelmare
parent ee4be13bda
commit 0aba49adce
6 changed files with 109 additions and 23 deletions

View File

@ -7,9 +7,11 @@ import voluptuous as vol
from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA
from homeassistant.components.ihc.const import (
ATTR_IHC_ID, ATTR_VALUE, CONF_AUTOSETUP, CONF_BINARY_SENSOR, CONF_DIMMABLE,
CONF_INFO, CONF_INVERTING, CONF_LIGHT, CONF_NODE, CONF_NOTE, CONF_POSITION,
CONF_SENSOR, CONF_SWITCH, CONF_XPATH, SERVICE_SET_RUNTIME_VALUE_BOOL,
SERVICE_SET_RUNTIME_VALUE_FLOAT, SERVICE_SET_RUNTIME_VALUE_INT)
CONF_INFO, CONF_INVERTING, CONF_LIGHT, CONF_NODE, CONF_NOTE, CONF_OFF_ID,
CONF_ON_ID, CONF_POSITION, CONF_SENSOR, CONF_SWITCH, CONF_XPATH,
SERVICE_SET_RUNTIME_VALUE_BOOL, SERVICE_SET_RUNTIME_VALUE_FLOAT,
SERVICE_SET_RUNTIME_VALUE_INT, SERVICE_PULSE)
from homeassistant.components.ihc.util import async_pulse
from homeassistant.config import load_yaml_config_file
from homeassistant.const import (
CONF_ID, CONF_NAME, CONF_PASSWORD, CONF_TYPE, CONF_UNIT_OF_MEASUREMENT,
@ -50,7 +52,10 @@ DEVICE_SCHEMA = vol.Schema({
})
SWITCH_SCHEMA = DEVICE_SCHEMA.extend({})
SWITCH_SCHEMA = DEVICE_SCHEMA.extend({
vol.Optional(CONF_OFF_ID, default=0): cv.positive_int,
vol.Optional(CONF_ON_ID, default=0): cv.positive_int,
})
BINARY_SENSOR_SCHEMA = DEVICE_SCHEMA.extend({
vol.Optional(CONF_INVERTING, default=False): cv.boolean,
@ -59,6 +64,8 @@ BINARY_SENSOR_SCHEMA = DEVICE_SCHEMA.extend({
LIGHT_SCHEMA = DEVICE_SCHEMA.extend({
vol.Optional(CONF_DIMMABLE, default=False): cv.boolean,
vol.Optional(CONF_OFF_ID, default=0): cv.positive_int,
vol.Optional(CONF_ON_ID, default=0): cv.positive_int,
})
SENSOR_SCHEMA = DEVICE_SCHEMA.extend({
@ -138,6 +145,10 @@ SET_RUNTIME_VALUE_FLOAT_SCHEMA = vol.Schema({
vol.Required(ATTR_VALUE): vol.Coerce(float),
})
PULSE_SCHEMA = vol.Schema({
vol.Required(ATTR_IHC_ID): cv.positive_int,
})
def setup(hass, config):
"""Set up the IHC platform."""
@ -197,6 +208,8 @@ def get_manual_configuration(
'product_cfg': {
'type': sensor_cfg.get(CONF_TYPE),
'inverting': sensor_cfg.get(CONF_INVERTING),
'off_id': sensor_cfg.get(CONF_OFF_ID),
'on_id': sensor_cfg.get(CONF_ON_ID),
'dimmable': sensor_cfg.get(CONF_DIMMABLE),
'unit_of_measurement': sensor_cfg.get(
CONF_UNIT_OF_MEASUREMENT)
@ -287,6 +300,11 @@ def setup_service_functions(hass: HomeAssistantType, ihc_controller):
value = call.data[ATTR_VALUE]
ihc_controller.set_runtime_value_float(ihc_id, value)
async def async_pulse_runtime_input(call):
"""Pulse a IHC controller input function."""
ihc_id = call.data[ATTR_IHC_ID]
await async_pulse(hass, ihc_controller, ihc_id)
hass.services.register(DOMAIN, SERVICE_SET_RUNTIME_VALUE_BOOL,
set_runtime_value_bool,
schema=SET_RUNTIME_VALUE_BOOL_SCHEMA)
@ -296,3 +314,6 @@ def setup_service_functions(hass: HomeAssistantType, ihc_controller):
hass.services.register(DOMAIN, SERVICE_SET_RUNTIME_VALUE_FLOAT,
set_runtime_value_float,
schema=SET_RUNTIME_VALUE_FLOAT_SCHEMA)
hass.services.register(DOMAIN, SERVICE_PULSE,
async_pulse_runtime_input,
schema=PULSE_SCHEMA)

View File

@ -9,6 +9,8 @@ CONF_LIGHT = 'light'
CONF_NAME = 'name'
CONF_NODE = 'node'
CONF_NOTE = 'note'
CONF_OFF_ID = 'off_id'
CONF_ON_ID = 'on_id'
CONF_POSITION = 'position'
CONF_SENSOR = 'sensor'
CONF_SWITCH = 'switch'
@ -20,3 +22,4 @@ ATTR_VALUE = 'value'
SERVICE_SET_RUNTIME_VALUE_BOOL = 'set_runtime_value_bool'
SERVICE_SET_RUNTIME_VALUE_FLOAT = 'set_runtime_value_float'
SERVICE_SET_RUNTIME_VALUE_INT = 'set_runtime_value_int'
SERVICE_PULSE = 'pulse'

View File

@ -2,7 +2,10 @@
import logging
from homeassistant.components.ihc import IHC_CONTROLLER, IHC_DATA, IHC_INFO
from homeassistant.components.ihc.const import CONF_DIMMABLE
from homeassistant.components.ihc.const import (
CONF_DIMMABLE, CONF_OFF_ID, CONF_ON_ID)
from homeassistant.components.ihc.util import (
async_pulse, async_set_bool, async_set_int)
from homeassistant.components.ihc.ihcdevice import IHCDevice
from homeassistant.components.light import (
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light)
@ -26,9 +29,11 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
ihc_key = IHC_DATA.format(ctrl_id)
info = hass.data[ihc_key][IHC_INFO]
ihc_controller = hass.data[ihc_key][IHC_CONTROLLER]
ihc_off_id = product_cfg.get(CONF_OFF_ID)
ihc_on_id = product_cfg.get(CONF_ON_ID)
dimmable = product_cfg[CONF_DIMMABLE]
light = IhcLight(ihc_controller, name, ihc_id, info,
dimmable, product)
light = IhcLight(ihc_controller, name, ihc_id, ihc_off_id, ihc_on_id,
info, dimmable, product)
devices.append(light)
add_entities(devices)
@ -41,10 +46,13 @@ class IhcLight(IHCDevice, Light):
an on/off (boolean) resource
"""
def __init__(self, ihc_controller, name, ihc_id: int, info: bool,
dimmable=False, product=None) -> None:
def __init__(self, ihc_controller, name, ihc_id: int, ihc_off_id: int,
ihc_on_id: int, info: bool, dimmable=False,
product=None) -> None:
"""Initialize the light."""
super().__init__(ihc_controller, name, ihc_id, info, product)
self._ihc_off_id = ihc_off_id
self._ihc_on_id = ihc_on_id
self._brightness = 0
self._dimmable = dimmable
self._state = None
@ -66,7 +74,7 @@ class IhcLight(IHCDevice, Light):
return SUPPORT_BRIGHTNESS
return 0
def turn_on(self, **kwargs) -> None:
async def async_turn_on(self, **kwargs):
"""Turn the light on."""
if ATTR_BRIGHTNESS in kwargs:
brightness = kwargs[ATTR_BRIGHTNESS]
@ -76,17 +84,28 @@ class IhcLight(IHCDevice, Light):
brightness = 255
if self._dimmable:
self.ihc_controller.set_runtime_value_int(
await async_set_int(self.hass, self.ihc_controller,
self.ihc_id, int(brightness * 100 / 255))
else:
self.ihc_controller.set_runtime_value_bool(self.ihc_id, True)
if self._ihc_on_id:
await async_pulse(self.hass, self.ihc_controller,
self._ihc_on_id)
else:
await async_set_bool(self.hass, self.ihc_controller,
self.ihc_id, True)
def turn_off(self, **kwargs) -> None:
async def async_turn_off(self, **kwargs):
"""Turn the light off."""
if self._dimmable:
self.ihc_controller.set_runtime_value_int(self.ihc_id, 0)
await async_set_int(self.hass, self.ihc_controller,
self.ihc_id, 0)
else:
self.ihc_controller.set_runtime_value_bool(self.ihc_id, False)
if self._ihc_off_id:
await async_pulse(self.hass, self.ihc_controller,
self._ihc_off_id)
else:
await async_set_bool(self.hass, self.ihc_controller,
self.ihc_id, False)
def on_ihc_change(self, ihc_id, value):
"""Handle IHC notifications."""

View File

@ -24,3 +24,8 @@ set_runtime_value_float:
value:
description: The float value to set.
pulse:
description: Pulses an input on the IHC controller.
fields:
ihc_id:
description: The integer IHC resource ID.

View File

@ -1,5 +1,7 @@
"""Support for IHC switches."""
from homeassistant.components.ihc import IHC_CONTROLLER, IHC_DATA, IHC_INFO
from homeassistant.components.ihc.const import CONF_OFF_ID, CONF_ON_ID
from homeassistant.components.ihc.util import async_pulse, async_set_bool
from homeassistant.components.ihc.ihcdevice import IHCDevice
from homeassistant.components.switch import SwitchDevice
@ -13,14 +15,18 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
devices = []
for name, device in discovery_info.items():
ihc_id = device['ihc_id']
product_cfg = device['product_cfg']
product = device['product']
# Find controller that corresponds with device id
ctrl_id = device['ctrl_id']
ihc_key = IHC_DATA.format(ctrl_id)
info = hass.data[ihc_key][IHC_INFO]
ihc_controller = hass.data[ihc_key][IHC_CONTROLLER]
ihc_off_id = product_cfg.get(CONF_OFF_ID)
ihc_on_id = product_cfg.get(CONF_ON_ID)
switch = IHCSwitch(ihc_controller, name, ihc_id, info, product)
switch = IHCSwitch(ihc_controller, name, ihc_id, ihc_off_id, ihc_on_id,
info, product)
devices.append(switch)
add_entities(devices)
@ -28,10 +34,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class IHCSwitch(IHCDevice, SwitchDevice):
"""Representation of an IHC switch."""
def __init__(self, ihc_controller, name: str, ihc_id: int,
info: bool, product=None) -> None:
def __init__(self, ihc_controller, name: str, ihc_id: int, ihc_off_id: int,
ihc_on_id: int, info: bool, product=None) -> None:
"""Initialize the IHC switch."""
super().__init__(ihc_controller, name, ihc_id, product)
self._ihc_off_id = ihc_off_id
self._ihc_on_id = ihc_on_id
self._state = False
@property
@ -39,13 +47,21 @@ class IHCSwitch(IHCDevice, SwitchDevice):
"""Return true if switch is on."""
return self._state
def turn_on(self, **kwargs):
async def async_turn_on(self, **kwargs):
"""Turn the switch on."""
self.ihc_controller.set_runtime_value_bool(self.ihc_id, True)
if self._ihc_on_id:
await async_pulse(self.hass, self.ihc_controller, self._ihc_on_id)
else:
await async_set_bool(self.hass, self.ihc_controller,
self.ihc_id, True)
def turn_off(self, **kwargs):
async def async_turn_off(self, **kwargs):
"""Turn the device off."""
self.ihc_controller.set_runtime_value_bool(self.ihc_id, False)
if self._ihc_off_id:
await async_pulse(self.hass, self.ihc_controller, self._ihc_off_id)
else:
await async_set_bool(self.hass, self.ihc_controller,
self.ihc_id, False)
def on_ihc_change(self, ihc_id, value):
"""Handle IHC resource change."""

View File

@ -0,0 +1,22 @@
"""Useful functions for the IHC component."""
import asyncio
async def async_pulse(hass, ihc_controller, ihc_id: int):
"""Send a short on/off pulse to an IHC controller resource."""
await async_set_bool(hass, ihc_controller, ihc_id, True)
await asyncio.sleep(0.1)
await async_set_bool(hass, ihc_controller, ihc_id, False)
def async_set_bool(hass, ihc_controller, ihc_id: int, value: bool):
"""Set a bool value on an IHC controller resource."""
return hass.async_add_executor_job(ihc_controller.set_runtime_value_bool,
ihc_id, value)
def async_set_int(hass, ihc_controller, ihc_id: int, value: int):
"""Set a int value on an IHC controller resource."""
return hass.async_add_executor_job(ihc_controller.set_runtime_value_int,
ihc_id, value)