mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add multiple gateways
* Add support for multiple serial gateways. * Fix serialization of python objects by adding dict representation of classes. * Add support for showing more than one child value type per entity. The entity state is always only one value type. This is defined by the platform value types. Value types that are not defined as the platform value type are shown as state_attributes. * Add more unit of measurement types. * Clean up code.
This commit is contained in:
parent
1d141566bd
commit
59524c7933
@ -23,27 +23,25 @@ CONF_VERSION = 'version'
|
|||||||
|
|
||||||
DOMAIN = 'mysensors'
|
DOMAIN = 'mysensors'
|
||||||
DEPENDENCIES = []
|
DEPENDENCIES = []
|
||||||
REQUIREMENTS = ['file:///home/martin/Dev/pymysensors-fifo_queue.zip'
|
REQUIREMENTS = [
|
||||||
'#pymysensors==0.3']
|
'https://github.com/MartinHjelmare/pymysensors/archive/fifo_queue.zip'
|
||||||
|
'#pymysensors==0.3']
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
ATTR_PORT = 'port'
|
||||||
|
ATTR_DEVICES = 'devices'
|
||||||
ATTR_NODE_ID = 'node_id'
|
ATTR_NODE_ID = 'node_id'
|
||||||
ATTR_CHILD_ID = 'child_id'
|
ATTR_CHILD_ID = 'child_id'
|
||||||
|
ATTR_UPDATE_TYPE = 'update_type'
|
||||||
|
|
||||||
PLATFORM_FORMAT = '{}.{}'
|
|
||||||
IS_METRIC = None
|
IS_METRIC = None
|
||||||
DEVICES = None
|
|
||||||
GATEWAY = None
|
|
||||||
|
|
||||||
EVENT_MYSENSORS_NODE_UPDATE = 'MYSENSORS_NODE_UPDATE'
|
|
||||||
UPDATE_TYPE = 'update_type'
|
|
||||||
NODE_ID = 'nid'
|
|
||||||
|
|
||||||
CONST = None
|
CONST = None
|
||||||
|
GATEWAYS = None
|
||||||
|
EVENT_MYSENSORS_NODE_UPDATE = 'MYSENSORS_NODE_UPDATE'
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config): # noqa
|
||||||
""" Setup the MySensors component. """
|
""" Setup the MySensors component. """
|
||||||
|
# pylint:disable=no-name-in-module
|
||||||
import mysensors.mysensors as mysensors
|
import mysensors.mysensors as mysensors
|
||||||
|
|
||||||
if not validate_config(config,
|
if not validate_config(config,
|
||||||
@ -57,53 +55,83 @@ def setup(hass, config):
|
|||||||
if version == '1.4':
|
if version == '1.4':
|
||||||
import mysensors.const_14 as const
|
import mysensors.const_14 as const
|
||||||
CONST = const
|
CONST = const
|
||||||
_LOGGER.info('CONST = %s, 1.4', const)
|
|
||||||
elif version == '1.5':
|
elif version == '1.5':
|
||||||
import mysensors.const_15 as const
|
import mysensors.const_15 as const
|
||||||
CONST = const
|
CONST = const
|
||||||
_LOGGER.info('CONST = %s, 1.5', const)
|
|
||||||
else:
|
else:
|
||||||
import mysensors.const_14 as const
|
import mysensors.const_14 as const
|
||||||
CONST = const
|
CONST = const
|
||||||
_LOGGER.info('CONST = %s, 1.4 default', const)
|
|
||||||
|
|
||||||
global IS_METRIC
|
|
||||||
# Just assume celcius means that the user wants metric for now.
|
# Just assume celcius means that the user wants metric for now.
|
||||||
# It may make more sense to make this a global config option in the future.
|
# It may make more sense to make this a global config option in the future.
|
||||||
|
global IS_METRIC
|
||||||
IS_METRIC = (hass.config.temperature_unit == TEMP_CELCIUS)
|
IS_METRIC = (hass.config.temperature_unit == TEMP_CELCIUS)
|
||||||
global DEVICES
|
|
||||||
DEVICES = {} # keep track of devices added to HA
|
|
||||||
|
|
||||||
def node_update(update_type, nid):
|
def callback_generator(port, devices):
|
||||||
""" Callback for node updates from the MySensors gateway. """
|
"""
|
||||||
_LOGGER.info('update %s: node %s', update_type, nid)
|
Generator of callback, should be run once per gateway setup.
|
||||||
|
"""
|
||||||
|
def node_update(update_type, nid):
|
||||||
|
""" Callback for node updates from the MySensors gateway. """
|
||||||
|
_LOGGER.info('update %s: node %s', update_type, nid)
|
||||||
|
|
||||||
hass.bus.fire(EVENT_MYSENSORS_NODE_UPDATE, {
|
hass.bus.fire(EVENT_MYSENSORS_NODE_UPDATE, {
|
||||||
UPDATE_TYPE: update_type,
|
ATTR_PORT: port,
|
||||||
NODE_ID: nid
|
ATTR_DEVICES: devices,
|
||||||
})
|
ATTR_UPDATE_TYPE: update_type,
|
||||||
|
ATTR_NODE_ID: nid
|
||||||
|
})
|
||||||
|
return
|
||||||
|
return node_update
|
||||||
|
|
||||||
|
def setup_gateway(port, persistence, persistence_file):
|
||||||
|
"""
|
||||||
|
Instantiate gateway, set gateway attributes and start gateway.
|
||||||
|
If persistence is true, update all nodes.
|
||||||
|
Listen for stop of home-assistant, then stop gateway.
|
||||||
|
"""
|
||||||
|
devices = {} # keep track of devices added to HA
|
||||||
|
gateway = mysensors.SerialGateway(port,
|
||||||
|
persistence=persistence,
|
||||||
|
persistence_file=persistence_file,
|
||||||
|
protocol_version=version)
|
||||||
|
gateway.event_callback = callback_generator(port, devices)
|
||||||
|
gateway.metric = IS_METRIC
|
||||||
|
gateway.debug = config[DOMAIN].get(CONF_DEBUG, False)
|
||||||
|
gateway.start()
|
||||||
|
|
||||||
|
if persistence:
|
||||||
|
for nid in gateway.sensors:
|
||||||
|
gateway.event_callback('node_update', nid)
|
||||||
|
|
||||||
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
|
||||||
|
lambda event: gateway.stop())
|
||||||
|
return gateway
|
||||||
|
|
||||||
port = config[DOMAIN].get(CONF_PORT)
|
port = config[DOMAIN].get(CONF_PORT)
|
||||||
|
|
||||||
persistence = config[DOMAIN].get(CONF_PERSISTENCE, True)
|
|
||||||
persistence_file = config[DOMAIN].get(
|
persistence_file = config[DOMAIN].get(
|
||||||
CONF_PERSISTENCE_FILE, hass.config.path('mysensors.pickle'))
|
CONF_PERSISTENCE_FILE, hass.config.path('mysensors.pickle'))
|
||||||
|
|
||||||
global GATEWAY
|
if isinstance(port, str):
|
||||||
GATEWAY = mysensors.SerialGateway(port, node_update,
|
port = [port]
|
||||||
persistence=persistence,
|
if isinstance(persistence_file, str):
|
||||||
persistence_file=persistence_file,
|
persistence_file = [persistence_file]
|
||||||
protocol_version=version)
|
|
||||||
GATEWAY.metric = IS_METRIC
|
|
||||||
GATEWAY.debug = config[DOMAIN].get(CONF_DEBUG, False)
|
|
||||||
GATEWAY.start()
|
|
||||||
|
|
||||||
if persistence:
|
# Setup all ports from config
|
||||||
for nid in GATEWAY.sensors:
|
global GATEWAYS
|
||||||
node_update('node_update', nid)
|
GATEWAYS = {}
|
||||||
|
for index, port_item in enumerate(port):
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
|
persistence = config[DOMAIN].get(CONF_PERSISTENCE, True)
|
||||||
lambda event: GATEWAY.stop())
|
try:
|
||||||
|
persistence_f_item = persistence_file[index]
|
||||||
|
except IndexError:
|
||||||
|
_LOGGER.exception(
|
||||||
|
'No persistence_file is set for port %s,'
|
||||||
|
' disabling persistence', port_item)
|
||||||
|
persistence = False
|
||||||
|
persistence_f_item = None
|
||||||
|
GATEWAYS[port_item] = setup_gateway(
|
||||||
|
port_item, persistence, persistence_f_item)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -113,7 +141,7 @@ def mysensors_update(platform_type):
|
|||||||
Decorator for callback function for sensor updates from the MySensors
|
Decorator for callback function for sensor updates from the MySensors
|
||||||
component.
|
component.
|
||||||
"""
|
"""
|
||||||
def wrapper(gateway, devices, nid):
|
def wrapper(gateway, port, devices, nid):
|
||||||
"""Wrapper function in the decorator."""
|
"""Wrapper function in the decorator."""
|
||||||
sensor = gateway.sensors[nid]
|
sensor = gateway.sensors[nid]
|
||||||
if sensor.sketch_name is None:
|
if sensor.sketch_name is None:
|
||||||
@ -123,26 +151,23 @@ def mysensors_update(platform_type):
|
|||||||
devices[nid] = {}
|
devices[nid] = {}
|
||||||
node = devices[nid]
|
node = devices[nid]
|
||||||
new_devices = []
|
new_devices = []
|
||||||
platform_def = platform_type(gateway, devices, nid)
|
# Get platform specific V_TYPES, class and add_devices function.
|
||||||
platform_object = platform_def['platform_class']
|
platform_v_types, platform_class, add_devices = platform_type(
|
||||||
platform_v_types = platform_def['types_to_handle']
|
gateway, port, devices, nid)
|
||||||
add_devices = platform_def['add_devices']
|
|
||||||
for child_id, child in sensor.children.items():
|
for child_id, child in sensor.children.items():
|
||||||
if child_id not in node:
|
if child_id not in node:
|
||||||
node[child_id] = {}
|
node[child_id] = {}
|
||||||
for value_type, value in child.values.items():
|
for value_type, _ in child.values.items():
|
||||||
if value_type not in node[child_id]:
|
if ((value_type not in node[child_id]) and
|
||||||
|
(value_type in platform_v_types)):
|
||||||
name = '{} {}.{}'.format(
|
name = '{} {}.{}'.format(
|
||||||
sensor.sketch_name, nid, child.id)
|
sensor.sketch_name, nid, child.id)
|
||||||
if value_type in platform_v_types:
|
node[child_id][value_type] = platform_class(
|
||||||
node[child_id][value_type] = \
|
port, nid, child_id, name, value_type)
|
||||||
platform_object(
|
new_devices.append(node[child_id][value_type])
|
||||||
gateway, nid, child_id, name, value_type)
|
elif value_type in platform_v_types:
|
||||||
new_devices.append(node[child_id][value_type])
|
|
||||||
else:
|
|
||||||
node[child_id][value_type].update_sensor(
|
node[child_id][value_type].update_sensor(
|
||||||
value, sensor.battery_level)
|
child.values, sensor.battery_level)
|
||||||
_LOGGER.info('sensor_update: %s', new_devices)
|
|
||||||
if new_devices:
|
if new_devices:
|
||||||
_LOGGER.info('adding new devices: %s', new_devices)
|
_LOGGER.info('adding new devices: %s', new_devices)
|
||||||
add_devices(new_devices)
|
add_devices(new_devices)
|
||||||
|
@ -17,9 +17,6 @@ from homeassistant.const import (
|
|||||||
|
|
||||||
import homeassistant.components.mysensors as mysensors
|
import homeassistant.components.mysensors as mysensors
|
||||||
|
|
||||||
ATTR_NODE_ID = "node_id"
|
|
||||||
ATTR_CHILD_ID = "child_id"
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
DEPENDENCIES = ['mysensors']
|
DEPENDENCIES = ['mysensors']
|
||||||
|
|
||||||
@ -27,28 +24,29 @@ DEPENDENCIES = ['mysensors']
|
|||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
""" Setup the mysensors platform for sensors. """
|
""" Setup the mysensors platform for sensors. """
|
||||||
|
|
||||||
|
# Define the V_TYPES that the platform should handle as states.
|
||||||
v_types = []
|
v_types = []
|
||||||
for _, member in mysensors.CONST.SetReq.__members__.items():
|
for _, member in mysensors.CONST.SetReq.__members__.items():
|
||||||
if (member.value != mysensors.CONST.SetReq.V_STATUS and
|
if (member.value != mysensors.CONST.SetReq.V_ARMED and
|
||||||
|
member.value != mysensors.CONST.SetReq.V_STATUS and
|
||||||
member.value != mysensors.CONST.SetReq.V_LIGHT and
|
member.value != mysensors.CONST.SetReq.V_LIGHT and
|
||||||
member.value != mysensors.CONST.SetReq.V_LOCK_STATUS):
|
member.value != mysensors.CONST.SetReq.V_LOCK_STATUS):
|
||||||
v_types.append(member)
|
v_types.append(member)
|
||||||
|
|
||||||
@mysensors.mysensors_update
|
@mysensors.mysensors_update
|
||||||
def _sensor_update(gateway, devices, nid):
|
def _sensor_update(gateway, port, devices, nid):
|
||||||
"""Internal callback for sensor updates."""
|
"""Internal callback for sensor updates."""
|
||||||
_LOGGER.info("sensor update = %s", devices)
|
return (v_types, MySensorsSensor, add_devices)
|
||||||
return {'types_to_handle': v_types,
|
|
||||||
'platform_class': MySensorsSensor,
|
|
||||||
'add_devices': add_devices}
|
|
||||||
|
|
||||||
def sensor_update(event):
|
def sensor_update(event):
|
||||||
""" Callback for sensor updates from the MySensors component. """
|
""" Callback for sensor updates from the MySensors component. """
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'update %s: node %s', event.data[mysensors.UPDATE_TYPE],
|
'update %s: node %s', event.data[mysensors.ATTR_UPDATE_TYPE],
|
||||||
event.data[mysensors.NODE_ID])
|
event.data[mysensors.ATTR_NODE_ID])
|
||||||
_sensor_update(mysensors.GATEWAY, mysensors.DEVICES,
|
_sensor_update(mysensors.GATEWAYS[event.data[mysensors.ATTR_PORT]],
|
||||||
event.data[mysensors.NODE_ID])
|
event.data[mysensors.ATTR_PORT],
|
||||||
|
event.data[mysensors.ATTR_DEVICES],
|
||||||
|
event.data[mysensors.ATTR_NODE_ID])
|
||||||
|
|
||||||
hass.bus.listen(mysensors.EVENT_MYSENSORS_NODE_UPDATE, sensor_update)
|
hass.bus.listen(mysensors.EVENT_MYSENSORS_NODE_UPDATE, sensor_update)
|
||||||
|
|
||||||
@ -58,16 +56,26 @@ class MySensorsSensor(Entity):
|
|||||||
""" Represents the value of a MySensors child node. """
|
""" Represents the value of a MySensors child node. """
|
||||||
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
||||||
|
|
||||||
def __init__(self, gateway, node_id, child_id, name, value_type):
|
def __init__(self, port, node_id, child_id, name, value_type):
|
||||||
self.gateway = gateway
|
self.port = port
|
||||||
self._name = name
|
self._name = name
|
||||||
self.node_id = node_id
|
self.node_id = node_id
|
||||||
self.child_id = child_id
|
self.child_id = child_id
|
||||||
self.battery_level = 0
|
self.battery_level = 0
|
||||||
self.value_type = value_type
|
self.value_type = value_type
|
||||||
self.metric = mysensors.IS_METRIC
|
self._values = {}
|
||||||
self._value = ''
|
|
||||||
self.const = mysensors.CONST
|
def as_dict(self):
|
||||||
|
""" Returns a dict representation of this Entity. """
|
||||||
|
return {
|
||||||
|
'port': self.port,
|
||||||
|
'name': self._name,
|
||||||
|
'node_id': self.node_id,
|
||||||
|
'child_id': self.child_id,
|
||||||
|
'battery_level': self.battery_level,
|
||||||
|
'value_type': self.value_type,
|
||||||
|
'values': self._values,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
@ -82,35 +90,69 @@ class MySensorsSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
""" Returns the state of the device. """
|
""" Returns the state of the device. """
|
||||||
return self._value
|
if not self._values:
|
||||||
|
return ''
|
||||||
|
return self._values[self.value_type]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
""" Unit of measurement of this entity. """
|
""" Unit of measurement of this entity. """
|
||||||
if self.value_type == self.const.SetReq.V_TEMP:
|
# pylint:disable=too-many-return-statements
|
||||||
return TEMP_CELCIUS if self.metric else TEMP_FAHRENHEIT
|
if self.value_type == mysensors.CONST.SetReq.V_TEMP:
|
||||||
elif self.value_type == self.const.SetReq.V_HUM or \
|
return TEMP_CELCIUS if mysensors.IS_METRIC else TEMP_FAHRENHEIT
|
||||||
self.value_type == self.const.SetReq.V_DIMMER or \
|
elif self.value_type == mysensors.CONST.SetReq.V_HUM or \
|
||||||
self.value_type == self.const.SetReq.V_LIGHT_LEVEL:
|
self.value_type == mysensors.CONST.SetReq.V_DIMMER or \
|
||||||
|
self.value_type == mysensors.CONST.SetReq.V_PERCENTAGE or \
|
||||||
|
self.value_type == mysensors.CONST.SetReq.V_LIGHT_LEVEL:
|
||||||
return '%'
|
return '%'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_WATT:
|
||||||
|
return 'W'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_KWH:
|
||||||
|
return 'kWh'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_VOLTAGE:
|
||||||
|
return 'V'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_CURRENT:
|
||||||
|
return 'A'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_IMPEDANCE:
|
||||||
|
return 'ohm'
|
||||||
|
elif mysensors.CONST.SetReq.V_UNIT_PREFIX in self._values:
|
||||||
|
return self._values[mysensors.CONST.SetReq.V_UNIT_PREFIX]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
""" Returns device specific state attributes. """
|
||||||
|
device_attr = dict(self._values)
|
||||||
|
device_attr.pop(self.value_type, None)
|
||||||
|
return device_attr
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
""" Returns the state attributes. """
|
""" Returns the state attributes. """
|
||||||
return {
|
|
||||||
ATTR_NODE_ID: self.node_id,
|
data = {
|
||||||
ATTR_CHILD_ID: self.child_id,
|
mysensors.ATTR_NODE_ID: self.node_id,
|
||||||
|
mysensors.ATTR_CHILD_ID: self.child_id,
|
||||||
ATTR_BATTERY_LEVEL: self.battery_level,
|
ATTR_BATTERY_LEVEL: self.battery_level,
|
||||||
}
|
}
|
||||||
|
|
||||||
def update_sensor(self, value, battery_level):
|
device_attr = self.device_state_attributes
|
||||||
""" Update the controller with the latest value from a sensor. """
|
|
||||||
_LOGGER.info("%s value = %s", self._name, value)
|
if device_attr is not None:
|
||||||
if self.value_type == self.const.SetReq.V_TRIPPED or \
|
data.update(device_attr)
|
||||||
self.value_type == self.const.SetReq.V_ARMED:
|
|
||||||
self._value = STATE_ON if int(value) == 1 else STATE_OFF
|
return data
|
||||||
else:
|
|
||||||
self._value = value
|
def update_sensor(self, values, battery_level):
|
||||||
|
""" Update the controller with the latest values from a sensor. """
|
||||||
|
for value_type, value in values.items():
|
||||||
|
_LOGGER.info(
|
||||||
|
"%s: value_type %s, value = %s", self._name, value_type, value)
|
||||||
|
if value_type == mysensors.CONST.SetReq.V_TRIPPED:
|
||||||
|
self._values[value_type] = STATE_ON if int(
|
||||||
|
value) == 1 else STATE_OFF
|
||||||
|
else:
|
||||||
|
self._values[value_type] = value
|
||||||
|
|
||||||
self.battery_level = battery_level
|
self.battery_level = battery_level
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
homeassistant.components.sensor.mysensors
|
homeassistant.components.switch.mysensors
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Support for MySensors switches.
|
Support for MySensors switches.
|
||||||
|
|
||||||
@ -17,9 +17,6 @@ from homeassistant.const import (
|
|||||||
|
|
||||||
import homeassistant.components.mysensors as mysensors
|
import homeassistant.components.mysensors as mysensors
|
||||||
|
|
||||||
ATTR_NODE_ID = "node_id"
|
|
||||||
ATTR_CHILD_ID = "child_id"
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
DEPENDENCIES = ['mysensors']
|
DEPENDENCIES = ['mysensors']
|
||||||
|
|
||||||
@ -27,28 +24,29 @@ DEPENDENCIES = ['mysensors']
|
|||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
""" Setup the mysensors platform for switches. """
|
""" Setup the mysensors platform for switches. """
|
||||||
|
|
||||||
|
# Define the V_TYPES that the platform should handle as states.
|
||||||
v_types = []
|
v_types = []
|
||||||
for _, member in mysensors.CONST.SetReq.__members__.items():
|
for _, member in mysensors.CONST.SetReq.__members__.items():
|
||||||
if (member.value == mysensors.CONST.SetReq.V_STATUS or
|
if (member.value == mysensors.CONST.SetReq.V_ARMED or
|
||||||
|
member.value == mysensors.CONST.SetReq.V_STATUS or
|
||||||
member.value == mysensors.CONST.SetReq.V_LIGHT or
|
member.value == mysensors.CONST.SetReq.V_LIGHT or
|
||||||
member.value == mysensors.CONST.SetReq.V_LOCK_STATUS):
|
member.value == mysensors.CONST.SetReq.V_LOCK_STATUS):
|
||||||
v_types.append(member)
|
v_types.append(member)
|
||||||
|
|
||||||
@mysensors.mysensors_update
|
@mysensors.mysensors_update
|
||||||
def _sensor_update(gateway, devices, nid):
|
def _sensor_update(gateway, port, devices, nid):
|
||||||
"""Internal callback for sensor updates."""
|
"""Internal callback for sensor updates."""
|
||||||
_LOGGER.info("sensor update = %s", devices)
|
return (v_types, MySensorsSwitch, add_devices)
|
||||||
return {'types_to_handle': v_types,
|
|
||||||
'platform_class': MySensorsSwitch,
|
|
||||||
'add_devices': add_devices}
|
|
||||||
|
|
||||||
def sensor_update(event):
|
def sensor_update(event):
|
||||||
""" Callback for sensor updates from the MySensors component. """
|
""" Callback for sensor updates from the MySensors component. """
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'update %s: node %s', event.data[mysensors.UPDATE_TYPE],
|
'update %s: node %s', event.data[mysensors.ATTR_UPDATE_TYPE],
|
||||||
event.data[mysensors.NODE_ID])
|
event.data[mysensors.ATTR_NODE_ID])
|
||||||
_sensor_update(mysensors.GATEWAY, mysensors.DEVICES,
|
_sensor_update(mysensors.GATEWAYS[event.data[mysensors.ATTR_PORT]],
|
||||||
event.data[mysensors.NODE_ID])
|
event.data[mysensors.ATTR_PORT],
|
||||||
|
event.data[mysensors.ATTR_DEVICES],
|
||||||
|
event.data[mysensors.ATTR_NODE_ID])
|
||||||
|
|
||||||
hass.bus.listen(mysensors.EVENT_MYSENSORS_NODE_UPDATE, sensor_update)
|
hass.bus.listen(mysensors.EVENT_MYSENSORS_NODE_UPDATE, sensor_update)
|
||||||
|
|
||||||
@ -58,16 +56,26 @@ class MySensorsSwitch(SwitchDevice):
|
|||||||
""" Represents the value of a MySensors child node. """
|
""" Represents the value of a MySensors child node. """
|
||||||
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
# pylint: disable=too-many-arguments, too-many-instance-attributes
|
||||||
|
|
||||||
def __init__(self, gateway, node_id, child_id, name, value_type):
|
def __init__(self, port, node_id, child_id, name, value_type):
|
||||||
self.gateway = gateway
|
self.port = port
|
||||||
self._name = name
|
self._name = name
|
||||||
self.node_id = node_id
|
self.node_id = node_id
|
||||||
self.child_id = child_id
|
self.child_id = child_id
|
||||||
self.battery_level = 0
|
self.battery_level = 0
|
||||||
self.value_type = value_type
|
self.value_type = value_type
|
||||||
self.metric = mysensors.IS_METRIC
|
self._values = {}
|
||||||
self._value = STATE_OFF
|
|
||||||
self.const = mysensors.CONST
|
def as_dict(self):
|
||||||
|
""" Returns a dict representation of this Entity. """
|
||||||
|
return {
|
||||||
|
'port': self.port,
|
||||||
|
'name': self._name,
|
||||||
|
'node_id': self.node_id,
|
||||||
|
'child_id': self.child_id,
|
||||||
|
'battery_level': self.battery_level,
|
||||||
|
'value_type': self.value_type,
|
||||||
|
'values': self._values,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
@ -79,60 +87,86 @@ class MySensorsSwitch(SwitchDevice):
|
|||||||
""" The name of this sensor. """
|
""" The name of this sensor. """
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self):
|
|
||||||
""" Returns the state of the device. """
|
|
||||||
return self._value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
""" Unit of measurement of this entity. """
|
""" Unit of measurement of this entity. """
|
||||||
if self.value_type == self.const.SetReq.V_TEMP:
|
# pylint:disable=too-many-return-statements
|
||||||
return TEMP_CELCIUS if self.metric else TEMP_FAHRENHEIT
|
if self.value_type == mysensors.CONST.SetReq.V_TEMP:
|
||||||
elif self.value_type == self.const.SetReq.V_HUM or \
|
return TEMP_CELCIUS if mysensors.IS_METRIC else TEMP_FAHRENHEIT
|
||||||
self.value_type == self.const.SetReq.V_DIMMER or \
|
elif self.value_type == mysensors.CONST.SetReq.V_HUM or \
|
||||||
self.value_type == self.const.SetReq.V_LIGHT_LEVEL:
|
self.value_type == mysensors.CONST.SetReq.V_DIMMER or \
|
||||||
|
self.value_type == mysensors.CONST.SetReq.V_PERCENTAGE or \
|
||||||
|
self.value_type == mysensors.CONST.SetReq.V_LIGHT_LEVEL:
|
||||||
return '%'
|
return '%'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_WATT:
|
||||||
|
return 'W'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_KWH:
|
||||||
|
return 'kWh'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_VOLTAGE:
|
||||||
|
return 'V'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_CURRENT:
|
||||||
|
return 'A'
|
||||||
|
elif self.value_type == mysensors.CONST.SetReq.V_IMPEDANCE:
|
||||||
|
return 'ohm'
|
||||||
|
elif mysensors.CONST.SetReq.V_UNIT_PREFIX in self._values:
|
||||||
|
return self._values[mysensors.CONST.SetReq.V_UNIT_PREFIX]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
""" Returns device specific state attributes. """
|
||||||
|
device_attr = dict(self._values)
|
||||||
|
device_attr.pop(self.value_type, None)
|
||||||
|
return device_attr
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
""" Returns the state attributes. """
|
""" Returns the state attributes. """
|
||||||
return {
|
|
||||||
ATTR_NODE_ID: self.node_id,
|
data = {
|
||||||
ATTR_CHILD_ID: self.child_id,
|
mysensors.ATTR_NODE_ID: self.node_id,
|
||||||
|
mysensors.ATTR_CHILD_ID: self.child_id,
|
||||||
ATTR_BATTERY_LEVEL: self.battery_level,
|
ATTR_BATTERY_LEVEL: self.battery_level,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_attr = self.device_state_attributes
|
||||||
|
|
||||||
|
if device_attr is not None:
|
||||||
|
data.update(device_attr)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
""" Returns True if switch is on. """
|
""" Returns True if switch is on. """
|
||||||
return self._value == STATE_ON
|
return self._values[self.value_type] == STATE_ON
|
||||||
|
|
||||||
def turn_on(self):
|
def turn_on(self):
|
||||||
""" Turns the switch on. """
|
""" Turns the switch on. """
|
||||||
self.gateway.set_child_value(
|
mysensors.GATEWAYS[self.port].set_child_value(
|
||||||
self.node_id, self.child_id, self.value_type, 1)
|
self.node_id, self.child_id, self.value_type, 1)
|
||||||
self._value = STATE_ON
|
self._values[self.value_type] = STATE_ON
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
||||||
def turn_off(self):
|
def turn_off(self):
|
||||||
""" Turns the pin to low/off. """
|
""" Turns the pin to low/off. """
|
||||||
self.gateway.set_child_value(
|
mysensors.GATEWAYS[self.port].set_child_value(
|
||||||
self.node_id, self.child_id, self.value_type, 0)
|
self.node_id, self.child_id, self.value_type, 0)
|
||||||
self._value = STATE_OFF
|
self._values[self.value_type] = STATE_OFF
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
||||||
def update_sensor(self, value, battery_level):
|
def update_sensor(self, values, battery_level):
|
||||||
""" Update the controller with the latest value from a sensor. """
|
""" Update the controller with the latest value from a sensor. """
|
||||||
_LOGGER.info("%s value = %s", self._name, value)
|
for value_type, value in values.items():
|
||||||
if self.value_type == self.const.SetReq.V_TRIPPED or \
|
_LOGGER.info(
|
||||||
self.value_type == self.const.SetReq.V_ARMED or \
|
"%s: value_type %s, value = %s", self._name, value_type, value)
|
||||||
self.value_type == self.const.SetReq.V_STATUS or \
|
if value_type == mysensors.CONST.SetReq.V_ARMED or \
|
||||||
self.value_type == self.const.SetReq.V_LIGHT or \
|
value_type == mysensors.CONST.SetReq.V_STATUS or \
|
||||||
self.value_type == self.const.SetReq.V_LOCK_STATUS:
|
value_type == mysensors.CONST.SetReq.V_LIGHT or \
|
||||||
self._value = STATE_ON if int(value) == 1 else STATE_OFF
|
value_type == mysensors.CONST.SetReq.V_LOCK_STATUS:
|
||||||
else:
|
self._values[value_type] = (
|
||||||
self._value = value
|
STATE_ON if int(value) == 1 else STATE_OFF)
|
||||||
|
else:
|
||||||
|
self._values[value_type] = value
|
||||||
self.battery_level = battery_level
|
self.battery_level = battery_level
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
@ -119,7 +119,7 @@ py-cpuinfo==0.1.6
|
|||||||
python-forecastio==1.3.3
|
python-forecastio==1.3.3
|
||||||
|
|
||||||
# homeassistant.components.sensor.mysensors
|
# homeassistant.components.sensor.mysensors
|
||||||
https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3
|
https://github.com/MartinHjelmare/pymysensors/archive/fifo_queue.zip#pymysensors==0.3
|
||||||
|
|
||||||
# homeassistant.components.sensor.openweathermap
|
# homeassistant.components.sensor.openweathermap
|
||||||
pyowm==2.2.1
|
pyowm==2.2.1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user