def onMessage(self, Connection, Data): try: self.miktUnpacker.feed(Data) for sentence in self.miktUnpacker: reply, tag, words = SentenceParser.parse_sentence(sentence) if tag == 'initial_login' and reply == '!done': self.miktConn.Send( sentence_pack([ '/login', '=name=%s' % Parameters['Username'], '=password=%s' % Parameters['Password'], '.tag=authorize' ])) elif tag == 'authorize' and reply == '!done' and not self.miktAuthError: Domoticz.Log('Mikrotik logged in successfully') self.miktLoggedIn = True if Parameters['Mode3']: self._miktCommand([ '/interface/listen', '=.proplist=.id,name,running,disabled', '?name=%s' % Parameters['Mode3'], '.tag=interface_status_update' ]) self._miktCommand([ '/interface/print', '=.proplist=.id,name,running,disabled', '?name=%s' % Parameters['Mode3'], '.tag=interface_status' ]) elif tag in ('interface_status', 'interface_status_update') and reply == '!re': if not self.statusInterfaceId: self.statusInterfaceId = words.get('.id', None) if words.get('running', None) is not None: self.statusRunning = words.get('running') if words.get('disabled', None) is not None: self.statusDisabled = words.get('disabled') if self.statusRunning: UpdateDevice(self.statusUnit, 1, '10', ShowInLog=True) elif self.statusDisabled: UpdateDevice(self.statusUnit, 0, '0', ShowInLog=True) else: UpdateDevice(self.statusUnit, 1, '20', ShowInLog=True) elif tag == 'bw' and reply == '!re': UpdateDevice( self.bwDownUnit, 1, str(bitToMbit(words.get('rx-bits-per-second', 0)))) UpdateDevice( self.bwUpUnit, 1, str(bitToMbit(words.get('tx-bits-per-second', 0)))) elif tag == 'authorize' and reply == '!trap': self.miktAuthError = True Domoticz.Error('Mikrotik login error [%s]' % words.get('message', None)) elif reply in ('!fatal', '!trap'): Domoticz.Error( 'Mikrotik error. Reply [%s]. Message [%s]. Tag [%s].' % (reply, words.get('message', None), tag)) except UnpackerException as e: Domoticz.Error('UnpackerException [%s]' % str(e)) except ParseException as e: Domoticz.Error('ParseException [%s]' % str(e))
<param field="Mode3" label="Authorization code" width="300px" required="true"/> <param field="Mode4" label="Poll Interval (seconds)" width="100px" required="true" default=30/> <param field="Mode5" label="Debug" width="100px"> <options> <option label="True" value="True"/> <option label="False" value="False" default="true"/> </options> </param> </params> </plugin> """ import Domoticz try: from Spotify import SpotifyConnection, SpotifyError except ImportError: Domoticz.Error("Error importing SpotifyConnection. Is spotipy installed?") # Unit defines SPOTDEVICE = 1 SPOTVOLUME = 2 SPOTCONTROLS = 3 class BasePlugin: enabled = False hasTimedOut = False def __init__(self): self.spotify_devices = {} self.credentials = None self.spotify = None
def discover(self, deviceID = None): if self.discovered: return True if len(self.IP) > 0: Domoticz.Debug('Loaded saved configuration.') Domoticz.Log('Attempt to connect to {2} device with ID: {0}, IP address: {1} '.format(self.deviceID, self.IP, self.hardware)) status = self.sendCommand(json.dumps({"id": self.id, "method": "get_state"})) if (status["state"] == "Error"): Domoticz.Log('Could not connect to {0} with IP {1}, starting discover.'.format(Parameters['Name'], self.IP)) self.IP = '' else: self.discovered = True return self.discovered Domoticz.Debug('Starting discover with Device ID: {}.'.format(deviceID)) self.discovered = False timeout = 5 addr = '<broadcast>' discoveredDevice = None helobytes = 'discover'.encode() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.settimeout(timeout) s.sendto(helobytes, (addr, 1000)) while True: try: data, addr = s.recvfrom(1024) reply = json.loads(data.decode()) self.deviceID = reply["deviceID"] self.IP = reply["IP"] self.hardware = reply["hardware"] if deviceID is None: Domoticz.Log('Discovered. Device ID: {0}, IP: {1}, Model: {2}'.format(self.deviceID, self.IP, self.hardware)) else: if self.deviceID == deviceID: Domoticz.Log('Connected to device ID: {0} with IP address: {1}'.format(self.deviceID, self.IP)) config = { "DeviceID": self.deviceID, "IP": self.IP, "Hardware": self.hardware } config_Path = os.path.join(str(Parameters['HomeFolder']), "ESPSmartHome_device"+str(Parameters["HardwareID"])+'.json') with open(config_Path, 'w') as outfile: if json.dump(config, outfile, indent=4): Domoticz.Debug('Config file was saved.') self.discovered = True for x in Devices: if Devices[x].TimedOut == True: Devices[x].Update(nValue=Devices[x].nValue, sValue=Devices[x].sValue, TimedOut = False) return self.discovered except socket.timeout: Domoticz.Debug('Discovery done') if ((deviceID is not None) and (self.discovered == False)): Domoticz.Error('Could not discover with Device ID = {0}. Check power/network/Device ID.'.format(deviceID)) self.IP = '' for x in Devices: if Devices[x].TimedOut == False: Devices[x].Update(nValue=Devices[x].nValue, sValue=Devices[x].sValue, TimedOut = True) return self.discovered except Exception as ex: Domoticz.Error('Error while reading discover results: {0}'.format(ex)) break
def UpdatePythonPlugin(self, ppAuthor, ppRepository, ppKey): Domoticz.Debug("UpdatePythonPlugin called") if ppKey == "PP-MANAGER": Domoticz.Log("Self Update Initiated") ppGitReset = "LANG=en_US /usr/bin/git reset --hard HEAD" try: pr = subprocess.Popen(ppGitReset, cwd=str(os.getcwd() + "/plugins/" + ppKey), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, error) = pr.communicate() if out: Domoticz.Debug("Git Response:" + str(out)) if error: Domoticz.Debug("Git Error:" + str(error.strip())) except OSError as eReset: Domoticz.Error("Git ErrorNo:" + str(eReset.errno)) Domoticz.Error("Git StrError:" + str(eReset.strerror)) elif (self.plugindata[ppKey][2] in self.ExceptionList): Domoticz.Log( "Plugin:" + self.plugindata[ppKey][2] + " excluded by Exclusion file (exclusion.txt). Skipping!!!") return Domoticz.Log("Updating Plugin:" + ppKey) ppUrl = "LANG=en_US /usr/bin/git pull --force" Domoticz.Debug("Calling:" + ppUrl + " on folder " + str(os.getcwd()) + "/plugins/" + ppKey) try: pr = subprocess.Popen(ppUrl, cwd=str(os.getcwd() + "/plugins/" + ppKey), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, error) = pr.communicate() if out: Domoticz.Debug("Git Response:" + str(out)) if (str(out).find("Already up-to-date") != -1) or (str(out).find("Already up to date") != -1): Domoticz.Log("Plugin " + ppKey + " already Up-To-Date") #Domoticz.Log("find(error):" + str(str(out).find("error"))) elif (str(out).find("Updating") != -1) and (str( str(out).find("error")) == "-1"): ppUrl = "chmod " Domoticz.Log("Succesfully pulled gitHub update:" + str(out)[str(out).find("Updating") + 8:26] + " for plugin " + ppKey) Domoticz.Log( "---Restarting Domoticz MAY BE REQUIRED to activate new plugins---" ) else: Domoticz.Error("Something went wrong with update of " + str(ppKey)) if error: Domoticz.Debug("Git Error:" + str(error.strip())) if str(error).find("Not a git repository") != -1: Domoticz.Log( "Plugin:" + ppKey + " is not installed from gitHub. Cannot be updated with PP-Manager!!." ) except OSError as e: Domoticz.Error("Git ErrorNo:" + str(e.errno)) Domoticz.Error("Git StrError:" + str(e.strerror)) return None
def parseFileForSecurityIssues(self, pyfilename, pypluginid): Domoticz.Debug("parseFileForSecurityIssues called") secmonitorOnly = False if Parameters["Mode5"] == 'Monitor': Domoticz.Log("Plugin Security Scan is enabled") secmonitorOnly = True # Open the file file = open(pyfilename, "r") ips = {} #safeStrings = ["['http://schemas.xmlsoap.org/soap/envelope/', 'http://schemas.xmlsoap.org/soap/encoding/']", # "127.0.0.1", # "http://schemas.xmlsoap.org/soap/envelope/'", # "import json", # "import time", # "import platform", # 'import re'] if pypluginid not in self.SecPolUserList: self.SecPolUserList[pypluginid] = [] lineNum = 1 #Domoticz.Error("self.SecPolUserList[pypluginid]:" + str(self.SecPolUserList[pypluginid])) for text in file.readlines(): text = text.rstrip() #Domoticz.Log("'text' is:'" + str(text)) regexFound = re.findall( r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})', text) paramFound = re.findall(r'<param field=', text) if ((regexFound) and not (paramFound)): #regexFound[rex] = regexFound[rex].strip('"]') #Domoticz.Error("Security Finding(IPregex):" + str(regexFound) + " LINE: " + str(lineNum) + " FILE:" + pyfilename) for rex in range(0, len(regexFound)): if ((str(text).strip() not in self.SecPolUserList["Global"]) and (str(text).strip() not in self.SecPolUserList[pypluginid]) and (str(text).strip() != "") and (mid(text, 0, 1) != "#")): Domoticz.Error("Security Finding(IP):-->" + str(text).strip() + "<-- LINE: " + str(lineNum) + " FILE:" + pyfilename) #Domoticz.Error("Security Finding(IPr):" + regexFound[rex] + " LINE: " + str(lineNum) + " FILE:" + pyfilename) ips["IP" + str(lineNum)] = (regexFound[rex], "IP Address") #rex = 0 #regexFound = re.findall('import', text) #if regexFound: #regexFound[rex] = regexFound[rex].strip('"]') #Domoticz.Error("Security Finding(IPregex):" + str(regexFound) + " LINE: " + str(lineNum) + " FILE:" + pyfilename) # for rex in range(0,len(regexFound)): # if ((str(text).strip() not in self.SecPolUserList["Global"]) and (str(text).strip() not in self.SecPolUserList[pypluginid]) and (str(text).strip() != "") and (mid(text,0,1) != "#")): # Domoticz.Error("Security Finding(IMP):-->" + str(text) + "<-- LINE: " + str(lineNum) + " FILE:" + pyfilename) #Domoticz.Error("Security Finding(IPr):" + regexFound[rex] + " LINE: " + str(lineNum) + " FILE:" + pyfilename) # ips["IP" + str(lineNum)] = (regexFound[rex], "Import") #rex = 0 #regexFound = re.findall('subprocess.Popen', text) #if regexFound: #regexFound[rex] = regexFound[rex].strip('"]') #Domoticz.Error("Security Finding(IPregex):" + str(regexFound) + " LINE: " + str(lineNum) + " FILE:" + pyfilename) # for rex in range(0,len(regexFound)): # if ((str(text).strip() not in self.SecPolUserList["Global"]) and (str(text).strip() not in self.SecPolUserList[pypluginid]) and (str(text).strip() != "") and (mid(text,0,1) != "#")): # Domoticz.Error("Security Finding(SUB):-->" + str(text) + "<-- LINE: " + str(lineNum) + " FILE:" + pyfilename) #Domoticz.Error("Security Finding(IPr):" + regexFound[rex] + " LINE: " + str(lineNum) + " FILE:" + pyfilename) # ips["IP" + str(lineNum)] = (regexFound[rex], "Subprocess") #rex = 0 #regexFound = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', text) #paramFound = re.findall(r'<param field=',text) #if ((regexFound) and not (paramFound)): #regexFound[rex] = regexFound[rex].strip('"]') #Domoticz.Error("Security Finding(IPregex):" + str(regexFound) + " LINE: " + str(lineNum) + " FILE:" + pyfilename) # for rex in range(0,len(regexFound)): # if ((str(text).strip() not in self.SecPolUserList[pypluginid]) and (str(text).strip() != "") and (mid(text,0,1) != "#")): # Domoticz.Error("Security Finding(HTTP):-->" + str(text) + "<-- LINE: " + str(lineNum) + " FILE:" + pyfilename) #Domoticz.Error("Security Finding(IPr):" + regexFound[rex] + " LINE: " + str(lineNum) + " FILE:" + pyfilename) # ips["IP" + str(lineNum)] = (regexFound[rex], "HTTP Address") lineNum = lineNum + 1 file.close() Domoticz.Debug("IPS Table contents are:" + str(ips))
def onCommand(Unit, Command, Level, Hue): global sendCommand, isRunning, learnedCommand Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level) + " , Connected : " + str(isConnected)) Command = Command.strip() if (Command == 'Set Level'): if (Unit == 1): # Command selector if (Level == 10): learn() if (Level == 20): sendCommand = learnedCommand if learnedCommand == "None": Domoticz.Log('Nothing to send') else: send() if (Level == 30): if learnedCommand == "None": Domoticz.Log('Nothing to save') else: custom = "" if save(): UpdateDevice(1, 0, 'Off') learnedCommand = "None" if (Level == 40): if learnedCommand == "None": Domoticz.Log('Nothing to reset') else: reset() elif (Unit == 255): if (Level == 10): if startWeb(): isRunning = True UpdateDevice(255, 1, '10') else: UpdateDevice(255, 0, 'Off') Domoticz.Error('Not able to start Web server') if (Level == 20): if createIniImport(): UpdateDevice(255, 1, '20') else: UpdateDevice(255, 0, 'Off') Domoticz.Error('Error with json files to import') if (Level == 30): clear = False if manageIniImport(clear): UpdateDevice(255, 1, '30') else: UpdateDevice(255, 0, 'Off') if (Level == 40): clear = True if manageIniImport(clear): UpdateDevice(255, 1, '40') else: UpdateDevice(255, 0, 'Off') else: Domoticz.Error('Unit unknown') elif (Command == 'On'): if (Unit == 1 and Devices[1].Name.endswith("Discover")): # Discovery if Discover(): UpdateDevice(Unit, 1, 'Found : ' + str(len(brodevices)) + ' device') else: Domoticz.Error('Not able to find Broadlink device') elif (Unit == 254 and RemoteCommand != ""): UpdateDevice(Unit, 1, 'On') else: genCommand(Unit) elif (Command == 'Off'): if (Unit == 1 and Devices[1].Name.endswith("Discover")): # Discovery UpdateDevice(Unit, 0, 'Off') else: try: UpdateDevice(Unit, 0, 'Off') except: Domoticz.Error('Unit error update') raise elif (Unit == 254): if remoteSend(Command): UpdateDevice(Unit, 1, Command) else: UpdateDevice(Unit, 1, 'undefined') else: Domoticz.Error('Unknown command') return True
def onStart(self): Domoticz.Status("onStart called - Zigate plugin V 3.0.4") if Parameters["Mode6"] != "0": Domoticz.Debugging(int(Parameters["Mode6"])) DumpConfigToLog() if Parameters["Mode1"] == "USB": z_var.transport = "USB" z_var.ZigateConn = Domoticz.Connection( Name="ZiGate", Transport="Serial", Protocol="None", Address=Parameters["SerialPort"], Baud=115200) z_var.ZigateConn.Connect() if Parameters["Mode1"] == "Wifi": z_var.transport = "Wifi" z_var.ZigateConn = Domoticz.Connection( Name="Zigate", Transport="TCP/IP", Protocol="None ", Address=Parameters["Address"], Port=Parameters["Port"]) z_var.ZigateConn.Connect() # CLD CLD # Import PluginConf.txt tmpPluginConf = "" with open(Parameters["HomeFolder"] + "PluginConf.txt", 'r') as myPluginConfFile: tmpPluginConf += myPluginConfFile.read().replace('\n', '') myPluginConfFile.close() Domoticz.Debug("PluginConf.txt = " + str(tmpPluginConf)) self.PluginConf = eval(tmpPluginConf) z_var.CrcCheck = 1 if self.PluginConf['CrcCheck'] == "False" or self.PluginConf[ 'CrcCheck'] == "Off": z_var.CrcCheck = 0 z_var.ReqRcv = bytearray() for x in Devices: # initialise listeofdevices avec les devices en bases domoticz ID = Devices[x].DeviceID self.ListOfDevices[ID] = {} try: self.ListOfDevices[ID] = eval(Devices[x].Options['Zigate']) except: Domoticz.Error("Error loading Device " + str(Devices[x]) + " not loaded int Zigate Plugin!") else: Domoticz.Log("Device : [" + str(x) + "] ID = " + ID + " Options['Zigate'] = " + Devices[x].Options['Zigate'] + " loaded into self.ListOfDevices") #Import DeviceConf.txt tmpread = "" with open(Parameters["HomeFolder"] + "DeviceConf.txt", 'r') as myfile: tmpread += myfile.read().replace('\n', '') myfile.close() Domoticz.Debug("DeviceConf.txt = " + str(tmpread)) self.DeviceConf = eval(tmpread) #Import DeviceList.txt with open(Parameters["HomeFolder"] + "DeviceList.txt", 'r') as myfile2: Domoticz.Debug("DeviceList.txt open ") for line in myfile2: (key, val) = line.split(":", 1) key = key.replace(" ", "") key = key.replace("'", "") z_tools.CheckDeviceList(self, key, val) return
def get_string_value(self, value, device): Domoticz.Error( 'Device with alias "' + self.alias + '" for key ' + self.value_key + ' can not calculate string value' )
def set_configuration(self): Domoticz.Debug("set_configuration. IP-Connected: %d" % (self.ipConnected)) if self.ipConnected == 0: write_to_log( STATUSLEVELERROR, "Set configuration. Not connected to the Master Brick. Check settings, correct and restart Domoticz." ) return try: state = SWITCHON if Devices[UNITBACKLIGHT].nValue == 1 else SWITCHOFF set_backlight(self, state) state = SWITCHON if Devices[UNITCURSOR].nValue == 1 else SWITCHOFF set_cursor(self, state) state = SWITCHON if Devices[UNITBLINKING].nValue == 1 else SWITCHOFF set_blinking(self, state) # Set Custom Characters with index 0-7 as max 8 custom characters can be defined. # dzVents Lua scripts: # The \ character needs to be escaped, i.e. line = string.format(line, l, p, "\\u0008", domoticz.helpers.isnowhhmm(domoticz) ) # Ensure to write in unicode \u00NN and NOT \xNN - Example: lcdDev.write_line(0, 0, "Battery: " + "\u0008") # JSON has no hex escape \xNN but supports unicode escape \uNNNN # # Example custom character definition and write to the lcd: # battery = [14,27,17,17,17,17,17,31] # clock = [31,17,10,4,14,31,31,0] # lcdDev.set_custom_character(0, clock) # # JSON File # Read the custom characters from JSON array file as defined by constant CUSTOMCHARFILE # JSON format examplewith 2 characters: # [ # {"id":0,"name":"battery","char":"14,27,17,17,17,17,17,31"}, # {"id":1,"name":"clock","char":"31,17,10,4,14,31,31,0"} # ] # Use exception handling in case file not found # The id must be in range 0-7 as max 8 custom characters can be defined try: with open(CUSTOMCHARFILE) as f: json_char_array = json.load(f) Domoticz.Debug("Customchar: characters: %d" % (len(json_char_array))) if len(json_char_array) > 0: for item in json_char_array: id = int(item["id"]) name = item["name"] char = item["char"].strip().split(",") # Check if the character id is in range 0-7 if id >= 0 and id <= 7: self.lcdDev.set_custom_character(id, char) Domoticz.Debug( "Customchar: Index=%d,Name=%s,Char=%s" % (id, name, item["char"])) else: Domoticz.Error( "Customchar: Index=%d not in range 0-7." % (id)) else: Domoticz.Error( "Customchar: No or wrong characters defined.") except: Domoticz.Error("Customchar: Can not open file=%s." % (CUSTOMCHARFILE)) Domoticz.Debug("set_configuration OK") except: write_to_log( STATUSLEVELERROR, "Set configuration failed. Check settings, correct and restart Domoticz." ) return
def create_device(self, unit, device_id, device_name): Domoticz.Error( 'Unable to create device to handle "' + self.value_key + '" value for device "' + device_name + '"' )
def get_numeric_value(self, value, device): Domoticz.Error( 'Device with alias "' + self.alias + '" for key ' + self.value_key + ' can not calculate numeric value' )
def extractTagValue(tagName, XML): startPos = XML.find(tagName) endPos = XML.find(tagName, startPos+1) if ((startPos == -1) or (endPos == -1)): Domoticz.Error("'"+tagName+"' not found in supplied XML") return XML[startPos+len(tagName)+1:endPos-2]
def MajDomoDevice(self, Devices, DeviceID, Ep, clusterID, value, Color_=''): Domoticz.Debug("MajDomoDevice - Device ID : " + str(DeviceID) + " - Device EP : " + str(Ep) + " - Type : " + str(clusterID) + " - Value : " + str(value) + " - Hue : " + str(Color_)) x = 0 Type = TypeFromCluster(clusterID) Domoticz.Debug("MajDomoDevice - Type = " + str(Type)) for x in Devices: if Devices[x].DeviceID == str(DeviceID): DOptions = Devices[x].Options Dtypename = DOptions['TypeName'] DOptions['Zigate'] = str(self.ListOfDevices[DeviceID]) SignalLevel = self.ListOfDevices[DeviceID]['RSSI'] Domoticz.Debug("MajDomoDevice - Dtypename = " + str(Dtypename)) if Dtypename == "PowerMeter" and clusterID == "000c": nValue = float(value) sValue = value Domoticz.Debug("MajDomoDevice PowerMeter : " + sValue) UpdateDevice_v2(Devices, x, nValue, str(sValue), DOptions, SignalLevel) if Dtypename == "Temp+Hum+Baro": #temp+hum+Baro xiaomi Bar_forecast = '0' # Set barometer forecast to 0 (No info) if Type == "Temp": CurrentnValue = Devices[x].nValue CurrentsValue = Devices[x].sValue Domoticz.Debug("MajDomoDevice temp CurrentsValue : " + CurrentsValue) SplitData = CurrentsValue.split(";") NewSvalue = '%s;%s;%s;%s;%s' % (str(value), SplitData[1], SplitData[2], SplitData[3], Bar_forecast) Domoticz.Debug("MajDomoDevice temp NewSvalue : " + NewSvalue) UpdateDevice_v2(Devices, x, 0, str(NewSvalue), DOptions, SignalLevel) if Type == "Humi": CurrentnValue = Devices[x].nValue CurrentsValue = Devices[x].sValue Domoticz.Debug("MajDomoDevice hum CurrentsValue : " + CurrentsValue) SplitData = CurrentsValue.split(";") NewSvalue = '%s;%s;%s;%s;%s' % (SplitData[0], str(value), SplitData[2], SplitData[3], Bar_forecast) Domoticz.Debug("MajDomoDevice hum NewSvalue : " + NewSvalue) UpdateDevice_v2(Devices, x, 0, str(NewSvalue), DOptions, SignalLevel) if Type == "Baro": # barometer CurrentnValue = Devices[x].nValue CurrentsValue = Devices[x].sValue Domoticz.Debug("MajDomoDevice baro CurrentsValue : " + CurrentsValue) SplitData = CurrentsValue.split(";") valueBaro = '%s;%s;%s;%s;%s' % (SplitData[0], SplitData[1], str(value), SplitData[3], Bar_forecast) UpdateDevice_v2(Devices, x, 0, str(valueBaro), DOptions, SignalLevel) if Dtypename == "Temp+Hum": #temp+hum xiaomi if Type == "Temp": CurrentnValue = Devices[x].nValue CurrentsValue = Devices[x].sValue Domoticz.Debug("MajDomoDevice temp CurrentsValue : " + CurrentsValue) SplitData = CurrentsValue.split(";") NewSvalue = '%s;%s;%s' % (str(value), SplitData[1], SplitData[2]) Domoticz.Debug("MajDomoDevice temp NewSvalue : " + NewSvalue) UpdateDevice_v2(Devices, x, 0, str(NewSvalue), DOptions, SignalLevel) if Type == "Humi": CurrentnValue = Devices[x].nValue CurrentsValue = Devices[x].sValue Domoticz.Debug("MajDomoDevice hum CurrentsValue : " + CurrentsValue) SplitData = CurrentsValue.split(";") NewSvalue = '%s;%s;%s' % (SplitData[0], str(value), SplitData[2]) Domoticz.Debug("MajDomoDevice hum NewSvalue : " + NewSvalue) UpdateDevice_v2(Devices, x, 0, str(NewSvalue), DOptions, SignalLevel) if Type == Dtypename == "Temp": # temperature UpdateDevice_v2(Devices, x, 0, str(value), DOptions, SignalLevel) if Type == Dtypename == "Humi": # humidite UpdateDevice_v2(Devices, x, int(value), "0", DOptions, SignalLevel) if Type == Dtypename == "Baro": # barometre CurrentnValue = Devices[x].nValue CurrentsValue = Devices[x].sValue Domoticz.Debug("MajDomoDevice baro CurrentsValue : " + CurrentsValue) SplitData = CurrentsValue.split(";") valueBaro = '%s;%s' % (value, SplitData[0]) UpdateDevice_v2(Devices, x, 0, str(valueBaro), DOptions, SignalLevel) # CLD CLD if Dtypename == "Plug" and Type == "Switch": if value == "01": UpdateDevice_v2(Devices, x, 1, "On", DOptions, SignalLevel) elif value == "00": UpdateDevice_v2(Devices, x, 0, "Off", DOptions, SignalLevel) if Type == "Door" and Dtypename == "Door": # Door / Window if value == "01": state = "Open" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) elif value == "00": state = "Closed" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) if Type == "Switch" and Dtypename == "Door": # porte / fenetre if value == "01": state = "Open" #Correction Thiklop : value n'est pas toujours un entier. Exécution de l'updatedevice dans le test UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) elif value == "00": state = "Closed" #Correction Thiklop : idem UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) #Fin de la correction if Type == Dtypename == "Switch": # switch simple if value == "01": state = "On" elif value == "00": state = "Off" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) if value == "01": state = "Open" elif value == "00": state = "Closed" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) if Type == "Switch" and Dtypename == "Button": # boutton simple if value == "01": state = "On" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) else: return if Type == "Switch" and Dtypename == "Water": # detecteur d eau if value == "01": state = "On" elif value == "00": state = "Off" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) if Type == "Switch" and Dtypename == "Smoke": # detecteur de fume if value == "01": state = "On" elif value == "00": state = "Off" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) if Type == "Switch" and Dtypename == "MSwitch": # multi lvl switch if value == "00": state = "00" elif value == "01": state = "10" elif value == "02": state = "20" elif value == "03": state = "30" elif value == "04": state = "40" else: state = "0" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) if Type == "Switch" and Dtypename == "DSwitch": # double switch avec EP different ====> a voir pour passer en deux switch simple ... a corriger/modifier if Ep == "01": if value == "01" or value == "00": state = "10" data = "01" elif Ep == "02": if value == "01" or value == "00": state = "20" data = "02" elif Ep == "03": if value == "01" or value == "00": state = "30" data = "03" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) if Type == "Switch" and Dtypename == "DButton": # double bouttons avec EP different ====> a voir pour passer en deux bouttons simple ... idem DSwitch ??? if Ep == "01": if value == "01" or value == "00": state = "10" data = "01" elif Ep == "02": if value == "01" or value == "00": state = "20" data = "02" elif Ep == "03": if value == "01" or value == "00": state = "30" data = "03" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) if Type == "XCube" and Dtypename == "Aqara" and Ep == "02": #Magic Cube Acara Domoticz.Debug( "MajDomoDevice - XCube update device with data = " + str(value)) UpdateDevice_v2(Devices, x, int(value), str(value), DOptions, SignalLevel) if Type == "XCube" and Dtypename == "Aqara" and Ep == "03": #Magic Cube Acara Rotation Domoticz.Debug( "MajDomoDevice - XCube update device with data = " + str(value)) UpdateDevice_v2(Devices, x, int(value), str(value), DOptions, SignalLevel) if Type == Dtypename == "XCube" and Ep == "02": # cube xiaomi if value == "0000": #shake state = "10" data = "01" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) elif value == "0204" or value == "0200" or value == "0203" or value == "0201" or value == "0202" or value == "0205": #tap state = "50" data = "05" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) elif value == "0103" or value == "0100" or value == "0104" or value == "0101" or value == "0102" or value == "0105": #Slide state = "20" data = "02" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) elif value == "0003": #Free Fall state = "70" data = "07" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) elif value >= "0004" and value <= "0059": #90° state = "30" data = "03" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) elif value >= "0060": #180° state = "90" data = "09" UpdateDevice_v2(Devices, x, int(data), str(state), DOptions, SignalLevel) if Type == Dtypename == "Lux": UpdateDevice_v2(Devices, x, int(value), str(value), DOptions, SignalLevel) if Type == Dtypename == "Motion": #Correction Thiklop : value pas toujours un entier : #'onMessage' failed 'ValueError':'invalid literal for int() with base 10: '00031bd000''. # UpdateDevice dans le if if value == "01": state = "On" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) elif value == "00": state = "Off" UpdateDevice_v2(Devices, x, int(value), str(state), DOptions, SignalLevel) #Fin de correction if Type == Dtypename == "LvlControl": try: sValue = round((int(value, 16) / 255) * 100) except: Domoticz.Error("MajDomoDevice - value is not an int = " + str(value)) else: Domoticz.Debug("MajDomoDevice LvlControl - DvID : " + str(DeviceID) + " - Device EP : " + str(Ep) + " - Value : " + str(sValue) + " sValue : " + str(Devices[x].sValue)) nValue = 2 if str(nValue) != str( Devices[x].nValue) or str(sValue) != str( Devices[x].sValue): Domoticz.Debug("MajDomoDevice update DevID : " + str(DeviceID) + " from " + str(Devices[x].nValue) + " to " + str(nValue)) UpdateDevice_v2(Devices, x, str(nValue), str(sValue), DOptions, SignalLevel) if Type == Dtypename == "ColorControl": try: sValue = round((int(value, 16) / 255) * 100) except: Domoticz.Error("MajDomoDevice - value is not an int = " + str(value)) else: Domoticz.Debug("MajDomoDevice ColorControl - DvID : " + str(DeviceID) + " - Device EP : " + str(Ep) + " - Value : " + str(sValue) + " sValue : " + str(Devices[x].sValue)) nValue = 2 if str(nValue) != str(Devices[x].nValue) or str(sValue) != str( Devices[x].sValue) or str(Color_) != str( Devices[x].Color): Domoticz.Debug("MajDomoDevice update DevID : " + str(DeviceID) + " from " + str(Devices[x].nValue) + " to " + str(nValue)) UpdateDevice_v2(Devices, x, str(nValue), str(sValue), DOptions, SignalLevel, Color_)
def _miktCommand(self, words_list): if self.miktLoggedIn and self.miktConn.Connected(): try: self.miktConn.Send(sentence_pack(words_list)) except PackException as e: Domoticz.Error('PackException [%s]' % str(e))
def UpdateDevice_v2(self, Devices, Unit, nValue, sValue, BatteryLvl, SignalLvl, Color_="", ForceUpdate_=False): if Unit not in Devices: Domoticz.Error("Droping Update to Device due to Unit %s not found" % Unit) return if Devices[Unit].DeviceID not in self.IEEE2NWK: Domoticz.Error( "Droping Update to Device due to DeviceID %s not found in IEEE2NWK %s" % (Devices[Unit].DeviceID, str(self.IEEE2NWK))) return self.log.logging( "Widget", "Debug", "UpdateDevice_v2 %s:%s:%s %3s:%3s:%5s (%15s)" % (nValue, sValue, Color_, BatteryLvl, SignalLvl, ForceUpdate_, Devices[Unit].Name), self.IEEE2NWK[Devices[Unit].DeviceID], ) # Make sure that the Domoticz device still exists (they can be deleted) before updating it if Unit not in Devices: return if ((Devices[Unit].nValue != int(nValue)) or (Devices[Unit].sValue != sValue) or (Color_ != "" and Devices[Unit].Color != Color_) or ForceUpdate_ or Devices[Unit].BatteryLevel != int(BatteryLvl) or Devices[Unit].TimedOut): if (self.pluginconf.pluginConf["forceSwitchSelectorPushButton"] and ForceUpdate_ and (Devices[Unit].nValue == int(nValue)) and (Devices[Unit].sValue == sValue)): # Due to new version of Domoticz which do not log in case we Update the same value nReset = 0 sReset = "0" if "LevelOffHidden" in Devices[Unit].Options: LevelOffHidden = Devices[Unit].Options["LevelOffHidden"] if LevelOffHidden == "false": sReset = "00" Devices[Unit].Update(nValue=nReset, sValue=sReset) if Color_: Devices[Unit].Update( nValue=int(nValue), sValue=str(sValue), Color=Color_, SignalLevel=int(SignalLvl), BatteryLevel=int(BatteryLvl), TimedOut=0, ) else: Devices[Unit].Update( nValue=int(nValue), sValue=str(sValue), SignalLevel=int(SignalLvl), BatteryLevel=int(BatteryLvl), TimedOut=0, ) if self.pluginconf.pluginConf["logDeviceUpdate"]: Domoticz.Log("UpdateDevice - (%15s) %s:%s" % (Devices[Unit].Name, nValue, sValue)) self.log.logging( "Widget", "Debug", "---> [Unit: %s] %s:%s:%s %s:%s %s (%15s)" % (Unit, nValue, sValue, Color_, BatteryLvl, SignalLvl, ForceUpdate_, Devices[Unit].Name), self.IEEE2NWK[Devices[Unit].DeviceID], )
def write_to_log(level, text): if level == STATUSLEVELOK: Domoticz.Log(text) if level == STATUSLEVELERROR: Domoticz.Error(text) return
def execute(self, params): Domoticz.Error('Command is not implemented')
def onMessage(self, Connection, Data): Domoticz.Debug("onMessage: data received: Data : '" + str(Data) + "'") status = int(Data["Status"]) if status == 200: apiUrl = "" try: #apiResponse sometimes contains invalid data, catch the exception if "Data" in Data: responseText = Data["Data"].decode("utf-8", "ignore") else: responseText = "" Domoticz.Debug("onMessage: no data found in data") return apiResponse = json.loads(responseText) apiUrl = apiResponse["components"]["api"] apiData = apiResponse["data"] except json.JSONDecodeError as err: msg, doc, pos = err.args Domoticz.Error(msg) apiResponse = None Domoticz.Debug("The faulty message: '" + doc) if "api/v2/Common/CrossLogin" in apiUrl: Domoticz.Debug("message received: CrossLogin") if apiData == 'Null': Domoticz.Log("SEMS API Token not received") self.goodWeAccount.tokenAvailable = False self.httpConn.Disconnect() #self.httpConn = None else: Domoticz.Debug("message apiData: '" + str(apiData) + "'") self.goodWeAccount.token = apiData Domoticz.Debug("SEMS API Token: " + json.dumps(self.goodWeAccount.token)) self.goodWeAccount.tokenAvailable = True #request list of stations on this account Connection.Send(self.goodWeAccount.stationListRequest()) elif "/api/v2/HistoryData/QueryPowerStationByHistory" in apiUrl: Domoticz.Debug("message received: QueryPowerStationByHistory") if apiData is None or len(apiData) == 0: Domoticz.Log("Power station history not received") self.httpConn.Disconnect() #self.httpConn = None else: Domoticz.Debug("message apiData: '" + str(apiData) + "'") for stations in apiData["list"]: for data in stations: Domoticz.Debug("station element: '" + str(data) + "', value: '" + str(stations[data]) + "'") for key, station in enumerate(apiData["list"]): if len(Parameters["Mode1"]) <= 0 or ( len(Parameters["Mode1"]) > 0 and station["id"] == Parameters["Mode1"]): #add all found stations if no ID entered, else only log the one that matches the ID self.goodWeAccount.createStation(key, station) Domoticz.Log("Station found: " + station["id"]) Connection.Send( self.goodWeAccount.stationDataRequest( self.baseDeviceIndex)) elif "api/v2/PowerStation/GetMonitorDetailByPowerstationId" in apiUrl: Domoticz.Debug( "message received: GetMonitorDetailByPowerstationId") #Domoticz.Debug("message: '" + apiData + "'") if apiData is None or len(apiData) == 0: Domoticz.Error( "No station data received from GoodWe SEMS API (Station ID: " + str(self.goodWeAccount.powerStationList[ self.goodWeAccount.powerStationIndex]) + ")") self.goodWeAccount.tokenAvailable = False else: #Domoticz.Debug("message apiData: '" + str(apiData) + "'") Domoticz.Log( "Station data received from GoodWe SEMS API ('" + str(self.goodWeAccount.powerStationList[ self.goodWeAccount.powerStationIndex]) + "', index : '" + str(self.goodWeAccount.powerStationIndex) + "')") theStation = self.goodWeAccount.powerStationList[ self.goodWeAccount.powerStationIndex] for inverter in apiData["inverter"]: Domoticz.Debug("inverter found with SN: '" + inverter["sn"] + "'") if inverter["sn"] in theStation.inverters: theStation.inverters[inverter["sn"]].createDevices( Devices) #invertFull = inverter["invert_full"] #Domoticz.Debug("found in inverter: '" + str(inverter) + "'") #Domoticz.Debug("found in inverter full: '" + str(invertFull) + "'") # for data in inverter: # Domoticz.Debug("data in inverter: '" + str(data) + "', value '" + str(inverter[data]) + "'") Domoticz.Debug("Details d in inverter: '" + str(inverter['d']) + "'") theInverter = theStation.inverters[inverter["sn"]] if len(inverter['fault_message']) > 0: Domoticz.Log( "Fault message from GoodWe inverter (SN: " + inverter["sn"] + "): '" + str(inverter['fault_message']) + "'") Domoticz.Log("Status of GoodWe inverter (SN: " + inverter["sn"] + "): '" + str(inverter["status"]) + ' ' + self.goodWeAccount.INVERTER_STATE[ inverter["status"]] + "'") Devices[theInverter.inverterStateUnit].Update( nValue=inverter["status"] + 1, sValue=str((inverter["status"] + 2) * 10)) if self.goodWeAccount.INVERTER_STATE[ inverter["status"]] == 'generating': Domoticz.Debug("inverter generating, log temp") UpdateDevice( theInverter.inverterTemperatureUnit, 0, str(inverter["tempperature"])) UpdateDevice(theInverter.outputFreq1Unit, 0, str(inverter["d"]["fac1"])) UpdateDevice(theInverter.outputCurrentUnit, 0, str(inverter["output_current"]), AlwaysUpdate=True) UpdateDevice(theInverter.outputVoltageUnit, 0, str(inverter["output_voltage"]), AlwaysUpdate=True) UpdateDevice(theInverter.outputPowerUnit, 0, str(inverter["output_power"]) + ";" + str(inverter["etotal"] * 1000), AlwaysUpdate=True) inputVoltage, inputAmps = inverter[ "pv_input_1"].split('/') inputPower = (float(inputVoltage[:-1])) * (float( inputAmps[:-1])) #Domoticz.Debug("power calc = V: '"+inputVoltage[:-1]+"', A: '"+inputAmps[:-1]+"', power: W: '" + str(inputPower) + "'") UpdateDevice(theInverter.inputVoltage1Unit, 0, inputVoltage, AlwaysUpdate=True) UpdateDevice(theInverter.inputAmps1Unit, 0, inputAmps, AlwaysUpdate=True) UpdateDevice(theInverter.inputPower1Unit, 0, str(inputPower) + ";0", AlwaysUpdate=True) #test to log cumulative counting previousPower, currentCount = Devices[ theInverter.inputPowerTest].sValue.split(";") newCounter = inputPower + float(currentCount) UpdateDevice(theInverter.inputPowerTest, 0, str(inputPower) + ";" + str(newCounter), AlwaysUpdate=True) Domoticz.Debug( "test previousPower, currentCount, newCounter = " + str(previousPower) + ", " + str(currentCount) + ", " + str(newCounter)) if "pv_input_2" in inverter: Domoticz.Debug("Second string found") inputVoltage, inputAmps = inverter[ "pv_input_2"].split('/') UpdateDevice(theInverter.inputVoltage2Unit, 0, inputVoltage, AlwaysUpdate=True) UpdateDevice(theInverter.inputAmps2Unit, 0, inputAmps, AlwaysUpdate=True) inputPower = (float(inputVoltage[:-1])) * ( float(inputAmps[:-1])) UpdateDevice(theInverter.inputPower2Unit, 0, str(inputPower) + ";0", AlwaysUpdate=True) if "pv_input_3" in inverter: Domoticz.Debug("Third string found") inputVoltage, inputAmps = inverter[ "pv_input_3"].split('/') UpdateDevice(theInverter.inputVoltage3Unit, 0, inputVoltage, AlwaysUpdate=True) UpdateDevice(theInverter.inputAmps3Unit, 0, inputAmps, AlwaysUpdate=True) inputPower = float(inputVoltage[:-1]) * float( inputAmps[:-1]) UpdateDevice(theInverter.inputPower3Unit, 0, str(inputPower) + ";0", AlwaysUpdate=True) if "pv_input_4" in inverter: Domoticz.Debug("Fourth string found") inputVoltage, inputAmps = inverter[ "pv_input_4"].split('/') UpdateDevice(theInverter.inputVoltage4Unit, 0, inputVoltage, AlwaysUpdate=True) UpdateDevice(theInverter.inputAmps4Unit, 0, inputAmps, AlwaysUpdate=True) inputPower = float(inputVoltage[:-1]) * float( inputAmps[:-1]) UpdateDevice(theInverter.inputPower4Unit, 0, str(inputPower) + ";0", AlwaysUpdate=True) else: Domoticz.Log("Unknown inverter found with S/N: '" + inverter["sn"] + "'.") if self.goodWeAccount.powerStationIndex == ( len(self.goodWeAccount.powerStationList) - 1): Domoticz.Debug("Last station of list found") if self.runAgain > 2: Domoticz.Log( "Next active heartbeat far away, disconnecting and dropping connection." ) self.httpConn.Disconnect() #self.httpConn = None #Domoticz.Log("Updated " + str(len(Devices)) + " device(s) for " + str(len(self.goodWeAccount.powerStationList)) + " station(s) with " + str(int(self.baseDeviceIndex / self.maxDeviceIndex)) + " inverter(s)") self.devicesUpdated = True else: Domoticz.Debug("Retrieving next station data (ID: " + self.goodWeAccount.powerStationList[ self.baseDeviceIndex] + ")") self.baseDeviceIndex += 1 Connection.Send( self.goodWeAccount.stationDataRequest( self.baseDeviceIndex)) elif status == 302: Domoticz.Error("GoodWe SEMS API returned a Page Moved Error.") elif status == 400: Domoticz.Error("GoodWe SEMS API returned a Bad Request Error.") elif (status == 500): Domoticz.Error("GoodWe SEMS API returned a Server Error.") else: Domoticz.Error("GoodWe SEMS API returned a status: " + str(status))
def onMessage(self, Connection, Data): Domoticz.Debug("onMessage called on Connection " + str(Connection) + " Data = '" + str(Data) + "'") ### CLD FrameIsKo = 0 # Version 3 - Binary reading to avoid mixing end of Frame - Thanks to CLDFR z_var.ReqRcv += Data # Add the incoming data Domoticz.Debug("onMessage incoming data : '" + str(binascii.hexlify(z_var.ReqRcv).decode('utf-8')) + "'") # Zigate Frames start with 0x01 and finished with 0x03 # It happens that we get some while 1: # Loop until we have 0x03 Zero1 = -1 Zero3 = -1 idx = 0 for val in z_var.ReqRcv[0:len(z_var.ReqRcv)]: if Zero1 == -1 and Zero3 == -1 and val == 1: # Do we get a 0x01 Zero1 = idx # we have identify the Frame start if Zero1 != -1 and val == 3: # If we have already started a Frame and do we get a 0x03 Zero3 = idx + 1 break # If we got 0x03, let process the Frame idx += 1 if Zero3 == -1: # No 0x03 in the Buffer, let's breat and wait to get more data return Domoticz.Debug("onMessage Frame : Zero1=" + str(Zero1) + " Zero3=" + str(Zero3)) # CLD CLD if Zero1 != 0: Domoticz.Log( "onMessage : we have probably lost some datas, zero1 = " + str(Zero1)) # uncode the frame BinMsg = bytearray() iterReqRcv = iter(z_var.ReqRcv[Zero1:Zero3]) for iByte in iterReqRcv: # for each received byte if iByte == 2: # Coded flag ? iByte = next(iterReqRcv) ^ 16 # then uncode the next value BinMsg.append(iByte) # copy z_var.ReqRcv = z_var.ReqRcv[ Zero3:] # What is after 0x03 has to be reworked. # Check length Zero1, MsgType, Length, ReceivedChecksum = struct.unpack( '>BHHB', BinMsg[0:6]) ### Domoticz.Debug("onMessage Frame CLD : " + str(Zero1) + " " + str(MsgType) + " " + str(Length) ) ComputedLength = Length + 7 ReceveidLength = len(BinMsg) Domoticz.Debug("onMessage Frame length : " + str(ComputedLength) + " " + str(ReceveidLength)) # For testing purpose if ComputedLength != ReceveidLength: FrameIsKo = 1 Domoticz.Error("onMessage : Frame size is bad, computed = " + str(ComputedLength) + " received = " + str(ReceveidLength)) # Compute checksum ComputedChecksum = 0 for idx, val in enumerate(BinMsg[1:-1]): if idx != 4: # Jump the checksum itself ComputedChecksum ^= val Domoticz.Debug("onMessage Frame : ComputedChekcum=" + str(ComputedChecksum) + " ReceivedChecksum=" + str(ReceivedChecksum)) # For testing purpose if ComputedChecksum != ReceivedChecksum and z_var.CrcCheck == 1: FrameIsKo = 1 Domoticz.Error("onMessage : Frame CRC is bad, computed = " + str(ComputedChecksum) + " received = " + str(ReceivedChecksum)) AsciiMsg = binascii.hexlify(BinMsg).decode('utf-8') # ZigateDecode(self, AsciiMsg) # decode this Frame if FrameIsKo == 0: z_input.ZigateRead(self, Devices, AsciiMsg) # process this frame Domoticz.Debug("onMessage Remaining Frame : " + str(binascii.hexlify(z_var.ReqRcv).decode('utf-8'))) return
def onMessage(self, Connection, Data): Status = int(Data["Status"]) if (Status == 200 and not self.logged_in): self.logged_in = True Domoticz.Status("Tahoma auth succeed") tmp = Data["Headers"] self.cookie = tmp["Set-Cookie"] elif (Status == 401): strData = Data["Data"].decode("utf-8", "ignore") Domoticz.Error("Tahoma auth error") self.logged_in = False self.cookie = None if ("Too many" in strData): Domoticz.Error("Too much connexions must wait") self.heartbeat = True return if ("Bad credentials" in strData): Domoticz.Error( "Bad credentials please update credentials and restart device" ) self.heartbeat = False return if (not self.logged_in): Login = str(Parameters["Username"]) pwd = str(Parameters["Password"]) Headers = { 'Host': self.srvaddr, "Connection": "keep-alive", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Content-Type": "application/x-www-form-urlencoded" } postData = "userId=" + urllib.parse.quote( Login) + "&userPassword="******"" self.httpConn.Send({ 'Verb': 'POST', 'Headers': Headers, 'URL': '/enduser-mobile-web/enduserAPI/login', 'Data': postData }) self.heartbeat_delay = 0 return elif (Status == 200 and self.logged_in and self.heartbeat and self.refresh): self.refresh = False Headers = { 'Host': self.srvaddr, "Connection": "keep-alive", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Content-Type": "application/x-www-form-urlencoded", "Cookie": self.cookie } self.httpConn.Send({ 'Verb': 'GET', 'Headers': Headers, 'URL': '/enduser-mobile-web/enduserAPI/setup/devices' }) return elif (Status == 200 and self.logged_in and self.heartbeat and (not self.refresh)): strData = Data["Data"].decode("utf-8", "ignore") if (not "uiClass" in strData): Domoticz.Debug(str(strData)) return self.devices = json.loads(strData) self.filtered_devices = list() for device in self.devices: Domoticz.Debug("Device name: " + device["label"] + " Device class: " + device["uiClass"]) if (((device["uiClass"] == "RollerShutter") or (device["uiClass"] == "ExteriorScreen") or (device["uiClass"] == "Screen") or (device["uiClass"] == "Awning") or (device["uiClass"] == "Pergola") or (device["uiClass"] == "GarageDoor") or (device["uiClass"] == "Window") or (device["uiClass"] == "VenetianBlind") or (device["uiClass"] == "ExteriorVenetianBlind")) and ((device["deviceURL"].startswith("io://")) or (device["deviceURL"].startswith("rts://")))): self.filtered_devices.append(device) if (len(Devices) == 0 and self.startup): count = 1 for device in self.filtered_devices: Domoticz.Status("Creating device: " + device["label"]) swtype = None if (device["deviceURL"].startswith("io://")): swtype = 16 elif (device["deviceURL"].startswith("rts://")): swtype = 6 Domoticz.Device(Name=device["label"], Unit=count, Type=244, Subtype=73, Switchtype=swtype, DeviceID=device["deviceURL"]).Create() if not (count in Devices): Domoticz.Error( "Device creation not allowed, please allow device creation" ) else: Domoticz.Status("Device created: " + device["label"]) count += 1 if ((len(Devices) < len(self.filtered_devices)) and len(Devices) != 0 and self.startup): Domoticz.Log("New device(s) detected") found = False for device in self.filtered_devices: for dev in Devices: UnitID = Devices[dev].Unit if Devices[dev].DeviceID == device["deviceURL"]: found = True break if (not found): idx = firstFree() swtype = None Domoticz.Status("Must create device: " + device["label"]) if (device["deviceURL"].startswith("io://")): swtype = 16 elif (device["deviceURL"].startswith("rts://")): swtype = 6 Domoticz.Device(Name=device["label"], Unit=idx, Type=244, Subtype=73, Switchtype=swtype, DeviceID=device["deviceURL"]).Create() if not (idx in Devices): Domoticz.Error( "Device creation not allowed, please allow device creation" ) else: Domoticz.Status("New device created: " + device["label"]) else: found = False self.startup = False for dev in Devices: for device in self.filtered_devices: if (Devices[dev].DeviceID == device["deviceURL"]) and ( device["deviceURL"].startswith("io://")): level = 0 status_l = False status = None states = device["states"] for state in states: if state["name"] == "core:ClosureState": level = state["value"] level = 100 - level status_l = True if status_l: if (Devices[dev].sValue): int_level = int(Devices[dev].sValue) else: int_level = 0 if (level != int_level): Domoticz.Log("Updating device:" + Devices[dev].Name) if (level == 0): Devices[dev].Update(0, "0") if (level == 100): Devices[dev].Update(1, "100") if (level != 0 and level != 100): Devices[dev].Update(2, str(level)) break elif (Status == 200 and (not self.heartbeat)): return else: Domoticz.Log("Return status" + str(Status))
def onStart(self): Domoticz.Debug("onStart called") if Parameters["Mode6"] == 'Debug': self.debug = True Domoticz.Debugging(1) DumpConfigToLog() else: Domoticz.Debugging(0) Domoticz.Log("Domoticz Node Name is:" + platform.node()) Domoticz.Log("Domoticz Platform System is:" + platform.system()) Domoticz.Debug("Domoticz Platform Release is:" + platform.release()) Domoticz.Debug("Domoticz Platform Version is:" + platform.version()) Domoticz.Log("Default Python Version is:" + str(sys.version_info[0]) + "." + str(sys.version_info[1]) + "." + str(sys.version_info[2]) + ".") if platform.system() == "Windows": Domoticz.Error("Windows Platform NOT YET SUPPORTED!!") return pluginText = "" pluginAuthor = "" pluginRepository = "" pluginKey = "" pluginKey = Parameters["Mode2"] pluginAuthor = self.plugindata[pluginKey][0] pluginRepository = self.plugindata[pluginKey][1] pluginText = self.plugindata[pluginKey][2] pluginBranch = self.plugindata[pluginKey][3] # GitHub branch to clone if (Parameters["Mode5"] == 'True'): Domoticz.Log("Plugin Security Scan is enabled") # Reading secpoluserFile and populating array of values secpoluserFile = str( os.getcwd()) + "/plugins/PP-MANAGER/secpoluser.txt" Domoticz.Debug("Checking for SecPolUser file on:" + secpoluserFile) if (os.path.isfile(secpoluserFile) == True): Domoticz.Log("secpoluser file found. Processing!!!") # Open the file secpoluserFileHandle = open(secpoluserFile) # use readline() to read the first line line = secpoluserFileHandle.readline() while line: if mid(line, 0, 4) == "--->": secpoluserSection = mid(line, 4, len(line)) Domoticz.Log("secpoluser settings found for plugin:" + secpoluserSection) if ((mid(line, 0, 4) != "--->") and (line.strip() != "") and (line.strip() != " ")): Domoticz.Debug("SecPolUserList exception (" + secpoluserSection.strip() + "):'" + line.strip() + "'") #SecPolUserList.append(line.strip()) #SecPolUserList[secpoluserSection].append(line.strip()) if secpoluserSection.strip( ) not in self.SecPolUserList: self.SecPolUserList[secpoluserSection.strip()] = [] self.SecPolUserList[secpoluserSection.strip()].append( line.strip()) # use realine() to read next line line = secpoluserFileHandle.readline() secpoluserFileHandle.close() Domoticz.Log("SecPolUserList exception:" + str(self.SecPolUserList)) else: self.SecPolUserList = {"Global": []} i = 0 path = str(os.getcwd()) + "/plugins/" for (path, dirs, files) in os.walk(path): for dir in dirs: if str(dir) != "": #self.UpdatePythonPlugin(pluginAuthor, pluginRepository, str(dir)) #parseFileForSecurityIssues(str(os.getcwd()) + "/plugins/PP-MANAGER/plugin.py") if (os.path.isfile( str(os.getcwd()) + "/plugins/" + str(dir) + "/plugin.py") == True): self.parseFileForSecurityIssues( str(os.getcwd()) + "/plugins/" + str(dir) + "/plugin.py", str(dir)) i += 1 if i >= 1: break # Reading exception file and populating array of values exceptionFile = str(os.getcwd()) + "/plugins/PP-MANAGER/exceptions.txt" Domoticz.Debug("Checking for Exception file on:" + exceptionFile) if (os.path.isfile(exceptionFile) == True): Domoticz.Log("Exception file found. Processing!!!") # Open the file f = open(exceptionFile) # use readline() to read the first line line = f.readline() while line: if ((line[:1].strip() != "#") and (line[:1].strip() != " ") and (line[:1].strip() != "")): Domoticz.Log("File ReadLine result:'" + line.strip() + "'") self.ExceptionList.append(line.strip()) # use realine() to read next line line = f.readline() f.close() Domoticz.Debug("self.ExceptionList:" + str(self.ExceptionList)) if Parameters["Mode4"] == 'All': Domoticz.Log("Updating All Plugins!!!") i = 0 path = str(os.getcwd()) + "/plugins/" for (path, dirs, files) in os.walk(path): for dir in dirs: if str(dir) != "": if str(dir) in self.plugindata: self.UpdatePythonPlugin(pluginAuthor, pluginRepository, str(dir)) elif str(dir) == "PP-MANAGER": Domoticz.Debug( "PP-Manager Folder found. Skipping!!") else: Domoticz.Log( "Plugin:" + str(dir) + " cannot be managed with PP-Manager!!.") i += 1 if i >= 1: break if Parameters["Mode4"] == 'AllNotify': Domoticz.Log("Collecting Updates for All Plugins!!!") i = 0 path = str(os.getcwd()) + "/plugins/" for (path, dirs, files) in os.walk(path): for dir in dirs: if str(dir) != "": if str(dir) in self.plugindata: self.CheckForUpdatePythonPlugin( pluginAuthor, pluginRepository, str(dir)) elif str(dir) == "PP-MANAGER": Domoticz.Debug( "PP-Manager Folder found. Skipping!!") else: Domoticz.Log( "Plugin:" + str(dir) + " cannot be managed with PP-Manager!!.") i += 1 if i >= 1: break if (Parameters["Mode4"] == 'SelectedNotify'): Domoticz.Log("Collecting Updates for Plugin:" + pluginKey) self.CheckForUpdatePythonPlugin(pluginAuthor, pluginRepository, pluginKey) if pluginKey == "Idle": Domoticz.Log("Plugin Idle") Domoticz.Heartbeat(60) else: Domoticz.Debug("Checking for dir:" + str(os.getcwd()) + "/plugins/" + pluginKey) #If plugin Directory exists if (os.path.isdir(str(os.getcwd()) + "/plugins/" + pluginKey)) == True: Domoticz.Debug("Folder for Plugin:" + pluginKey + " already exists!!!") #Domoticz.Debug("Set 'Python Plugin Manager'/ 'Domoticz plugin' attribute to 'idle' in order t.") if Parameters["Mode4"] == 'Selected': Domoticz.Debug("Updating Enabled for Plugin:" + pluginText + ".Checking For Update!!!") self.UpdatePythonPlugin(pluginAuthor, pluginRepository, pluginKey) Domoticz.Heartbeat(60) else: Domoticz.Log("Installation requested for Plugin:" + pluginText) Domoticz.Debug("Installation URL is:" + "https://github.com/" + pluginAuthor + "/" + pluginRepository) Domoticz.Debug("Current Working dir is:" + str(os.getcwd())) if pluginKey in self.plugindata: Domoticz.Log("Plugin Display Name:" + pluginText) Domoticz.Log("Plugin Author:" + pluginAuthor) Domoticz.Log("Plugin Repository:" + pluginRepository) Domoticz.Log("Plugin Key:" + pluginKey) Domoticz.Log("Plugin Branch:" + pluginBranch) self.InstallPythonPlugin(pluginAuthor, pluginRepository, pluginKey, pluginBranch) Domoticz.Heartbeat(60)
def handleTasks(self): try: Domoticz.Debug('> Entering tasks handler') while True: task = self.tasksQueue.get(block=True) if task is None: Domoticz.Debug('> Exiting task handler') try: self.myNest.terminate() except AttributeError: pass self.tasksQueue.task_done() break Domoticz.Debug('> Handling task: {}.'.format(task['Action'])) DeviceUpdate = False DeviceUpdateRequested = False if task['Action'] == 'StatusUpdate': DeviceUpdateRequested = True DeviceUpdate = self.myNest.UpdateDevices() elif task['Action'] == 'SetHeatingTemp': DeviceUpdateRequested = True DeviceUpdate = self.myNest.SetTemperature( task['Device'], task['Value']) and self.myNest.UpdateDevices() elif task['Action'] == 'SetAway': DeviceUpdateRequested = True Away = True if task['Value'] == 'On' else False DeviceUpdate = self.myNest.SetAway( task['Device'], Away) and self.myNest.UpdateDevices() elif task['Action'] == 'SetEcoMode': DeviceUpdateRequested = True Eco = 'manual-eco' if task['Value'] == 'On' else 'schedule' DeviceUpdate = self.myNest.SetEco( task['Device'], Eco) and self.myNest.UpdateDevices() elif task['Action'] == 'SetHeating': DeviceUpdateRequested = True Heat = 'heat' if task['Value'] == 'On' else 'off' DeviceUpdate = self.myNest.SetThermostat( task['Device'], Heat) and self.myNest.UpdateDevices() elif task['Action'] == 'OutsideWeather': WeatherUpdate = self.myNest.GetOutsideTempHum() if WeatherUpdate: updated_units = self.updateWeather(WeatherUpdate) self.ErrorLevel = 0 Domoticz.Debug( '> Updated {} units for weather.'.format( updated_units)) else: self.ErrorLevel += 1 Domoticz.Debug( 'Unable to get weather data from Nest (last error: {}).' .format(self.myNest._nest_access_error)) else: Domoticz.Error( '> TaskHandler: unknown action code {}'.format( task['Action'])) DeviceUpdate = self.myNest.UpdateDevices() if DeviceUpdate: updated_units = self.updateNestInfo( ) + self.updateThermostats() + self.updateProtects() self.ErrorLevel = 0 Domoticz.Debug( '> Updated {} units for {} device(s)'.format( updated_units, len(self.myNest.device_list) + len(self.myNest.protect_list))) else: if DeviceUpdateRequested: self.ErrorLevel += 1 Domoticz.Debug( 'Unable to get update data from Nest (last error: {}).' .format(self.myNest._nest_access_error)) self.tasksQueue.task_done() Domoticz.Debug('> Finished handling task: {}.'.format( task['Action'])) except Exception as err: self.tasksQueue.task_done() Domoticz.Error('> General error TaskHandler: {}'.format(err))
def CheckForUpdatePythonPlugin(self, ppAuthor, ppRepository, ppKey): Domoticz.Debug("CheckForUpdatePythonPlugin called") if (self.plugindata[ppKey][2] in self.ExceptionList): Domoticz.Log( "Plugin:" + self.plugindata[ppKey][2] + " excluded by Exclusion file (exclusion.txt). Skipping!!!") return Domoticz.Debug("Checking Plugin:" + ppKey + " for updates") #Domoticz.Log("Fetching Repository Details") ppGitFetch = "LANG=en_US /usr/bin/git fetch" try: prFetch = subprocess.Popen(ppGitFetch, cwd=str(os.getcwd() + "/plugins/" + ppKey), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (outFetch, errorFetch) = prFetch.communicate() if outFetch: Domoticz.Debug("Git Response:" + str(outFetch)) if errorFetch: Domoticz.Debug("Git Error:" + str(errorFetch.strip())) except OSError as eFetch: Domoticz.Error("Git ErrorNo:" + str(eFetch.errno)) Domoticz.Error("Git StrError:" + str(eFetch.strerror)) ppUrl = "LANG=en_US /usr/bin/git status -uno" Domoticz.Debug("Calling:" + ppUrl + " on folder " + str(os.getcwd()) + "/plugins/" + ppKey) try: pr = subprocess.Popen(ppUrl, cwd=str(os.getcwd() + "/plugins/" + ppKey), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, error) = pr.communicate() if out: Domoticz.Debug("Git Response:" + str(out)) if (str(out).find("up-to-date") != -1) or (str(out).find("up to date") != -1): Domoticz.Log("Plugin " + ppKey + " already Up-To-Date") Domoticz.Debug("find(error):" + str(str(out).find("error"))) elif (str(out).find("Your branch is behind") != -1) and (str( str(out).find("error")) == "-1"): Domoticz.Log("Found that we are behind on plugin " + ppKey) self.fnSelectedNotify(ppKey) elif (str(out).find("Your branch is ahead") != -1) and (str( str(out).find("error")) == "-1"): Domoticz.Debug("Found that we are ahead on plugin " + ppKey + ". No need for update") else: Domoticz.Error("Something went wrong with update of " + str(ppKey)) if error: Domoticz.Debug("Git Error:" + str(error.strip())) if str(error).find("Not a git repository") != -1: Domoticz.Log("Plugin:" + ppKey + " is not installed from gitHub. Ignoring!!.") except OSError as e: Domoticz.Error("Git ErrorNo:" + str(e.errno)) Domoticz.Error("Git StrError:" + str(e.strerror)) return None
def onHeartbeatInternal(self, fetch=False): try: # check if another thread is not running # and time between last fetch has elapsed self.inProgress = True res = self.sensor_measurement() try: self.variables[self.UNIT_AVARAGE_AQI]['sValue'] = str( res.average_aqi) except KeyError: pass # No airQualityIndex value try: self.variables[self.UNIT_AIR_QUALITY_INDEX]['sValue'] = str( res.aqi) except KeyError: pass # No airQualityIndex value # AQI Air Pollution - base on https://en.wikipedia.org/wiki/Air_quality_index # Level Health Implications # 0–50 Excellent # 51–100 Good # 101–150 Lightly Polluted # 151–200 Moderately Polluted # 201–300 Heavily Polluted # 300+ Severely Polluted if int(res.aqi) < 50: pollutionLevel = 1 # green pollutionText = _("Great air quality") elif int(res.aqi) < 100: pollutionLevel = 1 # green pollutionText = _("Good air quality") elif int(res.aqi) < 150: pollutionLevel = 2 # yellow pollutionText = _("Average air quality") elif int(res.aqi) < 200: pollutionLevel = 3 # orange pollutionText = _("Poor air quality") elif int(res.aqi) < 300: pollutionLevel = 4 # red pollutionText = _("Bad air quality") elif int(res.aqi) >= 300: pollutionLevel = 4 # red pollutionText = _("Really bad air quality") else: pollutionLevel = 0 self.variables[ self.UNIT_AIR_POLLUTION_LEVEL]['nValue'] = pollutionLevel self.variables[ self.UNIT_AIR_POLLUTION_LEVEL]['sValue'] = pollutionText try: humidity = int(round(res.humidity)) if humidity < 40: humidity_status = 2 # dry humidity elif 40 <= humidity <= 60: humidity_status = 0 # normal humidity elif 40 < humidity <= 70: humidity_status = 1 # comfortable humidity else: humidity_status = 3 # wet humidity self.variables[self.UNIT_HUMIDITY]['nValue'] = humidity self.variables[self.UNIT_HUMIDITY]['sValue'] = str( humidity_status) except KeyError: pass # No humidity value try: self.variables[self.UNIT_TEMPERATURE]['sValue'] = str( res.temperature) except KeyError: pass # No temperature value try: self.variables[self.UNIT_MOTOR_SPEED]['sValue'] = str( res.motor_speed) except KeyError: pass # No motor_speed value try: self.variables[ self.FILTER_WORK_HOURS]['nValue'] = res.filter_hours_used self.variables[self.FILTER_WORK_HOURS]['sValue'] = str( res.filter_hours_used) except KeyError: pass # No filter_hours_used try: self.variables[self.FILTER_LIFE_REMAINING][ 'nValue'] = res.filter_life_remaining self.variables[self.FILTER_LIFE_REMAINING]['sValue'] = str( res.filter_life_remaining) except KeyError: pass # No filter_life_remaining try: self.variables[ self.UNIT_ILLUMINANCE_SENSOR]['nValue'] = res.illuminance self.variables[self.UNIT_ILLUMINANCE_SENSOR]['sValue'] = str( res.illuminance) except KeyError: pass # No illuminance try: if res.power == "on": UpdateDevice(self.UNIT_POWER_CONTROL, 1, "AirPurifier ON") elif res.power == "off": UpdateDevice(self.UNIT_POWER_CONTROL, 0, "AirPurifier OFF") except KeyError: pass # No power value try: self.UpdateLedStatus(bool(res.led)) except KeyError: pass # No led value try: if res.mode == "OperationMode.Idle": UpdateDevice(self.UNIT_MODE_CONTROL, 0, '0') elif res.mode == "OperationMode.Silent": UpdateDevice(self.UNIT_MODE_CONTROL, 10, '10') elif res.mode == "OperationMode.Favorite": UpdateDevice(self.UNIT_MODE_CONTROL, 20, '20') elif res.mode == "OperationMode.Auto": UpdateDevice(self.UNIT_MODE_CONTROL, 30, '30') except KeyError: pass # No mode value try: UpdateDevice(self.UNIT_MOTOR_SPEED_FAVORITE, 1, str(int(res.favorite_level) * 10)) except KeyError: pass # No motor_speed value self.doUpdate() except Exception as e: Domoticz.Error(_("Unrecognized heartbeat error: %s") % str(e)) finally: self.inProgress = False if Parameters["Mode6"] == 'Debug': Domoticz.Debug("onHeartbeat finished") return True
def onMessage(self, Connection, Data): Domoticz.Log("onMessage called for connection: "+Connection.Address+":"+Connection.Port) if Parameters["Mode6"] != "Normal": Domoticz.Log("URL CALLED: " + Data["URL"]) parsed = urlparse.urlparse(Data["URL"]) paramdict = urlparse.parse_qs(parsed.query) self.Data = {} for key,param in paramdict.items(): value = param[0] if key in SensorTable: device = SensorTable[key] if (device["name"] != "") : unitnr = device["nr"] scale = device["scale"] offset = device["offset"] minval = device["min"] maxval = device["max"] self.Data[key] = None if Parameters["Mode6"] != "Normal": Domoticz.Log("Updating sensor: %s (Scale %.3f, offset %.3f" % (str(unitnr),scale,offset)) try: if (is_number(value)): fvalue = float(value) * scale + offset if (fvalue >= minval and fvalue <= maxval): svalue = "%.1f" % fvalue UpdateDevice(unitnr,0,svalue) svalue = "%.6f" % fvalue self.Data[key] = svalue else: Domoticz.Log("Sensor value for device %i out of range and discarded: %.1f" % (unitnr, fvalue)) else: Domoticz.Log("Sensor value for device %i NOT numeric: %s" % (unitnr, str(value))) # UpdateDevice(unitnr,0,value) self.Data[key] = None except: Domoticz.Log("Sensor update EXCEPTION for unit %i" % unitnr) else: if Parameters["Mode6"] != "Normal": Domoticz.Log("Sensor NOT handled in code: %s" % (key)) else: if Parameters["Mode6"] != "Normal": Domoticz.Log("Sensor NOT found: %s" % (key)) for key,device in CompositeSensors.items(): unitnr = device["nr"] data_lst = [] value = None for src in device["src"]: if (src[0] == '_'): function,paramstr = src[1:].split(',',1) params = paramstr.split(',') if None in params: continue if (function == 'forecast'): paramval = parseFloatValue(self.Data[params[0]]) if paramval != None: value = str(getBarometerForecast(paramval)) else: value = None elif (function == 'humstat'): param0val = parseFloatValue(self.Data[params[0]]) param1val = parseFloatValue(self.Data[params[1]]) if param0val != None and param1val != None: value = str (getHumidityStatus(param0val,param1val)) else: value = None elif (function == 'winddir'): paramval = parseFloatValue(self.Data[params[0]]) if paramval != None: value = getWindDirection(paramval) else: value = None elif (function == 'rain100'): rain = parseFloatValue(self.Data[params[0]]) if rain != None: value = floatToString(rain * 100.0 ) else: value = None elif (function == 'windms10'): wind = parseFloatValue(self.Data[params[0]]) if wind != None: value = floatToString(wind * 10.0 /3.6 ) else: value = None else: if src in self.Data: value = self.Data[src] if (is_number(value)): fvalue = float(value) value = "%.1f" % fvalue if (value != None and type(value) == str): data_lst.append( value ) if len(data_lst) == len(device["src"]): # exactly right amount of values? svalue = ';'.join(data_lst) UpdateDevice(unitnr,0,svalue) else: Domoticz.Log("Device %s expected %i parameters but received %i." % (key, len(src), len(data_lst))) # EXAMPLE URL: # /weatherstation/updateweatherstation.php?ID=IXXXXXX&PASSWORD=NoKeyNeeded&indoortempf=72.9&tempf=66.9&dewptf=63.0&windchillf=66.9&indoorhumidity=65&humidity=87&windspeedmph=1.6&windgustmph=2.2&winddir=196&absbaromin=29.740&baromin=29.918&rainin=0.000&dailyrainin=0.059&weeklyrainin=1.220&monthlyrainin=1.500&solarradiation=86.73&UV=0&dateutc=2019-08-17%2012:42:23&softwaretype=EasyWeatherV1.4.1&action=updateraw&realtime=1&rtfreq=5 # Incoming Requests if "Verb" in Data: strVerb = Data["Verb"] LogMessage(strVerb+" request received.") data = "<!doctype html><html><head></head><body><h1>Successful GET!!!</h1></body></html>" if (strVerb == "GET"): Connection.Send({"Status":"200 OK", "Headers": {"Connection": "keep-alive", "Accept": "Content-Type: text/html; charset=UTF-8"}, "Data": data}) elif (strVerb == "POST"): Connection.Send({"Status":"200 OK", "Headers": {"Connection": "keep-alive", "Accept": "Content-Type: text/html; charset=UTF-8"}, "Data": data}) else: Domoticz.Error("Unknown verb in request: "+strVerb) Domoticz.Log("onMessage called")
def onStart(self): Domoticz.Log("onStart called") try: Domoticz.Log( "Modbus RTU/ASCII/TCP - Universal READ loaded!, using python v" + sys.version[:6] + " and pymodbus v" + pymodbus.__version__) except: Domoticz.Log("Modbus RTU/ASCII/TCP - Universal READ loaded!") # Dependancies notification try: if (float(Parameters["DomoticzVersion"][:6]) < float("2020.2")): Domoticz.Error( "WARNING: Domoticz version is outdated/not supported, please update!" ) if (float(sys.version[:1]) < 3): Domoticz.Error("WARNING: Python3 should be used!") if (float(pymodbus.__version__[:3]) < float("2.3")): Domoticz.Error( "WARNING: Pymodbus version is outdated, please update!") except: Domoticz.Error("WARNING: Dependancies could not be checked!") ######################################## # READ-IN OPTIONS AND SETTINGS ######################################## # Convert "option names" to variables for easy reading and debugging. # Note: Parameters["Port"] cannot accept other value then int! (e.g. 192.168.0.0 will result in 192) Domoticz_Setting_Communication_MODDEB = Parameters["Mode1"].split( ":") # Split MODE and DEBUG setting MODE:DEBUG self.Domoticz_Setting_Communication_Mode = Domoticz_Setting_Communication_MODDEB[ 0] self.Domoticz_Setting_Serial_Port = Parameters["SerialPort"] self.Domoticz_Setting_Baudrate = Parameters["Mode2"] self.Domoticz_Setting_Port_Mode = Parameters["Mode3"] self.Domoticz_Setting_Modbus_Function = Parameters["Username"] self.Domoticz_Setting_Register_Number = Parameters["Port"] self.Domoticz_Setting_Data_Type = Parameters["Mode6"] self.Domoticz_Setting_Scale_Factor = Parameters["Mode5"] self.Domoticz_Setting_Sensor_Type = Parameters["Mode4"] self.Domoticz_Setting_Device_IDPOL = Parameters["Password"].split( ":") # Split ID and pollrate setting ID:POLL (heartbeat) self.Domoticz_Setting_Device_ID = 1 # Default if len(self.Domoticz_Setting_Device_IDPOL) > 0: self.Domoticz_Setting_Device_ID = self.Domoticz_Setting_Device_IDPOL[ 0] self.Domoticz_Setting_Device_Pollrate = 10 # Default if len(self.Domoticz_Setting_Device_IDPOL) > 1: self.Domoticz_Setting_Device_Pollrate = self.Domoticz_Setting_Device_IDPOL[ 1] self.Domoticz_Setting_TCP_IPPORT = Parameters["Address"].split( ":") # Split address and port setting TCP:IP self.Domoticz_Setting_TCP_IP = 0 # Default if len(self.Domoticz_Setting_TCP_IPPORT) > 0: self.Domoticz_Setting_TCP_IP = self.Domoticz_Setting_TCP_IPPORT[0] self.Domoticz_Setting_TCP_PORT = 0 # Default if len(self.Domoticz_Setting_TCP_IPPORT) > 1: self.Domoticz_Setting_TCP_PORT = self.Domoticz_Setting_TCP_IPPORT[ 1] # Set debug yes/no if (Domoticz_Setting_Communication_MODDEB[1] == "debug"): Domoticz.Debugging(1) # Enable debugging DumpConfigToLog() Domoticz.Debug("***** NOTIFICATION: Debug enabled!") else: Domoticz.Debugging(0) # Disable debugging # Set device pollrate (heartbeat) Domoticz.Heartbeat(int(self.Domoticz_Setting_Device_Pollrate)) Domoticz.Debug("***** NOTIFICATION: Pollrate (heartbeat): " + self.Domoticz_Setting_Device_Pollrate + " seconds.") # RTU - Serial port settings if (self.Domoticz_Setting_Port_Mode == "S1B7PN"): self.StopBits, self.ByteSize, self.Parity = 1, 7, "N" if (self.Domoticz_Setting_Port_Mode == "S1B7PE"): self.StopBits, self.ByteSize, self.Parity = 1, 7, "E" if (self.Domoticz_Setting_Port_Mode == "S1B7PO"): self.StopBits, self.ByteSize, self.Parity = 1, 7, "O" if (self.Domoticz_Setting_Port_Mode == "S1B8PN"): self.StopBits, self.ByteSize, self.Parity = 1, 8, "N" if (self.Domoticz_Setting_Port_Mode == "S1B8PE"): self.StopBits, self.ByteSize, self.Parity = 1, 8, "E" if (self.Domoticz_Setting_Port_Mode == "S1B8PO"): self.StopBits, self.ByteSize, self.Parity = 1, 8, "O" if (self.Domoticz_Setting_Port_Mode == "S2B7PN"): self.StopBits, self.ByteSize, self.Parity = 2, 7, "N" if (self.Domoticz_Setting_Port_Mode == "S2B7PE"): self.StopBits, self.ByteSize, self.Parity = 2, 7, "E" if (self.Domoticz_Setting_Port_Mode == "S2B7PO"): self.StopBits, self.ByteSize, self.Parity = 2, 7, "O" if (self.Domoticz_Setting_Port_Mode == "S2B8PN"): self.StopBits, self.ByteSize, self.Parity = 2, 8, "N" if (self.Domoticz_Setting_Port_Mode == "S2B8PE"): self.StopBits, self.ByteSize, self.Parity = 2, 8, "E" if (self.Domoticz_Setting_Port_Mode == "S2B8PO"): self.StopBits, self.ByteSize, self.Parity = 2, 8, "O" # Read n registers depending on data type # Added additional options for byte/word swapping self.Register_Count = 1 # Default if (self.Domoticz_Setting_Data_Type == "noco"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "bool"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "int8LSB"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "int8MSB"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "int16"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "int16s"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "int32"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "int32s"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "int64"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "int64s"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "uint8LSB"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "uint8MSB"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "uint16"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "uint16s"): self.Register_Count = 1 if (self.Domoticz_Setting_Data_Type == "uint32"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "uint32s"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "uint64"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "uint64s"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "float32"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "float32s"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "float64"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "float64s"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "string2"): self.Register_Count = 2 if (self.Domoticz_Setting_Data_Type == "string4"): self.Register_Count = 4 if (self.Domoticz_Setting_Data_Type == "string6"): self.Register_Count = 6 if (self.Domoticz_Setting_Data_Type == "string8"): self.Register_Count = 8 self.Read_Scale_Factor = 0 if (self.Domoticz_Setting_Scale_Factor == "sfnextreg"): self.Read_Scale_Factor = 1 self.Register_Count = self.Register_Count + 1 # Due to the lack of more parameter posibility, the name will be the hardware name self.Domoticz_Setting_Sensor_Type = Parameters["Mode4"] if (len(Devices) == 0): Domoticz.Device(Name="Modbus-READ", Unit=1, TypeName=self.Domoticz_Setting_Sensor_Type, Image=0, Used=1).Create() #Added sensor type return
def onHeartbeatInternal(self, fetch=False): now = datetime.datetime.now() if fetch == False: if now < self.nextpoll: Domoticz.Debug( _("Awaiting next pool: %s") % str(self.nextpoll)) return # Set next pool time self.postponeNextPool(seconds=self.pollinterval) try: res = self.MyAir.status() Domoticz.Log(str(res)) # check if another thread is not running # and time between last fetch has elapsed self.inProgress = True try: if str(res.mode) == "OperationMode.Idle": UpdateDevice(self.UNIT_MODE_CONTROL, 0, '0') elif str(res.mode) == "OperationMode.Silent": UpdateDevice(self.UNIT_MODE_CONTROL, 10, '10') elif str(res.mode) == "OperationMode.Favorite": UpdateDevice(self.UNIT_MODE_CONTROL, 20, '20') elif str(res.mode) == "OperationMode.Auto": UpdateDevice(self.UNIT_MODE_CONTROL, 30, '30') else: Domoticz.Log("Wrong state for UNIT_MODE_CONTROL: " + str(res.mode)) except KeyError: Domoticz.Log("Cannot update: UNIT_MODE_CONTROL") pass # No mode value UpdateDevice(self.UNIT_MOTOR_SPEED_FAVORITE, 1, str(int(int(res.favorite_level) - 1) * 10)) try: self.variables[self.UNIT_AVARAGE_AQI]['sValue'] = str( res.average_aqi) except KeyError: pass # No airQualityIndex value try: self.variables[self.UNIT_AIR_QUALITY_INDEX]['sValue'] = str( res.aqi) except KeyError: pass # No airQualityIndex value try: self.variables[self.UNIT_TEMPERATURE]['sValue'] = str( res.temperature) except KeyError: pass # No temperature value try: self.variables[self.UNIT_MOTOR_SPEED]['sValue'] = str( res.motor_speed) except KeyError: pass # No motor_speed value try: if str(res.power) == "on": UpdateDevice(self.UNIT_POWER_CONTROL, 1, "AirPurifier ON") elif str(res.power) == "off": UpdateDevice(self.UNIT_POWER_CONTROL, 0, "AirPurifier OFF") except KeyError: pass # No power value # AQI Air Pollution - base on https://en.wikipedia.org/wiki/Air_quality_index # Level Health Implications # 0–50 Excellent # 51–100 Good # 101–150 Lightly Polluted # 151–200 Moderately Polluted # 201–300 Heavily Polluted # 300+ Severely Polluted # sometimes response has 10 times lower value - uncomment below # res.aqi = int(res.aqi) * 10 if int(res.aqi) < 50: pollutionLevel = 1 # green pollutionText = _("Great air quality") elif int(res.aqi) < 100: pollutionLevel = 1 # green pollutionText = _("Good air quality") elif int(res.aqi) < 150: pollutionLevel = 2 # yellow pollutionText = _("Average air quality") elif int(res.aqi) < 200: pollutionLevel = 3 # orange pollutionText = _("Poor air quality") elif int(res.aqi) < 300: pollutionLevel = 4 # red pollutionText = _("Bad air quality") elif int(res.aqi) >= 300: pollutionLevel = 4 # red pollutionText = _("Really bad air quality") else: pollutionLevel = 0 self.variables[ self.UNIT_AIR_POLLUTION_LEVEL]['nValue'] = pollutionLevel self.variables[ self.UNIT_AIR_POLLUTION_LEVEL]['sValue'] = pollutionText try: humidity = int(round(res.humidity)) if humidity < 40: humidity_status = 2 # dry humidity elif 40 <= humidity <= 60: humidity_status = 0 # normal humidity elif 40 < humidity <= 70: humidity_status = 1 # comfortable humidity else: humidity_status = 3 # wet humidity self.variables[self.UNIT_HUMIDITY]['nValue'] = humidity self.variables[self.UNIT_HUMIDITY]['sValue'] = str( humidity_status) except KeyError: pass # No humidity value try: self.variables[ self.FILTER_WORK_HOURS]['nValue'] = res.filter_hours_used self.variables[self.FILTER_WORK_HOURS]['sValue'] = str( res.filter_hours_used) except KeyError: pass # No filter_hours_used try: self.variables[self.FILTER_LIFE_REMAINING][ 'nValue'] = res.filter_life_remaining self.variables[self.FILTER_LIFE_REMAINING]['sValue'] = str( res.filter_life_remaining) except KeyError: pass # No filter_life_remaining try: self.variables[ self.UNIT_ILLUMINANCE_SENSOR]['nValue'] = res.illuminance self.variables[self.UNIT_ILLUMINANCE_SENSOR]['sValue'] = str( res.illuminance) except KeyError: pass # No illuminance self.doUpdate() try: self.UpdateLedStatus(bool(res.led)) except KeyError: pass # No led value # child lock if res.child_lock: UpdateDevice(self.UNIT_CHILD_LOCK, 1, "ChildLock ON") else: UpdateDevice(self.UNIT_CHILD_LOCK, 0, "ChildLock OFF") # beep if res.volume is not None and res.volume > 0: UpdateDevice(self.UNIT_BEEP, 1, "Beep ON") else: UpdateDevice(self.UNIT_BEEP, 0, "Beep OFF") except miio.airpurifier.AirPurifierException as e: Domoticz.Error("onHeartbeatInternal: " + str(e)) self.MyAir = None return except Exception as e: Domoticz.Error(_("Unrecognized heartbeat error: %s") % str(e)) finally: self.inProgress = False if Parameters["Mode6"] == 'Debug': Domoticz.Debug("onHeartbeat finished")
def onHeartbeat(self): Domoticz.Log("onHeartbeat called") ######################################## # SET HARDWARE - pymodbus: RTU / ASCII ######################################## if (self.Domoticz_Setting_Communication_Mode == "rtu" or self.Domoticz_Setting_Communication_Mode == "ascii"): Domoticz.Debug("MODBUS DEBUG - INTERFACE: Port=" + self.Domoticz_Setting_Serial_Port + ", BaudRate=" + self.Domoticz_Setting_Baudrate + ", StopBits=" + str(self.StopBits) + ", ByteSize=" + str(self.ByteSize) + " Parity=" + self.Parity) Domoticz.Debug("MODBUS DEBUG - SETTINGS: Method=" + self.Domoticz_Setting_Communication_Mode + ", Device ID=" + self.Domoticz_Setting_Device_ID + ", Register=" + self.Domoticz_Setting_Register_Number + ", Function=" + self.Domoticz_Setting_Modbus_Function + ", Data type=" + self.Domoticz_Setting_Data_Type + ", Pollrate=" + self.Domoticz_Setting_Device_Pollrate) try: client = ModbusSerialClient( method=self.Domoticz_Setting_Communication_Mode, port=self.Domoticz_Setting_Serial_Port, stopbits=self.StopBits, bytesize=self.ByteSize, parity=self.Parity, baudrate=int(self.Domoticz_Setting_Baudrate), timeout=2, retries=2) except: Domoticz.Error("Error opening Serial interface on " + self.Domoticz_Setting_Serial_Port) Devices[1].Update(1, "0") # Set value to 0 (error) ######################################## # SET HARDWARE - pymodbus: RTU over TCP ######################################## if (self.Domoticz_Setting_Communication_Mode == "rtutcp"): Domoticz.Debug("MODBUS DEBUG - INTERFACE: IP=" + self.Domoticz_Setting_TCP_IP + ", Port=" + self.Domoticz_Setting_TCP_PORT) Domoticz.Debug("MODBUS DEBUG - SETTINGS: Method=" + self.Domoticz_Setting_Communication_Mode + ", Device ID=" + self.Domoticz_Setting_Device_ID + ", Register=" + self.Domoticz_Setting_Register_Number + ", Function=" + self.Domoticz_Setting_Modbus_Function + ", Data type=" + self.Domoticz_Setting_Data_Type + ", Pollrate=" + self.Domoticz_Setting_Device_Pollrate) try: client = ModbusTcpClient(host=self.Domoticz_Setting_TCP_IP, port=int( self.Domoticz_Setting_TCP_PORT), framer=ModbusRtuFramer, auto_open=True, auto_close=True, timeout=2) except: Domoticz.Error( "Error opening RTU over TCP interface on address: " + self.Domoticz_Setting_TCP_IPPORT) Devices[1].Update(1, "0") # Set value to 0 (error) ######################################## # SET HARDWARE - pymodbusTCP: TCP/IP ######################################## if (self.Domoticz_Setting_Communication_Mode == "tcpip"): Domoticz.Debug("MODBUS DEBUG - INTERFACE: IP=" + self.Domoticz_Setting_TCP_IP + ", Port=" + self.Domoticz_Setting_TCP_PORT) Domoticz.Debug("MODBUS DEBUG - SETTINGS: Method=" + self.Domoticz_Setting_Communication_Mode + ", Device ID=" + self.Domoticz_Setting_Device_ID + ", Register=" + self.Domoticz_Setting_Register_Number + ", Function=" + self.Domoticz_Setting_Modbus_Function + ", Data type=" + self.Domoticz_Setting_Data_Type + ", Pollrate=" + self.Domoticz_Setting_Device_Pollrate) try: client = ModbusClient(host=self.Domoticz_Setting_TCP_IP, port=int(self.Domoticz_Setting_TCP_PORT), unit_id=int( self.Domoticz_Setting_Device_ID), auto_open=True, auto_close=True, timeout=2) except: Domoticz.Error("Error opening TCP/IP interface on address: " + self.Domoticz_Setting_TCP_IPPORT) Devices[1].Update(1, "0") # Set value to 0 (error) ######################################## # GET DATA - pymodbus: RTU / ASCII / RTU over TCP ######################################## if (self.Domoticz_Setting_Communication_Mode == "rtu" or self.Domoticz_Setting_Communication_Mode == "ascii" or self.Domoticz_Setting_Communication_Mode == "rtutcp"): try: # Function to execute if (self.Domoticz_Setting_Modbus_Function == "1"): data = client.read_coils( int(self.Domoticz_Setting_Register_Number), self.Register_Count, unit=int(self.Domoticz_Setting_Device_ID)) if (self.Domoticz_Setting_Modbus_Function == "2"): data = client.read_discrete_inputs( int(self.Domoticz_Setting_Register_Number), self.Register_Count, unit=int(self.Domoticz_Setting_Device_ID)) if (self.Domoticz_Setting_Modbus_Function == "3"): data = client.read_holding_registers( int(self.Domoticz_Setting_Register_Number), self.Register_Count, unit=int(self.Domoticz_Setting_Device_ID)) if (self.Domoticz_Setting_Modbus_Function == "4"): data = client.read_input_registers( int(self.Domoticz_Setting_Register_Number), self.Register_Count, unit=int(self.Domoticz_Setting_Device_ID)) if (self.Read_Scale_Factor == 1): decoder = BinaryPayloadDecoder.fromRegisters( data, byteorder=Endian.Big, wordorder=Endian.Big) decoder.skip_bytes((self.Register_Count - 1) * 2) sf_value = decoder.decode_16bit_int() data = data[0:self.Register_Count - 1] else: sf_value = 0 Domoticz.Debug("MODBUS DEBUG - RESPONSE: " + str(data)) except: Domoticz.Error( "Modbus error communicating! (RTU/ASCII/RTU over TCP), check your settings!" ) Devices[1].Update(1, "0") # Set value to 0 (error) ######################################## # GET DATA - pymodbusTCP: TCP/IP ######################################## if (self.Domoticz_Setting_Communication_Mode == "tcpip"): try: # Function to execute if (self.Domoticz_Setting_Modbus_Function == "1"): data = client.read_coils( int(self.Domoticz_Setting_Register_Number), self.Register_Count) if (self.Domoticz_Setting_Modbus_Function == "2"): data = client.read_discrete_inputs( int(self.Domoticz_Setting_Register_Number), self.Register_Count) if (self.Domoticz_Setting_Modbus_Function == "3"): data = client.read_holding_registers( int(self.Domoticz_Setting_Register_Number), self.Register_Count) if (self.Domoticz_Setting_Modbus_Function == "4"): data = client.read_input_registers( int(self.Domoticz_Setting_Register_Number), self.Register_Count) if (self.Read_Scale_Factor == 1): decoder = BinaryPayloadDecoder.fromRegisters( data, byteorder=Endian.Big, wordorder=Endian.Big) decoder.skip_bytes((self.Register_Count - 1) * 2) sf_value = decoder.decode_16bit_int() data = data[0:self.Register_Count - 1] else: sf_value = 0 Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data)) except: Domoticz.Error( "Modbus error communicating! (TCP/IP), check your settings!" ) Devices[1].Update(1, "0") # Set value to 0 (error) ######################################## # DECODE DATA TYPE ######################################## # pymodbus (RTU/ASCII/RTU over TCP) will reponse in ARRAY, no matter what values read e.g. MODBUS DEBUG RESPONSE: [2] = data.registers # pymodbusTCP (TCP/IP) will give the value back e.g. MODBUS DEBUG RESPONSE: [61, 44] = data if (self.Domoticz_Setting_Communication_Mode == "rtu" or self.Domoticz_Setting_Communication_Mode == "ascii" or self.Domoticz_Setting_Communication_Mode == "rtutcp"): try: Domoticz.Debug("MODBUS DEBUG - VALUE before conversion: " + str(data.registers[0])) # Added option to swap bytes (little endian) if (self.Domoticz_Setting_Data_Type == "int16s" or self.Domoticz_Setting_Data_Type == "uint16s"): decoder = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Little, wordorder=Endian.Big) # Added option to swap words (little endian) elif (self.Domoticz_Setting_Data_Type == "int32s" or self.Domoticz_Setting_Data_Type == "uint32s" or self.Domoticz_Setting_Data_Type == "int64s" or self.Domoticz_Setting_Data_Type == "uint64s" or self.Domoticz_Setting_Data_Type == "float32s" or self.Domoticz_Setting_Data_Type == "float64s"): decoder = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) # Otherwise always big endian else: decoder = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Big) except: Domoticz.Error( "Modbus error decoding or received no data (RTU/ASCII/RTU over TCP)!, check your settings!" ) Devices[1].Update(1, "0") # Set value to 0 (error) if (self.Domoticz_Setting_Communication_Mode == "tcpip"): try: Domoticz.Debug("MODBUS DEBUG - VALUE before conversion: " + str(data)) #value = data[0] # Added option to swap bytes (little endian) if (self.Domoticz_Setting_Data_Type == "int16s" or self.Domoticz_Setting_Data_Type == "uint16s"): decoder = BinaryPayloadDecoder.fromRegisters( data, byteorder=Endian.Little, wordorder=Endian.Big) # Added option to swap words (little endian) elif (self.Domoticz_Setting_Data_Type == "int32s" or self.Domoticz_Setting_Data_Type == "uint32s" or self.Domoticz_Setting_Data_Type == "int64s" or self.Domoticz_Setting_Data_Type == "uint64s" or self.Domoticz_Setting_Data_Type == "float32s" or self.Domoticz_Setting_Data_Type == "float64s"): decoder = BinaryPayloadDecoder.fromRegisters( data, byteorder=Endian.Big, wordorder=Endian.Little) # Otherwise always big endian else: decoder = BinaryPayloadDecoder.fromRegisters( data, byteorder=Endian.Big, wordorder=Endian.Big) except: Domoticz.Error( "Modbus error decoding or received no data (TCP/IP)!, check your settings!" ) Devices[1].Update(1, "0") # Set value to 0 (error) ######################################## # DECODE DATA VALUE ######################################## try: if (self.Domoticz_Setting_Data_Type == "noco"): value = data.registers[0] if (self.Domoticz_Setting_Data_Type == "bool"): value = bool(data.registers[0]) if (self.Domoticz_Setting_Data_Type == "int8LSB"): ignored = decoder.skip_bytes(1) value = decoder.decode_8bit_int() if (self.Domoticz_Setting_Data_Type == "int8MSB"): value = decoder.decode_8bit_int() if (self.Domoticz_Setting_Data_Type == "int16"): value = decoder.decode_16bit_int() if (self.Domoticz_Setting_Data_Type == "int16s"): value = decoder.decode_16bit_int() if (self.Domoticz_Setting_Data_Type == "int32"): value = decoder.decode_32bit_int() if (self.Domoticz_Setting_Data_Type == "int32s"): value = decoder.decode_32bit_int() if (self.Domoticz_Setting_Data_Type == "int64"): value = decoder.decode_64bit_int() if (self.Domoticz_Setting_Data_Type == "int64s"): value = decoder.decode_64bit_int() if (self.Domoticz_Setting_Data_Type == "uint8LSB"): ignored = decoder.skip_bytes(1) value = decoder.decode_8bit_uint() if (self.Domoticz_Setting_Data_Type == "uint8MSB"): value = decoder.decode_8bit_uint() if (self.Domoticz_Setting_Data_Type == "uint16"): value = decoder.decode_16bit_uint() if (self.Domoticz_Setting_Data_Type == "uint16s"): value = decoder.decode_16bit_uint() if (self.Domoticz_Setting_Data_Type == "uint32"): value = decoder.decode_32bit_uint() if (self.Domoticz_Setting_Data_Type == "uint32s"): value = decoder.decode_32bit_uint() if (self.Domoticz_Setting_Data_Type == "uint64"): value = decoder.decode_64bit_uint() if (self.Domoticz_Setting_Data_Type == "uint64s"): value = decoder.decode_64bit_uint() if (self.Domoticz_Setting_Data_Type == "float32"): value = decoder.decode_32bit_float() if (self.Domoticz_Setting_Data_Type == "float32s"): value = decoder.decode_32bit_float() if (self.Domoticz_Setting_Data_Type == "float64"): value = decoder.decode_64bit_float() if (self.Domoticz_Setting_Data_Type == "float64s"): value = decoder.decode_64bit_float() if (self.Domoticz_Setting_Data_Type == "string2"): value = decoder.decode_string(2) if (self.Domoticz_Setting_Data_Type == "string4"): value = decoder.decode_string(4) if (self.Domoticz_Setting_Data_Type == "string6"): value = decoder.decode_string(6) if (self.Domoticz_Setting_Data_Type == "string8"): value = decoder.decode_string(8) # Apply a scale factor (decimal) if (self.Domoticz_Setting_Scale_Factor == "div0"): value = str(value) if (self.Domoticz_Setting_Scale_Factor == "div10"): value = str(round(value / 10, 1)) if (self.Domoticz_Setting_Scale_Factor == "div100"): value = str(round(value / 100, 2)) if (self.Domoticz_Setting_Scale_Factor == "div1000"): value = str(round(value / 1000, 3)) if (self.Domoticz_Setting_Scale_Factor == "div10000"): value = str(round(value / 10000, 4)) if (self.Domoticz_Setting_Scale_Factor == "mul10"): value = str(value * 10) if (self.Domoticz_Setting_Scale_Factor == "mul100"): value = str(value * 100, 2) if (self.Domoticz_Setting_Scale_Factor == "mul1000"): value = str(value * 1000, 3) if (self.Domoticz_Setting_Scale_Factor == "mul10000"): value = str(value * 10000, 4) if (self.Domoticz_Setting_Scale_Factor == "sfnextreg"): if (sf_value == 0): value = str(value) if (sf_value == 1): value = str(round(value * 10, 1)) if (sf_value == 2): value = str(round(value * 100, 1)) if (sf_value == -1): value = str(round(value / 10, 1)) if (sf_value == -2): value = str(round(value / 100, 1)) Domoticz.Debug("MODBUS DEBUG - VALUE after conversion: " + str(value)) Devices[1].Update(1, value) # Update value except: Domoticz.Error( "Modbus error decoding or received no data!, check your settings!" ) Devices[1].Update(1, "0") # Set value to 0 (error)
def onHeartbeat(self, fetch=False): Domoticz.Debug("onHeartbeat called") now = datetime.datetime.now() if fetch == False: if self.inProgress or (now < self.nextpoll): Domoticz.Debug( _("Awaiting next pool: %s") % str(self.nextpoll)) return # Set next pool time self.postponeNextPool(seconds=self.pollinterval) try: # check if another thread is not running # and time between last fetch has elapsed self.inProgress = True res = self.sensor_measurement(Parameters["Address"], Parameters["Mode1"]) try: self.variables[self.UNIT_HUMIDITY]['sValue'] = str( res.humidity) except KeyError: pass # No humidity value try: humidity = int(round(res.humidity)) if humidity >= 60 and humidity <= 70: pollutionText = _("Great humidity") humidity_status = 1 # great elif (humidity >= 45 and humidity < 60) or (humidity > 70 and humidity <= 80): pollutionText = _("Good humidity") humidity_status = 0 # normal elif (humidity >= 30 and humidity < 45) or (humidity > 80): pollutionText = _("Poor humidity") humidity_status = 3 # wet/poor elif humidity < 30: pollutionText = _("Bad humidity") humidity_status = 2 # dry self.variables[self.UNIT_HUMIDITY]['nValue'] = humidity self.variables[self.UNIT_HUMIDITY]['sValue'] = str( humidity_status) except KeyError: pass # No humidity value try: self.variables[ self.UNIT_TEMPERATURE]['sValue'] = res.temperature except KeyError: pass # No temperature value try: if res.power == "on": UpdateDevice(self.UNIT_POWER_CONTROL, 1, "AirHumidifier ON") elif res.power == "off": UpdateDevice(self.UNIT_POWER_CONTROL, 0, "AirHumidifier OFF") except KeyError: pass # No power value try: if res.mode == "OperationMode.Auto": UpdateDevice(self.UNIT_MODE_CONTROL, 0, '0') elif res.mode == "OperationMode.Silent": UpdateDevice(self.UNIT_MODE_CONTROL, 10, '10') elif res.mode == "OperationMode.Medium": UpdateDevice(self.UNIT_MODE_CONTROL, 20, '20') elif res.mode == "OperationMode.High": UpdateDevice(self.UNIT_MODE_CONTROL, 30, '30') except KeyError: pass # No mode value try: humidity = int(res.target_humidity) if humidity == 50: UpdateDevice(self.UNIT_TARGET_HUMIDITY, 0, '0') elif humidity == 60: UpdateDevice(self.UNIT_TARGET_HUMIDITY, 10, '10') elif humidity == 70: UpdateDevice(self.UNIT_TARGET_HUMIDITY, 20, '20') except KeyError: pass # No mode value self.doUpdate() except Exception as e: Domoticz.Error(_("Unrecognized error: %s") % str(e)) finally: self.inProgress = False if Parameters["Mode6"] == 'Debug': Domoticz.Debug("onHeartbeat finished") return True
def onMessage(self, Connection, Data): Status = int(Data["Status"]) if (Status == 200): Data = Data['Data'].decode('UTF-8') Data = json.loads(Data) if Connection.Name == ("Get Refresh"): self.reftoken = Data["refresh_token"] if len(self.Refresh) < 50: Domoticz.Log( "Copy token to Setup->Hardware->NibeUplink->Refresh Token:" ) Domoticz.Log(str(self.reftoken)) if self.GetRefresh.Connected() or self.GetRefresh.Connecting(): self.GetRefresh.Disconnect() self.GetToken.Connect() elif Connection.Name == ("Get SystemID"): self.SystemID = str(Data["objects"][0]["systemId"]) if self.GetSystemID.Connected() or self.GetSystemID.Connecting( ): self.GetSystemID.Disconnect() self.GetNoOfSystems.Connect() elif Connection.Name == ("Get NoOfSystems"): Domoticz.Log("Systems found:" + str(len(Data))) self.NoOfSystems = len( Data) # will be 1 higher then SystemUnitId if self.GetNoOfSystems.Connected( ) or self.GetNoOfSystems.Connecting(): self.GetNoOfSystems.Disconnect() if self.FirstRun == True and self.ShowCategories == "Yes": self.GetCategories.Connect() self.GetData.Connect() elif Connection.Name == ("Get Target"): WriteDebug("inne i Message Target1") sValue = Data[0]["rawValue"] / 10.0 WriteDebug("inne i Message Target2") UpdateDevice(int(117), str(sValue), Data[0]["unit"], Data[0]["title"], Data[0]["parameterId"], Data[0]["designation"], 0) WriteDebug("inne i Message Target3") if self.GetTarget.Connected() or self.GetTarget.Connecting(): self.GetTarget.Disconnect() WriteDebug("inne i Message Target4") elif Connection.Name == ("Get Token"): self.token = Data["access_token"] if self.GetToken.Connected() or self.GetToken.Connecting(): self.GetToken.Disconnect() if self.SystemID == "": self.GetSystemID.Connect() else: self.GetData.Connect() elif Connection.Name == ("Get Categories"): for each in Data: self.Categories.append(each["categoryId"]) Domoticz.Log(str(self.Categories)) if self.GetCategories.Connected( ) or self.GetCategories.Connecting(): self.GetCategories.Disconnect() elif Connection.Name == ("Get Data 0"): if self.loop == 6: SPAIDS = [] for ID in Data: SPAIDS.append(ID["parameterId"]) if 10069 not in SPAIDS: UpdateDevice(int(64), str(0), "", "price of electricity", 10069, "", self.SystemUnitId) if 44908 not in SPAIDS: UpdateDevice(int(63), str(0), "", "smart price adaption status", 44908, "", self.SystemUnitId) if 44896 not in SPAIDS: UpdateDevice(int(61), str(0), "", "comfort mode heating", 44896, "", self.SystemUnitId) if 44897 not in SPAIDS: UpdateDevice(int(62), str(0), "", "comfort mode hot water", 44897, "", self.SystemUnitId) loop2 = 0 for each in Data: loop2 += 1 Unit = str(self.loop) + str(loop2) sValue = each["rawValue"] # unit if each["unit"] == "bar" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "°C" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "kWh" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "DM" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "l/m" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "A" and each["title"] != "fuse size": sValue = sValue / 10.0 elif each["unit"] == "öre/kWh": sValue = (sValue / 1000.0) # title if each["title"] == "set max electrical add.": sValue = sValue / 100.0 elif each["title"] == "time factor": sValue = (sValue / 10.0) each["title"] = "electrical time factor" elif each["title"] == "electrical addition power": sValue = (sValue / 100.0) # parameterId if each["parameterId"] == 44896: sValue = (sValue / 10.0) elif each["parameterId"] == 40121: sValue = (sValue / 10.0) elif each["parameterId"] == 43144: sValue = (sValue / 10.0) elif each["parameterId"] == 43136: sValue = (sValue / 10.0) elif each["parameterId"] == 43305: sValue = (sValue / 10.0) # other if int(Unit) > 70 and int(Unit) < 80: sValue = each["displayValue"] UpdateDevice(int(Unit), str(sValue), each["unit"], each["title"], each["parameterId"], each["designation"], self.SystemUnitId) self.loop += 1 if self.loop == len(categories) - 1: Domoticz.Log("System 1 Updated") if self.GetData.Connected() or self.GetData.Connecting(): self.GetData.Disconnect() WriteDebug("Innan Target") # self.GetTarget.Connect() WriteDebug("Efter Target") elif Connection.Name == ("Get Data 1"): if self.loop == 6: SPAIDS = [] for ID in Data: SPAIDS.append(ID["parameterId"]) if 10069 not in SPAIDS: UpdateDevice(int(64), str(0), "", "price of electricity", 10069, "", self.SystemUnitId) if 44908 not in SPAIDS: UpdateDevice(int(63), str(0), "", "smart price adaption status", 44908, "", self.SystemUnitId) if 44896 not in SPAIDS: UpdateDevice(int(61), str(0), "", "comfort mode heating", 44896, "", self.SystemUnitId) if 44897 not in SPAIDS: UpdateDevice(int(62), str(0), "", "comfort mode hot water", 44897, "", self.SystemUnitId) loop2 = 0 for each in Data: loop2 += 1 Unit = str(self.loop) + str(loop2) sValue = each["rawValue"] if each["unit"] == "bar" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "°C" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "kWh" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "DM" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "l/m" and sValue != -32768: sValue = sValue / 10.0 elif each["unit"] == "A" and each["title"] != "fuse size": sValue = sValue / 10.0 elif each["unit"] == "öre/kWh": sValue = (sValue / 1000.0) if each["title"] == "set max electrical add.": sValue = sValue / 100.0 elif each["title"] == "time factor": sValue = (sValue / 10.0) each["title"] = "electrical time factor" elif each["title"] == "electrical addition power": sValue = (sValue / 100.0) if each["parameterId"] == 44896: sValue = (sValue / 10.0) elif each["parameterId"] == 40121: sValue = (sValue / 10.0) elif each["parameterId"] == 43144: sValue = (sValue / 10.0) elif each["parameterId"] == 43136: sValue = (sValue / 10.0) elif each["parameterId"] == 43305: sValue = (sValue / 10.0) elif each["parameterId"] == 44701: sValue = (sValue / 10.0) if int(Unit) > 70 and int(Unit) < 80: sValue = each["displayValue"] UpdateDevice(int(Unit), str(sValue), each["unit"], each["title"], each["parameterId"], each["designation"], self.SystemUnitId) self.loop += 1 if self.loop == len(categories) - 1: Domoticz.Log("System 2 Updated") if self.GetData1.Connected() or self.GetData1.Connecting(): self.GetData1.Disconnect() else: WriteDebug("Status = " + str(Status)) Domoticz.Error(str("Status " + str(Status))) Domoticz.Error(str(Data)) if _plugin.GetCategories.Connected(): _plugin.GetCategories.Disconnect() if _plugin.GetRefresh.Connected(): _plugin.GetRefresh.Disconnect() if _plugin.GetToken.Connected(): _plugin.GetToken.Disconnect() if _plugin.GetData.Connected(): _plugin.GetData.Disconnect() if _plugin.GetSystemID.Connected(): _plugin.GetSystemID.Disconnect() if _plugin.GetTarget.Connected(): _plugin.GetTarget.Disconnect() if _plugin.GetNoOfSystems.Connected(): _plugin.GetNoOfSystems.Disconnect()