LCN cover control via output ports (#25511)

* LCN motor control via oputput ports

* Remove default value from cover validator
This commit is contained in:
Andre Lengwenus 2019-07-29 20:49:44 +02:00 committed by Martin Hjelmare
parent dc722adbb5
commit c4f673c894
5 changed files with 100 additions and 17 deletions

View file

@ -4,23 +4,23 @@ import logging
import pypck
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.climate import DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP
from homeassistant.const import (
CONF_ADDRESS, CONF_BINARY_SENSORS, CONF_COVERS, CONF_HOST, CONF_LIGHTS,
CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_SENSORS, CONF_SWITCHES,
CONF_UNIT_OF_MEASUREMENT, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import async_load_platform
from homeassistant.helpers.entity import Entity
from .const import (
BINSENSOR_PORTS, CONF_CLIMATES, CONF_CONNECTIONS, CONF_DIM_MODE,
CONF_DIMMABLE, CONF_LOCKABLE, CONF_MAX_TEMP, CONF_MIN_TEMP, CONF_MOTOR,
CONF_OUTPUT, CONF_OUTPUTS, CONF_REGISTER, CONF_SCENE, CONF_SCENES,
CONF_SETPOINT, CONF_SK_NUM_TRIES, CONF_SOURCE, CONF_TRANSITION, DATA_LCN,
DIM_MODES, DOMAIN, KEYS, LED_PORTS, LOGICOP_PORTS, MOTOR_PORTS,
OUTPUT_PORTS, RELAY_PORTS, S0_INPUTS, SETPOINTS, THRESHOLDS, VAR_UNITS,
VARIABLES)
CONF_OUTPUT, CONF_OUTPUTS, CONF_REGISTER, CONF_REVERSE_TIME, CONF_SCENE,
CONF_SCENES, CONF_SETPOINT, CONF_SK_NUM_TRIES, CONF_SOURCE,
CONF_TRANSITION, DATA_LCN, DIM_MODES, DOMAIN, KEYS, LED_PORTS,
LOGICOP_PORTS, MOTOR_PORTS, MOTOR_REVERSE_TIME, OUTPUT_PORTS, RELAY_PORTS,
S0_INPUTS, SETPOINTS, THRESHOLDS, VAR_UNITS, VARIABLES)
from .helpers import has_unique_connection_names, is_address
from .services import (
DynText, Led, LockKeys, LockRegulator, OutputAbs, OutputRel, OutputToggle,
@ -51,7 +51,9 @@ CLIMATES_SCHEMA = vol.Schema({
COVERS_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_ADDRESS): is_address,
vol.Required(CONF_MOTOR): vol.All(vol.Upper, vol.In(MOTOR_PORTS))
vol.Required(CONF_MOTOR): vol.All(vol.Upper, vol.In(MOTOR_PORTS)),
vol.Optional(CONF_REVERSE_TIME): vol.All(vol.Upper,
vol.In(MOTOR_REVERSE_TIME))
})
LIGHTS_SCHEMA = vol.Schema({

View file

@ -36,6 +36,7 @@ CONF_SCENES = 'scenes'
CONF_REGISTER = 'register'
CONF_SCENE = 'scene'
CONF_OUTPUTS = 'outputs'
CONF_REVERSE_TIME = 'reverse_time'
DIM_MODES = ['STEPS50', 'STEPS200']
@ -46,7 +47,7 @@ RELAY_PORTS = ['RELAY1', 'RELAY2', 'RELAY3', 'RELAY4',
'MOTORONOFF1', 'MOTORUPDOWN1', 'MOTORONOFF2', 'MOTORUPDOWN2',
'MOTORONOFF3', 'MOTORUPDOWN3', 'MOTORONOFF4', 'MOTORUPDOWN4']
MOTOR_PORTS = ['MOTOR1', 'MOTOR2', 'MOTOR3', 'MOTOR4']
MOTOR_PORTS = ['MOTOR1', 'MOTOR2', 'MOTOR3', 'MOTOR4', 'OUTPUTS']
LED_PORTS = ['LED1', 'LED2', 'LED3', 'LED4', 'LED5', 'LED6',
'LED7', 'LED8', 'LED9', 'LED10', 'LED11', 'LED12']
@ -96,3 +97,5 @@ TIME_UNITS = ['SECONDS', 'SECOND', 'SEC', 'S',
'MINUTES', 'MINUTE', 'MIN', 'M',
'HOURS', 'HOUR', 'H',
'DAYS', 'DAY', 'D']
MOTOR_REVERSE_TIME = ['RT70', 'RT600', 'RT1200']

View file

@ -5,7 +5,7 @@ from homeassistant.components.cover import CoverDevice
from homeassistant.const import CONF_ADDRESS
from . import LcnDevice
from .const import CONF_CONNECTIONS, CONF_MOTOR, DATA_LCN
from .const import CONF_CONNECTIONS, CONF_MOTOR, CONF_REVERSE_TIME, DATA_LCN
from .helpers import get_connection
@ -23,13 +23,91 @@ async def async_setup_platform(hass, hass_config, async_add_entities,
connection = get_connection(connections, connection_id)
address_connection = connection.get_address_conn(addr)
devices.append(LcnCover(config, address_connection))
if config[CONF_MOTOR] == 'OUTPUTS':
devices.append(LcnOutputsCover(config, address_connection))
else: # RELAYS
devices.append(LcnRelayCover(config, address_connection))
async_add_entities(devices)
class LcnCover(LcnDevice, CoverDevice):
"""Representation of a LCN cover."""
class LcnOutputsCover(LcnDevice, CoverDevice):
"""Representation of a LCN cover connected to output ports."""
def __init__(self, config, address_connection):
"""Initialize the LCN cover."""
super().__init__(config, address_connection)
self.output_ids = [pypck.lcn_defs.OutputPort['OUTPUTUP'].value,
pypck.lcn_defs.OutputPort['OUTPUTDOWN'].value]
if CONF_REVERSE_TIME in config:
self.reverse_time = pypck.lcn_defs.MotorReverseTime[
config[CONF_REVERSE_TIME]]
else:
self.reverse_time = None
self._closed = None
self.state_up = False
self.state_down = False
async def async_added_to_hass(self):
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
await self.address_connection.activate_status_request_handler(
pypck.lcn_defs.OutputPort['OUTPUTUP'])
await self.address_connection.activate_status_request_handler(
pypck.lcn_defs.OutputPort['OUTPUTDOWN'])
@property
def is_closed(self):
"""Return if the cover is closed."""
return self._closed
async def async_close_cover(self, **kwargs):
"""Close the cover."""
self._closed = True
state = pypck.lcn_defs.MotorStateModifier.DOWN
self.address_connection.control_motors_outputs(
state)
await self.async_update_ha_state()
async def async_open_cover(self, **kwargs):
"""Open the cover."""
self._closed = False
state = pypck.lcn_defs.MotorStateModifier.UP
self.address_connection.control_motors_outputs(
state, self.reverse_time)
await self.async_update_ha_state()
async def async_stop_cover(self, **kwargs):
"""Stop the cover."""
self._closed = None
state = pypck.lcn_defs.MotorStateModifier.STOP
self.address_connection.control_motors_outputs(
state, self.reverse_time)
await self.async_update_ha_state()
def input_received(self, input_obj):
"""Set cover states when LCN input object (command) is received."""
if not isinstance(input_obj, pypck.inputs.ModStatusOutput) or \
input_obj.get_output_id() not in self.output_ids:
return
if input_obj.get_output_id() == self.output_ids[0]:
self.state_up = (input_obj.get_percent() > 0)
else: # self.output_ids[1]
self.state_down = (input_obj.get_percent() > 0)
if self.state_up and not self.state_down:
self._closed = False # Cover open
elif self.state_down and not self.state_up:
self._closed = True # Cover closed
self.async_schedule_update_ha_state()
class LcnRelayCover(LcnDevice, CoverDevice):
"""Representation of a LCN cover connected to relays."""
def __init__(self, config, address_connection):
"""Initialize the LCN cover."""
@ -57,7 +135,7 @@ class LcnCover(LcnDevice, CoverDevice):
self._closed = True
states = [pypck.lcn_defs.MotorStateModifier.NOCHANGE] * 4
states[self.motor.value] = pypck.lcn_defs.MotorStateModifier.DOWN
self.address_connection.control_motors(states)
self.address_connection.control_motors_relays(states)
await self.async_update_ha_state()
async def async_open_cover(self, **kwargs):
@ -65,7 +143,7 @@ class LcnCover(LcnDevice, CoverDevice):
self._closed = False
states = [pypck.lcn_defs.MotorStateModifier.NOCHANGE] * 4
states[self.motor.value] = pypck.lcn_defs.MotorStateModifier.UP
self.address_connection.control_motors(states)
self.address_connection.control_motors_relays(states)
await self.async_update_ha_state()
async def async_stop_cover(self, **kwargs):
@ -73,7 +151,7 @@ class LcnCover(LcnDevice, CoverDevice):
self._closed = None
states = [pypck.lcn_defs.MotorStateModifier.NOCHANGE] * 4
states[self.motor.value] = pypck.lcn_defs.MotorStateModifier.STOP
self.address_connection.control_motors(states)
self.address_connection.control_motors_relays(states)
await self.async_update_ha_state()
def input_received(self, input_obj):

View file

@ -3,7 +3,7 @@
"name": "Lcn",
"documentation": "https://www.home-assistant.io/components/lcn",
"requirements": [
"pypck==0.6.2"
"pypck==0.6.3"
],
"dependencies": [],
"codeowners": [

View file

@ -1330,7 +1330,7 @@ pyowm==2.10.0
pypca==0.0.4
# homeassistant.components.lcn
pypck==0.6.2
pypck==0.6.3
# homeassistant.components.pjlink
pypjlink2==1.2.0