예제 #1
0
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)
예제 #2
0
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