class EnOceanDongle: """Representation of an EnOcean dongle.""" def __init__(self, hass, ser): """Initialize the EnOcean dongle.""" from enocean.communicators.serialcommunicator import SerialCommunicator self.__communicator = SerialCommunicator( port=ser, callback=self.callback) self.__communicator.start() self.hass = hass self.hass.helpers.dispatcher.dispatcher_connect( SIGNAL_SEND_MESSAGE, self._send_message_callback) def _send_message_callback(self, command): """Send a command through the EnOcean dongle.""" self.__communicator.send(command) 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(packet, RadioPacket): _LOGGER.debug("Received radio packet: %s", packet) self.hass.helpers.dispatcher.dispatcher_send( SIGNAL_RECEIVE_MESSAGE, packet)
def seriallistener(): global on_raspi, sys_init, id_list senderID = None fire_event = False if(on_raspi is True): p = Packet(PACKET.COMMON_COMMAND, [0x08]) c = SerialCommunicator() c.start() c.send(p) while sys_init is True: try: p = c.receive.get(block=True, timeout=1) if(p.type == PACKET.RADIO and p.rorg == RORG.BS4): timestamp = datetime.datetime.now() senderID = p.data[5]*1677216+p.data[6]*65536+p.data[7]*256+p.data[8] if len(id_list) == 0: id_list.append(senderID) fire_event = True else: i=0 for i in range(0,len(id_list)): if id_list[i] == senderID: id_list.remove(senderID) fire_event = False break elif id_list[i] != senderID and i == (len(id_list)-1): id_list.append(senderID) fire_event = True break if fire_event is True: serialevent = pygame.event.Event(EV_SERIAL_INPUT, id=senderID, tm=timestamp) pygame.event.post(serialevent) fire_event = False except queue.Empty: continue except KeyboardInterrupt: break except Exception: traceback.print_exc(file=sys.stdout) break c.stop() else: while pygame.display.get_init() is True: pygame.event.post(serialevent) time.sleep(random.uniform(1,5))
class Encocean_Sat(object): def __init__(self): self.communicator = SerialCommunicator(port='/dev/ttyUSB0') self.communicator.start() def assemble_radio_packet(transmitter_id): return RadioPacket.create(rorg=RORG.BS4, rorg_func=0x20, rorg_type=0x01, sender=transmitter_id, CV=50, TMP=21.5, ES='true') def monitor(self): while self.communicator.is_alive(): try: # Loop to empty the queue... packet = self.communicator.receive.get(block=True, timeout=1) if packet.packet_type == PACKET.RADIO and packet.rorg == RORG.BS4: # parse packet with given FUNC and TYPE for k in packet.parse_eep(0x02, 0x05): print('A %s: %s' % (k, packet.parsed[k])) if packet.packet_type == PACKET.RADIO and packet.rorg == RORG.BS1: # alternatively you can select FUNC and TYPE explicitely packet.select_eep(0x00, 0x01) # parse it packet.parse_eep() for k in packet.parsed: print('B %s: %s' % (k, packet.parsed[k])) if packet.packet_type == PACKET.RADIO and packet.rorg == RORG.RPS: received = packet.parse_eep(0x02, 0x02) print packet.sender_hex, packet.parsed['EB']['raw_value'] # udp_send.send_to_server('Enocean.' + packet.sender_hex, packet.parsed['EB']['raw_value']) dicti = {'Name': 'Enocean.'+str(packet.sender_hex), 'Value': str(packet.parsed['EB']['raw_value'])} mqtt_publish.mqtt_pub('Inputs/Satellite/' + constants.name + '/Enocean/'+str(packet.sender_hex),dicti) except queue.Empty: continue except KeyboardInterrupt: break except Exception: traceback.print_exc(file=sys.stdout) break if self.communicator.is_alive(): self.communicator.stop()
class EnOceanDongle: """Representation of an EnOcean dongle.""" def __init__(self, hass, ser): """Initialize the EnOcean dongle.""" from enocean.communicators.serialcommunicator import SerialCommunicator self.__communicator = SerialCommunicator( port=ser, callback=self.callback) self.__communicator.start() self.__devices = [] def register_device(self, dev): """Register another device.""" self.__devices.append(dev) def send_command(self, command): """Send a command from 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): """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 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: rxtype = "switch_status" 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": 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)
import queue except ImportError: import Queue as queue def assemble_radio_packet(transmitter_id): return RadioPacket.create(rorg=RORG.BS4, rorg_func=0x20, rorg_type=0x01, sender=transmitter_id, CV=50, TMP=21.5, ES='true') init_logging() communicator = SerialCommunicator() communicator.start() print('The Base ID of your module is %s.' % enocean.utils.to_hex_string(communicator.base_id)) if communicator.base_id is not None: print('Sending example package.') communicator.send(assemble_radio_packet(communicator.base_id)) # endless loop receiving radio packets while communicator.is_alive(): try: # Loop to empty the queue... packet = communicator.receive.get(block=True, timeout=1) if packet.packet_type == PACKET.RADIO and packet.rorg == RORG.BS4: # parse packet with given FUNC and TYPE for k in packet.parse_eep(0x02, 0x05):
import queue except ImportError: import Queue as queue def assemble_radio_packet(transmitter_id): return RadioPacket.create(rorg=RORG.BS4, func=0x20, type=0x01, sender=transmitter_id, CV=50, TMP=21.5, ES='true') init_logging() c = SerialCommunicator() c.start() # Request transmitter ID p = Packet(PACKET.COMMON_COMMAND, [0x08]) c.send(p) # Fetch the transmitter ID for sending packages. # NOT TESTED!!! # Needs testing, and if functional, a similar loop should be implemented to the communicator initialization. # This ID would then be used to send all future messages. transmitter_id = None while transmitter_id is None: try: p = c.receive.get(block=True, timeout=1) if p.type == PACKET.RESPONSE: transmitter_id = p.response_data
#!/usr/bin/env python # -*- encoding: utf-8 -*- from enocean.consolelogger import init_logging from enocean.communicators.serialcommunicator import SerialCommunicator from enocean.communicators.utils import send_to_tcp_socket import sys import traceback try: import queue except ImportError: import Queue as queue init_logging() c = SerialCommunicator() c.start() while c.is_alive(): try: # Loop to empty the queue... p = c.receive.get(block=True, timeout=1) send_to_tcp_socket('localhost', 9637, p) except queue.Empty: continue except KeyboardInterrupt: break except Exception: traceback.print_exc(file=sys.stdout) break if c.is_alive(): c.stop()
import queue except ImportError: import Queue as queue def assemble_radio_packet(transmitter_id): return RadioPacket.create(rorg=RORG.BS4, rorg_func=0x20, rorg_type=0x01, sender=transmitter_id, CV=50, TMP=21.5, ES='true') init_logging() communicator = SerialCommunicator() communicator.start() print('The Base ID of your module is %s.' % enocean.utils.to_hex_string(communicator.base_id)) if communicator.base_id is not None: print('Sending example package.') communicator.send(assemble_radio_packet(communicator.base_id)) # endless loop receiving radio packets while communicator.is_alive(): try: # Loop to empty the queue... packet = communicator.receive.get(block=True, timeout=1) vreturn = packet if packet.packet_type == PACKET.RADIO and packet.rorg == RORG.BS4: # parse packet with given FUNC and TYPE for k in packet.parse_eep(0x02, 0x05):
class Communicator: mqtt = None enocean = None CONNECTION_RETURN_CODE = [ "connection successful", "incorrect protocol version", "invalid client identifier", "server unavailable", "bad username or password", "not authorised", ] def __init__(self, config, sensors): self.conf = config self.sensors = sensors # check for mandatory configuration if 'mqtt_host' not in self.conf or 'enocean_port' not in self.conf: raise Exception("Mandatory configuration not found: mqtt_host/enocean_port") mqtt_port = int(self.conf['mqtt_port']) if 'mqtt_port' in self.conf else 1883 mqtt_keepalive = int(self.conf['mqtt_keepalive']) if 'mqtt_keepalive' in self.conf else 0 # setup mqtt connection client_id = self.conf['mqtt_client_id'] if 'mqtt_client_id' in self.conf else '' self.mqtt = mqtt.Client(client_id=client_id) self.mqtt.on_connect = self._on_connect self.mqtt.on_disconnect = self._on_disconnect self.mqtt.on_message = self._on_mqtt_message self.mqtt.on_publish = self._on_mqtt_publish if 'mqtt_user' in self.conf: logging.info("Authenticating: " + self.conf['mqtt_user']) self.mqtt.username_pw_set(self.conf['mqtt_user'], self.conf['mqtt_pwd']) if str(self.conf.get('mqtt_ssl')) in ("True", "true", "1"): logging.info("Enabling SSL") ca_certs = self.conf['mqtt_ssl_ca_certs'] if 'mqtt_ssl_ca_certs' in self.conf else None certfile = self.conf['mqtt_ssl_certfile'] if 'mqtt_ssl_certfile' in self.conf else None keyfile = self.conf['mqtt_ssl_keyfile'] if 'mqtt_ssl_keyfile' in self.conf else None self.mqtt.tls_set(ca_certs=ca_certs, certfile=certfile, keyfile=keyfile) if str(self.conf.get('mqtt_ssl_insecure')) in ("True", "true", "1"): logging.warning("Disabling SSL certificate verification") self.mqtt.tls_insecure_set(True) if str(self.conf.get('mqtt_debug')) in ("True", "true", "1"): self.mqtt.enable_logger() logging.debug("Connecting to host " + self.conf['mqtt_host'] + ", port " + str(mqtt_port) + ", keepalive " + str(mqtt_keepalive)) self.mqtt.connect_async(self.conf['mqtt_host'], port=mqtt_port, keepalive=mqtt_keepalive) self.mqtt.loop_start() # setup enocean communication self.enocean = SerialCommunicator(self.conf['enocean_port']) self.enocean.start() # sender will be automatically determined self.enocean_sender = None def __del__(self): if self.enocean is not None and self.enocean.is_alive(): self.enocean.stop() def _on_connect(self, mqtt_client, userdata, flags, rc): '''callback for when the client receives a CONNACK response from the MQTT server.''' if rc == 0: logging.info("Succesfully connected to MQTT broker.") # listen to enocean send requests for cur_sensor in self.sensors: mqtt_client.subscribe(cur_sensor['name']+'/req/#') else: logging.error("Error connecting to MQTT broker: %s", self.CONNECTION_RETURN_CODE[rc]) def _on_disconnect(self, mqtt_client, userdata, rc): '''callback for when the client disconnects from the MQTT server.''' if rc == 0: logging.warning("Successfully disconnected from MQTT broker") else: logging.warning("Unexpectedly disconnected from MQTT broker: " + self.CONNECTION_RETURN_CODE[rc]) def _on_mqtt_message(self, mqtt_client, userdata, msg): '''the callback for when a PUBLISH message is received from the MQTT server.''' # search for sensor for cur_sensor in self.sensors: if cur_sensor['name'] in msg.topic: # store data for this sensor if 'data' not in cur_sensor: cur_sensor['data'] = {} prop = msg.topic[len(cur_sensor['name']+"/req/"):] try: cur_sensor['data'][prop] = int(msg.payload) except ValueError: logging.warning("Cannot parse int value for %s: %s", msg.topic, msg.payload) def _on_mqtt_publish(self, mqtt_client, userdata, mid): '''the callback for when a PUBLISH message is successfully sent to the MQTT server.''' #logging.debug("Published MQTT message "+str(mid)) pass def _read_packet(self, packet): '''interpret packet, read properties and publish to MQTT''' mqtt_publish_json = ('mqtt_publish_json' in self.conf and self.conf['mqtt_publish_json'] in ("True", "true", "1")) mqtt_json = { } # loop through all configured devices for cur_sensor in self.sensors: # does this sensor match? if enocean.utils.combine_hex(packet.sender) == cur_sensor['address']: # found sensor configured in config file if str(cur_sensor.get('publish_rssi')) in ("True", "true", "1"): if mqtt_publish_json: mqtt_json['RSSI'] = packet.dBm else: self.mqtt.publish(cur_sensor['name']+"/RSSI", packet.dBm) if not packet.learn or str(cur_sensor.get('log_learn')) in ("True", "true", "1"): # data packet received found_property = False if packet.packet_type == PACKET.RADIO and packet.rorg == cur_sensor['rorg']: # radio packet of proper rorg type received; parse EEP direction = cur_sensor.get('direction') properties = packet.parse_eep(cur_sensor['func'], cur_sensor['type'], direction) # loop through all EEP properties for prop_name in properties: found_property = True cur_prop = packet.parsed[prop_name] # we only extract numeric values, either the scaled ones or the raw values for enums if isinstance(cur_prop['value'], numbers.Number): value = cur_prop['value'] else: value = cur_prop['raw_value'] # publish extracted information logging.debug("{}: {} ({})={} {}".format(cur_sensor['name'], prop_name, cur_prop['description'], cur_prop['value'], cur_prop['unit'])) retain = str(cur_sensor.get('persistent')) in ("True", "true", "1") if mqtt_publish_json: mqtt_json[prop_name] = value else: self.mqtt.publish(cur_sensor['name']+"/"+prop_name, value, retain=retain) if not found_property: logging.warn('message not interpretable: {}'.format(cur_sensor['name'])) elif mqtt_publish_json: name = cur_sensor['name'] value = json.dumps(mqtt_json) logging.debug("{}: Sent MQTT: {}".format(name, value)) self.mqtt.publish(name, value, retain=retain) else: # learn request received logging.info("learn request not emitted to mqtt") def _reply_packet(self, in_packet, sensor): '''send enocean message as a reply to an incoming message''' # prepare addresses destination = in_packet.sender # prepare packet if 'direction' in sensor: # we invert the direction in this reply direction = 1 if sensor['direction'] == 2 else 2 else: direction = None packet = RadioPacket.create(RORG.BS4, sensor['func'], sensor['type'], direction=direction, sender=self.enocean_sender, destination=destination, learn=in_packet.learn) # assemble data based on packet type (learn / data) if not in_packet.learn: # data packet received # start with default data packet.data[1:5] = [ (sensor['default_data'] >> i & 0xff) for i in (24,16,8,0) ] # do we have specific data to send? if 'data' in sensor: # override with specific data settings packet.set_eep(sensor['data']) else: # what to do if we have no data to send yet? logging.warn('sending default data as answer to %s', sensor['name']) else: # learn request received # copy EEP and manufacturer ID packet.data[1:5] = in_packet.data[1:5] # update flags to acknowledge learn request packet.data[4] = 0xf0 # send it logging.info('sending: {}'.format(packet)) self.enocean.send(packet) def _process_radio_packet(self, packet): # first, look whether we have this sensor configured found_sensor = False for cur_sensor in self.sensors: if enocean.utils.combine_hex(packet.sender) == cur_sensor['address']: found_sensor = cur_sensor # skip ignored sensors if found_sensor and 'ignore' in found_sensor and found_sensor['ignore']: return # log packet, if not disabled if str(self.conf.get('log_packets')) in ("True", "true", "1"): logging.info('received: {}'.format(packet)) # abort loop if sensor not found if not found_sensor: logging.info('unknown sensor: {}'.format(enocean.utils.to_hex_string(packet.sender))) return # interpret packet, read properties and publish to MQTT self._read_packet(packet) # check for neccessary reply if str(found_sensor.get('answer')) in ("True", "true", "1"): self._reply_packet(packet, found_sensor) def run(self): # start endless loop for listening while self.enocean.is_alive(): # Request transmitter ID, if needed if self.enocean_sender is None: self.enocean_sender = self.enocean.base_id # Loop to empty the queue... try: # get next packet if (platform.system() == 'Windows'): # only timeout on Windows for KeyboardInterrupt checking packet = self.enocean.receive.get(block=True, timeout=1) else: packet = self.enocean.receive.get(block=True) # check packet type if packet.packet_type == PACKET.RADIO: self._process_radio_packet(packet) elif packet.packet_type == PACKET.RESPONSE: response_code = RETURN_CODE(packet.data[0]) logging.info("got response packet: {}".format(response_code.name)) else: logging.info("got non-RF packet: {}".format(packet)) continue except queue.Empty: continue except KeyboardInterrupt: logging.debug("Exception: KeyboardInterrupt") break # Run finished, close MQTT client and stop Enocean thread logging.debug("Cleaning up") self.mqtt.loop_stop() self.mqtt.disconnect() self.mqtt.loop_forever() # will block until disconnect complete self.enocean.stop()
class Communicator: mqtt = None enocean = None CONNECTION_RETURN_CODE = [ "connection successful", "incorrect protocol version", "invalid client identifier", "server unavailable", "bad username or password", "not authorised", ] def __init__(self, config, sensors): self.conf = config self.sensors = sensors # setup mqtt connection self.mqtt = mqtt.Client() self.mqtt.on_connect = self._on_connect self.mqtt.on_disconnect = self._on_disconnect self.mqtt.on_message = self._on_mqtt_message self.mqtt.on_publish = self._on_mqtt_publish if 'mqtt_user' in self.conf: logging.info("Authenticating: " + self.conf['mqtt_user']) self.mqtt.username_pw_set(self.conf['mqtt_user'], self.conf['mqtt_pwd']) self.mqtt.connect(self.conf['mqtt_host'], int(self.conf['mqtt_port'],0)) self.mqtt.loop_start() # setup enocean communication self.enocean = SerialCommunicator(self.conf['enocean_port']) self.enocean.start() # sender will be automatically determined self.enocean_sender = None def __del__(self): if self.enocean is not None and self.enocean.is_alive(): self.enocean.stop() def _on_connect(self, mqtt_client, userdata, flags, rc): '''callback for when the client receives a CONNACK response from the MQTT server.''' if rc == 0: logging.info("Succesfully connected to MQTT broker.") # listen to enocean send requests for cur_sensor in self.sensors: mqtt_client.subscribe(cur_sensor['name']+'/req/#') else: logging.error("Error connecting to MQTT broker: %s", self.CONNECTION_RETURN_CODE[rc]) def _on_disconnect(self, mqtt_client, userdata, rc): '''callback for when the client disconnects from the MQTT server.''' if rc == 0: logging.warning("Successfully disconnected from MQTT broker") else: logging.warning("Unexpectedly disconnected from MQTT broker: "+str(rc)) def _on_mqtt_message(self, mqtt_client, userdata, msg): '''the callback for when a PUBLISH message is received from the MQTT server.''' # search for sensor for cur_sensor in self.sensors: if cur_sensor['name'] in msg.topic: # store data for this sensor if 'data' not in cur_sensor: cur_sensor['data'] = {} prop = msg.topic[len(cur_sensor['name']+"/req/"):] try: cur_sensor['data'][prop] = int(msg.payload) except ValueError: logging.warning("Cannot parse int value for %s: %s", msg.topic, msg.payload) def _on_mqtt_publish(self, mqtt_client, userdata, mid): '''the callback for when a PUBLISH message is successfully sent to the MQTT server.''' #logging.debug("Published MQTT message "+str(mid)) pass def _read_packet(self, packet): '''interpret packet, read properties and publish to MQTT''' # loop through all configured devices for cur_sensor in self.sensors: # does this sensor match? if enocean.utils.combine_hex(packet.sender) == cur_sensor['address']: # found sensor configured in config file if 'publish_rssi' in cur_sensor and cur_sensor['publish_rssi']: self.mqtt.publish(cur_sensor['name']+"/RSSI", packet.dBm) if not packet.learn or ('log_learn' in cur_sensor and cur_sensor['log_learn']): # data packet received found_property = False if packet.packet_type == PACKET.RADIO and packet.rorg == cur_sensor['rorg']: # radio packet of proper rorg type received; parse EEP direction = cur_sensor['direction'] if 'direction' in cur_sensor else None properties = packet.parse_eep(cur_sensor['func'], cur_sensor['type'], direction) # loop through all EEP properties for prop_name in properties: found_property = True cur_prop = packet.parsed[prop_name] # we only extract numeric values, either the scaled ones or the raw values for enums if isinstance(cur_prop['value'], numbers.Number): value = cur_prop['value'] else: value = cur_prop['raw_value'] # publish extracted information logging.debug("{}: {} ({})={} {}".format(cur_sensor['name'], prop_name, cur_prop['description'], cur_prop['value'], cur_prop['unit'])) retain = 'persistent' in cur_sensor and cur_sensor['persistent'] self.mqtt.publish(cur_sensor['name']+"/"+prop_name, value, retain=retain) break if not found_property: logging.warn('message not interpretable: {}'.format(found_sensor['name'])) else: # learn request received logging.info("learn request not emitted to mqtt") def _reply_packet(self, in_packet, sensor): '''send enocean message as a reply to an incoming message''' # prepare addresses destination = in_packet.sender # prepare packet if 'direction' in sensor: # we invert the direction in this reply direction = 1 if sensor['direction'] == 2 else 2 else: direction = None packet = RadioPacket.create(RORG.BS4, sensor['func'], sensor['type'], direction=direction, sender=self.enocean_sender, destination=destination, learn=in_packet.learn) # assemble data based on packet type (learn / data) if not in_packet.learn: # data packet received # start with default data packet.data[1:5] = [ (sensor['default_data'] >> i & 0xff) for i in (24,16,8,0) ] # do we have specific data to send? if 'data' in sensor: # override with specific data settings packet.set_eep(sensor['data']) else: # what to do if we have no data to send yet? logging.warn('sending default data as answer to %s', sensor['name']) else: # learn request received # copy EEP and manufacturer ID packet.data[1:5] = in_packet.data[1:5] # update flags to acknowledge learn request packet.data[4] = 0xf0 # send it logging.info('sending: {}'.format(packet)) self.enocean.send(packet) def _process_radio_packet(self, packet): # first, look whether we have this sensor configured found_sensor = False for cur_sensor in self.sensors: if enocean.utils.combine_hex(packet.sender) == cur_sensor['address']: found_sensor = cur_sensor # skip ignored sensors if found_sensor and 'ignore' in found_sensor and found_sensor['ignore']: return # log packet, if not disabled if int(self.conf['log_packets']): logging.info('received: {}'.format(packet)) # abort loop if sensor not found if not found_sensor: logging.info('unknown sensor: {}'.format(enocean.utils.to_hex_string(packet.sender))) return # interpret packet, read properties and publish to MQTT self._read_packet(packet) # check for neccessary reply if 'answer' in found_sensor and found_sensor['answer']: self._reply_packet(packet, found_sensor) def run(self): # start endless loop for listening while self.enocean.is_alive(): # Request transmitter ID, if needed if self.enocean_sender is None: self.enocean_sender = self.enocean.base_id # Loop to empty the queue... try: # get next packet packet = self.enocean.receive.get(block=True, timeout=1) # check packet type if packet.packet_type == PACKET.RADIO: self._process_radio_packet(packet) elif packet.packet_type == PACKET.RESPONSE: response_code = RETURN_CODE(packet.data[0]) logging.info("got response packet: {}".format(response_code.name)) else: logging.info("got non-RF packet: {}".format(packet)) continue except queue.Empty: continue
class EnOceanDongle: """Representation of an EnOcean dongle.""" def __init__(self, hass, ser): """Initialize the EnOcean dongle.""" from enocean.communicators.serialcommunicator import SerialCommunicator self.__communicator = SerialCommunicator(port=ser, callback=self.callback) self.__communicator.start() self.__devices = [] def register_device(self, dev): """Register another device.""" self.__devices.append(dev) def send_command(self, command): """Send a command from 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): """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)