class BasePlugin: mqttClient = None def CS_2_DZ_decoder(self, topic, message): success = 0 Domoticz.Debug("CS_Decoder") EUI = str(topic.split("device/")[1].split("/")[0]) Domoticz.Debug("EUI : " + EUI) ############ ## Devices payload = json.loads(message) Domoticz.Debug("Payload:\n" + str(payload)) if not 'loRaSNR' in str(payload): Domoticz.Log( "Decoding LoRa message problem. Check ChirpStack application.") return success RSSI = payload['rxInfo'][0]['loRaSNR'] RSSI = int(round(mapFromTo(int(RSSI), -20, 0, 0, 10), 0)) #Domoticz : between 0 and 10 Domoticz.Debug("RSSI : " + str(RSSI)) CS_objects = json.loads(payload['objectJSON']) if (len(CS_objects) == 0): Domoticz.Log( "Decoding cayenne message problem. Check ChirpStack application." ) return success #Domoticz.Debug(str(CS_objects))#{'temperatureSensor': {'1': 12}, 'humiditySensor': {'1': 80}} #Reorganize data data = [] for obj in CS_objects: if (str(obj) in CS_cayenne_to_DZ): for channel in CS_objects[str(obj)]: #Get the value of the sensor value = str(CS_objects[str(obj)][str(channel)]) #build DATA : [Channel, value, [Corresp.DZ_TypeName, Corresp.DZ_pType,DZ_sType, Corresp.FancyName, Corresp.UNIT_ID] ] data.append([channel, value, CS_cayenne_to_DZ[str(obj)]]) else: Domoticz.Log("Unfound/Unproccessable Cayenne Data Type : " + str(obj)) Domoticz.Debug("DATA structure:" + str(data)) #[['1', '12', ['Temperature', 243, 17, 'temp']], ['2', '14', ['Temperature', 243, 17, 'temp']], ['3', '15', ['Temperature', 243, 17, 'temp']], ['1', '80', ['Humidity', 243, 3, 'hum']]] # #aggregate several sensor types into one sensor. Decide whi one is nvalue, which one is svalue # # TODO data_ag = data #Devices ID d_ids = [] d_units = [] for x in Devices: d_ids.append([ str(x), str(Devices[x].ID), str(Devices[x].Name), str(Devices[x].DeviceID) ]) d_units.append(int(x)) Domoticz.Debug(str(d_ids)) Domoticz.Debug(str(d_units)) #Device for d in range(0, len(data_ag)): # Case there is Type_Name assigned if data_ag[d][2][0] != "": #Shape the values device_fancyname = str(data_ag[d][2][3]) device_id = "eui-" + EUI + "-" + str( data_ag[d] [0]) + "-" + device_fancyname #eui-a8d4fdf51239f322-1-hum device_Name = "Unknown " + device_fancyname device_TypeName = str(data_ag[d][2][0]) Domoticz.Debug("===================") Domoticz.Debug("device_id: " + str(device_id)) #If not exist, create if (device_id not in str(d_ids)): #Find a new unit ID device_Unit = 0 for u in range(1, 255): if u not in d_units: device_Unit = u d_units.append(u) break if device_Unit == 0: Domoticz.Log( "ERROR - No more UNIT ID to allocate. Device not created" ) return 0 Domoticz.Debug("device_Name: " + str(device_Name)) Domoticz.Debug("device_TypeName: " + str(device_TypeName)) if self.create_new_devices == "True": Domoticz.Log( "ChirpStack Plugin - Create NEW device with ID=" + str(device_id) + ", Name=" + str(device_Name) + ", Type=" + str(device_TypeName)) #Create Domoticz.Device(Name=device_Name, TypeName=device_TypeName, Unit=device_Unit, DeviceID=device_id).Create() else: Domoticz.Log( "ChirpStack Plugin - DISBALED [Create device " + str(device_id) + "]") for x in Devices: #Check if now exists, and update if (str(Devices[x].DeviceID) == device_id): device_svalue = str(data_ag[d][1]) #Update Domoticz.Log("Chirpstack Plugin - Update device (ID=" + str(Devices[x].ID) + ") value =" + data_ag[d][1]) Devices[x].Update(nValue=int(device_svalue), sValue=str(device_svalue), SignalLevel=RSSI) Domoticz.Debug("===================") return success def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) DumpConfigToLog() Domoticz.Log("Chirpstack2Domoticz Plugin started") #App ID Base TOPIC if (Parameters["Mode1"].strip() != ""): self.base_topic = "application/" + Parameters["Mode1"].strip() else: Domoticz.Log( "Warning : No Application ID submitted. It will subscribe to all application topics" ) self.base_topic = "application" self.subscribed_for_devices = False self.create_new_devices = Parameters["Mode2"].strip() mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.api = API(Devices, self.publishToMqtt) def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") #self.uninstall() def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) message = None device = Devices[ Unit] #Devices is Domoticz collection of devices for this hardware device_params = device.DeviceID.split('_') entity_id = device_params[0] Domoticz.Debug("OnCommand --> Partie desctivee") # if (self.devices_manager.get_device_by_id(entity_id) != None): # message = self.devices_manager.handle_command(Devices, device, Command, Level, Color) # elif(self.groups_manager.get_group_by_deviceid(device.DeviceID) != None): # message = self.groups_manager.handle_command(device, Command, Level, Color) # else: # Domoticz.Log('Can\'t process command from device "' + device.Name + '"') # if (message != None): # self.publishToMqtt(message['topic'], message['payload']) def publishToMqtt(self, topic, payload): self.mqttClient.publish(self.base_topic + '/' + topic, payload) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onDeviceModified(self, unit): if (unit == 255): self.api.handle_request(Devices[unit].sValue) return def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): #if connected subscirbe to topic self.mqttClient.subscribe([self.base_topic + "/#"]) Domoticz.Log("MQTT subscribed to : " + self.base_topic + "/#") def onMQTTDisconnected(self): self.subscribed_for_devices = False def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("On MQTT Publish") payload = json.dumps(message) Domoticz.Debug("MQTT message: " + topic + " " + str(payload)) topic = topic.replace(self.base_topic + '/', '') #self.api.handle_mqtt_message(topic, message) #Decode the pyaload and message. --> Will automatically add sensors self.CS_2_DZ_decoder(topic, payload)
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) Domoticz.Debug("onStart called") self.base_topic = Parameters["Mode1"].strip() self.pairing_enabled = True if Parameters["Mode2"] == 'true' else False self.subscribed_for_devices = False mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.available_devices = DeviceStorage.getInstance() def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") def handlePairingMode(self): permit_join = 'true' if self.pairing_enabled else 'false' self.mqttClient.publish(self.base_topic + '/bridge/config/permit_join', permit_join) def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) device = Devices[ Unit] #Devices is Domoticz collection of devices for this hardware device_params = device.DeviceID.split('_') device_id = device_params[0] alias = device_params[1] device_data = self.available_devices.get_device_by_id(device_id) if (device_data == None): Domoticz.Log('Device ' + device.Name + ' does not have registered zigbee2mqtt device') return model = device_data['model'] if (model in adapter_by_model): adapter = adapter_by_model[model](Devices) message = adapter.handleCommand(alias, device, device_data, Command, Level, Color) if (message != None): self.mqttClient.publish( self.base_topic + '/' + message['topic'], message['payload']) else: Domoticz.Log('Device ' + device.Name + ' does not have adapter (model: "' + model + '"') def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): self.mqttClient.subscribe([self.base_topic + '/bridge/#']) def onMQTTDisconnected(self): self.subscribed_for_devices = False def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT message: " + topic + " " + str(message)) if (topic == self.base_topic + '/bridge/config/permit_join' or topic == self.base_topic + '/bridge/config/devices'): return if (topic == self.base_topic + '/bridge/config'): permit_join = 'enabled' if message['permit_join'] else 'disabled' Domoticz.Debug('Zigbee2mqtt log level is ' + message['log_level']) Domoticz.Log('Joining new devices is ' + permit_join + ' on the zigbee bridge') return if (topic == self.base_topic + '/bridge/state'): Domoticz.Log('Zigbee2mqtt bridge is ' + message) if message == 'online': self.mqttClient.publish( self.base_topic + '/bridge/config/devices', '') self.handlePairingMode() return if (topic == self.base_topic + '/bridge/log'): if message['type'] == 'devices': Domoticz.Log('Received available devices list from bridge') self.available_devices.clear() self.available_devices.update(Devices, message['message']) if self.subscribed_for_devices == False: self.mqttClient.subscribe([self.base_topic + '/+']) self.subscribed_for_devices = True if message['type'] == 'device_connected' or message[ 'type'] == 'device_removed': self.mqttClient.publish( self.base_topic + '/bridge/config/devices', '') return device_name = topic.replace(self.base_topic + "/", "") device_data = self.available_devices.get_device_by_name(device_name) if (device_data != None): model = device_data['model'] if (model in adapter_by_model): zigbee_message = ZigbeeMessage(message) adapter = adapter_by_model[model](Devices) adapter.handleMqttMessage(device_data, zigbee_message) else: Domoticz.Debug('Unsupported zigbee device type with model "' + model + '"') else: Domoticz.Debug('Unhandled message from zigbee2mqtt: ' + topic + ' ' + str(message))
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) Domoticz.Debug("onStart called") self.install() self.base_topic = Parameters["Mode1"].strip() self.subscribed_for_devices = False mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.api = API(Devices, self.publishToMqtt) self.devices_manager = DevicesManager() self.groups_manager = GroupsManager() def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") self.uninstall() def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) message = None device = Devices[ Unit] #Devices is Domoticz collection of devices for this hardware device_params = device.DeviceID.split('_') entity_id = device_params[0] if (self.devices_manager.get_device_by_id(entity_id) != None): message = self.devices_manager.handle_command( Devices, device, Command, Level, Color) elif (self.groups_manager.get_group_by_deviceid(device.DeviceID) != None): message = self.groups_manager.handle_command( device, Command, Level, Color) else: Domoticz.Log('Can\'t process command from device "' + device.Name + '"') if (message != None): self.publishToMqtt(message['topic'], message['payload']) def publishToMqtt(self, topic, payload): self.mqttClient.publish(self.base_topic + '/' + topic, payload) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onDeviceModified(self, unit): if (unit == 255): self.api.handle_request(Devices[unit].sValue) return def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): self.mqttClient.subscribe([self.base_topic + '/bridge/#']) def onMQTTDisconnected(self): self.subscribed_for_devices = False def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT message: " + topic + " " + str(message)) topic = topic.replace(self.base_topic + '/', '') self.api.handle_mqtt_message(topic, message) if (topic == 'bridge/config/permit_join' or topic == 'bridge/config/devices'): return if (topic == 'bridge/config'): permit_join = 'enabled' if message['permit_join'] else 'disabled' Domoticz.Debug('Zigbee2mqtt log level is ' + message['log_level']) Domoticz.Log('Joining new devices is ' + permit_join + ' on the zigbee bridge') return if (topic == 'bridge/state'): Domoticz.Log('Zigbee2mqtt bridge is ' + message) if message == 'online': self.publishToMqtt('bridge/config/devices', '') self.publishToMqtt('bridge/config/groups', '') return if (topic == 'bridge/log'): if message['type'] == 'devices': Domoticz.Log('Received available devices list from bridge') self.devices_manager.clear() self.devices_manager.update(Devices, message['message']) if self.subscribed_for_devices == False: self.mqttClient.subscribe([self.base_topic + '/+']) self.subscribed_for_devices = True if message['type'] == 'groups': Domoticz.Log('Received groups list from bridge') self.groups_manager.register_groups(Devices, message['message']) if message['type'] == 'device_connected' or message[ 'type'] == 'device_removed': self.publishToMqtt('bridge/config/devices', '') if message['type'] == 'ota_update': Domoticz.Log(message['message']) return if (self.devices_manager.get_device_by_name(topic) != None): self.devices_manager.handle_mqtt_message(Devices, topic, message) elif (self.groups_manager.get_group_by_name(topic) != None): self.groups_manager.handle_mqtt_message(topic, message) def install(self): Domoticz.Log('Installing plugin custom page...') try: source_path = os.path.dirname( os.path.abspath(__file__)) + '/frontend' templates_path = os.path.abspath(source_path + '/../../../www/templates') dst_plugin_path = templates_path + '/zigbee2mqtt' Domoticz.Debug('Copying files from ' + source_path + ' to ' + templates_path) if not (os.path.isdir(dst_plugin_path)): os.makedirs(dst_plugin_path) copy2(source_path + '/zigbee2mqtt.html', templates_path) copy2(source_path + '/zigbee2mqtt.js', templates_path) copy2(source_path + '/zigbee_devices.js', dst_plugin_path) copy2(source_path + '/zigbee_groups.js', dst_plugin_path) copy2(source_path + '/libs/leaflet.js', dst_plugin_path) copy2(source_path + '/libs/leaflet.css', dst_plugin_path) copy2(source_path + '/libs/viz.js', dst_plugin_path) copy2(source_path + '/libs/viz.full.render.js', dst_plugin_path) Domoticz.Log('Installing plugin custom page completed.') except Exception as e: Domoticz.Error('Error during installing plugin custom page') Domoticz.Error(repr(e)) def uninstall(self): Domoticz.Log('Uninstalling plugin custom page...') try: templates_path = os.path.abspath( os.path.dirname(os.path.abspath(__file__)) + '/../../www/templates') dst_plugin_path = templates_path + '/zigbee2mqtt' Domoticz.Debug('Removing files from ' + templates_path) if (os.path.isdir(dst_plugin_path)): rmtree(dst_plugin_path) if os.path.exists(templates_path + "/zigbee2mqtt.html"): os.remove(templates_path + "/zigbee2mqtt.html") if os.path.exists(templates_path + "/zigbee2mqtt.js"): os.remove(templates_path + "/zigbee2mqtt.js") Domoticz.Log('Uninstalling plugin custom page completed.') except Exception as e: Domoticz.Error('Error during uninstalling plugin custom page') Domoticz.Error(repr(e))
class BasePlugin: enabled = False mqttConn = None counter = 0 def __init__(self): return def onStart(self): if Parameters["Mode6"] == "Debug": Domoticz.Debugging(1) DumpConfigToLog() self.devices = {} Parameters["Username"] = "******" Parameters["Port"] = "8884" Parameters["Protocol"] = "MQTTS" mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, "NHCDomoticz", self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Hue): for uuid, device in self.devices.items(): if device.getUnit() == Unit: device.handleCommand(Command, Level, Hue) #MQTT forwards.. def onConnect(self, Connection, Status, Description): self.mqttClient.onConnect(Connection, Status, Description) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onHeartbeat(self): self.mqttClient.onHeartbeat() # MQTT stuff def onMQTTConnected(self): self.mqttClient.subscribe(['hobby/control/devices/rsp']) self.mqttClient.subscribe(['hobby/control/devices/evt']) self.mqttClient.subscribe(['hobby/control/devices/err']) # fetch all devices self.mqttClient.publish('hobby/control/devices/cmd', '{"Method": "devices.list"}') def onMQTTDisconnected(self): Domoticz.Log("onMQTT disconnected") def onMQTTSubscribed(self): Domoticz.Log("onMQTTSubscribed") def onMQTTPublish(self, topic, message): if topic == "hobby/control/devices/rsp": if message["Params"]: nhcDeviceIDs = [] if message["Params"][0]["Devices"]: for device in message["Params"][0]["Devices"]: if device["Type"] == "action": uuid = device["Uuid"] self.devices[uuid] = Device( Devices, device, self.mqttClient) self.devices[uuid].handleMessage(topic, device) if topic == "hobby/control/devices/evt": if message["Method"] == "devices.status": if message["Params"]: if message["Params"][0]["Devices"]: for device in message["Params"][0]["Devices"]: uuid = device["Uuid"] if uuid in self.devices: self.devices[uuid].handleMessage(topic, device) if topic == "hobby/control/devices/err": Domoticz.Log("Err")
class Plugin: mqttClient = None tasmotaHandler = None def __init__(self): return def onStart(self): if errmsg == "": try: Domoticz.Heartbeat(10) self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) global pluginDebug pluginDebug = False setTasmotaDebug(True) setMqttDebug(False) Debug("Plugin::onStart: Parameters: {}".format( repr(Parameters))) self.mqttserveraddress = Parameters["Address"].strip() self.mqttserverport = Parameters["Port"].strip() self.mqttClient = MqttClient( self.mqttserveraddress, self.mqttserverport, Parameters["Mode5"], self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.mqttClient.debug(False) self.tasmotaHandler = Handler( Parameters["Mode4"].strip().split('|'), Parameters["Mode1"].strip(), Parameters["Mode2"].strip(), Parameters["Mode3"].strip(), self.mqttClient, Devices) self.tasmotaHandler.debug(True) except Exception as e: Domoticz.Error("Plugin::onStart: {}".format(str(e))) self.mqttClient = None else: Domoticz.Error( "Plugin::onStart: Domoticz Python env error {}".format(errmsg)) self.mqttClient = None def debug(self, flag): global pluginDebug pluginDebug = flag def checkDevices(self): Debug("Plugin::checkDevices") # Let tasmotaHandler react to commands from Domoticz def onCommand(self, Unit, Command, Level, Color): if self.mqttClient is None: return False return self.tasmotaHandler.onDomoticzCommand(Unit, Command, Level, Color) def onConnect(self, Connection, Status, Description): Debug("Plugin::onConnect") if self.mqttClient is not None: self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): if self.mqttClient is not None: self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): if self.mqttClient is not None: self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): Debug("Plugin::onHeartbeat") if self.mqttClient is not None: try: # Reconnect if connection has dropped if (self.mqttClient._connection is None) or (not self.mqttClient.isConnected): Debug("Plugin::onHeartbeat: Reconnecting") self.mqttClient._open() else: self.mqttClient.ping() except Exception as e: Domoticz.Error("Plugin::onHeartbeat error {}".format(str(e))) # Let tasmotaHandler subscribe its topics def onMQTTConnected(self): if self.mqttClient is not None: self.tasmotaHandler.onMQTTConnected() def onMQTTDisconnected(self): Debug("Plugin::onMQTTDisconnected") def onMQTTSubscribed(self): Debug("Plugin::onMQTTSubscribed") # Let tasmotaHandler process incoming MQTT messages def onMQTTPublish(self, topic, message): return self.tasmotaHandler.onMQTTPublish(topic, message)
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2+4+8+16+64) if self.debugging == "Debug": Domoticz.Debugging(2) Domoticz.Debug("onStart called") self.install() self.base_topic = Parameters["Mode1"].strip() mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.api = API(Devices, self.onApiCommand) self.devices_manager = DevicesManager() self.groups_manager = GroupsManager() def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") self.uninstall() def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) message = None device = Devices[Unit] #Devices is Domoticz collection of devices for this hardware device_params = device.DeviceID.split('_') entity_id = device_params[0] if (self.devices_manager.get_device_by_id(entity_id) != None): message = self.devices_manager.handle_command(device, Command, Level, Color) elif(self.groups_manager.get_group_by_deviceid(device.DeviceID) != None): message = self.groups_manager.handle_command(device, Command, Level, Color) else: Domoticz.Log('Can\'t process command from device "' + device.Name + '"') if (message != None): self.publishToMqtt(message['topic'], message['payload']) def onApiCommand(self, command, data): if command == 'publish_mqtt': return self.publishToMqtt(data['topic'], data['payload']) elif command == 'remove_device': return self.devices_manager.remove(data) else: Domoticz.Error('Internal API command "' + command +'" is not supported by plugin') def publishToMqtt(self, topic, payload): self.mqttClient.publish(self.base_topic + '/' + topic, payload) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onDeviceModified(self, unit): if (unit == 255): self.api.handle_request(Devices[unit].sValue) return def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): self.mqttClient.subscribe([self.base_topic + '/#']) def onMQTTDisconnected(self): Domoticz.Debug('Disconnected from MQTT server') def onMQTTSubscribed(self): Domoticz.Debug('Subscribed to "' + self.base_topic + '/#" topic') def onMQTTPublish(self, topic, message): # Domoticz.Debug("MQTT message: " + topic + " " + str(message)) topic = topic.replace(self.base_topic + '/', '') self.api.handle_mqtt_message(topic, message) if (topic == 'bridge/config/permit_join'): return if (topic == 'bridge/config/logging'): # TODO: Add log feature return if (topic == 'bridge/devices'): Domoticz.Log('Received available devices list from bridge') self.devices_manager.set_devices(message) return if (topic == 'bridge/config'): permit_join = 'enabled' if message['permit_join'] else 'disabled' Domoticz.Debug('Zigbee2mqtt log level is ' + message['log_level']) Domoticz.Log('Joining new devices is ' + permit_join + ' on the zigbee bridge') return if (topic == 'bridge/state'): Domoticz.Log('Zigbee2mqtt bridge is ' + message) if message == 'online': # self.publishToMqtt('bridge/config/devices', '') self.publishToMqtt('bridge/config/groups', '') return if (topic == 'bridge/log'): is_connected = message['type'] == 'device_connected' is_removed = message['type'] == 'device_removed' is_paired = message['type'] == 'pairing' and message['message'] == 'interview_successful' if message['type'] == 'groups': Domoticz.Log('Received groups list from bridge') self.groups_manager.register_groups(message['message']) if is_connected or is_removed or is_paired: self.publishToMqtt('bridge/config/devices/get', '') if message['type'] == 'ota_update': Domoticz.Log(message['message']) if message['type'] == 'zigbee_publish_error': #an error occured on publish to the zigbee network deviceMeta = message['meta'] Domoticz.Error("A Zigbee publish error occured for device '" + deviceMeta['friendly_name'] + "' with error message: " + message['message']) return if (self.devices_manager.get_device_by_name(topic) != None): self.devices_manager.handle_mqtt_message(topic, message) elif (self.groups_manager.get_group_by_name(topic) != None): self.groups_manager.handle_mqtt_message(topic, message) def install(self): Domoticz.Log('Installing plugin custom page...') try: source_path = Parameters['HomeFolder'] + 'frontend' templates_path = Parameters['StartupFolder'] + 'www/templates' dst_plugin_path = templates_path + '/zigbee2mqtt' Domoticz.Debug('Copying files from ' + source_path + ' to ' + templates_path) if not (os.path.isdir(dst_plugin_path)): os.makedirs(dst_plugin_path) copy2(source_path + '/zigbee2mqtt.html', templates_path) copy2(source_path + '/zigbee2mqtt.js', templates_path) copy2(source_path + '/zigbee_devices.js', dst_plugin_path) copy2(source_path + '/zigbee_groups.js', dst_plugin_path) copy2(source_path + '/libs/leaflet.js', dst_plugin_path) copy2(source_path + '/libs/leaflet.css', dst_plugin_path) copy2(source_path + '/libs/viz.js', dst_plugin_path) copy2(source_path + '/libs/viz.full.render.js', dst_plugin_path) Domoticz.Log('Installing plugin custom page completed.') except Exception as e: Domoticz.Error('Error during installing plugin custom page') Domoticz.Error(repr(e)) def uninstall(self): Domoticz.Log('Uninstalling plugin custom page...') try: templates_path = Parameters['StartupFolder'] + 'www/templates' dst_plugin_path = templates_path + '/zigbee2mqtt' Domoticz.Debug('Removing files from ' + templates_path) if (os.path.isdir(dst_plugin_path)): rmtree(dst_plugin_path) if os.path.exists(templates_path + "/zigbee2mqtt.html"): os.remove(templates_path + "/zigbee2mqtt.html") if os.path.exists(templates_path + "/zigbee2mqtt.js"): os.remove(templates_path + "/zigbee2mqtt.js") Domoticz.Log('Uninstalling plugin custom page completed.') except Exception as e: Domoticz.Error('Error during uninstalling plugin custom page') Domoticz.Error(repr(e))
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose+": Domoticz.Debugging(2+4+8+16+64) if self.debugging == "Verbose": Domoticz.Debugging(2+4+8+16+64) if self.debugging == "Debug": Domoticz.Debugging(2+4+8) self.devices_manager = DevicesManager() self.devices_manager.set_devices(Devices) device_topic = Parameters["Mode1"].strip() if (Parameters["Mode2"] == "Dimmer"): self.controller = Dimmer(self.devices_manager, device_topic) elif (Parameters["Mode2"] == "PwmDimmer"): self.controller = PwmDimmer(self.devices_manager, device_topic) elif (Parameters["Mode2"] == "RGB"): self.controller = ColorDimmer(self.devices_manager, device_topic, 3) elif (Parameters["Mode2"] == "RGBW"): self.controller = ColorDimmer(self.devices_manager, device_topic, 4) elif (Parameters["Mode2"] == "RGBWW"): self.controller = ColorDimmer(self.devices_manager, device_topic, 5) self.controller.checkDevices() self.topics = list(["stat/" + device_topic + "/RESULT", "tele/" + device_topic + "/STATE"]) mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) def checkDevices(self): Domoticz.Log("checkDevices called") def onStop(self): Domoticz.Log("onStop called") def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("Command: " + Command + " (" + str(Level) + ") Color:" + Color) self.controller.onCommand(self.mqttClient, Unit, Command, Level, Color) def onConnect(self, Connection, Status, Description): self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): Domoticz.Debug("onMQTTConnected") self.mqttClient.subscribe(self.topics) def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT message: " + topic + " " + str(message)) if (topic in self.topics): self.controller.onMqttMessage(topic, message)
class EwpeSmartOverMqttPlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) self.devices = {} self.base_topic = Parameters["Mode1"].strip() mqttserver_address = Parameters["Address"].strip() mqttserver_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqttserver_address, mqttserver_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) Domoticz.Debug("onStart called") def onMQTTConnected(self): self.mqttClient.subscribe([self.base_topic + '/#']) self.mqttClient.publish(self.base_topic + '/devices/list', '') def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT message: " + topic + " " + str(message)) if topic == self.base_topic + '/devices': Domoticz.Log('Received available devices list') self.devices = {} for item in message: mac = item['mac'] Domoticz.Log('Device ' + item['name'].strip() + ' (MAC: ' + mac + ')') self.devices[mac] = Device(Devices, self.base_topic, item) else: for mac, device in self.devices.items(): if topic.startswith(self.base_topic + '/' + mac): Domoticz.Debug(self.base_topic + '/' + mac) device.handle_message(topic, message) def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) [mac, alias] = Devices[Unit].DeviceID.split('_') if mac in self.devices: state = self.devices[mac].handle_command(alias, Command, Level, Color) topic = '/'.join([self.base_topic, mac, 'set']) self.mqttClient.publish(topic, json.dumps(state)) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat()
class DysonPureLinkPlugin: #define class variables enabled = False mqttClient = None #unit numbers for devices to create #for Pure Cool models fanModeUnit = 1 nightModeUnit = 2 fanSpeedUnit = 3 fanOscillationUnit = 4 standbyMonitoringUnit = 5 filterLifeUnit = 6 qualityTargetUnit = 7 tempHumUnit = 8 volatileUnit = 9 particlesUnit = 10 sleepTimeUnit = 11 fanStateUnit = 12 fanFocusUnit = 13 fanModeAutoUnit = 14 particles2_5Unit = 15 particles10Unit = 16 nitrogenDioxideDensityUnit = 17 runCounter = 6 def __init__(self): self.myDevice = None self.password = None self.ip_address = None self.port_number = None self.sensor_data = None self.state_data = None self.mqttClient = None def onStart(self): Domoticz.Log("onStart called") if Parameters['Mode4'] == 'Debug': Domoticz.Debugging(2) DumpConfigToLog() if Parameters['Mode4'] == 'Verbose': Domoticz.Debugging(1 + 2 + 4 + 8 + 16 + 64) DumpConfigToLog() #PureLink needs polling, get from config Domoticz.Heartbeat(10) #check, per device, if it is created. If not,create it Options = { "LevelActions": "|||", "LevelNames": "|OFF|ON|AUTO", "LevelOffHidden": "true", "SelectorStyle": "1" } if self.fanModeUnit not in Devices: Domoticz.Device(Name='Fan mode', Unit=self.fanModeUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() Options = { "LevelActions": "||", "LevelNames": "|OFF|ON", "LevelOffHidden": "true", "SelectorStyle": "1" } if self.fanStateUnit not in Devices: Domoticz.Device(Name='Fan state', Unit=self.fanStateUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.nightModeUnit not in Devices: Domoticz.Device(Name='Night mode', Unit=self.nightModeUnit, Type=244, Subtype=62, Switchtype=0, Image=9).Create() Options = { "LevelActions": "|||||||||||", "LevelNames": "|1|2|3|4|5|6|7|8|9|10|Auto", "LevelOffHidden": "false", "SelectorStyle": "1" } if self.fanSpeedUnit not in Devices: Domoticz.Device(Name='Fan speed', Unit=self.fanSpeedUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.fanOscillationUnit not in Devices: Domoticz.Device(Name='Oscilation mode', Unit=self.fanOscillationUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.standbyMonitoringUnit not in Devices: Domoticz.Device(Name='Standby monitor', Unit=self.standbyMonitoringUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.filterLifeUnit not in Devices: Domoticz.Device(Name='Remaining filter life', Unit=self.filterLifeUnit, TypeName="Custom").Create() if self.tempHumUnit not in Devices: Domoticz.Device(Name='Temperature and Humidity', Unit=self.tempHumUnit, TypeName="Temp+Hum").Create() if self.volatileUnit not in Devices: Domoticz.Device(Name='Volatile organic', Unit=self.volatileUnit, TypeName="Air Quality").Create() if self.sleepTimeUnit not in Devices: Domoticz.Device(Name='Sleep timer', Unit=self.sleepTimeUnit, TypeName="Custom").Create() if self.particlesUnit not in Devices: Domoticz.Device(Name='Dust', Unit=self.particlesUnit, TypeName="Air Quality").Create() if self.qualityTargetUnit not in Devices: Options = { "LevelActions": "||", "LevelNames": "|Normal|Sensitive (Medium)|Very Sensitive (High)", "LevelOffHidden": "true", "SelectorStyle": "1" } Domoticz.Device(Name='Air quality setpoint', Unit=self.qualityTargetUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.particles2_5Unit not in Devices: Domoticz.Device(Name='Dust (PM 2,5)', Unit=self.particles2_5Unit, TypeName="Air Quality").Create() if self.particles10Unit not in Devices: Domoticz.Device(Name='Dust (PM 10)', Unit=self.particles10Unit, TypeName="Air Quality").Create() Options = { "LevelActions": "|||", "LevelNames": "|OFF|ON", "LevelOffHidden": "true", "SelectorStyle": "1" } if self.fanModeAutoUnit not in Devices: Domoticz.Device(Name='Fan mode auto', Unit=self.fanModeAutoUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() Options = { "LevelActions": "|||", "LevelNames": "|OFF|ON", "LevelOffHidden": "true", "SelectorStyle": "1" } if self.fanFocusUnit not in Devices: Domoticz.Device(Name='Fan focus mode', Unit=self.fanFocusUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.nitrogenDioxideDensityUnit not in Devices: Domoticz.Device(Name='Nitrogen Dioxide Density (NOx)', Unit=self.nitrogenDioxideDensityUnit, TypeName="Air Quality").Create() #read out parameters for local connection self.ip_address = Parameters["Address"].strip() self.port_number = Parameters["Port"].strip() self.password = self._hashed_password(Parameters['Password']) mqtt_client_id = "" self.runCounter = int(Parameters['Mode2']) #create a Dyson account Domoticz.Debug("=== start making connection to Dyson account ===") dysonAccount = DysonAccount(Parameters['Mode5'], Parameters['Mode3'], "NL") dysonAccount.login() #deviceList = () deviceList = [] deviceList = dysonAccount.devices() if deviceList == None or len(deviceList) < 1: Domoticz.Log("No devices found in Dyson cloud account") else: Domoticz.Debug("Number of devices from cloud: '" + str(len(deviceList)) + "'") if deviceList != None and len(deviceList) > 0: if len(Parameters['Mode6']) > 0: if Parameters['Mode6'] in deviceList: self.myDevice = deviceList[Parameters['Mode6']] else: Domoticz.Error( "The configured device name '" + Parameters['Mode6'] + "' was not found in the cloud account. Available options: " + str(list(deviceList))) return elif len(deviceList) == 1: self.myDevice = deviceList[list(deviceList)[0]] Domoticz.Log( "1 device found in cloud, none configured, assuming we need this one: '" + self.myDevice.name + "'") else: Domoticz.Error( "More than 1 device found in cloud account but no device name given to select" ) return Domoticz.Debug("local device pwd: '" + self.password + "'") Domoticz.Debug("cloud device pwd: '" + self.myDevice.password + "'") Parameters[ 'Username'] = self.myDevice.serial #take username from account Parameters[ 'Password'] = self.myDevice.password #override the default password with the one returned from the cloud elif len(Parameters['Username']) > 0: Domoticz.Log( "No cloud devices found, the local credentials will be used") #create a Dyson device object using plugin parameters Domoticz.Debug("local device pwd: '" + self.password + "'") Domoticz.Debug("local device usn: '" + Parameters['Username'] + "'") Parameters['Password'] = self.password self.myDevice = DysonPureLinkDevice(Parameters['Password'], Parameters['Username'], Parameters['Mode1']) else: Domoticz.Error("No usable credentials found") Domoticz.Log("Device instance created: " + str(self.myDevice)) self.base_topic = self.myDevice.device_base_topic Domoticz.Debug("base topic defined: '" + self.base_topic + "'") #create the connection if self.myDevice != None: self.mqttClient = MqttClient(self.ip_address, self.port_number, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Hue): Domoticz.Debug("DysonPureLink plugin: onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level)) topic = '' payload = '' if Unit == self.qualityTargetUnit and Level <= 100: topic, payload = self.myDevice.set_quality_target(Level) if Unit == self.fanSpeedUnit and Level <= 100: arg = "0000" + str(Level // 10) topic, payload = self.myDevice.set_fan_speed( arg[-4:]) #use last 4 characters as speed level or AUTO if Unit == self.fanModeUnit or (Unit == self.fanSpeedUnit and Level > 100): if Level == 10: arg = "OFF" if Level == 20: arg = "FAN" if Level >= 30: arg = "AUTO" topic, payload = self.myDevice.set_fan_mode(arg) if Unit == self.fanStateUnit: if Level == 10: arg = "OFF" if Level == 20: arg = "ON" topic, payload = self.myDevice.set_fan_state(arg) if Unit == self.fanOscillationUnit: topic, payload = self.myDevice.set_oscilation(str(Command).upper()) if Unit == self.fanFocusUnit: topic, payload = self.myDevice.set_focus(str(Command).upper()) if Unit == self.fanModeAutoUnit: topic, payload = self.myDevice.set_fan_mode_auto( str(Command).upper()) if Unit == self.standbyMonitoringUnit: topic, payload = self.myDevice.set_standby_monitoring( str(Command).upper()) if Unit == self.nightModeUnit: topic, payload = self.myDevice.set_night_mode(str(Command).upper()) self.mqttClient.Publish(topic, payload) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called: Connection '" + str(Connection) + "', Status: '" + str(Status) + "', Description: '" + Description + "'") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile): Domoticz.Log("DysonPureLink plugin: onNotification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile) def onHeartbeat(self): if self.myDevice != None: self.mqttClient.onHeartbeat() self.runCounter = self.runCounter - 1 if self.runCounter <= 0: Domoticz.Debug("DysonPureLink plugin: Poll unit") self.runCounter = int(Parameters['Mode2']) topic, payload = self.myDevice.request_state() self.mqttClient.Publish( topic, payload) #ask for update of current status else: Domoticz.Debug("Polling unit in " + str(self.runCounter) + " heartbeats.") def onDeviceRemoved(self, unit): Domoticz.Log( "DysonPureLink plugin: onDeviceRemoved called for unit '" + str(unit) + "'") def updateDevices(self): """Update the defined devices from incoming mesage info""" #update the devices UpdateDevice(self.fanOscillationUnit, self.state_data.oscillation.state, str(self.state_data.oscillation)) UpdateDevice(self.nightModeUnit, self.state_data.night_mode.state, str(self.state_data.night_mode)) # Fan speed f_rate = self.state_data.fan_speed if (f_rate == "AUTO"): sValueNew = "110" # Auto else: sValueNew = str(int(f_rate) * 10) UpdateDevice(self.fanSpeedUnit, 1, sValueNew) UpdateDevice(self.fanModeUnit, self.state_data.fan_mode.state, str((self.state_data.fan_mode.state + 1) * 10)) UpdateDevice(self.fanStateUnit, self.state_data.fan_state.state, str((self.state_data.fan_state.state + 1) * 10)) UpdateDevice(self.filterLifeUnit, self.state_data.filter_life, str(self.state_data.filter_life)) UpdateDevice(self.qualityTargetUnit, self.state_data.quality_target.state, str((self.state_data.quality_target.state + 1) * 10)) UpdateDevice(self.standbyMonitoringUnit, self.state_data.standby_monitoring.state, str((self.state_data.standby_monitoring.state + 1) * 10)) if self.state_data.fan_mode_auto is not None: UpdateDevice(self.fanModeAutoUnit, self.state_data.fan_mode_auto.state, str((self.state_data.fan_mode_auto.state + 1) * 10)) if self.state_data.focus is not None: UpdateDevice(self.fanFocusUnit, self.state_data.focus.state, str(self.state_data.focus)) def updateSensors(self): """Update the defined devices from incoming mesage info""" #update the devices if self.sensor_data.temperature is not None: tempNum = int(self.sensor_data.temperature) humNum = int(self.sensor_data.humidity) UpdateDevice( self.tempHumUnit, 1, str(self.sensor_data.temperature)[:4] + ';' + str(self.sensor_data.humidity) + ";1") UpdateDevice(self.volatileUnit, self.sensor_data.volatile_compounds, str(self.sensor_data.volatile_compounds)) if self.sensor_data.particles is not None: UpdateDevice(self.particlesUnit, self.sensor_data.particles, str(self.sensor_data.particles)) if self.sensor_data.particles2_5 is not None: UpdateDevice(self.particles2_5Unit, self.sensor_data.particles2_5, str(self.sensor_data.particles2_5)) if self.sensor_data.particles10 is not None: UpdateDevice(self.particles10Unit, self.sensor_data.particles10, str(self.sensor_data.particles10)) if self.sensor_data.nitrogenDioxideDensity is not None: UpdateDevice(self.nitrogenDioxideDensityUnit, self.sensor_data.nitrogenDioxideDensity, str(self.sensor_data.nitrogenDioxideDensity)) UpdateDevice(self.sleepTimeUnit, self.sensor_data.sleep_timer, str(self.sensor_data.sleep_timer)) Domoticz.Debug("update SensorData: " + str(self.sensor_data)) Domoticz.Debug("update StateData: " + str(self.state_data)) def onMQTTConnected(self): """connection to device established""" Domoticz.Debug("onMQTTConnected called") Domoticz.Log("MQTT connection established") self.mqttClient.Subscribe([self.base_topic + '/#' ]) #subscribe to all topics on the machine topic, payload = self.myDevice.request_state() self.mqttClient.Publish(topic, payload) #ask for update of current status def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT Publish: MQTT message incoming: " + topic + " " + str(message)) if (topic == self.base_topic + '/status/current'): #update of the machine's status if StateData.is_state_data(message): Domoticz.Debug("machine state or state change recieved") self.state_data = StateData(message) self.updateDevices() if SensorsData.is_sensors_data(message): Domoticz.Debug("sensor state recieved") self.sensor_data = SensorsData(message) self.updateSensors() if (topic == self.base_topic + '/status/connection'): #connection status received Domoticz.Debug("connection state recieved") if (topic == self.base_topic + '/status/software'): #connection status received Domoticz.Debug("software state recieved") if (topic == self.base_topic + '/status/summary'): #connection status received Domoticz.Debug("summary state recieved") def _hashed_password(self, pwd): """Hash password (found in manual) to a base64 encoded of its sha512 value""" hash = hashlib.sha512() hash.update(pwd.encode('utf-8')) return base64.b64encode(hash.digest()).decode('utf-8')
class BasePlugin: HEARTBEAT_SEC = 10 def __init__(self): self.mqttClient = None self.myroomba = None self.state = None self.batpct = None self.execute = None self.MqttUpdatereceived = False self.lastMqttUpdate = datetime.now() return def onStart(self): # Debugging On/Off self.debug = _DEBUG_ON if Parameters["Mode6"] == "Debug" else _DEBUG_OFF Domoticz.Debugging(self.debug) # Create images if necessary if _IMAGE_ROOMBA not in Images: Domoticz.Image("Roomba.zip").Create() # Create devices (USED BY DEFAULT) CreateDevicesUsed() TimeoutDevice(All=True) # Create devices (NOT USED BY DEFAULT) CreateDevicesNotUsed() # Global settings DumpConfigToLog() # Start MQTT try: self.mqttClient = MqttClient('localhost', '1883', self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) except Exception as e: Domoticz.Error("MQTT client start error: " + str(e)) self.mqttClient = None def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Color): # react to commands arrived from Domoticz Domoticz.Debug("Command: " + Command + " (" + str(Level) + ") Color:" + Color) if Unit == _UNIT_RUNNING: if Command == 'On': if self.state == 'Charging': self.mqttClient.Publish(_COMMANDS, 'start') else: self.mqttClient.Publish(_COMMANDS, 'dock') else: self.mqttClient.Publish(_COMMANDS, 'stop') self.execute = _DOCK def onConnect(self, Connection, Status, Description): Domoticz.Debug("Connection: " + str(Status)) if self.mqttClient is not None: self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): if self.mqttClient is not None: self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): if self.mqttClient is not None: self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): Domoticz.Debug("Heartbeating...") if self.mqttClient is not None: try: # Reconnect if connection has dropped if self.mqttClient.mqttConn is None or ( not self.mqttClient.mqttConn.Connecting() and not self.mqttClient.mqttConn.Connected() or not self.mqttClient.isConnected): Domoticz.Debug("Reconnecting") self.mqttClient.Open() else: self.mqttClient.Ping() # Commands to Roomba if self.execute == _DOCK: if self.state == 'Stopped': self.mqttClient.Publish(_COMMANDS, 'dock') if self.state == 'Charging': self.execute = None except Exception as e: Domoticz.Error("onHeartbeat: " + str(e)) # Update devices if self.MqttUpdatereceived: if self.state: UpdateDevice(_UNIT_STATE, 0, self.state, Images[_IMAGE_ROOMBA].ID) if self.state == 'Running': UpdateDevice(_UNIT_RUNNING, 1, 1, Images[_IMAGE_ROOMBA].ID) else: UpdateDevice(_UNIT_RUNNING, 0, 0, Images[_IMAGE_ROOMBA].ID) if self.batpct: UpdateDeviceBatSig(_UNIT_RUNNING, self.batpct) UpdateDevice(_UNIT_BAT, self.batpct, self.batpct, Images[_IMAGE_ROOMBA].ID) self.MqttUpdatereceived = False # Check if getting information from MQTT Broker if (datetime.now() - self.lastMqttUpdate).total_seconds() > int( Parameters["Mode5"]) * 60: TimeoutDevice(All=True) def onMQTTConnected(self): Domoticz.Debug("onMQTTConnected") if self.mqttClient is not None: self.mqttClient.Subscribe([_STATE, _BATPCT]) def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): # process incoming MQTT statuses message = message.decode('utf-8') Domoticz.Debug("MQTT message: " + topic + " " + message) if topic == _STATE: self.state = message self.lastMqttUpdate = datetime.now() self.MqttUpdatereceived = True if topic == _BATPCT: self.batpct = int(message) self.lastMqttUpdate = datetime.now() self.MqttUpdatereceived = True
class BasePlugin: mqttClient = None def __init__(self): return def onStart(self): global errmsg self.devnames = [] self.devtimes = [] if errmsg == "": try: Domoticz.Heartbeat(10) self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) self.base_topic = Parameters["Mode1"] self.learnmode = Parameters["Mode2"] self.mqttserveraddress = Parameters["Address"].strip() self.mqttserverport = Parameters["Port"].strip() self.mqttClient = MqttClient(self.mqttserveraddress, self.mqttserverport, "", self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) except Exception as e: Domoticz.Error("MQTT client start error: " + str(e)) self.mqttClient = None else: Domoticz.Error( "Your Domoticz Python environment is not functional! " + errmsg) self.mqttClient = None def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Color): # react to commands arrived from Domoticz if self.mqttClient is None: return False Domoticz.Debug("Command: " + Command + " (" + str(Level) + ") Color:" + Color) if Command in ["On", "Off"]: if Command == "On": Devices[Unit].Update(nValue=1, sValue=str(Command)) else: Devices[Unit].Update(nValue=0, sValue=str(Command)) def onConnect(self, Connection, Status, Description): if self.mqttClient is not None: self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): if self.mqttClient is not None: self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): if self.mqttClient is not None: try: self.mqttClient.onMessage(Connection, Data) except: pass def onHeartbeat(self): Domoticz.Debug("Heartbeating...") if self.mqttClient is not None: try: # Reconnect if connection has dropped if (self.mqttClient._connection is None) or (not self.mqttClient.isConnected): Domoticz.Debug("Reconnecting") self.mqttClient._open() else: self.mqttClient.ping() except Exception as e: Domoticz.Error(str(e)) def onMQTTConnected(self): if self.mqttClient is not None: if self.base_topic and self.base_topic != "#": topic = self.base_topic + '/#' else: topic = "rtl_433/#" # if "events" not in topic: # topic += "/events" self.mqttClient.subscribe([topic]) def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): # process incoming MQTT statuses try: topic = str(topic) message2 = str(message) except: Domoticz.Debug("MQTT message is not a valid string!" ) #if message is not a real string, drop it return False mqttpath = topic.split('/') if "/events" in topic: Domoticz.Debug("MQTT message: " + topic + " " + str(message2)) data = "" if 'rows' in message: # raw data in events - check for Flex encoder output! th = [] for row in message['rows']: try: if int(row['len']) > 4 and str( row['data']).strip() != "": th.append(str(row['data'])) except: pass mf = 0 for i in th: cf = th.count(i) if cf > mf: data = i mf = cf model = "" ch = "" st = "" if 'model' in message: # model name in events model = str(message['model']).replace("-", "_") if 'channel' in message: ch = str(message['channel']) if 'subtype' in message: st = str(message['subtype']) if st == "": if 'unit' in message: st = str(message['unit']) if ch == "" and st == "": if 'id' in message: st = str( message['id'] ) # use id only for last resort, as cheap weather stations generates new id on every restart devname = self.createdevname(model, st, ch, data, "") Domoticz.Debug(devname) if 'time' in message: devtime = str(message['time']) else: devtime = str(time.time()) if devname not in self.devnames: self.devnames.append(devname) self.devtimes.append(devtime) else: didx = self.devnames.index(devname) if didx > 0 and didx < len(self.devtimes): if self.devtimes[ didx] == devtime: # filter duplicated messages return False # Domoticz.Debug(devtime) signal = 12 if "rssi" in message: try: rssi = float(message["rssi"]) except: rssi = 0 if rssi > -0.134: signal = 10 elif rssi <= -7: signal = 0 else: signal = 10 - (rssi * -1.34) try: Domoticz.Debug( str(message["rssi"]) + " " + str(message["snr"]) + " " + str(message["noise"])) except: pass battery = 255 if "battery" in message: if (str(message["battery"]).lower() == "low") or (str( message["battery"]) == "0"): battery = 10 elif (str(message["battery"]).lower() == "ok") or (str( message["battery"]) == "100"): battery = 100 if "battery_ok" in message: if (str(message["battery_ok"]) == "0"): battery = 10 elif (str(message["battery_ok"]) == "1"): battery = 100 state = None # check if is it a binary sensor if "state" in message or "command" in message: state = False if "state" in message: state = (message["state"] == "ON") if "command" in message: state = (message["command"] == "On") elif data != "": if data[:16] == "ffffffffffffffff": # false positive return False state = True if state is not None: self.SendSwitch(devname, state, battery, signal) return True tempc = None if "temperature_C" in message: tempc = message['temperature_C'] elif "temperature_F" in message: tempc = str((float(message['temperature_F']) - 32) * 5.0 / 9.0) try: tempc = float(tempc) except: tempc = None if tempc < -40 or tempc > 80: tempc = None return False # out of range - false positive humi = None if "humidity" in message: if message["humidity"] == "HH": humi = 90 elif message["humidity"] == "LL": humi = 10 else: try: humi = float(message['humidity']) except: humi = None if humi < 0 or humi > 100: humi = None pressure = None if "pressure_hPa" in message: pressure = message['pressure'] if (tempc is not None) and (humi is not None) and (pressure is not None): self.SendTempHumBaroSensor(devname, tempc, humi, pressure, battery, signal) elif (tempc is not None) and (humi is not None): self.SendTempHumSensor(devname, tempc, humi, battery, signal) elif (tempc is not None): self.SendTempSensor(devname, tempc, battery, signal) elif (humi is not None): self.SendHumSensor(devname, humi, battery, signal) rain = None if "rain" in message: rain = message['rain'] elif "rain_mm" in message: rain = message['rain_mm'] elif "rainfall_mm" in message: rain = message['rainfall_mm'] raintotal = None if "rain_total" in message: raintotal = message['rain_total'] if rain is not None: self.SendRainSensor(devname, rain, raintotal, battery, signal) depth = None if "depth_cm" in message: depth = message['depth_cm'] elif "depth" in message: depth = message['depth'] if depth is not None: self.SendDistanceSensor(devname, depth, battery, signal) windstr = None if "windstrength" in message: windstr = message['windstrength'] elif "wind_speed" in message: windstr = message['wind_speed'] elif "average" in message: windstr = message['average'] elif "wind_avg_km_h" in message: windstr = message['wind_avg_km_h'] elif "wind_avg_m_s" in message: windstr = message['wind_avg_m_s'] winddir = None if "winddirection" in message: winddir = message['winddirection'] elif "wind_direction" in message: winddir = message['wind_direction'] elif "direction" in message: winddir = message['direction'] winddirdeg = 0 if "wind_dir_deg" in message: winddirdeg = message['wind_dir_deg'] windgust = None if "wind_gust" in message: windgust = message['wind_gust'] elif "gust" in message: windgust = message['gust'] if winddir is not None: self.SendWind(devname, winddirdeg, winddir, windstr, windgust, tempc, battery, signal) moisture = None if "moisture" in message: moisture = message['moisture'] if (moisture is not None): self.SendMoisture(devname, moisture, battery, signal) power = None if "power_W" in message: power = message['power_W'] if (power is not None): self.SendWattMeter(devname, watt, battery, signal) def getdevID(self, unitname): iUnit = -1 for Device in Devices: try: if (Devices[Device].DeviceID.strip() == unitname): iUnit = Device break except: pass return iUnit def SendSwitch(self, unitname, state, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Switch", Used=0, DeviceID=unitname).Create() except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: try: if state == False or (str(state).strip().lower() in ["0", "off"]): scmd = "Off" ncmd = 0 else: scmd = "On" ncmd = 1 if battery is None: battery = 255 Devices[iUnit].Update(nValue=ncmd, sValue=scmd, BatteryLevel=int(battery), SignalLevel=int(rssi)) except Exception as e: Domoticz.Debug(str(e)) return False def SendTempHumBaroSensor(self, unitname, temp, hum, press, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, Type=84, Subtype=16, Used=0, DeviceID=unitname).Create() # Temp+Hum+Baro except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(temp) + ";" + str(hum) + ";" + str( self.gethumstatus(hum)) + ";" + str(press) + ";0" try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendTempHumSensor(self, unitname, temp, hum, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Temp+Hum", Used=0, DeviceID=unitname).Create() # Temp+Hum except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(temp) + ";" + str(hum) + ";" + str( self.gethumstatus(hum)) try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendTempSensor(self, unitname, temp, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Temperature", Used=0, DeviceID=unitname).Create() # Temp except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(temp) try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendHumSensor(self, unitname, hum, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Humidity", Used=0, DeviceID=unitname).Create() # Hum except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(hum) try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendRainSensor(self, unitname, rain, raintotal, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Rain", Used=0, DeviceID=unitname).Create() # Rain except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: if raintotal is None: try: curval = Devices[iUnit].sValue prevdata = curval.split(";") except: prevdata = [] if len(prevdata) < 2: prevdata.append(0) prevdata.append(0) raintotal = prevdata[1] + rain sval = str(int(float(rain) * 100)) + ";" + str(raintotal) try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendDistanceSensor(self, unitname, dist, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Distance", Used=0, DeviceID=unitname).Create() # Distance except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(dist) try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendWind(self, unitname, winddirdeg, winddir, windstr, windgust, tempc, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Wind", Used=0, DeviceID=unitname).Create() # Wind except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(winddirdeg) if winddir is not None: sval += ";" + str(winddir) else: sval += ";" ts = ";" try: ts = ";" + str(float(windstr) * 10) except: ts = ";" sval += ts ts = ";" try: ts = ";" + str(float(windgust) * 10) except: ts = ";" sval += ts if tempc is not None: sval += ";" + str(tempc) else: sval += ";;" try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendMoisture(self, unitname, moist, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Soil Moisture", Used=0, DeviceID=unitname).Create() # Moisture except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: sval = str(moist) try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def SendWattMeter(self, unitname, watt, battery, rssi): iUnit = self.getdevID(unitname) if iUnit < 0 and self.learnmode != False: # if device does not exists in Domoticz, than create it try: iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, Type=243, Subtype=29, Used=0, DeviceID=unitname).Create() # kWh except Exception as e: Domoticz.Debug(str(e)) return False if iUnit > 0: try: sval = str(float(watt) / 1000) + ";0" except: sval = "0;0" try: if battery is None: battery = 255 Devices[iUnit].Update(nValue=0, sValue=str(sval), BatteryLevel=int(battery), SignalLevel=int(rssi)) except: Domoticz.Debug(str(e)) def gethumstatus(self, mval): hstat = 0 if int(mval) >= 50 and int(mval) <= 70: hstat = 1 elif int(mval) < 40: hstat = 2 elif int(mval) > 70: hstat = 3 return hstat def createdevname(self, m, s, c, d, t): tn = "" if s: tn += s if c: tn += c if d: tn += "-" + d[:16] if t: tn += "-" + t[:16] lplen = 25 - len(tn) if lplen == 0: return tn elif lplen < 0: return tn[:25] else: if tn[0] != "-": tn = "-" + tn tn = m[:(25 - len(tn) - 1)] + tn return tn
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) self.install() self.base_topic = Parameters["Mode1"].strip() mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.api = API(self.onApiCommand) self.devices_manager = DevicesManager() self.groups_manager = GroupsManager() def checkDevices(self): domoticz.debug("checkDevices called") def onStop(self): domoticz.debug("onStop called") self.uninstall() def onCommand(self, device_id, unit, command, Level, Color): domoticz.debug("[Command] Device " + device_id + '(' + str(unit) + '): ' + command + "(level = " + str(Level) + ", color = " + Color + ')') message = None domoticz_device = domoticz.get_device(device_id, unit) zigbee_device_alias = configuration.get_zigbee_feature_data( device_id, unit) if zigbee_device_alias == None: domoticz.log('Can\'t process command from device "' + domoticz_device.Name + '"') if self.groups_manager.get_group_by_id( zigbee_device_alias['zigbee']['address']) != None: message = self.groups_manager.handle_command( device_id, unit, command, Level, Color) else: message = self.devices_manager.handle_command( device_id, unit, command, Level, Color) if (message != None): self.publishToMqtt(message['topic'], message['payload']) def onApiCommand(self, command, data): if command == 'publish_mqtt': return self.publishToMqtt(data['topic'], data['payload']) elif command == 'remove_device': return self.devices_manager.remove(data) else: domoticz.error('Internal API command "' + command + '" is not supported by plugin') def publishToMqtt(self, topic, payload): self.mqttClient.publish(self.base_topic + '/' + topic, payload) def onConnect(self, Connection, Status, Description): domoticz.debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onDeviceModified(self, device_id, unit): if device_id == 'api_transport' and unit == 255: device = domoticz.get_device(device_id, unit) self.api.handle_request(device.sValue) return def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): self.mqttClient.subscribe([self.base_topic + '/#']) def onMQTTDisconnected(self): domoticz.debug('Disconnected from MQTT server') def onMQTTSubscribed(self): domoticz.debug('Subscribed to "' + self.base_topic + '/#" topic') def onMQTTPublish(self, topic, message): # domoticz.debug("MQTT message: " + topic + " " + str(message)) topic = topic.replace(self.base_topic + '/', '') self.api.handle_mqtt_message(topic, message) bridge.handle_mqtt_message(topic, message) if (topic == 'bridge/config/permit_join'): return if (topic == 'bridge/config/logging') or (topic == 'bridge/logging'): # TODO: Add log feature return if (topic == 'bridge/devices'): self.devices_manager.set_devices(message) return if (topic == 'bridge/config'): permit_join = 'enabled' if message['permit_join'] else 'disabled' domoticz.debug('Zigbee2mqtt log level is ' + message['log_level']) domoticz.log('Joining new devices is ' + permit_join + ' on the zigbee bridge') return if (topic == 'bridge/state'): domoticz.log('Zigbee2mqtt bridge is ' + message) return if (topic == 'bridge/log'): is_connected = message['type'] == 'device_connected' is_removed = message['type'] == 'device_removed' is_paired = message['type'] == 'pairing' and message[ 'message'] == 'interview_successful' if message['type'] == 'groups': domoticz.log('Received groups list from bridge') self.groups_manager.register_groups(message['message']) if is_connected or is_removed or is_paired: self.publishToMqtt('bridge/config/devices/get', '') if message['type'] == 'ota_update': domoticz.log(message['message']) if (message['type'] == 'device_renamed'): domoticz.debug("Device renamed from '{0}' to '{1}'".format( message['message']['from'], message['message']['to'])) if (self.devices_manager.get_device_by_name( message['message']['from']) != None): domoticz.debug("attempt to rename on bridge/log") toRename = self.devices_manager.get_device_by_name( message['message']['from']) toRename.zigbee_device['friendly_name'] = message[ 'message']['to'] self.devices_manager.devices[ toRename.zigbee_device['ieee_address']] = toRename else: domoticz.debug("attempt to rename failed on bridge/log") if message['type'] == 'zigbee_publish_error': #an error occured on publish to the zigbee network deviceMeta = message['meta'] domoticz.error("A Zigbee publish error occured for device '" + deviceMeta['friendly_name'] + "' with error message: " + message['message']) return if (self.groups_manager.get_group_by_name(topic) != None): self.groups_manager.handle_mqtt_message(topic, message) elif (self.devices_manager.get_device_by_name(topic) != None): self.devices_manager.handle_mqtt_message(topic, message) def install(self): domoticz.log('Installing plugin custom page...') try: source_path = Parameters['HomeFolder'] + 'frontend' templates_path = Parameters['StartupFolder'] + 'www/templates' dst_plugin_path = templates_path + '/zigbee2mqtt' domoticz.debug('Copying files from ' + source_path + ' to ' + templates_path) if not (os.path.isdir(dst_plugin_path)): os.makedirs(dst_plugin_path) copy2(source_path + '/zigbee2mqtt.html', templates_path) copy2(source_path + '/zigbee2mqtt.js', templates_path) copy2(source_path + '/plugin_config.js', dst_plugin_path) copy2(source_path + '/zigbee_devices.js', dst_plugin_path) copy2(source_path + '/zigbee_groups.js', dst_plugin_path) copy2(source_path + '/libs/leaflet.js', dst_plugin_path) copy2(source_path + '/libs/leaflet.css', dst_plugin_path) copy2(source_path + '/libs/viz.js', dst_plugin_path) copy2(source_path + '/libs/viz.full.render.js', dst_plugin_path) copy2(source_path + '/libs/ace_json_mode.js', dst_plugin_path) copy2(source_path + '/libs/ace_worker_json.js', dst_plugin_path) domoticz.log('Installing plugin custom page completed.') except Exception as e: domoticz.error('Error during installing plugin custom page') domoticz.error(repr(e)) def uninstall(self): domoticz.log('Uninstalling plugin custom page...') try: templates_path = Parameters['StartupFolder'] + 'www/templates' dst_plugin_path = templates_path + '/zigbee2mqtt' domoticz.debug('Removing files from ' + templates_path) if (os.path.isdir(dst_plugin_path)): rmtree(dst_plugin_path) if os.path.exists(templates_path + "/zigbee2mqtt.html"): os.remove(templates_path + "/zigbee2mqtt.html") if os.path.exists(templates_path + "/zigbee2mqtt.js"): os.remove(templates_path + "/zigbee2mqtt.js") domoticz.log('Uninstalling plugin custom page completed.') except Exception as e: domoticz.error('Error during uninstalling plugin custom page') domoticz.error(repr(e))
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) self.base_topic = "shellies" # hardwired self.mqttserveraddress = Parameters["Address"].strip() self.mqttserverport = Parameters["Port"].strip() self.mqttClient = MqttClient(self.mqttserveraddress, self.mqttserverport, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Color): # react to commands arrived from Domoticz Domoticz.Debug("Command: " + Command + " (" + str(Level) + ") Color:" + Color) device = Devices[Unit] device_id = device.DeviceID.split('-') relnum = -1 try: relnum = int(device_id[2].strip()) except: relnum = -1 if relnum in range( 0, 4) and len(device_id) == 3: # check if is it a normal relay mqttpath = self.base_topic + "/" + device_id[0] + "-" + device_id[ 1] + "/relay/" + device_id[2] + "/command" cmd = Command.strip().lower() Domoticz.Debug(mqttpath + " " + cmd) if cmd in ["on", "off"]: # commands are simply on or off self.mqttClient.Publish(mqttpath, cmd) if cmd == "off": device.Update( Level, Command) # force device update if it is offline # otherwise check if it is a roller shutter elif relnum in range( 0, 4) and len(device_id) == 4 and device_id[len(device_id) - 1] == "roller": cmd = Command.strip().lower() scmd = "" # Translate Domoticz command to Shelly command if cmd == "stop": scmd = "stop" elif cmd == "on": scmd = "open" elif cmd == "off": scmd = "close" if scmd != "": mqttpath = self.base_topic + "/" + device_id[ 0] + "-" + device_id[1] + "/roller/" + device_id[ 2] + "/command" self.mqttClient.Publish(mqttpath, scmd) # experimental support for v1.4 Percentage poisitioning elif relnum in range( 0, 4) and len(device_id) == 4 and device_id[len(device_id) - 1] == "pos": cmnd = str(Command).strip().lower() pos = str(Level).strip().lower() if ((cmnd == "set level") or (cmnd == "off" and pos != "50" and pos != "100")): # percentage requested mqttpath = self.base_topic + "/" + device_id[ 0] + "-" + device_id[1] + "/roller/" + device_id[ 2] + "/command/pos" Domoticz.Debug(mqttpath + " " + str(Command) + " " + str(Level)) self.mqttClient.Publish(mqttpath, pos) else: # command arrived scmd = "" # Translate Domoticz command to Shelly command if cmnd == "on": scmd = "open" elif cmnd == "off": scmd = "close" if scmd != "": mqttpath = self.base_topic + "/" + device_id[ 0] + "-" + device_id[1] + "/roller/" + device_id[ 2] + "/command" self.mqttClient.Publish(mqttpath, scmd) def onConnect(self, Connection, Status, Description): self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): Domoticz.Debug("Heartbeating...") # Reconnect if connection has dropped if self.mqttClient.mqttConn is None or ( not self.mqttClient.mqttConn.Connecting() and not self.mqttClient.mqttConn.Connected() or not self.mqttClient.isConnected): Domoticz.Debug("Reconnecting") self.mqttClient.Open() else: self.mqttClient.Ping() def onMQTTConnected(self): self.mqttClient.Subscribe([self.base_topic + '/#']) def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): # process incoming MQTT statuses if "/announce" in topic: # announce did not contain any information for us return False try: topic = str(topic) message = str(message) except: Domoticz.Debug("MQTT message is not a valid string!" ) #if message is not a real string, drop it return False Domoticz.Debug("MQTT message: " + topic + " " + str(message)) mqttpath = topic.split('/') if (mqttpath[0] == self.base_topic): # RELAY type, not command->process if (len(mqttpath) > 3) and (mqttpath[2] == "relay") and ("/command" not in topic): unitname = mqttpath[1] + "-" + mqttpath[3] unitname = unitname.strip() devtype = 1 try: funcid = int(mqttpath[3].strip()) devtype = 0 except: devtype = 1 if len(mqttpath) == 5 and devtype == 0: devtype = 2 subval = "" if devtype == 1: subval = mqttpath[3].strip() elif devtype == 2: subval = mqttpath[4].strip() if subval == "power" or subval == "energy": unitname = mqttpath[1] + "-energy" iUnit = -1 for Device in Devices: try: if (Devices[Device].DeviceID.strip() == unitname): iUnit = Device break except: pass if iUnit < 0: # if device does not exists in Domoticz, than create it iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 if devtype == 0: Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Switch", Used=1, DeviceID=unitname).Create() else: if subval == "energy" or subval == "power": Domoticz.Device(Name=unitname, Unit=iUnit, Type=243, Subtype=29, Used=1, DeviceID=unitname).Create() if devtype == 0: scmd = str(message).strip().lower() if (str(Devices[iUnit].sValue).lower() != scmd): if (scmd == "on"): # set device status if needed Devices[iUnit].Update(1, "On") else: Devices[iUnit].Update(0, "Off") else: curval = Devices[iUnit].sValue try: prevdata = curval.split(";") except: prevdata = [] if len(prevdata) < 2: prevdata.append(0) prevdata.append(0) try: mval = float(str(message).strip()) except: mval = str(message).strip() sval = "" if subval == "power": sval = str(mval) + ";" + str(prevdata[1]) elif subval == "energy": try: mval2 = (mval / 100) # 10*Wh? except: mval2 = str(mval) sval = str(prevdata[0]) + ";" + str(mval2) Devices[iUnit].Update(0, sval) return True # ROLLER type, not command->process elif (len(mqttpath) > 3) and (mqttpath[2] == "roller") and ("/command" not in topic): if mqttpath[len(mqttpath) - 1] == "pos": unitname = mqttpath[1] + "-" + mqttpath[3] + "-pos" else: unitname = mqttpath[1] + "-" + mqttpath[3] + "-roller" unitname = unitname.strip() iUnit = -1 for Device in Devices: try: if (Devices[Device].DeviceID.strip() == unitname): iUnit = Device break except: pass if iUnit < 0: # if device does not exists in Domoticz, than create it iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 if "-pos" in unitname: Domoticz.Device(Name=unitname, Unit=iUnit, Type=244, Subtype=62, Switchtype=13, Used=1, DeviceID=unitname).Create( ) # create Blinds Percentage else: Domoticz.Device(Name=unitname, Unit=iUnit, Type=244, Subtype=62, Switchtype=15, Used=1, DeviceID=unitname).Create( ) # create Venetian Blinds EU type if "-pos" in unitname: try: pval = str(message).strip() nval = 0 if int(pval) > 0 and int(pval) < 100: nval = 2 if int(pval) > 99: nval = 1 Devices[iUnit].Update(nval, pval) except: Domoticz.Debug("MQTT message error " + str(topic) + ":" + str(message)) else: bcmd = str(message).strip().lower() if bcmd == "stop" and str( Devices[iUnit].sValue).lower() != "stop": Devices[iUnit].Update(17, "Stop") # stop return True elif bcmd == "open" and str( Devices[iUnit].sValue).lower() != "off": Devices[iUnit].Update(0, "Off") # open return True elif bcmd == "close" and str( Devices[iUnit].sValue).lower() != "on": Devices[iUnit].Update(1, "On") # close return True # INPUT type, not command->process elif (len(mqttpath) > 3) and (mqttpath[2] == "input") and ( mqttpath[len(mqttpath) - 1] != "command"): unitname = mqttpath[1] + "-" + mqttpath[3] + "-input" unitname = unitname.strip() iUnit = -1 for Device in Devices: try: if (Devices[Device].DeviceID.strip() == unitname): iUnit = Device break except: pass if iUnit < 0: # if device does not exists in Domoticz, than create it iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device(Name=unitname, Unit=iUnit, TypeName="Switch", Used=1, DeviceID=unitname).Create() if str(message).lower == "on" or str(message) == "1": scmd = "on" else: scmd = "off" if (str(Devices[iUnit].sValue).lower() != scmd): if (scmd == "on"): # set device status if needed Devices[iUnit].Update(1, "On") else: Devices[iUnit].Update(0, "Off") # SENSOR type, not command->process elif (len(mqttpath) > 3) and (mqttpath[2] == "sensor") and ( mqttpath[3] in ['temperature', 'humidity', 'battery' ]) and (("shellysense" in mqttpath[1]) or ("shellyht" in mqttpath[1])): unitname = mqttpath[1] + "-sensor" unitname = unitname.strip() iUnit = -1 for Device in Devices: try: if (Devices[Device].DeviceID.strip() == unitname): iUnit = Device break except: pass if iUnit < 0: # if device does not exists in Domoticz, than create it iUnit = 0 for x in range(1, 256): if x not in Devices: iUnit = x break if iUnit == 0: iUnit = len(Devices) + 1 Domoticz.Device( Name=unitname, Unit=iUnit, TypeName="Temp+Hum", Used=1, DeviceID=unitname).Create() # create Temp+Hum Type=82 stype = mqttpath[3].strip().lower() curval = Devices[iUnit].sValue try: mval = float(message) except: mval = str(message).strip() if stype == "battery": Devices[iUnit].Update(0, curval, BatteryLevel=int(mval)) elif stype == "temperature": try: env = curval.split(";") except: env = [0, 0] if len(env) < 3: env.append(0) env.append(0) env.append(0) sval = str(mval) + ";" + str(env[1]) + ";" + str(env[2]) Devices[iUnit].Update(0, sval) elif stype == "humidity": hstat = 0 try: env = curval.split(";") except: env = [0, 0] if len(env) < 1: env.append(0) if int(mval) >= 50 and int(mval) <= 70: hstat = 1 elif int(mval) < 40: hstat = 2 elif int(mval) > 70: hstat = 3 sval = str(env[0]) + ";" + str(mval) + ";" + str(hstat) Devices[iUnit].Update(0, sval)
class DysonPureLinkPlugin: #define class variables #plugin version version = "4.0.3" enabled = False mqttClient = None #unit numbers for devices to create #for Pure Cool models fanModeUnit = 1 nightModeUnit = 2 fanSpeedUnit = 3 fanOscillationUnit = 4 standbyMonitoringUnit = 5 filterLifeUnit = 6 qualityTargetUnit = 7 tempHumUnit = 8 volatileUnit = 9 particlesUnit = 10 sleepTimeUnit = 11 fanStateUnit = 12 fanFocusUnit = 13 fanModeAutoUnit = 14 particles2_5Unit = 15 particles10Unit = 16 nitrogenDioxideDensityUnit = 17 heatModeUnit = 18 heatTargetUnit = 19 heatStateUnit = 20 particlesMatter25Unit = 21 particlesMatter10Unit = 22 resetFilterLifeUnit = 23 deviceStatusUnit = 24 runCounter = 6 def __init__(self): self.myDevice = None self.password = None self.ip_address = None self.port_number = None self.sensor_data = None self.state_data = None self.mqttClient = None self.log_level = None def onStart(self): Domoticz.Debug("onStart called") #read out parameters for local connection self.ip_address = Parameters["Address"].strip() self.port_number = Parameters["Port"].strip() self.otp_code = Parameters['Mode1'] self.runCounter = int(Parameters['Mode2']) self.log_level = Parameters['Mode4'] self.account_password = Parameters['Mode3'] self.account_email = Parameters['Mode5'] self.machine_name = Parameters['Mode6'] if self.log_level == 'Debug': Domoticz.Debugging(2) DumpConfigToLog() if self.log_level == 'Verbose': Domoticz.Debugging(1 + 2 + 4 + 8 + 16 + 64) DumpConfigToLog() if self.log_level == 'Reset': Domoticz.Log( "Plugin config will be erased to retreive new cloud account data" ) Config = {} Config = Domoticz.Configuration(Config) #PureLink needs polling, get from config Domoticz.Heartbeat(10) self.checkVersion(self.version) mqtt_client_id = "" #create a Dyson account deviceList = self.get_device_names() if deviceList != None and len(deviceList) > 0: Domoticz.Debug( "Number of devices found in plugin configuration: '" + str(len(deviceList)) + "'") else: Domoticz.Log( "No devices found in plugin configuration, request from Dyson cloud account" ) #new authentication Domoticz.Debug( "=== start making connection to Dyson account, new method as of 2021 ===" ) dysonAccount2 = DysonAccount() challenge_id = getConfigItem(Key="challenge_id", Default="") setConfigItem(Key="challenge_id", Value="") #clear after use if challenge_id == "": #request otp code via email when no code entered challenge_id = dysonAccount2.login_email_otp( self.account_email, "NL") setConfigItem(Key="challenge_id", Value=challenge_id) Domoticz.Log( '==== An OTP verification code had been requested, please check email and paste code into plugin=====' ) return else: #verify the received code if len(self.otp_code) < 6: Domoticz.Error("invalid verification code supplied") return dysonAccount2.verify(self.otp_code, self.account_email, self.account_password, challenge_id) setConfigItem( Key="challenge_id", Value="") #reset challenge id as it is no longer valid Parameters['Mode1'] = "0" #reset the stored otp code #get list of devices info's deviceList = dysonAccount2.devices() deviceNames = list(deviceList.keys()) Domoticz.Log("Received new devices: " + str(deviceNames) + ", they will be stored in plugin configuration") i = 0 for device in deviceList: setConfigItem( Key="{0}.name".format(i), Value=deviceNames[i]) #store the name of the machine Domoticz.Debug('Key="{0}.name", Value = {1}'.format( i, deviceNames[i])) #store the name of the machine setConfigItem( Key="{0}.credential".format( deviceList[deviceNames[i]].name), Value=deviceList[ deviceNames[i]].credential) #store the credential Domoticz.Debug('Key="{0}.credential", Value = {1}'.format( deviceList[deviceNames[i]].name, deviceList[ deviceNames[i]].credential)) #store the credential setConfigItem( Key="{0}.serial".format( deviceList[deviceNames[i]].name), Value=deviceList[ deviceNames[i]].serial) #store the serial Domoticz.Debug('Key="{0}.serial", Value = {1}'.format( deviceList[deviceNames[i]].name, deviceList[deviceNames[i]].serial)) #store the serial setConfigItem(Key="{0}.product_type".format( deviceList[deviceNames[i]].name), Value=deviceList[deviceNames[i]].product_type ) #store the product_type Domoticz.Debug( 'Key="{0}.product_type" , Value = {1}'.format( deviceList[deviceNames[i]].name, deviceList[deviceNames[i]].product_type) ) #store the product_type i = i + 1 if deviceList == None or len(deviceList) < 1: Domoticz.Error( "No devices found in plugin configuration or Dyson cloud account" ) return else: Domoticz.Debug("Number of devices in plugin: '" + str(len(deviceList)) + "'") if deviceList != None and len(deviceList) > 0: if len(self.machine_name) > 0: if self.machine_name in deviceList: password, serialNumber, deviceType = self.get_device_config( self.machine_name) Domoticz.Debug( "password: {0}, serialNumber: {1}, deviceType: {2}". format(password, serialNumber, deviceType)) self.myDevice = DysonPureLinkDevice( password, serialNumber, deviceType, self.machine_name) else: Domoticz.Error( "The configured device name '" + self.machine_name + "' was not found in the cloud account. Available options: " + str(list(deviceList))) return elif len(deviceList) == 1: self.myDevice = deviceList[list(deviceList)[0]] Domoticz.Log( "1 device found in plugin, none configured, assuming we need this one: '" + self.myDevice.name + "'") else: #more than 1 device returned in cloud and no name configured, which the the plugin can't handle Domoticz.Error( "More than 1 device found in cloud account but no device name given to select. Select and filter one from available options: " + str(list(deviceList))) return #the Domoticz connection object takes username and pwd from the Parameters so write them back Parameters[ 'Username'] = self.myDevice.serial #take username from account Parameters[ 'Password'] = self.myDevice.password #override the default password with the one returned from the cloud else: Domoticz.Error("No usable credentials found") return #check, per device, if it is created. If not,create it Options = { "LevelActions": "|||", "LevelNames": "|OFF|ON|AUTO", "LevelOffHidden": "true", "SelectorStyle": "1" } if self.fanModeUnit not in Devices: Domoticz.Device(Name='Fan mode', Unit=self.fanModeUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.fanStateUnit not in Devices: Domoticz.Device(Name='Fan state', Unit=self.fanStateUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.heatStateUnit not in Devices: Domoticz.Device(Name='Heating state', Unit=self.heatStateUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.nightModeUnit not in Devices: Domoticz.Device(Name='Night mode', Unit=self.nightModeUnit, Type=244, Subtype=62, Switchtype=0, Image=9).Create() Options = { "LevelActions": "|||||||||||", "LevelNames": "OFF|1|2|3|4|5|6|7|8|9|10|AUTO", "LevelOffHidden": "false", "SelectorStyle": "1" } if self.fanSpeedUnit not in Devices: Domoticz.Device(Name='Fan speed', Unit=self.fanSpeedUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.fanOscillationUnit not in Devices: Domoticz.Device(Name='Oscilation mode', Unit=self.fanOscillationUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.standbyMonitoringUnit not in Devices: Domoticz.Device(Name='Standby monitor', Unit=self.standbyMonitoringUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.filterLifeUnit not in Devices: Options: {'Custom': '1;hrs'} Domoticz.Device(Name='Remaining filter life', Unit=self.filterLifeUnit, TypeName="Custom", Options=Options).Create() if self.resetFilterLifeUnit not in Devices: Domoticz.Device(Name='Reset filter: 0 hrs', Unit=self.resetFilterLifeUnit, TypeName="Switch", Image=9).Create() if self.tempHumUnit not in Devices: Domoticz.Device(Name='Temperature and Humidity', Unit=self.tempHumUnit, TypeName="Temp+Hum").Create() if self.volatileUnit not in Devices: Domoticz.Device(Name='Volatile organic', Unit=self.volatileUnit, TypeName="Air Quality").Create() if self.sleepTimeUnit not in Devices: Domoticz.Device(Name='Sleep timer', Unit=self.sleepTimeUnit, TypeName="Custom").Create() if self.particlesUnit not in Devices: Domoticz.Device(Name='Dust', Unit=self.particlesUnit, TypeName="Air Quality").Create() if self.qualityTargetUnit not in Devices: Options = { "LevelActions": "|||", "LevelNames": "|Normal|Sensitive (Medium)|Very Sensitive (High)|Off", "LevelOffHidden": "true", "SelectorStyle": "1" } Domoticz.Device(Name='Air quality setpoint', Unit=self.qualityTargetUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.particles2_5Unit not in Devices: Domoticz.Device(Name='Dust (PM 2,5)', Unit=self.particles2_5Unit, TypeName="Air Quality").Create() if self.particles10Unit not in Devices: Domoticz.Device(Name='Dust (PM 10)', Unit=self.particles10Unit, TypeName="Air Quality").Create() if self.particlesMatter25Unit not in Devices: Domoticz.Device(Name='Particles (PM 25)', Unit=self.particlesMatter25Unit, TypeName="Air Quality").Create() if self.particlesMatter10Unit not in Devices: Domoticz.Device(Name='Particles (PM 10)', Unit=self.particlesMatter10Unit, TypeName="Air Quality").Create() if self.fanModeAutoUnit not in Devices: Domoticz.Device(Name='Fan mode auto', Unit=self.fanModeAutoUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.fanFocusUnit not in Devices: Domoticz.Device(Name='Fan focus mode', Unit=self.fanFocusUnit, Type=244, Subtype=62, Image=7, Switchtype=0).Create() if self.nitrogenDioxideDensityUnit not in Devices: Domoticz.Device(Name='Nitrogen Dioxide Density (NOx)', Unit=self.nitrogenDioxideDensityUnit, TypeName="Air Quality").Create() if self.heatModeUnit not in Devices: Options = { "LevelActions": "||", "LevelNames": "|Off|Heating", "LevelOffHidden": "true", "SelectorStyle": "1" } Domoticz.Device(Name='Heat mode', Unit=self.heatModeUnit, TypeName="Selector Switch", Image=7, Options=Options).Create() if self.heatTargetUnit not in Devices: Domoticz.Device(Name='Heat target', Unit=self.heatTargetUnit, Type=242, Subtype=1).Create() if self.deviceStatusUnit not in Devices: Domoticz.Device(Name='Machine status', Unit=self.deviceStatusUnit, TypeName="Text", Image=7).Create() Domoticz.Log("Device instance created: " + str(self.myDevice)) self.base_topic = self.myDevice.device_base_topic Domoticz.Debug("base topic defined: '" + self.base_topic + "'") #create the connection if self.myDevice != None: self.mqttClient = MqttClient(self.ip_address, self.port_number, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Hue): Domoticz.Debug("DysonPureLink plugin: onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level)) topic = '' payload = '' arg = '' fan_pwr_list = ['438', '520', '527'] if Unit == self.qualityTargetUnit and Level <= 100: topic, payload = self.myDevice.set_quality_target(Level) if Unit == self.fanSpeedUnit and Level <= 100: arg = "0000" + str(Level // 10) topic, payload = self.myDevice.set_fan_speed( arg[-4:]) #use last 4 characters as speed level or AUTO self.mqttClient.Publish(topic, payload) if Level > 0: #when setting a speed value, make sure that the fan is actually on if self.myDevice.product_type in fan_pwr_list: topic, payload = self.myDevice.set_fan_power("ON") else: topic, payload = self.myDevice.set_fan_mode("FAN") else: if self.myDevice.product_type in fan_pwr_list: topic, payload = self.myDevice.set_fan_power("OFF") else: topic, payload = self.myDevice.set_fan_mode( "OFF") #use last 4 characters as speed level or AUTO if Unit == self.fanModeUnit or (Unit == self.fanSpeedUnit and Level > 100): if self.myDevice.product_type in fan_pwr_list: if Level >= 30: arg = "ON" #Switch to Auto topic, payload = self.myDevice.set_fan_power(arg) self.mqttClient.Publish(topic, payload) topic, payload = self.myDevice.set_fan_mode_auto(arg) elif Level == 20: arg = "ON" #Switch on, auto depends on previous setting topic, payload = self.myDevice.set_fan_power(arg) else: #Switch Off arg = 'OFF' topic, payload = self.myDevice.set_fan_power(arg) else: if Level == 10: arg = "OFF" if Level == 20: arg = "FAN" if Level >= 30: arg = "AUTO" topic, payload = self.myDevice.set_fan_mode(arg) if Unit == self.fanStateUnit: Domoticz.Log("Unit Fans State is read only, no command sent") if Unit == self.fanOscillationUnit: topic, payload = self.myDevice.set_oscilation(str(Command).upper()) if Unit == self.fanFocusUnit: topic, payload = self.myDevice.set_focus(str(Command).upper()) if Unit == self.fanModeAutoUnit: topic, payload = self.myDevice.set_fan_mode_auto( str(Command).upper()) if Unit == self.standbyMonitoringUnit: topic, payload = self.myDevice.set_standby_monitoring( str(Command).upper()) if Unit == self.nightModeUnit: topic, payload = self.myDevice.set_night_mode(str(Command).upper()) if Unit == self.heatModeUnit: if Level == 10: arg = "OFF" if Level == 20: arg = "HEAT" topic, payload = self.myDevice.set_heat_mode(arg) if Unit == self.heatTargetUnit: topic, payload = self.myDevice.set_heat_target(Level) if Unit == self.resetFilterLifeUnit: UpdateDevice(self.resetFilterLifeUnit, 1, "On") #acknowlegde switching on topic, payload = self.myDevice.reset_filter() self.mqttClient.Publish(topic, payload) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called: Connection '" + str(Connection) + "', Status: '" + str(Status) + "', Description: '" + Description + "'") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile): Domoticz.Log("DysonPureLink plugin: onNotification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile) def onHeartbeat(self): if self.myDevice != None: self.runCounter = self.runCounter - 1 if self.runCounter <= 0: Domoticz.Debug("DysonPureLink plugin: Poll unit") self.runCounter = int(Parameters['Mode2']) topic, payload = self.myDevice.request_state() self.mqttClient.Publish( topic, payload) #ask for update of current status else: Domoticz.Debug("Polling unit in " + str(self.runCounter) + " heartbeats.") self.mqttClient.onHeartbeat() def onDeviceRemoved(self, unit): Domoticz.Log( "DysonPureLink plugin: onDeviceRemoved called for unit '" + str(unit) + "'") def updateDevices(self): """Update the defined devices from incoming mesage info""" #update the devices if self.state_data.oscillation is not None: UpdateDevice(self.fanOscillationUnit, self.state_data.oscillation.state, str(self.state_data.oscillation)) if self.state_data.night_mode is not None: UpdateDevice(self.nightModeUnit, self.state_data.night_mode.state, str(self.state_data.night_mode)) # Fan speed if self.state_data.fan_speed is not None: f_rate = self.state_data.fan_speed if (f_rate == "AUTO"): nValueNew = 110 sValueNew = "110" # Auto else: nValueNew = (int(f_rate)) * 10 sValueNew = str((int(f_rate)) * 10) if self.state_data.fan_mode is not None: Domoticz.Debug("update fanspeed, state of FanMode: " + str(self.state_data.fan_mode)) if self.state_data.fan_mode.state == 0: nValueNew = 0 sValueNew = "0" UpdateDevice(self.fanSpeedUnit, nValueNew, sValueNew) if self.state_data.fan_mode is not None: UpdateDevice(self.fanModeUnit, self.state_data.fan_mode.state, str((self.state_data.fan_mode.state + 1) * 10)) if self.state_data.fan_state is not None: UpdateDevice(self.fanStateUnit, self.state_data.fan_state.state, str((self.state_data.fan_state.state + 1) * 10)) if self.state_data.filter_life is not None: UpdateDevice(self.filterLifeUnit, self.state_data.filter_life, str(self.state_data.filter_life)) if self.state_data.filter_life is not None: nameBase, curValue = Devices[self.resetFilterLifeUnit].Name.split( ":") UpdateDevice(self.resetFilterLifeUnit, 0, "Off", Name=nameBase + ": " + str(self.state_data.filter_life) + " hrs") if self.state_data.quality_target is not None: UpdateDevice(self.qualityTargetUnit, self.state_data.quality_target.state, str((self.state_data.quality_target.state + 1) * 10)) if self.state_data.standby_monitoring is not None: UpdateDevice( self.standbyMonitoringUnit, self.state_data.standby_monitoring.state, str((self.state_data.standby_monitoring.state + 1) * 10)) if self.state_data.fan_mode_auto is not None: UpdateDevice(self.fanModeAutoUnit, self.state_data.fan_mode_auto.state, str((self.state_data.fan_mode_auto.state + 1) * 10)) if self.state_data.focus is not None: UpdateDevice(self.fanFocusUnit, self.state_data.focus.state, str(self.state_data.focus)) if self.state_data.heat_mode is not None: UpdateDevice(self.heatModeUnit, self.state_data.heat_mode.state, str((self.state_data.heat_mode.state + 1) * 10)) if self.state_data.heat_target is not None: UpdateDevice(self.heatTargetUnit, 0, str(self.state_data.heat_target)) if self.state_data.heat_state is not None: UpdateDevice(self.heatStateUnit, self.state_data.heat_state.state, str((self.state_data.heat_state.state + 1) * 10)) if self.state_data.error is not None and self.state_data.warning is not None: status_string = "Error: {}<br> Warning: {}".format( self.state_data.error, self.state_data.warning) UpdateDevice(self.deviceStatusUnit, 0, status_string) Domoticz.Debug("update StateData: " + str(self.state_data)) def updateSensors(self): """Update the defined devices from incoming mesage info""" #update the devices if self.sensor_data.temperature is not None and self.sensor_data.humidity is not None: tempNum = int(self.sensor_data.temperature) humNum = int(self.sensor_data.humidity) UpdateDevice( self.tempHumUnit, 1, str(self.sensor_data.temperature)[:4] + ';' + str(self.sensor_data.humidity) + ";1") if self.sensor_data.volatile_compounds is not None: UpdateDevice(self.volatileUnit, self.sensor_data.volatile_compounds, str(self.sensor_data.volatile_compounds)) if self.sensor_data.particles is not None: UpdateDevice(self.particlesUnit, self.sensor_data.particles, str(self.sensor_data.particles)) if self.sensor_data.particles2_5 is not None: UpdateDevice(self.particles2_5Unit, self.sensor_data.particles2_5, str(self.sensor_data.particles2_5)) if self.sensor_data.particles10 is not None: UpdateDevice(self.particles10Unit, self.sensor_data.particles10, str(self.sensor_data.particles10)) if self.sensor_data.particulate_matter_25 is not None: UpdateDevice(self.particlesMatter25Unit, self.sensor_data.particulate_matter_25, str(self.sensor_data.particulate_matter_25)) if self.sensor_data.particulate_matter_10 is not None: UpdateDevice(self.particlesMatter10Unit, self.sensor_data.particulate_matter_10, str(self.sensor_data.particulate_matter_10)) if self.sensor_data.nitrogenDioxideDensity is not None: UpdateDevice(self.nitrogenDioxideDensityUnit, self.sensor_data.nitrogenDioxideDensity, str(self.sensor_data.nitrogenDioxideDensity)) if self.sensor_data.heat_target is not None: UpdateDevice(self.heatTargetUnit, self.sensor_data.heat_target, str(self.sensor_data.heat_target)) UpdateDevice(self.sleepTimeUnit, self.sensor_data.sleep_timer, str(self.sensor_data.sleep_timer)) if self.sensor_data.has_data: Domoticz.Debug("update SensorData: " + str(self.sensor_data)) else: Domoticz.Debug("partial SensorData to update") def onMQTTConnected(self): """connection to device established""" Domoticz.Debug("onMQTTConnected called") Domoticz.Log("MQTT connection established") self.mqttClient.Subscribe([ self.base_topic + '/status/current', self.base_topic + '/status/connection', self.base_topic + '/status/faults' ]) #subscribe to all topics on the machine topic, payload = self.myDevice.request_state() self.mqttClient.Publish(topic, payload) #ask for update of current status def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT Publish: MQTT message incoming: " + topic + " " + str(message)) if (topic == self.base_topic + '/status/current'): #update of the machine's status if StateData.is_state_data(message): Domoticz.Debug("machine state or state change recieved") self.state_data = StateData(message) self.updateDevices() if SensorsData.is_sensors_data(message): Domoticz.Debug("sensor state recieved") self.sensor_data = SensorsData(message) self.updateSensors() if (topic == self.base_topic + '/status/connection'): #connection status received Domoticz.Debug("connection state recieved") if (topic == self.base_topic + '/status/software'): #connection status received Domoticz.Debug("software state recieved") if (topic == self.base_topic + '/status/summary'): #connection status received Domoticz.Debug("summary state recieved") def checkVersion(self, version): """checks actual version against stored version as 'Ma.Mi.Pa' and checks if updates needed""" #read version from stored configuration ConfVersion = getConfigItem("plugin version", "0.0.0") Domoticz.Log("Starting version: " + version) MaCurrent, MiCurrent, PaCurrent = version.split('.') MaConf, MiConf, PaConf = ConfVersion.split('.') Domoticz.Debug("checking versions: current '{0}', config '{1}'".format( version, ConfVersion)) if int(MaConf) < int(MaCurrent): Domoticz.Log("Major version upgrade: {0} -> {1}".format( MaConf, MaCurrent)) #add code to perform MAJOR upgrades elif int(MiConf) < int(MiCurrent): Domoticz.Log("Minor version upgrade: {0} -> {1}".format( MiConf, MiCurrent)) #add code to perform MINOR upgrades elif int(PaConf) < int(PaCurrent): Domoticz.Log("Patch version upgrade: {0} -> {1}".format( PaConf, PaCurrent)) #add code to perform PATCH upgrades, if any if ConfVersion != version: #store new version info self._setVersion(MaCurrent, MiCurrent, PaCurrent) def get_device_names(self): """find the amount of stored devices""" Configurations = getConfigItem() devices = {} for x in Configurations: if x.find(".") > -1 and x.split(".")[1] == "name": devices[str(Configurations[x])] = str(Configurations[x]) return devices def get_device_config(self, name): """fetch all relevant config items from Domoticz.Configuration for device with name""" Configurations = getConfigItem() for x in Configurations: if x.split(".")[1] == "name": Domoticz.Debug("Found a machine name: " + x + " value: '" + str(Configurations[x]) + "'") if Configurations[x] == name: password = getConfigItem( Key="{0}.{1}".format(name, "credential")) serialNumber = getConfigItem( Key="{0}.{1}".format(name, "serial")) deviceType = getConfigItem( Key="{0}.{1}".format(name, "product_type")) return password, serialNumber, deviceType return def _setVersion(self, major, minor, patch): #set configs Domoticz.Debug("Setting version to {0}.{1}.{2}".format( major, minor, patch)) setConfigItem(Key="MajorVersion", Value=major) setConfigItem(Key="MinorVersion", Value=minor) setConfigItem(Key="patchVersion", Value=patch) setConfigItem(Key="plugin version", Value="{0}.{1}.{2}".format(major, minor, patch)) def _storeCredentials(self, creds, auths): #store credentials as config item Domoticz.Debug("Storing credentials: " + str(creds) + " and auth object: " + str(auths)) currentCreds = getConfigItem(Key="credentials", Default=None) if currentCreds is None or currentCreds != creds: Domoticz.Log( "Credentials from user authentication do not match those stored in config, updating config" ) setConfigItem(Key="credentials", Value=creds) return True
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) Domoticz.Debug("onStart called") self.base_topic = Parameters["Mode1"].strip() self.pairing_enabled = True if Parameters["Mode2"] == 'true' else False self.subscribed_for_devices = False mqtt_server_address = Parameters["Address"].strip() mqtt_server_port = Parameters["Port"].strip() mqtt_client_id = Parameters["Mode3"].strip() self.mqttClient = MqttClient(mqtt_server_address, mqtt_server_port, mqtt_client_id, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.devices_manager = DevicesManager() self.groups_manager = GroupsManager() def checkDevices(self): Domoticz.Debug("checkDevices called") def onStop(self): Domoticz.Debug("onStop called") def handlePairingMode(self): permit_join = 'true' if self.pairing_enabled else 'false' self.mqttClient.publish(self.base_topic + '/bridge/config/permit_join', permit_join) def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) device = Devices[ Unit] #Devices is Domoticz collection of devices for this hardware device_params = device.DeviceID.split('_') entity_id = device_params[0] if (self.devices_manager.get_device_by_id(entity_id) != None): message = self.devices_manager.handle_command( Devices, device, Command, Level, Color) elif (self.groups_manager.get_group_by_deviceid(device.DeviceID) != None): message = self.groups_manager.handle_command( device, Command, Level, Color) else: Domoticz.Log('Can\'t process command from device "' + device.Name + '"') if (message != None): self.mqttClient.publish(self.base_topic + '/' + message['topic'], message['payload']) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): self.mqttClient.onHeartbeat() def onMQTTConnected(self): self.mqttClient.subscribe([self.base_topic + '/bridge/#']) def onMQTTDisconnected(self): self.subscribed_for_devices = False def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT message: " + topic + " " + str(message)) if (topic == self.base_topic + '/bridge/config/permit_join' or topic == self.base_topic + '/bridge/config/devices'): return if (topic == self.base_topic + '/bridge/config'): permit_join = 'enabled' if message['permit_join'] else 'disabled' Domoticz.Debug('Zigbee2mqtt log level is ' + message['log_level']) Domoticz.Log('Joining new devices is ' + permit_join + ' on the zigbee bridge') return if (topic == self.base_topic + '/bridge/state'): Domoticz.Log('Zigbee2mqtt bridge is ' + message) if message == 'online': self.mqttClient.publish( self.base_topic + '/bridge/config/devices', '') self.mqttClient.publish( self.base_topic + '/bridge/config/groups', '') self.handlePairingMode() return if (topic == self.base_topic + '/bridge/log'): if message['type'] == 'devices': Domoticz.Log('Received available devices list from bridge') self.devices_manager.clear() self.devices_manager.update(Devices, message['message']) if self.subscribed_for_devices == False: self.mqttClient.subscribe([self.base_topic + '/+']) self.subscribed_for_devices = True if message['type'] == 'groups': Domoticz.Log('Received groups list from bridge') self.groups_manager.register_groups(Devices, message['message']) if message['type'] == 'device_connected' or message[ 'type'] == 'device_removed': self.mqttClient.publish( self.base_topic + '/bridge/config/devices', '') return entity_name = topic.replace(self.base_topic + "/", "") if (self.devices_manager.get_device_by_name(entity_name) != None): self.devices_manager.handle_mqtt_message(Devices, entity_name, message) elif (self.groups_manager.get_group_by_name(entity_name) != None): self.groups_manager.handle_mqtt_message(entity_name, message) else: Domoticz.Debug('Unhandled message from zigbee2mqtt: ' + topic + ' ' + str(message))
class BasePlugin: mqttClient = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose+": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2 + 4 + 8) self.controller = EmsDevices() self.controller.checkDevices() self.topics = list([ "home/ems-esp/thermostat_data", "home/ems-esp/boiler_data", "home/ems-esp/STATE" ]) self.mqttserveraddress = Parameters["Address"].replace(" ", "") self.mqttserverport = Parameters["Port"].replace(" ", "") self.mqttClient = MqttClient(self.mqttserveraddress, self.mqttserverport, self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) def checkDevices(self): Domoticz.Log("checkDevices called") def onStop(self): Domoticz.Log("onStop called") def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("Command: " + Command + " (" + str(Level)) self.controller.onCommand(self.mqttClient, Unit, Command, Level, Color) def onConnect(self, Connection, Status, Description): self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): Domoticz.Debug("Heartbeating...") # Reconnect if connection has dropped if self.mqttClient.mqttConn is None or ( not self.mqttClient.mqttConn.Connecting() and not self.mqttClient.mqttConn.Connected() or not self.mqttClient.isConnected): Domoticz.Debug("Reconnecting") self.mqttClient.Open() else: self.mqttClient.Ping() def onMQTTConnected(self): Domoticz.Debug("onMQTTConnected") self.mqttClient.Subscribe(self.topics) def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, rawmessage): Domoticz.Debug("MQTT message: " + topic + " " + str(rawmessage)) message = "" try: message = json.loads(rawmessage.decode('utf8')) except ValueError: message = rawmessage.decode('utf8') if (topic in self.topics): self.controller.onMqttMessage(topic, message)
class BasePlugin: mqttClient = None domoticzDevicesByName = None domoticzDevicesById = None linkedDevices = None def onStart(self): self.debugging = Parameters["Mode6"] if self.debugging == "Verbose": Domoticz.Debugging(2 + 4 + 8 + 16 + 64) if self.debugging == "Debug": Domoticz.Debugging(2) Domoticz.Debug("onStart called") self.base_topic = Parameters["Mode1"].strip() self.domoticz_port = int(Parameters["Port"].strip()) self.delete_removed_devices = Parameters["Mode5"].strip() if Parameters["Address"].find('mqtt.gbridge.io') >= 0: self.domoticz_mqtt_used = False else: self.domoticz_mqtt_used = True self.mqttClient = MqttClient(Parameters["Address"].strip().split(":")[0], Parameters["Address"].strip().split(":")[1], self.onMQTTConnected, self.onMQTTDisconnected, self.onMQTTPublish, self.onMQTTSubscribed) self.gBridgeClient = gBridgeClient(Parameters["Mode2"].strip(), Parameters["Mode3"].strip(), Parameters["Mode4"].strip()) self.domoticz_client = DomoticzClient(self.domoticz_port) self.syncDevices() Domoticz.Debug("Done") def syncDevices(self): Domoticz.Debug('Starting sync') bridge_devices = self.gBridgeClient.fetchDevicesFromBridge() domoticz_devices = self.domoticz_client.fetchDevicesFromDomoticz() self.linkedDevices = self.domoticz_client.getLinkedDevices(domoticz_devices) Domoticz.Debug('Linked devices: ' + str(self.linkedDevices)) self.domoticzDevicesByName = self.domoticz_client.getDevicesByName(domoticz_devices) self.domoticzDevicesById = {x['idx']: x for x in list(self.domoticzDevicesByName.values())} Domoticz.Debug('Domoticz devices available for gBridge: ' + str(self.domoticzDevicesByName.keys())) self.gBridgeClient.syncDevices(self.domoticzDevicesByName, bridge_devices, self.delete_removed_devices == 'True') def onStop(self): Domoticz.Debug("onStop called") def onCommand(self, Unit, Command, Level, Color): Domoticz.Debug("onCommand: " + Command + ", level (" + str(Level) + ") Color:" + Color) def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called") self.mqttClient.onConnect(Connection, Status, Description) def onDisconnect(self, Connection): self.mqttClient.onDisconnect(Connection) def onMessage(self, Connection, Data): Domoticz.Debug('Incoming message!' + str(Data)) self.mqttClient.onMessage(Connection, Data) def onHeartbeat(self): Domoticz.Debug("Heartbeating...") # Reconnect if connection has dropped if self.mqttClient.mqttConn is None or ( not self.mqttClient.mqttConn.Connecting() and not self.mqttClient.mqttConn.Connected() or not self.mqttClient.isConnected): Domoticz.Debug("Reconnecting") self.mqttClient.Open() else: self.mqttClient.Ping() def onMQTTConnected(self): self.mqttClient.Subscribe([self.base_topic + '/#']) if self.domoticz_mqtt_used: self.mqttClient.Subscribe(['domoticz/out']) def onMQTTDisconnected(self): Domoticz.Debug("onMQTTDisconnected") def onMQTTSubscribed(self): Domoticz.Debug("onMQTTSubscribed") def onMQTTPublish(self, topic, message): Domoticz.Debug("MQTT message: " + topic + " " + str(message)) if str(topic) == 'domoticz/out': if message.get('idx') is not None: domoticz_id = str(message['idx']) if message.get('Type') is not None and (message['Type'] == 'Scene' or message['Type'] == 'Group'): domoticz_id = 'group_' + domoticz_id else: return device = None if domoticz_id in self.domoticzDevicesById: device = self.domoticzDevicesById[domoticz_id] elif domoticz_id in self.linkedDevices and self.linkedDevices[domoticz_id] in self.domoticzDevicesById: # Get the device to which this device message is linked to, for example, device id 13 -> update device 12 device = self.domoticzDevicesById[self.linkedDevices[domoticz_id]] if device is not None: adapter = getAdapter(device) if adapter is not None: adapter.publishStateFromDomoticzTopic(self.mqttClient, device, self.base_topic, message) else: Domoticz.Error('No adapter registered to publish state for device: %s' % str(device)) else: if message == 'SYNC': self.syncDevices() elif topic.endswith('/set'): Domoticz.Debug('Published new state for device, topic: %s, state: %s' % (topic, message)) else: match = re.search(self.base_topic + '/(.*)/(.*)', topic) if match: device_id = match.group(1) # Backwards compatibility, previously the device name was used as topic name if device_id in self.domoticzDevicesByName: device = self.domoticzDevicesByName[device_id] elif device_id in self.domoticzDevicesById: device = self.domoticzDevicesById[device_id] else: Domoticz.Log('Received message for device which is not in Domoticz: %s, skipping' % device_id) return action = match.group(2) adapter = getAdapter(device) if adapter is not None: adapter.handleMqttMessage(device, str(message), action, self.domoticz_port) if not self.domoticz_mqtt_used: adapter.publishState(self.mqttClient, device, self.base_topic, message) # answer directly else: Domoticz.Error('No adapter registered for action: %s for device: %s' % (action, str(device)))