diff --git a/CODEOWNERS b/CODEOWNERS index 20fd91b75d3..c3126205810 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -66,6 +66,7 @@ homeassistant/components/egardia/* @jeroenterheerdt homeassistant/components/eight_sleep/* @mezz64 homeassistant/components/emby/* @mezz64 homeassistant/components/enigma2/* @fbradyirl +homeassistant/components/enocean/* @bdurrer homeassistant/components/ephember/* @ttroy50 homeassistant/components/epsonworkforce/* @ThaStealth homeassistant/components/eq3btsmart/* @rytilahti diff --git a/homeassistant/components/enocean/__init__.py b/homeassistant/components/enocean/__init__.py index 2dcf6a3a0ac..9d51821082a 100644 --- a/homeassistant/components/enocean/__init__.py +++ b/homeassistant/components/enocean/__init__.py @@ -4,13 +4,13 @@ import logging import voluptuous as vol from homeassistant.const import CONF_DEVICE +from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) DOMAIN = 'enocean' - -ENOCEAN_DONGLE = None +DATA_ENOCEAN = 'enocean' CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -18,14 +18,15 @@ CONFIG_SCHEMA = vol.Schema({ }), }, extra=vol.ALLOW_EXTRA) +SIGNAL_RECEIVE_MESSAGE = 'enocean.receive_message' +SIGNAL_SEND_MESSAGE = 'enocean.send_message' + def setup(hass, config): """Set up the EnOcean component.""" - global ENOCEAN_DONGLE - serial_dev = config[DOMAIN].get(CONF_DEVICE) - - ENOCEAN_DONGLE = EnOceanDongle(hass, serial_dev) + dongle = EnOceanDongle(hass, serial_dev) + hass.data[DATA_ENOCEAN] = dongle return True @@ -39,87 +40,53 @@ class EnOceanDongle: self.__communicator = SerialCommunicator( port=ser, callback=self.callback) self.__communicator.start() - self.__devices = [] + self.hass = hass + self.hass.helpers.dispatcher.dispatcher_connect( + SIGNAL_SEND_MESSAGE, self._send_message_callback) - def register_device(self, dev): - """Register another device.""" - self.__devices.append(dev) - - def send_command(self, command): - """Send a command from the EnOcean dongle.""" + def _send_message_callback(self, command): + """Send a command through the EnOcean dongle.""" self.__communicator.send(command) - # pylint: disable=no-self-use - def _combine_hex(self, data): - """Combine list of integer values to one big integer.""" - output = 0x00 - for i, j in enumerate(reversed(data)): - output |= (j << i * 8) - return output - - def callback(self, temp): + def callback(self, packet): """Handle EnOcean device's callback. This is the callback function called by python-enocan whenever there is an incoming packet. """ from enocean.protocol.packet import RadioPacket - if isinstance(temp, RadioPacket): - _LOGGER.debug("Received radio packet: %s", temp) - rxtype = None - value = None - channel = 0 - if temp.data[6] == 0x30: - rxtype = "wallswitch" - value = 1 - elif temp.data[6] == 0x20: - rxtype = "wallswitch" - value = 0 - elif temp.data[4] == 0x0c: - rxtype = "power" - value = temp.data[3] + (temp.data[2] << 8) - elif temp.data[2] & 0x60 == 0x60: - rxtype = "switch_status" - channel = temp.data[2] & 0x1F - if temp.data[3] == 0xe4: - value = 1 - elif temp.data[3] == 0x80: - value = 0 - elif temp.data[0] == 0xa5 and temp.data[1] == 0x02: - rxtype = "dimmerstatus" - value = temp.data[2] - for device in self.__devices: - if rxtype == "wallswitch" and device.stype == "listener": - if temp.sender_int == self._combine_hex(device.dev_id): - device.value_changed(value, temp.data[1]) - if rxtype == "power" and device.stype == "powersensor": - if temp.sender_int == self._combine_hex(device.dev_id): - device.value_changed(value) - if rxtype == "power" and device.stype == "switch": - if temp.sender_int == self._combine_hex(device.dev_id): - if value > 10: - device.value_changed(1) - if rxtype == "switch_status" and device.stype == "switch" and \ - channel == device.channel: - if temp.sender_int == self._combine_hex(device.dev_id): - device.value_changed(value) - if rxtype == "dimmerstatus" and device.stype == "dimmer": - if temp.sender_int == self._combine_hex(device.dev_id): - device.value_changed(value) + if isinstance(packet, RadioPacket): + _LOGGER.debug("Received radio packet: %s", packet) + self.hass.helpers.dispatcher.dispatcher_send( + SIGNAL_RECEIVE_MESSAGE, packet) -class EnOceanDevice(): +class EnOceanDevice(Entity): """Parent class for all devices associated with the EnOcean component.""" - def __init__(self): + def __init__(self, dev_id, dev_name="EnOcean device"): """Initialize the device.""" - ENOCEAN_DONGLE.register_device(self) - self.stype = "" - self.sensorid = [0x00, 0x00, 0x00, 0x00] + self.dev_id = dev_id + self.dev_name = dev_name + + async def async_added_to_hass(self): + """Register callbacks.""" + self.hass.helpers.dispatcher.async_dispatcher_connect( + SIGNAL_RECEIVE_MESSAGE, self._message_received_callback) + + def _message_received_callback(self, packet): + """Handle incoming packets.""" + from enocean.utils import combine_hex + if packet.sender_int == combine_hex(self.dev_id): + self.value_changed(packet) + + def value_changed(self, packet): + """Update the internal state of the device when a packet arrives.""" # pylint: disable=no-self-use def send_command(self, data, optional, packet_type): """Send a command via the EnOcean dongle.""" from enocean.protocol.packet import Packet packet = Packet(packet_type, data=data, optional=optional) - ENOCEAN_DONGLE.send_command(packet) + self.hass.helpers.dispatcher.dispatcher_send( + SIGNAL_SEND_MESSAGE, packet) diff --git a/homeassistant/components/enocean/binary_sensor.py b/homeassistant/components/enocean/binary_sensor.py index 649bec024e3..5e0a3b31817 100644 --- a/homeassistant/components/enocean/binary_sensor.py +++ b/homeassistant/components/enocean/binary_sensor.py @@ -3,16 +3,17 @@ import logging import voluptuous as vol -from homeassistant.components.binary_sensor import ( - BinarySensorDevice, PLATFORM_SCHEMA, DEVICE_CLASSES_SCHEMA) from homeassistant.components import enocean -from homeassistant.const import ( - CONF_NAME, CONF_ID, CONF_DEVICE_CLASS) +from homeassistant.components.binary_sensor import ( + DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA, BinarySensorDevice) +from homeassistant.const import CONF_DEVICE_CLASS, CONF_ID, CONF_NAME import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = 'EnOcean binary sensor' +DEPENDENCIES = ['enocean'] +EVENT_BUTTON_PRESSED = 'button_pressed' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), @@ -24,61 +25,80 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Binary Sensor platform for EnOcean.""" dev_id = config.get(CONF_ID) - devname = config.get(CONF_NAME) + dev_name = config.get(CONF_NAME) device_class = config.get(CONF_DEVICE_CLASS) - add_entities([EnOceanBinarySensor(dev_id, devname, device_class)]) + add_entities([EnOceanBinarySensor(dev_id, dev_name, device_class)]) class EnOceanBinarySensor(enocean.EnOceanDevice, BinarySensorDevice): - """Representation of EnOcean binary sensors such as wall switches.""" + """Representation of EnOcean binary sensors such as wall switches. - def __init__(self, dev_id, devname, device_class): + Supported EEPs (EnOcean Equipment Profiles): + - F6-02-01 (Light and Blind Control - Application Style 2) + - F6-02-02 (Light and Blind Control - Application Style 1) + """ + + def __init__(self, dev_id, dev_name, device_class): """Initialize the EnOcean binary sensor.""" - enocean.EnOceanDevice.__init__(self) - self.stype = 'listener' - self.dev_id = dev_id + super().__init__(dev_id, dev_name) + self._device_class = device_class self.which = -1 self.onoff = -1 - self.devname = devname - self._device_class = device_class @property def name(self): """Return the default name for the binary sensor.""" - return self.devname + return self.dev_name @property def device_class(self): """Return the class of this sensor.""" return self._device_class - def value_changed(self, value, value2): + def value_changed(self, packet): """Fire an event with the data that have changed. This method is called when there is an incoming packet associated with this platform. + + Example packet data: + - 2nd button pressed + ['0xf6', '0x10', '0x00', '0x2d', '0xcf', '0x45', '0x30'] + - button released + ['0xf6', '0x00', '0x00', '0x2d', '0xcf', '0x45', '0x20'] """ + # Energy Bow + pushed = None + + if packet.data[6] == 0x30: + pushed = 1 + elif packet.data[6] == 0x20: + pushed = 0 + self.schedule_update_ha_state() - if value2 == 0x70: + + action = packet.data[1] + if action == 0x70: self.which = 0 self.onoff = 0 - elif value2 == 0x50: + elif action == 0x50: self.which = 0 self.onoff = 1 - elif value2 == 0x30: + elif action == 0x30: self.which = 1 self.onoff = 0 - elif value2 == 0x10: + elif action == 0x10: self.which = 1 self.onoff = 1 - elif value2 == 0x37: + elif action == 0x37: self.which = 10 self.onoff = 0 - elif value2 == 0x15: + elif action == 0x15: self.which = 10 self.onoff = 1 - self.hass.bus.fire('button_pressed', {'id': self.dev_id, - 'pushed': value, - 'which': self.which, - 'onoff': self.onoff}) + self.hass.bus.fire(EVENT_BUTTON_PRESSED, + {'id': self.dev_id, + 'pushed': pushed, + 'which': self.which, + 'onoff': self.onoff}) diff --git a/homeassistant/components/enocean/light.py b/homeassistant/components/enocean/light.py index 9ec3f4ab27b..d40b2c01df6 100644 --- a/homeassistant/components/enocean/light.py +++ b/homeassistant/components/enocean/light.py @@ -4,10 +4,10 @@ import math import voluptuous as vol -from homeassistant.components.light import ( - Light, ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, PLATFORM_SCHEMA) -from homeassistant.const import (CONF_NAME, CONF_ID) from homeassistant.components import enocean +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, Light) +from homeassistant.const import CONF_ID, CONF_NAME import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -28,29 +28,26 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the EnOcean light platform.""" sender_id = config.get(CONF_SENDER_ID) - devname = config.get(CONF_NAME) + dev_name = config.get(CONF_NAME) dev_id = config.get(CONF_ID) - add_entities([EnOceanLight(sender_id, devname, dev_id)]) + add_entities([EnOceanLight(sender_id, dev_id, dev_name)]) class EnOceanLight(enocean.EnOceanDevice, Light): """Representation of an EnOcean light source.""" - def __init__(self, sender_id, devname, dev_id): + def __init__(self, sender_id, dev_id, dev_name): """Initialize the EnOcean light source.""" - enocean.EnOceanDevice.__init__(self) + super().__init__(dev_id, dev_name) self._on_state = False self._brightness = 50 self._sender_id = sender_id - self.dev_id = dev_id - self._devname = devname - self.stype = 'dimmer' @property def name(self): """Return the name of the device if any.""" - return self._devname + return self.dev_name @property def brightness(self): @@ -94,8 +91,14 @@ class EnOceanLight(enocean.EnOceanDevice, Light): self.send_command(command, [], 0x01) self._on_state = False - def value_changed(self, val): - """Update the internal state of this device.""" - self._brightness = math.floor(val / 100.0 * 256.0) - self._on_state = bool(val != 0) - self.schedule_update_ha_state() + def value_changed(self, packet): + """Update the internal state of this device. + + Dimmer devices like Eltako FUD61 send telegram in different RORGs. + We only care about the 4BS (0xA5). + """ + if packet.data[0] == 0xa5 and packet.data[1] == 0x02: + val = packet.data[2] + self._brightness = math.floor(val / 100.0 * 256.0) + self._on_state = bool(val != 0) + self.schedule_update_ha_state() diff --git a/homeassistant/components/enocean/manifest.json b/homeassistant/components/enocean/manifest.json index 7c4d7c0b8d9..e6f1c5d7826 100644 --- a/homeassistant/components/enocean/manifest.json +++ b/homeassistant/components/enocean/manifest.json @@ -3,8 +3,8 @@ "name": "Enocean", "documentation": "https://www.home-assistant.io/components/enocean", "requirements": [ - "enocean==0.40" + "enocean==0.50" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@bdurrer"] } diff --git a/homeassistant/components/enocean/sensor.py b/homeassistant/components/enocean/sensor.py index 530738e1f88..62d0277946f 100644 --- a/homeassistant/components/enocean/sensor.py +++ b/homeassistant/components/enocean/sensor.py @@ -3,58 +3,201 @@ import logging import voluptuous as vol -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import (CONF_NAME, CONF_ID, POWER_WATT) -from homeassistant.helpers.entity import Entity -import homeassistant.helpers.config_validation as cv from homeassistant.components import enocean +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + CONF_DEVICE_CLASS, CONF_ID, CONF_NAME, DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, POWER_WATT) +import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) +CONF_MAX_TEMP = 'max_temp' +CONF_MIN_TEMP = 'min_temp' +CONF_RANGE_FROM = 'range_from' +CONF_RANGE_TO = 'range_to' + DEFAULT_NAME = 'EnOcean sensor' + +DEVICE_CLASS_POWER = 'powersensor' + +SENSOR_TYPES = { + DEVICE_CLASS_HUMIDITY: { + 'name': 'Humidity', + 'unit': '%', + 'icon': 'mdi:water-percent', + 'class': DEVICE_CLASS_HUMIDITY, + }, + DEVICE_CLASS_POWER: { + 'name': 'Power', + 'unit': POWER_WATT, + 'icon': 'mdi:power-plug', + 'class': DEVICE_CLASS_POWER, + }, + DEVICE_CLASS_TEMPERATURE: { + 'name': 'Temperature', + 'unit': TEMP_CELSIUS, + 'icon': 'mdi:thermometer', + 'class': DEVICE_CLASS_TEMPERATURE, + }, +} + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_DEVICE_CLASS, default=DEVICE_CLASS_POWER): cv.string, + vol.Optional(CONF_MAX_TEMP, default=40): vol.Coerce(int), + vol.Optional(CONF_MIN_TEMP, default=0): vol.Coerce(int), + vol.Optional(CONF_RANGE_FROM, default=255): cv.positive_int, + vol.Optional(CONF_RANGE_TO, default=0): cv.positive_int, }) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an EnOcean sensor device.""" dev_id = config.get(CONF_ID) - devname = config.get(CONF_NAME) + dev_name = config.get(CONF_NAME) + dev_class = config.get(CONF_DEVICE_CLASS) - add_entities([EnOceanSensor(dev_id, devname)]) + if dev_class == DEVICE_CLASS_TEMPERATURE: + temp_min = config.get(CONF_MIN_TEMP) + temp_max = config.get(CONF_MAX_TEMP) + range_from = config.get(CONF_RANGE_FROM) + range_to = config.get(CONF_RANGE_TO) + add_entities([EnOceanTemperatureSensor( + dev_id, dev_name, temp_min, temp_max, range_from, range_to)]) + + elif dev_class == DEVICE_CLASS_HUMIDITY: + add_entities([EnOceanHumiditySensor(dev_id, dev_name)]) + + elif dev_class == DEVICE_CLASS_POWER: + add_entities([EnOceanPowerSensor(dev_id, dev_name)]) -class EnOceanSensor(enocean.EnOceanDevice, Entity): - """Representation of an EnOcean sensor device such as a power meter.""" +class EnOceanSensor(enocean.EnOceanDevice): + """Representation of an EnOcean sensor device such as a power meter.""" - def __init__(self, dev_id, devname): + def __init__(self, dev_id, dev_name, sensor_type): """Initialize the EnOcean sensor device.""" - enocean.EnOceanDevice.__init__(self) - self.stype = "powersensor" - self.power = None - self.dev_id = dev_id - self.which = -1 - self.onoff = -1 - self.devname = devname + super().__init__(dev_id, dev_name) + self._sensor_type = sensor_type + self._device_class = SENSOR_TYPES[self._sensor_type]['class'] + self._dev_name = '{} {}'.format( + SENSOR_TYPES[self._sensor_type]['name'], dev_name) + self._unit_of_measurement = SENSOR_TYPES[self._sensor_type]['unit'] + self._icon = SENSOR_TYPES[self._sensor_type]['icon'] + self._state = None @property def name(self): """Return the name of the device.""" - return 'Power %s' % self.devname + return self._dev_name - def value_changed(self, value): - """Update the internal state of the device.""" - self.power = value - self.schedule_update_ha_state() + @property + def icon(self): + """Icon to use in the frontend.""" + return self._icon + + @property + def device_class(self): + """Return the device class of the sensor.""" + return self._device_class @property def state(self): """Return the state of the device.""" - return self.power + return self._state @property def unit_of_measurement(self): """Return the unit of measurement.""" - return POWER_WATT + return self._unit_of_measurement + + def value_changed(self, packet): + """Update the internal state of the sensor.""" + + +class EnOceanPowerSensor(EnOceanSensor): + """Representation of an EnOcean power sensor. + + EEPs (EnOcean Equipment Profiles): + - A5-12-01 (Automated Meter Reading, Electricity) + """ + + def __init__(self, dev_id, dev_name): + """Initialize the EnOcean power sensor device.""" + super().__init__(dev_id, dev_name, DEVICE_CLASS_POWER) + + def value_changed(self, packet): + """Update the internal state of the sensor.""" + if packet.rorg != 0xA5: + return + packet.parse_eep(0x12, 0x01) + if packet.parsed['DT']['raw_value'] == 1: + # this packet reports the current value + raw_val = packet.parsed['MR']['raw_value'] + divisor = packet.parsed['DIV']['raw_value'] + self._state = raw_val / (10 ** divisor) + self.schedule_update_ha_state() + + +class EnOceanTemperatureSensor(EnOceanSensor): + """Representation of an EnOcean temperature sensor device. + + EEPs (EnOcean Equipment Profiles): + - A5-02-01 to A5-02-1B All 8 Bit Temperature Sensors of A5-02 + - A5-10-01 to A5-10-14 (Room Operating Panels) + - A5-04-01 (Temp. and Humidity Sensor, Range 0°C to +40°C and 0% to 100%) + - A5-04-02 (Temp. and Humidity Sensor, Range -20°C to +60°C and 0% to 100%) + - A5-10-10 (Temp. and Humidity Sensor and Set Point) + - A5-10-12 (Temp. and Humidity Sensor, Set Point and Occupancy Control) + - 10 Bit Temp. Sensors are not supported (A5-02-20, A5-02-30) + + For the following EEPs the scales must be set to "0 to 250": + - A5-04-01 + - A5-04-02 + - A5-10-10 to A5-10-14 + """ + + def __init__(self, dev_id, dev_name, scale_min, scale_max, + range_from, range_to): + """Initialize the EnOcean temperature sensor device.""" + super().__init__(dev_id, dev_name, DEVICE_CLASS_TEMPERATURE) + self._scale_min = scale_min + self._scale_max = scale_max + self.range_from = range_from + self.range_to = range_to + + def value_changed(self, packet): + """Update the internal state of the sensor.""" + if packet.data[0] != 0xa5: + return + temp_scale = self._scale_max - self._scale_min + temp_range = self.range_to - self.range_from + raw_val = packet.data[3] + temperature = temp_scale / temp_range * (raw_val - self.range_from) + temperature += self._scale_min + self._state = round(temperature, 1) + self.schedule_update_ha_state() + + +class EnOceanHumiditySensor(EnOceanSensor): + """Representation of an EnOcean humidity sensor device. + + EEPs (EnOcean Equipment Profiles): + - A5-04-01 (Temp. and Humidity Sensor, Range 0°C to +40°C and 0% to 100%) + - A5-04-02 (Temp. and Humidity Sensor, Range -20°C to +60°C and 0% to 100%) + - A5-10-10 to A5-10-14 (Room Operating Panels) + """ + + def __init__(self, dev_id, dev_name): + """Initialize the EnOcean humidity sensor device.""" + super().__init__(dev_id, dev_name, DEVICE_CLASS_HUMIDITY) + + def value_changed(self, packet): + """Update the internal state of the sensor.""" + if packet.rorg != 0xA5: + return + humidity = packet.data[2] * 100 / 250 + self._state = round(humidity, 1) + self.schedule_update_ha_state() diff --git a/homeassistant/components/enocean/switch.py b/homeassistant/components/enocean/switch.py index f0b132c9d1c..48d53949a47 100644 --- a/homeassistant/components/enocean/switch.py +++ b/homeassistant/components/enocean/switch.py @@ -3,16 +3,16 @@ import logging import voluptuous as vol -from homeassistant.components.switch import PLATFORM_SCHEMA -from homeassistant.const import (CONF_NAME, CONF_ID) from homeassistant.components import enocean -from homeassistant.helpers.entity import ToggleEntity +from homeassistant.components.switch import PLATFORM_SCHEMA +from homeassistant.const import CONF_ID, CONF_NAME import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import ToggleEntity _LOGGER = logging.getLogger(__name__) -DEFAULT_NAME = 'EnOcean Switch' CONF_CHANNEL = 'channel' +DEFAULT_NAME = 'EnOcean Switch' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), @@ -23,26 +23,23 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the EnOcean switch platform.""" - dev_id = config.get(CONF_ID) - devname = config.get(CONF_NAME) channel = config.get(CONF_CHANNEL) + dev_id = config.get(CONF_ID) + dev_name = config.get(CONF_NAME) - add_entities([EnOceanSwitch(dev_id, devname, channel)]) + add_entities([EnOceanSwitch(dev_id, dev_name, channel)]) class EnOceanSwitch(enocean.EnOceanDevice, ToggleEntity): """Representation of an EnOcean switch device.""" - def __init__(self, dev_id, devname, channel): + def __init__(self, dev_id, dev_name, channel): """Initialize the EnOcean switch device.""" - enocean.EnOceanDevice.__init__(self) - self.dev_id = dev_id - self._devname = devname + super().__init__(dev_id, dev_name) self._light = None self._on_state = False self._on_state2 = False self.channel = channel - self.stype = "switch" @property def is_on(self): @@ -52,7 +49,7 @@ class EnOceanSwitch(enocean.EnOceanDevice, ToggleEntity): @property def name(self): """Return the device name.""" - return self._devname + return self.dev_name def turn_on(self, **kwargs): """Turn on the switch.""" @@ -74,7 +71,24 @@ class EnOceanSwitch(enocean.EnOceanDevice, ToggleEntity): packet_type=0x01) self._on_state = False - def value_changed(self, val): + def value_changed(self, packet): """Update the internal state of the switch.""" - self._on_state = val - self.schedule_update_ha_state() + if packet.data[0] == 0xa5: + # power meter telegram, turn on if > 10 watts + packet.parse_eep(0x12, 0x01) + if packet.parsed['DT']['raw_value'] == 1: + raw_val = packet.parsed['MR']['raw_value'] + divisor = packet.parsed['DIV']['raw_value'] + watts = raw_val / (10 ** divisor) + if watts > 1: + self._on_state = True + self.schedule_update_ha_state() + elif packet.data[0] == 0xd2: + # actuator status telegram + packet.parse_eep(0x01, 0x01) + if packet.parsed['CMD']['raw_value'] == 4: + channel = packet.parsed['IO']['raw_value'] + output = packet.parsed['OV']['raw_value'] + if channel == self.channel: + self._on_state = output > 0 + self.schedule_update_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 2007491a903..b328c0f361d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -383,7 +383,7 @@ elkm1-lib==0.7.13 emulated_roku==0.1.8 # homeassistant.components.enocean -enocean==0.40 +enocean==0.50 # homeassistant.components.entur_public_transport enturclient==0.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c09da4b3bb8..7299a3cfdc5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -90,6 +90,9 @@ eebrightbox==0.0.4 # homeassistant.components.emulated_roku emulated_roku==0.1.8 +# homeassistant.components.enocean +enocean==0.50 + # homeassistant.components.season ephem==3.7.6.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 63b0ef737e2..9586dc17947 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -58,6 +58,7 @@ TEST_REQUIREMENTS = ( 'dsmr_parser', 'eebrightbox', 'emulated_roku', + 'enocean', 'ephem', 'evohomeclient', 'feedparser-homeassistant',