From 44723df93f404335094e993c4e6b0dc6df728d8f Mon Sep 17 00:00:00 2001 From: Gert05 Date: Tue, 19 Feb 2019 20:15:40 +0100 Subject: [PATCH] Add files via upload --- doc/Domoticz/nefit/mqtt.py | 113 ++++++++++++++++++++++++ doc/Domoticz/nefit/plugin.py | 165 +++++++++++++++++++++++++++++++++++ doc/Domoticz/readme.txt | 10 +++ 3 files changed, 288 insertions(+) create mode 100644 doc/Domoticz/nefit/mqtt.py create mode 100644 doc/Domoticz/nefit/plugin.py create mode 100644 doc/Domoticz/readme.txt diff --git a/doc/Domoticz/nefit/mqtt.py b/doc/Domoticz/nefit/mqtt.py new file mode 100644 index 000000000..21ddc42a5 --- /dev/null +++ b/doc/Domoticz/nefit/mqtt.py @@ -0,0 +1,113 @@ +# Based on https://github.com/emontnemery/domoticz_mqtt_discovery +import Domoticz +import time + +class MqttClient: + Address = "" + Port = "" + mqttConn = None + isConnected = False + mqttConnectedCb = None + mqttDisconnectedCb = None + mqttPublishCb = None + + def __init__(self, destination, port, mqttConnectedCb, mqttDisconnectedCb, mqttPublishCb, mqttSubackCb): + Domoticz.Debug("MqttClient::__init__") + self.Address = destination + self.Port = port + self.mqttConnectedCb = mqttConnectedCb + self.mqttDisconnectedCb = mqttDisconnectedCb + self.mqttPublishCb = mqttPublishCb + self.mqttSubackCb = mqttSubackCb + self.Open() + + def __str__(self): + Domoticz.Debug("MqttClient::__str__") + if (self.mqttConn != None): + return str(self.mqttConn) + else: + return "None" + + def Open(self): + Domoticz.Debug("MqttClient::Open") + if (self.mqttConn != None): + self.Close() + self.isConnected = False + self.mqttConn = Domoticz.Connection(Name=self.Address, Transport="TCP/IP", Protocol="MQTT", Address=self.Address, Port=self.Port) + self.mqttConn.Connect() + + def Connect(self): + Domoticz.Debug("MqttClient::Connect") + if (self.mqttConn == None): + self.Open() + else: + ID = 'Domoticz_'+str(int(time.time())) + Domoticz.Log("MQTT CONNECT ID: '" + ID + "'") + self.mqttConn.Send({'Verb': 'CONNECT', 'ID': ID}) + + def Ping(self): + Domoticz.Debug("MqttClient::Ping") + if (self.mqttConn == None or not self.isConnected): + self.Open() + else: + self.mqttConn.Send({'Verb': 'PING'}) + + def Publish(self, topic, payload, retain = 0): + Domoticz.Log("MqttClient::Publish " + topic + " (" + payload + ")") + if (self.mqttConn == None or not self.isConnected): + self.Open() + else: + self.mqttConn.Send({'Verb': 'PUBLISH', 'Topic': topic, 'Payload': bytearray(payload, 'utf-8'), 'Retain': retain}) + + def Subscribe(self, topics): + Domoticz.Debug("MqttClient::Subscribe") + subscriptionlist = [] + for topic in topics: + subscriptionlist.append({'Topic':topic, 'QoS':0}) + if (self.mqttConn == None or not self.isConnected): + self.Open() + else: + self.mqttConn.Send({'Verb': 'SUBSCRIBE', 'Topics': subscriptionlist}) + + def Close(self): + Domoticz.Log("MqttClient::Close") + #TODO: Disconnect from server + self.mqttConn = None + self.isConnected = False + + def onConnect(self, Connection, Status, Description): + Domoticz.Debug("MqttClient::onConnect") + if (Status == 0): + Domoticz.Log("Successful connect to: "+Connection.Address+":"+Connection.Port) + self.Connect() + else: + Domoticz.Log("Failed to connect to: "+Connection.Address+":"+Connection.Port+", Description: "+Description) + + def onDisconnect(self, Connection): + Domoticz.Log("MqttClient::onDisonnect Disconnected from: "+Connection.Address+":"+Connection.Port) + self.Close() + # TODO: Reconnect? + if self.mqttDisconnectedCb != None: + self.mqttDisconnectedCb() + + def onMessage(self, Connection, Data): + topic = '' + if 'Topic' in Data: + topic = Data['Topic'] + payloadStr = '' + if 'Payload' in Data: + payloadStr = Data['Payload'].decode('utf8','replace') + payloadStr = str(payloadStr.encode('unicode_escape')) + + if Data['Verb'] == "CONNACK": + self.isConnected = True + if self.mqttConnectedCb != None: + self.mqttConnectedCb() + + if Data['Verb'] == "SUBACK": + if self.mqttSubackCb != None: + self.mqttSubackCb() + + if Data['Verb'] == "PUBLISH": + if self.mqttPublishCb != None: + self.mqttPublishCb(topic, Data['Payload']) \ No newline at end of file diff --git a/doc/Domoticz/nefit/plugin.py b/doc/Domoticz/nefit/plugin.py new file mode 100644 index 000000000..abcf78c18 --- /dev/null +++ b/doc/Domoticz/nefit/plugin.py @@ -0,0 +1,165 @@ +""" + + + Plugin to control Nefit EMS-ESP with ' Proddy' firmware
+
+ Automatically creates Domoticz devices for connected device.
+ Do not forget to "Accept new Hardware Devices" on first run
+
+ + + + + + + + +
+""" + +import Domoticz +import json +import time +from mqtt import MqttClient + +class Thermostat: + def checkDevices(self): + if 1 not in Devices: + Domoticz.Debug("Create Temperature Device") + Domoticz.Device(Name="Woonkamer", Unit=1, Type=80, Subtype=5).Create() + if 2 not in Devices: + Domoticz.Debug("Create System Pressure Device") + Domoticz.Device(Name="System Pressure", Unit=2, Type=243, Subtype=9).Create() + if 3 not in Devices: + Domoticz.Debug("Create Thermostat Device") + Domoticz.Device(Name="Nefit", Unit=3, Type=242, Subtype=1).Create() + + def onMqttMessage(self, topic, payload): + if "thermostat_currtemp" in payload: + temp=round(float(payload["thermostat_currtemp"]),1) + Domoticz.Debug("Current temp: {}".format(temp)) + if Devices[1].sValue != temp: + Devices[1].Update(nValue=1, sValue=str(temp)) + if "sysPress" in payload: + pressure=payload["sysPress"] + Domoticz.Debug("System Pressure: {}".format(pressure)) + if Devices[2].sValue != pressure: + Devices[2].Update(nValue=1, sValue=str(pressure)) + if "thermostat_seltemp" in payload: + temp=payload["thermostat_seltemp"] + Domoticz.Debug("Temp setting: {}".format(temp)) + if Devices[3].sValue != temp: + Devices[3].Update(nValue=1, sValue=str(temp)) + + def onCommand(self, mqttClient, unit, command, level, color): + topic = "home/ems-esp/thermostat_cmd_temp" + if (command == "Set Level"): + mqttClient.Publish(topic, str(level)) + +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 = Thermostat() + + 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) + +global _plugin +_plugin = BasePlugin() + +def onStart(): + global _plugin + _plugin.onStart() + +def onStop(): + global _plugin + _plugin.onStop() + +def onConnect(Connection, Status, Description): + global _plugin + _plugin.onConnect(Connection, Status, Description) + +def onDisconnect(Connection): + global _plugin + _plugin.onDisconnect(Connection) + +def onMessage(Connection, Data): + global _plugin + _plugin.onMessage(Connection, Data) + +def onCommand(Unit, Command, Level, Color): + global _plugin + _plugin.onCommand(Unit, Command, Level, Color) + +def onHeartbeat(): + global _plugin + _plugin.onHeartbeat() diff --git a/doc/Domoticz/readme.txt b/doc/Domoticz/readme.txt new file mode 100644 index 000000000..cc8965ab6 --- /dev/null +++ b/doc/Domoticz/readme.txt @@ -0,0 +1,10 @@ +to install the plugin: +- copy the directory 'nefit' to the domoticz/plugins directory +- make sure that 'Accept new Hardware Devices' is enabeled in settings/sysem +- create new hardware with type 'Nefit EMS-ESP with Proddy firmware' +- set MQTT server and port + +The plugin crrently creates 3 devices: +- a room temperature meter +- a system pressure meter +- a thermostat setpoint control \ No newline at end of file