def reloadConfig(self, bootup = False) : #load known sensors from file for k, v in self.config.items("childIds") : value = v.split(';') self.childIdLookupTable[value[0]+";"+value[1]] = k self.availableIds[int(value[0])]=False #load unit M/I from file (A good programmer should check input values) self.unit = self.config.get('config','unit') #load InclutionMode from file and send it to gateway(A good programmer should check input values...) self.InclutionMode = self.config.get('config','inclusion-mode') #at bootup this is executed from init if bootup is False : self.setInclutionMode(self.InclutionMode) #initiate integrations #Openhab if self.config.get('config','openhab') == 'true': if self.oh is None : self.oh = Openhab(self.config, self.log) else : self.oh.reloadConfig() else : self.oh = None #Domoticz if self.config.get('config','domoticz') == 'true': if self.dom is None : self.dom = Domoticz(self.config, self.log) else : self.dom.reloadConfig() else : self.dom = None #RRD if self.config.get('config','rrd') == 'true': if self.rrd is None : self.rrd = Rrd(self.config, self.log) else : self.rrd.reloadConfig() else : self.rrd = None self.log.info("reloadConfig: Configuration reloaded.")
class msgw(): #supported integrations oh = None dom = None rrd = None #supported version PLUGIN_VERSION = "1.2+" GATEWAY_VERSION = "" BAUD_RATE = "115200" ARDUINO_SID = "urn:upnp-arduino-cc:serviceId:arduino1" VARIABLE_CONTAINER_SID = "urn:upnp-org:serviceId:VContainer1" MAX_RADIO_ID=255 NODE_CHILD_ID = "255" ARDUINO_DEVICE = None TASK_ERROR = 2 TASK_ERROR_PERM = -2 TASK_SUCCESS = 4 TASK_BUSY = 1 inclusionResult = {} includeCount = 0 #Variables in msgw can be overridded in config file InclusionMode = 0 unit = "M" #defines msgType = { 'PRESENTATION' : "0", 'SET_VARIABLE' : "1", 'REQ_VARIABLE' : "2", 'ACK_VARIABLE' : "3", 'INTERNAL' : "4" } tDeviceLookupNumType = {} tDeviceTypes = { 'DOOR' : [0, "urn:schemas-micasaverde-com:device:DoorSensor:1", "D_DoorSensor1.xml", "Door "], 'MOTION' : [1, "urn:schemas-micasaverde-com:device:MotionSensor:1", "D_MotionSensor1.xml", "Motion "], 'SMOKE' : [2, "urn:schemas-micasaverde-com:device:SmokeSensor:1", "D_SmokeSensor1.xml", "Smoke "], 'LIGHT' : [3, "urn:schemas-upnp-org:device:BinaryLight:1", "D_BinaryLight1.xml", "Light "], 'DIMMER' : [4, "urn:schemas-upnp-org:device:DimmableLight:1", "D_DimmableLight1.xml", "Dim Light "], 'COVER' : [5, "urn:schemas-micasaverde-com:device:WindowCovering:1", "D_WindowCovering1.xml", "Window " ], 'TEMP' : [6, "urn:schemas-micasaverde-com:device:TemperatureSensor:1", "D_TemperatureSensor1.xml", "Temp "], 'HUM' : [7, "urn:schemas-micasaverde-com:device:HumiditySensor:1", "D_HumiditySensor1.xml", "Humidity "], 'BARO' : [8, "urn:schemas-micasaverde-com:device:BarometerSensor:1", "D_BarometerSensor1.xml", "Baro "], 'WIND' : [9, "urn:schemas-micasaverde-com:device:WindSensor:1", "D_WindSensor1.xml", "Wind "], 'RAIN' : [10, "urn:schemas-micasaverde-com:device:RainSensor:1", "D_RainSensor1.xml", "Rain "], 'UV' : [11, "urn:schemas-micasaverde-com:device:UvSensor:1", "D_UvSensor1.xml", "UV "], 'WEIGHT' : [12, "urn:schemas-micasaverde-com:device:ScaleSensor:1", "D_ScaleSensor1.xml", "Weight "], 'POWER' : [13, "urn:schemas-micasaverde-com:device:PowerMeter:1", "D_PowerMeter1.xml", "Power "], 'HEATER' : [14, "urn:schemas-upnp-org:device:Heater:1", "D_Heater1.xml", "Heater "], 'DISTANCE' : [15, "urn:schemas-upnp-org:device:Distance:1", "D_DistanceSensor1.xml", "Distance "], 'LIGHT_LEVEL':[16, "urn:schemas-micasaverde-com:device:LightSensor:1", "D_LightSensor1.xml", "Light "], 'ARDUINO_NODE': [17, "urn:schemas-arduino-cc:device:arduinonode:1", "D_ArduinoNode1.xml", "Node "], 'ARDUINO_RELAY':[18, "urn:schemas-arduino-cc:device:arduinorelay:1", "D_ArduinoRelay1.xml", "Relay "], 'LOCK' : [19, "urn:micasaverde-com:serviceId:DoorLock1", "D_DoorLock1.xml", "Lock "], 'IR' : [20, "urn:schemas-arduino-cc:device:ArduinoIr:1", "D_ArduinoIr1.xml", "IR "], 'WATER' : [21, "urn:schemas-micasaverde-com:device:WaterMeter:1", "D_WaterMeter1.xml", "Water "] } tVarLookupNumType = {} tVarTypes = { 'TEMP' : [0, "urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", ""], 'HUM' : [1, "urn:micasaverde-com:serviceId:HumiditySensor1", "CurrentLevel", "" ], 'LIGHT' : [2, "urn:upnp-org:serviceId:SwitchPower1", "Status", "0" ], 'DIMMER' : [3, "urn:upnp-org:serviceId:Dimming1", "LoadLevelStatus", "" ], 'PRESSURE' : [4, "urn:upnp-org:serviceId:BarometerSensor1", "CurrentPressure", "" ], 'FORECAST' : [5, "urn:upnp-org:serviceId:BarometerSensor1", "Forecast", "" ], 'RAIN' : [6, "urn:upnp-org:serviceId:RainSensor1", "CurrentTRain", "" ], 'RAINRATE' : [7, "urn:upnp-org:serviceId:RainSensor1", "CurrentRain", "" ], 'WIND' : [8, "urn:upnp-org:serviceId:WindSensor1", "AvgSpeed", "" ], 'GUST' : [9, "urn:upnp-org:serviceId:WindSensor1", "GustSpeed", "" ], 'DIRECTION' : [10, "urn:upnp-org:serviceId:WindSensor1", "Direction", "" ], 'UV' : [11, "urn:upnp-org:serviceId:UvSensor1", "CurrentLevel", "" ], 'WEIGHT' : [12, "urn:micasaverde-com:serviceId:ScaleSensor1", "Weight", "" ], 'DISTANCE' : [13, "urn:micasaverde-com:serviceId:DistanceSensor1", "CurrentDistance", "" ], 'IMPEDANCE' : [14, "urn:micasaverde-com:serviceId:ScaleSensor1", "Impedance", "" ], 'ARMED' : [15, "urn:micasaverde-com:serviceId:SecuritySensor1", "Armed", "" ], 'TRIPPED' : [16, "urn:micasaverde-com:serviceId:SecuritySensor1", "Tripped", "0" ], 'WATT' : [17, "urn:micasaverde-com:serviceId:EnergyMetering1", "Watts", "" ], 'KWH' : [18, "urn:micasaverde-com:serviceId:EnergyMetering1", "KWH", "0" ], 'SCENE_ON' : [19, "urn:micasaverde-com:serviceId:SceneController1", "sl_SceneActivated", "" ], 'SCENE_OFF' : [20, "urn:micasaverde-com:serviceId:SceneController1", "sl_SceneDeactivated", "" ], 'HEATER' : [21, "urn:upnp-org:serviceId:HVAC_UserOperatingMode1", "ModeStatus", "" ], 'HEATER_SW' : [22, "urn:upnp-org:serviceId:SwitchPower1", "Status", "" ], 'LIGHT_LEVEL' : [23, "urn:micasaverde-com:serviceId:LightSensor1", "CurrentLevel", "" ], 'VAR_1' : [24, "urn:upnp-org:serviceId:VContainer1", "Variable1", ""], 'VAR_2' : [25, "urn:upnp-org:serviceId:VContainer1", "Variable2", ""], 'VAR_3' : [26, "urn:upnp-org:serviceId:VContainer1", "Variable3", ""], 'VAR_4' : [27, "urn:upnp-org:serviceId:VContainer1", "Variable4", ""], 'VAR_5' : [28, "urn:upnp-org:serviceId:VContainer1", "Variable5", ""], 'UP' : [29, None, None, ""], 'DOWN' : [30, None, None, ""], 'STOP' : [31, None, None, ""], 'IR_SEND' : [32, None, None, ""], 'IR_RECEIVE' : [33, "urn:upnp-org:serviceId:ArduinoIr1", "IrCode", ""], 'FLOW' : [34, "urn:micasaverde-com:serviceId:WaterMetering1", "Flow", "" ], 'VOLUME' : [35, "urn:micasaverde-com:serviceId:WaterMetering1", "Volume", "0" ], 'LOCK' : [36, "urn:micasaverde-com:serviceId:DoorLock1", "Status", ""] } tInternalLookupNumType = {} tInternalTypes = { "BATTERY_LEVEL" : [0, "urn:micasaverde-com:serviceId:HaDevice1", "BatteryLevel", "" ], "BATTERY_DATE" : [1, "urn:micasaverde-com:serviceId:HaDevice1", "BatteryDate", "" ], "LAST_TRIP" : [2, "urn:micasaverde-com:serviceId:SecuritySensor1", "LastTrip", "" ], "TIME" : [3, None, None, None], "VERSION" : [4, "urn:upnp-arduino-cc:serviceId:arduinonode1", "ArduinoLibVersion", ""], "REQUEST_ID" : [5, None, None, None], "INCLUSION_MODE" :[6, "urn:upnp-arduino-cc:serviceId:arduino1", "InclusionMode", "0"], "RELAY_NODE": [7, "urn:upnp-arduino-cc:serviceId:arduinonode1", "RelayNode", ""], "LAST_UPDATE" : [8, "urn:micasaverde-com:serviceId:HaDevice1", "LastUpdate", "" ], "PING" : [9, None, None, None ], "PING_ACK" : [10, None, None, None ], "LOG_MESSAGE" : [11, None, None, None ], "CHILDREN" : [12, "urn:upnp-arduino-cc:serviceId:arduinonode1", "Children", "0"], "UNIT" : [13, "urn:upnp-arduino-cc:serviceId:arduino1", "Unit", "M"], # M : Metric / I : Imperial "SKETCH_NAME" : [14, "urn:upnp-arduino-cc:serviceId:arduinonode1", "SketchName", ""], "SKETCH_VERSION" : [15, "urn:upnp-arduino-cc:serviceId:arduinonode1", "SketchVersion", ""] } #lookup tables childIdLookupTable = {} availableIds = [True]*254 for k, v in tVarTypes.iteritems(): tVarLookupNumType[v[0]] = k for k, v in tDeviceTypes.iteritems(): tDeviceLookupNumType[v[0]] = k for k, v in tInternalTypes.iteritems(): tInternalLookupNumType[v[0]] = k #poor mans hook. def hooking(self,incomingData,ChildId) : index = int(incomingData[3]); variable = self.tVarTypes[self.tVarLookupNumType[index]] value = incomingData[4].strip() if int(ChildId) == 3 : f = open('/usr/share/nginx/www/info.dat', 'w') f.write(value) f.close() def loop(self): response = self.ser.readline() if response: self.log.debug("loop: Incomming message: "+response) self.processIncoming(response) return response return None def setVariable(self, incomingData, childId, nodeId): if (childId is not None) : # Set variable reported from a child sensor. childId = str(childId) index = int(incomingData[3]); varType = self.tVarLookupNumType[index] var = self.tVarTypes[varType] value = incomingData[4] if (var[1] is not None): self.log.info("setVariable: RaidoId: "+incomingData[0]+" Sensor: "+incomingData[1]+" ChildId: "+str(childId)+" Type: " +self.tVarLookupNumType[index]+" reporting value: "+ value) #Support integrations # Add info to RRD if self.config.has_option('rrds',childId) and self.rrd is not None: self.rrd.setVariable(incomingData, childId, nodeId) # Add info to Domoticz if self.config.has_option('domoticz',childId) and self.dom is not None: self.dom.setVariable(incomingData, childId, nodeId) # Add info to Openhab if self.config.has_option('openhab',childId) and self.oh is not None: self.oh.setVariable(incomingData, childId, nodeId) self.setVariableIfChanged(var[1], var[2], value, childId) # Handle special variables battery level and tripped which also # should update other variables to os.time(). This part should be removed... if (varType == "TRIPPED" and value == "1") : variable = self.tInternalTypes["LAST_TRIP"] self.setVariableIfChanged(variable[1], variable[2], int(time.time()), childId) # Still here since a lot of methods sends info to this one. def setVariableIfChanged(self, serviceId, name, value, deviceId): self.log.info("setVariableIfChanged: "+serviceId +","+name+", "+str(value)+", "+str(deviceId)) #done def nextAvailiableRadioId(self): for i in xrange(10,254): if (self.availableIds[i] == True): self.availableIds[i] = False return i return 255 #almost done def presentation(self, incomingData, device, childId, altId): type = incomingData[3] data = incomingData[4] mode = bool(self.InclusionMode) if (mode == 'true' and device is None): #A new sensor (not created before) was presented during inclusion mode if (altId not in self.inclusionResult): self.log.info("presentation: New sensor starting up. Radio: "+ incomingData[0] + " Sensor: "+incomingData[1]) self.includeCount = self.includeCount+1; ###check the line below need to do something #setVariableIfChanged(ARDUINO_SID, "InclusionFoundCountHR", includeCount .." devices found", ARDUINO_DEVICE) #calc and write to config file. #Find max current childId add one for the new sensor. # not nice but this is how I try to learn python, 5 years from now I will cry over this solution. index = -1 for k, v in self.config.items("childIds") : if int(k) > index : index = int(k) index += 1 self.childIdLookupTable[altId] = index self.config.set('childIds',str(index),altId+";"+type) self.writeConfigFile() self.inclusionResult[altId] = type elif (mode == 0 and device is not None and childId == self.NODE_CHILD_ID and data != self.GATEWAY_VERSION): #The library version of sensor differs from plugin version. Warn about it. self.log.warn("presentation: Doesn't match Gateway version("+self.GATEWAY_VERSION+ "). Radio: "+ incomingData[0] + " Sensor: "+incomingData[1] + " using version: " + incomingData[4]) #done is going to need a lot of work... def processInternalMessage(self, incomingData, iChildId, iAltId): data = incomingData[4] index = int(incomingData[3]); varType = self.tInternalLookupNumType[index] var = self.tInternalTypes[varType] if (varType == "VERSION" and iAltId == "0;0"): #Store version of Arduino Gateway self.GATEWAY_VERSION = data self.log.info('processInternalMessage: Gateway running version: '+self.GATEWAY_VERSION ) print("Connected to Mysensor Gateway running version %s" % data) elif ((varType == "SKETCH_NAME" or varType == "SKETCH_VERSION") and iChildId is not None) : # Store the Sketch name and Version v = self.config.get('childIds',str(iChildId)) d = v.split(";") name = d[2] version = d[2] if varType == "SKETCH_NAME" : name = data.rstrip() elif varType == "SKETCH_VERSION" : version = data.rstrip() self.config.set('childIds',str(iChildId),iAltId+";"+name+";"+version) self.writeConfigFile() elif (varType == "TIME"): #Request time was sent from one of the sensors self.sendInternalCommand(iAltId,"TIME",time.time()) elif (varType == "UNIT"): #Request for unit was sent from one of the sensors self.sendInternalCommand(iAltId,"UNIT",self.unit) elif (varType == "REQUEST_ID"): #Determine next available radioid and sent it to the sensor self.sendInternalCommand(iAltId,"REQUEST_ID",self.nextAvailiableRadioId()) elif (varType == "RELAY_NODE" and iChildId is not None): #Set human readable relay mode status self.setVariableIfChanged(var[1], var[2], data, iChildId) ### Have a look at the one below #setVariableIfChanged(var[1], "RelayNodeHR", data == "0" and "GW" or data, iChildId) elif (varType == "BATTERY_LEVEL"): # Send to serVariable since you usally want to store this info. self.setVariable(incomingData, str(iChildId), iAltId) elif (varType == "INCLUSION_MODE"): if data == "0" : self.log.info("processInternalMessage: Inclusion mode started") elif data == "1" : self.log.info("processInternalMessage: Inclusion mode ended") elif (varType == "CHILDREN"): self.setVariableIfChanged(var[1], var[2], data, iChildId) elif (varType == "LOG_MESSAGE"): self.log.info("processInternalMessage: Log message:" + data) else: self.log.info("processInternalMessage: Incoming internal command discarded:" + data) def sendCommandOne(self,cmd): if self.ser.writable: self.ser.write(cmd+"\n") self.log.debug("sendCommandOne: Sending: "+cmd) else: self.log.error("sendCommandOne: Can't write to serial port") def setUnit(unit): self.setVariableIfChanged(ARDUINO_SID, "Unit", unit, ARDUINO_DEVICE) #done # Function to send a message to sensor def sendCommand(self, altid, variableId, value): return self.sendCommandWithMessageType(altid, "SET_VARIABLE", int(tVarTypes[variableId][0]), value) #done def sendNodeCommand(self, device, variableId, value): return self.sendCommandWithMessageType(device+";255", "SET_VARIABLE", int(tVarTypes[variableId][0]), value) #done def sendInternalCommand(self, altid, variableId, value): return self.sendCommandWithMessageType(altid, "INTERNAL", int(self.tInternalTypes[variableId][0]), str(value)) #done def sendRequestResponse(self, altid, variableId, value): return self.sendCommandWithMessageType(altid, "ACK_VARIABLE", int(self.tVarTypes[variableId][0]), value) #done def sendCommandWithMessageType(self, altid, messageType, variableId, value): cmd = altid+";"+self.msgType[messageType]+";"+str(variableId)+";"+value+"\n" if self.ser.writable: self.ser.write(cmd) self.log.debug("sendCommandWithMessageType: Sending: "+cmd) return True else: self.log.error("sendCommandWithMessageType: Can't write to serial port") return False #done def processIncoming(self, s): self.log.info("processIncoming: Receiving: "+s) incomingData = s.split(';') if len(incomingData) >= 4: nodeId = incomingData[0] childId = incomingData[1] messageType = incomingData[2] altId = nodeId+";"+childId if altId in self.childIdLookupTable : device = self.childIdLookupTable[altId] else : device = None if messageType==self.msgType["SET_VARIABLE"]: self.setVariable(incomingData, device, nodeId) elif messageType == self.msgType["PRESENTATION"]: self.presentation(incomingData, device, childId, altId) elif messageType == self.msgType["REQ_VARIABLE"]: self.requestStatus(incomingData, device, altId) elif messageType == self.msgType["INTERNAL"]: self.processInternalMessage(incomingData, device, altId) else: self.log.error("processIncoming: Error: Classic you shouldn't end up here: "+ s) else: self.log.error("processIncoming: Error: Receive unknown data: "+ s) def requestStatus(self, incomingData, childId, altId): self.log.debug("Requesting status for: "+altId) #A device request its current status from msgw (when staring up) index = int(incomingData[3]) varType = self.tVarLookupNumType[index] #Requested variable value from one of the sensors variable = self.tVarTypes[varType] if (variable[2] is not None and childId is not None): value = None self.log.debug("Request status for "+ variable[2]) #openhab if self.config.has_option('openhab',childId) and self.oh is not None: oh = Openhab(self.config, self.log) value=self.oh.requestStatus(incomingData, childId, altId) #support others here like Domoticz #Get default if there is none in the external system if value is None : self.sendRequestResponse(altId,varType,variable[3]) else : self.sendRequestResponse(altId,varType,value) #Arduino GW device commands def startInclusion(self): self.config.set('config','inclusion-mode',"true") return self.sendInternalCommand("0;0","INCLUSION_MODE","1") def stopInclusion(self): self.config.set('config','inclusion-mode',"false") return self.sendInternalCommand("0;0","INCLUSION_MODE","0") #Arduino relay node device commands def fetchChildren(self, device): variable = self.tInternalTypes["CHILDREN"] self.setVariableIfChanged(variable[1], variable[2], "Fetching...", device) #self.sendInternalCommand(luup.devices[device].id,"CHILDREN","F") self.sendInternalCommand(luup.devices[device].id,"CHILDREN","F") def clearChildren(self, device): variable = self.tInternalTypes["CHILDREN"] self.setVariableIfChanged(variable[1], variable[2], "Clearing...", device) #self.sendInternalCommand(luup.devices[device].id,"CHILDREN","C") self.sendInternalCommand(device+";255","CHILDREN","C") def refreshRelay(self, device): variable = self.tInternalTypes["RELAY_NODE"] self.setVariableIfChanged(variable[1], variable[2], "Refreshing...", device) #self.sendInternalCommand(luup.devices[device].id,"RELAY_NODE","") self.sendInternalCommand(device+";255","RELAY_NODE","") def updateLookupTables(self, radioId, childId, deviceId): self.childIdLookupTable[radioId+";"+childId] = deviceId self.availableIds[radioId] = False ### Support functions def reloadConfig(self, bootup = False) : #load known sensors from file for k, v in self.config.items("childIds") : value = v.split(';') self.childIdLookupTable[value[0]+";"+value[1]] = k self.availableIds[int(value[0])]=False #load unit M/I from file (A good programmer should check input values) self.unit = self.config.get('config','unit') #load InclutionMode from file and send it to gateway(A good programmer should check input values...) self.InclutionMode = self.config.get('config','inclusion-mode') #at bootup this is executed from init if bootup is False : self.setInclutionMode(self.InclutionMode) #initiate integrations #Openhab if self.config.get('config','openhab') == 'true': if self.oh is None : self.oh = Openhab(self.config, self.log) else : self.oh.reloadConfig() else : self.oh = None #Domoticz if self.config.get('config','domoticz') == 'true': if self.dom is None : self.dom = Domoticz(self.config, self.log) else : self.dom.reloadConfig() else : self.dom = None #RRD if self.config.get('config','rrd') == 'true': if self.rrd is None : self.rrd = Rrd(self.config, self.log) else : self.rrd.reloadConfig() else : self.rrd = None self.log.info("reloadConfig: Configuration reloaded.") #Parse Inclusion mode and sends the command to the Gateway def setInclutionMode(self, value) : if value == 'true' : self.startInclusion() elif value == 'false' : self.stopInclusion() else : self.log.warn("setInclutionMode : Invalid value :" +str(value)) self.writeConfigFile() # Write persist the config file def writeConfigFile(self) : with open('msgw.conf', 'wb') as configfile: self.config.write(configfile) #Parse command from external GUI:s like Openhab move this to Openhab file def parseExternalCommand(self,external,name,type,state) : #Openhab support if external == "OpenHab" and self.oh is not None: value=self.oh.parseCommand(type,state) childId = self.oh.getChildIdFromNane(name) if type == "InclusionMode" : self.setInclutionMode(value) elif value is not None and childId is not None : device = self.config.get('childIds',childId) action=self.msgType["SET_VARIABLE"] self.sendCommandOne(device+";"+value+'\n') else : self.log.error("parseExternalCommand: Missing value to send") #elif external == "Domoticz" .... #Write the code to support Domoticz else : self.log.error("parseExternalCommand: Don't support external commands for type: "+ external) #main def __init__(self, xconfig, xlog): self.log=xlog self.config=xconfig self.reloadConfig(True) #open serial interface self.ser = serial.Serial(self.config.get('config','port'),self.config.get('config','baudrate'),timeout=1) self.log.info("Start up: Listening on :" + self.config.get('config','port') +" using baudrate: "+ self.config.get('config','baudrate') ) self.ser.close() self.ser.open() print("Using Serial port %s at baudrate %s" % (self.config.get('config','port'), self.config.get('config','baudrate'))) #Give Arduino time to start up. sleep(5) self.sendCommandWithMessageType("0;0","INTERNAL",int(self.tInternalTypes["VERSION"][0]),"Get Version") self.setInclutionMode(self.InclutionMode)
def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile): Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile)
def onConnect(self, Connection, Status, Description): Domoticz.Log("onConnect called")
def onHeartbeat(self): #Domoticz.Log("onHeartbeat called") # Wich serial port settings to use? if (Parameters["Mode3"] == "S1B7PN"): StopBits, ByteSize, Parity = 1, 7, "N" if (Parameters["Mode3"] == "S1B7PE"): StopBits, ByteSize, Parity = 1, 7, "E" if (Parameters["Mode3"] == "S1B7PO"): StopBits, ByteSize, Parity = 1, 7, "O" if (Parameters["Mode3"] == "S1B8PN"): StopBits, ByteSize, Parity = 1, 8, "N" if (Parameters["Mode3"] == "S1B8PE"): StopBits, ByteSize, Parity = 1, 8, "E" if (Parameters["Mode3"] == "S1B8PO"): StopBits, ByteSize, Parity = 1, 8, "O" if (Parameters["Mode3"] == "S2B7PN"): StopBits, ByteSize, Parity = 2, 7, "N" if (Parameters["Mode3"] == "S2B7PE"): StopBits, ByteSize, Parity = 2, 7, "E" if (Parameters["Mode3"] == "S2B7PO"): StopBits, ByteSize, Parity = 2, 7, "O" if (Parameters["Mode3"] == "S2B8PN"): StopBits, ByteSize, Parity = 2, 8, "N" if (Parameters["Mode3"] == "S2B8PE"): StopBits, ByteSize, Parity = 2, 8, "E" if (Parameters["Mode3"] == "S2B8PO"): StopBits, ByteSize, Parity = 2, 8, "O" # How many registers to read (depending on data type)? # Added additional options for byte/word swapping registercount = 1 # Default if (Parameters["Mode6"] == "noco"): registercount = 1 if (Parameters["Mode6"] == "int8"): registercount = 1 if (Parameters["Mode6"] == "int16"): registercount = 1 if (Parameters["Mode6"] == "int16s"): registercount = 1 if (Parameters["Mode6"] == "int32"): registercount = 2 if (Parameters["Mode6"] == "int32s"): registercount = 2 if (Parameters["Mode6"] == "int64"): registercount = 4 if (Parameters["Mode6"] == "int64s"): registercount = 4 if (Parameters["Mode6"] == "uint8"): registercount = 1 if (Parameters["Mode6"] == "uint16"): registercount = 1 if (Parameters["Mode6"] == "uint16s"): registercount = 1 if (Parameters["Mode6"] == "uint32"): registercount = 2 if (Parameters["Mode6"] == "uint32s"): registercount = 2 if (Parameters["Mode6"] == "uint64"): registercount = 4 if (Parameters["Mode6"] == "uint64s"): registercount = 4 if (Parameters["Mode6"] == "float32"): registercount = 2 if (Parameters["Mode6"] == "float32s"): registercount = 2 if (Parameters["Mode6"] == "float64"): registercount = 4 if (Parameters["Mode6"] == "float64s"): registercount = 4 if (Parameters["Mode6"] == "string2"): registercount = 2 if (Parameters["Mode6"] == "string4"): registercount = 4 if (Parameters["Mode6"] == "string6"): registercount = 6 if (Parameters["Mode6"] == "string8"): registercount = 8 ################################### # pymodbus: RTU / ASCII ################################### if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"): Domoticz.Debug("MODBUS DEBUG USB SERIAL HW - Port="+Parameters["SerialPort"]+", BaudRate="+Parameters["Mode2"]+", StopBits="+str(StopBits)+", ByteSize="+str(ByteSize)+" Parity="+Parity) Domoticz.Debug("MODBUS DEBUG USB SERIAL CMD - Method="+Parameters["Mode1"]+", Address="+Parameters["Address"]+", Register="+Parameters["Password"]+", Function="+Parameters["Username"]+", Data type="+Parameters["Mode6"]) try: client = ModbusSerialClient(method=Parameters["Mode1"], port=Parameters["SerialPort"], stopbits=StopBits, bytesize=ByteSize, parity=Parity, baudrate=int(Parameters["Mode2"]), timeout=1, retries=2) except: Domoticz.Log("Error opening Serial interface on "+Parameters["SerialPort"]) Devices[1].Update(0, "0") # Update device in Domoticz ################################### # pymodbus: RTU over TCP ################################### if (Parameters["Mode1"] == "rtutcp"): Domoticz.Debug("MODBUS DEBUG TCP CMD - Method="+Parameters["Mode1"]+", Address="+Parameters["Address"]+", Port="+Parameters["Port"]+", Register="+Parameters["Password"]+", Data type="+Parameters["Mode6"]) try: client = ModbusTcpClient(host=Parameters["Address"], port=int(Parameters["Port"]), timeout=5) except: Domoticz.Log("Error opening TCP interface on address: "+Parameters["Address"]) Devices[1].Update(0, "0") # Update device in Domoticz ################################### # pymodbusTCP: TCP/IP ################################### if (Parameters["Mode1"] == "tcpip"): Domoticz.Debug("MODBUS DEBUG TCP CMD - Method="+Parameters["Mode1"]+", Address="+Parameters["Address"]+", Port="+Parameters["Port"]+", Register="+Parameters["Password"]+", Data type="+Parameters["Mode6"]) try: client = ModbusClient(host=Parameters["Address"], port=int(Parameters["Port"]), auto_open=True, auto_close=True, timeout=5) except: Domoticz.Log("Error opening TCP/IP interface on address: "+Parameters["Address"]) Devices[1].Update(0, "0") # Update device in Domoticz ################################### # pymodbus section ################################### if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii" or Parameters["Mode1"] == "rtutcp"): try: # Which function to execute? RTU/ASCII/RTU over TCP if (Parameters["Username"] == "1"): data = client.read_coils(int(Parameters["Password"]), registercount, unit=int(Parameters["Address"])) if (Parameters["Username"] == "2"): data = client.read_discrete_inputs(int(Parameters["Password"]), registercount, unit=int(Parameters["Address"])) if (Parameters["Username"] == "3"): data = client.read_holding_registers(int(Parameters["Password"]), registercount, unit=int(Parameters["Address"])) if (Parameters["Username"] == "4"): data = client.read_input_registers(int(Parameters["Password"]), registercount, unit=int(Parameters["Address"])) Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data)) except: Domoticz.Log("Modbus error communicating! (RTU/ASCII/RTU over TCP), check your settings!") Devices[1].Update(0, "0") # Update device to OFF in Domoticz try: # How to decode the input? # Added option to swap bytes (little endian) if (Parameters["Mode6"] == "int16s" or Parameters["Mode6"] == "uint16s"): decoder = BinaryPayloadDecoder.fromRegisters(data.registers, byteorder=Endian.Little, wordorder=Endian.Big) # Added option to swap words (little endian) elif (Parameters["Mode6"] == "int32s" or Parameters["Mode6"] == "uint32s" or Parameters["Mode6"] == "int64s" or Parameters["Mode6"] == "uint64s" or Parameters["Mode6"] == "float32s" or Parameters["Mode6"] == "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) if (Parameters["Mode6"] == "noco"): value = data.registers[0] if (Parameters["Mode6"] == "int8"): value = decoder.decode_8bit_int() if (Parameters["Mode6"] == "int16"): value = decoder.decode_16bit_int() if (Parameters["Mode6"] == "int16s"): value = decoder.decode_16bit_int() if (Parameters["Mode6"] == "int32"): value = decoder.decode_32bit_int() if (Parameters["Mode6"] == "int32s"): value = decoder.decode_32bit_int() if (Parameters["Mode6"] == "int64"): value = decoder.decode_64bit_int() if (Parameters["Mode6"] == "int64s"): value = decoder.decode_64bit_int() if (Parameters["Mode6"] == "uint8"): value = decoder.decode_8bit_uint() if (Parameters["Mode6"] == "uint16"): value = decoder.decode_16bit_uint() if (Parameters["Mode6"] == "uint16s"): value = decoder.decode_16bit_uint() if (Parameters["Mode6"] == "uint32"): value = decoder.decode_32bit_uint() if (Parameters["Mode6"] == "uint32s"): value = decoder.decode_32bit_uint() if (Parameters["Mode6"] == "uint64"): value = decoder.decode_64bit_uint() if (Parameters["Mode6"] == "uint64s"): value = decoder.decode_64bit_uint() if (Parameters["Mode6"] == "float32"): value = decoder.decode_32bit_float() if (Parameters["Mode6"] == "float32s"): value = decoder.decode_32bit_float() if (Parameters["Mode6"] == "float64"): value = decoder.decode_64bit_float() if (Parameters["Mode6"] == "float64s"): value = decoder.decode_64bit_float() if (Parameters["Mode6"] == "string2"): value = decoder.decode_string(2) if (Parameters["Mode6"] == "string4"): value = decoder.decode_string(4) if (Parameters["Mode6"] == "string6"): value = decoder.decode_string(6) if (Parameters["Mode6"] == "string8"): value = decoder.decode_string(8) Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value)) # Divide the value (decimal)? # Added 10000 option if (Parameters["Mode5"] == "div0"): value = str(value) if (Parameters["Mode5"] == "div10"): value = str(round(value / 10, 1)) if (Parameters["Mode5"] == "div100"): value = str(round(value / 100, 2)) if (Parameters["Mode5"] == "div1000"): value = str(round(value / 1000, 3)) if (Parameters["Mode5"] == "div10000"): value = str(round(value / 10000, 4)) Devices[1].Update(0, value) # Update value in Domoticz except: Domoticz.Log("Modbus error decoding or recieved no data (RTU/ASCII/RTU over TCP)!, check your settings!") Devices[1].Update(0, "0") # Update value in Domoticz ################################### # pymodbusTCP section ################################### if (Parameters["Mode1"] == "tcpip"): try: # Which function to execute? TCP/IP if (Parameters["Username"] == "1"): data = client.read_coils(int(Parameters["Password"]), registercount) if (Parameters["Username"] == "2"): data = client.read_discrete_inputs(int(Parameters["Password"]), registercount) if (Parameters["Username"] == "3"): data = client.read_holding_registers(int(Parameters["Password"]), registercount) if (Parameters["Username"] == "4"): data = client.read_input_registers(int(Parameters["Password"]), registercount) Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data[0])) except: Domoticz.Log("Modbus error communicating! (TCP/IP), check your settings!") Devices[1].Update(0, "0") # Update device to OFF in Domoticz try: # How to decode the input? # Added option to swap bytes (little endian) if (Parameters["Mode6"] == "int16s" or Parameters["Mode6"] == "uint16s"): decoder = BinaryPayloadDecoder.fromRegisters(data.registers, byteorder=Endian.Little, wordorder=Endian.Big) # Added option to swap words (little endian) elif (Parameters["Mode6"] == "int32s" or Parameters["Mode6"] == "uint32s" or Parameters["Mode6"] == "int64s" or Parameters["Mode6"] == "uint64s" or Parameters["Mode6"] == "float32s" or Parameters["Mode6"] == "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) if (Parameters["Mode6"] == "noco"): value = data.registers[0] if (Parameters["Mode6"] == "int8"): value = decoder.decode_8bit_int() if (Parameters["Mode6"] == "int16"): value = decoder.decode_16bit_int() if (Parameters["Mode6"] == "int16s"): value = decoder.decode_16bit_int() if (Parameters["Mode6"] == "int32"): value = decoder.decode_32bit_int() if (Parameters["Mode6"] == "int32s"): value = decoder.decode_32bit_int() if (Parameters["Mode6"] == "int64"): value = decoder.decode_64bit_int() if (Parameters["Mode6"] == "int64s"): value = decoder.decode_64bit_int() if (Parameters["Mode6"] == "uint8"): value = decoder.decode_8bit_uint() if (Parameters["Mode6"] == "uint16"): value = decoder.decode_16bit_uint() if (Parameters["Mode6"] == "uint16s"): value = decoder.decode_16bit_uint() if (Parameters["Mode6"] == "uint32"): value = decoder.decode_32bit_uint() if (Parameters["Mode6"] == "uint32s"): value = decoder.decode_32bit_uint() if (Parameters["Mode6"] == "uint64"): value = decoder.decode_64bit_uint() if (Parameters["Mode6"] == "uint64s"): value = decoder.decode_64bit_uint() if (Parameters["Mode6"] == "float32"): value = decoder.decode_32bit_float() if (Parameters["Mode6"] == "float32s"): value = decoder.decode_32bit_float() if (Parameters["Mode6"] == "float64"): value = decoder.decode_64bit_float() if (Parameters["Mode6"] == "float64s"): value = decoder.decode_64bit_float() if (Parameters["Mode6"] == "string2"): value = decoder.decode_string(2) if (Parameters["Mode6"] == "string4"): value = decoder.decode_string(4) if (Parameters["Mode6"] == "string6"): value = decoder.decode_string(6) if (Parameters["Mode6"] == "string8"): value = decoder.decode_string(8) Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value)) # Divide the value (decimal)? # Added 10000 option if (Parameters["Mode5"] == "div0"): value = str(value) if (Parameters["Mode5"] == "div10"): value = str(round(value / 10, 1)) if (Parameters["Mode5"] == "div100"): value = str(round(value / 100, 2)) if (Parameters["Mode5"] == "div1000"): value = str(round(value / 1000, 3)) if (Parameters["Mode5"] == "div10000"): value = str(round(value / 10000, 4)) if (Parameters["Username"] == "1") and (value != "0"): Devices[1].Update(1, value) # Update value in Domoticz except: Domoticz.Log("Modbus error decoding or recieved no data (TCP/IP)!, check your settings!") Devices[1].Update(0, "0") # Update value in Domoticz
def onMessage(self, Connection, Data, Status, Extra): Domoticz.Log("onMessage called")
def getNearbyWeatherStation(self): # Is the tree set? if self.tree == None: Domoticz.Log('No XML file found, try again later') return # Start distance far away distance = 10000.0 # Go through all the weather stations for stations in self.tree.iterfind( 'weergegevens/actueel_weer/weerstations'): ### Check if XML contains weather stations if stations.find('weerstation'): Domoticz.Debug('XML file contains weather station information') else: Domoticz.Log( 'XML file contains no weather station information, try again later' ) return for station in stations.findall('weerstation'): # What is the temperature at this station? temp = self.parseFloatValue(station.find('temperatuurGC').text) # If no is temperature set, skip this entry # Many weather stations only measure wind speed # They are not useful for weather information in domoticz if temp == None: continue # Where is this station? lat = float(station.find('lat').text) lon = float(station.find('lon').text) # Is this the station nearby? dist = self.haversine(self._lat, self._lon, lat, lon) if dist < distance: distance = dist self.stationID = station.get('id') # This is the station nearby for station in self.tree.iterfind( 'weergegevens/actueel_weer/weerstations/weerstation[@id=\'' + self.stationID + '\']'): Domoticz.Log('Found ' + station.find('stationnaam').text + ' (ID: ' + station.find('stationcode').text + ') at ' + "{:.1f}".format(distance) + ' km from your home location') break # Check if location is outside of The Netherlands if distance > 100: Domoticz.Log("Your location (" + str(self._lat) + "," + str(self._lon) + ") is too far away...") Domoticz.Log( "This plugin only works for locations within The Netherlands") self.stationID = ""
def onStop(self): Domoticz.Debug("onStop called") Domoticz.Debugging(0)
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 onStart(self): if Parameters["Mode6"] != "Normal": Domoticz.Debugging(1) DumpConfigToLog() self.SourceOptions = { "LevelActions" : "||||", "LevelNames" : "Off|Previous|Play|Pause|Next", "LevelOffHidden": "true", "SelectorStyle" : "0" } # Check if images are in database if 'Sonos' not in Images: Domoticz.Image('Sonos.zip').Create() if 'Sonos1' not in Images: Domoticz.Image('Sonos1.zip').Create() if 'Sonos5' not in Images: Domoticz.Image('Sonos5.zip').Create() # Create devices if required if 1 not in Devices: Domoticz.Device(Name="Status", Unit=1, Type=17, Switchtype=17, Used=1).Create() Domoticz.Log("Status device created") if 2 not in Devices: Domoticz.Device(Name="Volume", Unit=2, Type=244, Subtype=73, Switchtype=7, Image=8, Used=1).Create() Domoticz.Log("Volume device created.") if 3 not in Devices: Domoticz.Device(Name="Control", Unit=3, TypeName="Selector Switch", Switchtype=18, Image=8, Options=self.SourceOptions, Used=1).Create() Domoticz.Log("Control device created") # Create or update radio stations selector switch self.sonos_GetFavorites() LogMessage("Number of radio stations in favorites: " + str(len(self.radioFavorites))) sradioStations = sorted(list(self.radioFavorites.keys())) #get radiostations in sorted list, source is key in dict sradioStations = '|'.join(sradioStations) #get radiostations in string, divided with | for selector switch LogMessage("Radio stations in favorites: " + str(sradioStations)) self.SourceOptions2 = { "LevelActions" : "|"*int(len(self.radioFavorites)), "LevelNames" : "Off|" + sradioStations, "LevelOffHidden": "false", "SelectorStyle" : "1" } if 4 not in Devices: Domoticz.Device(Name="Radio", Unit=4, TypeName="Selector Switch", Switchtype=18, Image=8, Options=self.SourceOptions2, Used=1).Create() Domoticz.Log("Radio device created") if 4 in Devices and Parameters["Mode5"] == "Refresh": Devices[4].Delete() Domoticz.Device(Name="Radio", Unit=4, TypeName="Selector Switch", Switchtype=18, Image=8, Options=self.SourceOptions2, Used=1).Create() Domoticz.Log("Radio device updated (device will be on last position of Switches tab...)") Domoticz.Log("Number of radio stations in favorites: " + str(len(self.radioFavorites))) Domoticz.Log("Radio stations in favorites: " + str(sradioStations)) # Update images and status if 1 in Devices: UpdateImage(1) self.playerState = Devices[1].nValue if 2 in Devices: self.mediaLevel = Devices[2].nValue if 3 in Devices: UpdateImage(3) self.sonosControl = Devices[3].sValue if 4 in Devices: UpdateImage(4) self.sonosControl = Devices[3].sValue # Add notifier if required if Parameters["Mode3"] == "True": notifierName = Devices[1].Name #use hardware name from device name notifierName = notifierName.split(' -')[0] #remove everything after - notifierName = notifierName.replace(' ', '_') #replace spaces by underscore notifierName = notifierName.lower() #lower case Domoticz.Notifier(notifierName) #add notifier Domoticz.Log("Notifier '" + notifierName + "' added") # Set refresh if is_number(Parameters["Mode1"]): if int(Parameters["Mode1"]) < 30: Domoticz.Log("Update interval set to " + Parameters["Mode1"]) Domoticz.Heartbeat(int(Parameters["Mode1"])) else: Domoticz.Heartbeat(30) else: Domoticz.Heartbeat(30) return
def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile): LogMessage("Notification: " + Name + ", " + Status + ", " + Subject + ", " + Text + ", " + str(Priority) + ", " + Sound) if Parameters["Mode3"] == "True": # Example notification: doorbell.mp3/30 if "/" in Subject: notificationFile = Subject.split('/')[0] notificationVolume = Subject.split('/')[1] else: notificationFile = Subject notificationVolume = "10" #default volume # Get what's playing and volume saveVolume = self.sonos_GetVolume() savePositionInfo, saveTrackURI, saveTime, saveTrack = self.sonos_GetPositionInfo() saveMediainfo, saveURI, saveStation = self.sonos_GetMediaInfo() #saveTrackURI = saveTrackURI.split("?")[0] LogMessage(">> Show what is currently playing before switching to notification") LogMessage("Current volume: " + str(saveVolume)) if self.radioState == 1: LogMessage("Current URI: " + str(saveURI) + ". Current radio station: " + str(saveStation)) else: LogMessage("Currently playing: " + str(savePositionInfo) + ". Current URI: " + str(saveURI)) LogMessage("Current time in song: " + str(saveTime) + ". Number: " +str(saveTrack)) # Pause when Sonos is on if self.playerState == 1: wasOn = True self.sonos_SetCommand('Pause') else: wasOn = False # Check if Sonos is muted, if yes then unmute if self.muted == 0: wasMuted = True DesiredMute = "0" self.sonos_SetMute(DesiredMute) else: wasMuted = False # Get information on path and file slash = "" if str(Parameters["Mode4"]).endswith("/") else "/" # Check if path is a http website if str(Parameters["Mode4"]).startswith("http"): try: ret = urllib.request.urlopen(str(Parameters["Mode4"]) + slash + notificationFile) LogMessage("Notification: file '" + notificationFile + "' found") self.sonos_SetAVTransportURI(str(Parameters["Mode4"] + slash + notificationFile)) notificationReady2Play = True except (urllib.error.HTTPError, urllib.error.URLError) as e: Domoticz.Error("Notification: file '" + notificationFile + "' not found. " + str(e)) notificationReady2Play = False # Path is a network share elif str(Parameters["Mode4"]).startswith("//"): ###trying to find a way to check if file on smb share exist ###from smb.SMBConnection import SMBConnection is not working ''' try: with open("smb:" + str(Parameters["Mode4"]) + slash + notificationFile) as file: LogMessage("Notification: file '" + notificationFile + "' found") self.sonos_SetAVTransportURI("x-file-cifs:" + str(Parameters["Mode4"] + slash + notificationFile)) notificationReady2Play = True pass except IOError as e: Domoticz.Error("Notification: file '" + notificationFile + "' not found. " + str(e)) notificationReady2Play = False or try: ret = urllib.request.urlopen("smb:" + str(Parameters["Mode4"]) + slash + notificationFile) LogMessage("Notification: file '" + notificationFile + "' found") self.sonos_SetAVTransportURI("x-file-cifs:" + str(Parameters["Mode4"] + slash + notificationFile)) notificationReady2Play = True except (urllib.error.HTTPError, urllib.error.URLError) as e: Domoticz.Error("Notification: file '" + notificationFile + "' not found. " + str(e)) notificationReady2Play = False ''' self.sonos_SetAVTransportURI("x-file-cifs:" + str(Parameters["Mode4"] + slash + notificationFile)) notificationReady2Play = True else: Domoticz.Error("Notification folder '" + str(Parameters["Mode4"]) + "'not starting with 'http' or '//'") notificationReady2Play = False # Set volume and play notification if notificationReady2Play: self.sonos_SetVolume(str(notificationVolume)) self.sonos_SetCommand('Play') Domoticz.Log("Notification '" + str(notificationFile) + "' played with volume " + str(notificationVolume)) # Small pause needed when Sonos was off before playing notification, otherwise script won't see that Sonos is playing notification if wasOn == False: if self.sonos_GetTransportInfo() == 0: time.sleep(1) #delays for 1 second # Check if file is still playing while self.sonos_GetTransportInfo() == 1: time.sleep(1) #delays for 1 second LogMessage("Notification is playing") # Restore what was playing and volume if wasMuted: wasMuted = False DesiredMute = "1" self.sonos_SetMute(DesiredMute) self.sonos_SetVolume(str(saveVolume)) if self.radioState == 1: self.sonos_SetRadio(str(saveURI), str(saveStation)) #use CurrentURI from GetMediaInfo, using TrackURI is also possible else: self.sonos_SetAVTransportURI(str(saveURI)) #use CurrentURI from GetMediaInfo to restore the queue, using TrackURI ignores the queue self.sonos_Seek("TRACK_NR", str(saveTrack)) self.sonos_Seek("REL_TIME", str(saveTime)) # Play if previous list was playing if wasOn: self.sonos_SetCommand('Play') wasOn = False return
def create_device(self, name, unit, type, sub_type, switch_type): Domoticz.Device(Name=name, Unit=unit, Type=type, Subtype=sub_type, Switchtype=switch_type).Create()
def onHeartbeat(self): Domoticz.Log("onHeartbeat called " + str(self.lastPolled)) ## Read SMA Inverter ## url_base = "http://" + Parameters["Address"] + "/dyn/" url = url_base + "login.json" payload = ('{"pass" : "' + Parameters["Password"] + '", "right" : "usr"}') headers = { 'Content-Type': 'application/json', 'Accept-Charset': 'UTF-8' } self.lastPolled = self.lastPolled + 1 if (self.lastPolled > 3): self.lastPolled = 1 if (self.lastPolled == 1): try: r = requests.post(url, data=payload, headers=headers) except: Domoticz.Log("Error accessing SMA inverter on " + Parameters["Address"]) else: j = json.loads(r.text) try: sid = j['result']['sid'] except: Domoticz.Log("No response from SMA inverter on " + Parameters["Address"]) else: url = url_base + "getValues.json?sid=" + sid payload = ( '{"destDev":[],"keys":["6400_00260100","6400_00262200","6100_40263F00"]}' ) headers = { 'Content-Type': 'application/json', 'Accept-Charset': 'UTF-8' } try: r = requests.post(url, data=payload, headers=headers) except: Domoticz.Log("No data from SMA inverter on " + Parameters["Address"]) else: j = json.loads(r.text) sma_pv_watt = j['result']['012F-730B00E6'][ '6100_40263F00']['1'][0]['val'] if sma_pv_watt is None: sma_pv_watt = 0 sma_kwh_today = j['result']['012F-730B00E6'][ '6400_00262200']['1'][0]['val'] sma_kwh_total = j['result']['012F-730B00E6'][ '6400_00260100']['1'][0]['val'] / 1000 # Domoticz.Log(r.text) # Domoticz.Log(str(sma_pv_watt)) # Domoticz.Log(str(sma_kwh_today)) Devices[1].Update(nValue=sma_pv_watt, sValue=str(sma_pv_watt)) Devices[2].Update(nValue=sma_kwh_today, sValue=str(sma_kwh_today)) sValue = "%.2f" % sma_kwh_total Devices[3].Update(nValue=0, sValue=sValue.replace('.', ','))
def onHeartbeat(self): Domoticz.Debug("onHeartbeat called")
def onNotification(self, Data): Domoticz.Debug("onNotification: " + str(Data))
def onConnect(self, Connection, Status, Description): Domoticz.Debug("onConnect called. Status: " + str(Status))
def Open(self): if (self.icmpConn != None): self.Close() self.icmpConn = Domoticz.Connection(Name=self.Address, Transport="ICMP/IP", Protocol="ICMP", Address=self.Address) self.icmpConn.Listen()
def onStop(self): Domoticz.Log("Goobye from MELCloud plugin.")
def onStart(self): global icons Domoticz.Debug("onStart called") if Parameters["Mode6"] == 'Debug': self.debug = True Domoticz.Debugging(1) DumpConfigToLog() else: Domoticz.Debugging(0) # load custom battery images for key, value in icons.items(): if key not in Images: Domoticz.Image(value).Create() Domoticz.Debug("Added icon: " + key + " from file " + value) Domoticz.Debug("Number of icons loaded = " + str(len(Images))) for image in Images: Domoticz.Debug("Icon " + str(Images[image].ID) + " " + Images[image].Name) # check polling interval parameter try: temp = int(Parameters["Mode1"]) except: Domoticz.Error("Invalid polling interval parameter") else: if temp < 30: temp = 30 # minimum polling interval Domoticz.Error("Specified polling interval too short: changed to 30 minutes") elif temp > 1440: temp = 1440 # maximum polling interval is 1 day Domoticz.Error("Specified polling interval too long: changed to 1440 minutes (24 hours)") self.pollinterval = temp Domoticz.Log("Using polling interval of {} minutes".format(str(self.pollinterval))) # find zwave controller(s)... only one active allowed ! self.error = True controllers = glob.glob("./Config/zwcfg_0x????????.xml") if not controllers: # test if we are running on a synology (different file locations) controllers = glob.glob("/volume1/@appstore/domoticz/var/zwcfg_0x????????.xml") for controller in controllers: lastmod = datetime.fromtimestamp(os.stat(controller).st_mtime) if lastmod < datetime.now() - timedelta(hours=2): Domoticz.Error("Ignoring controller {} since presumed dead (not updated for more than 2 hours)".format(controller)) else: self.zwaveinfofilepath = controller self.error = False break if self.error: Domoticz.Error("Enable to find a zwave controller configuration file !")
def onMessage(self, Connection, Data): Status = int(Data["Status"]) if (Status == 200): strData = Data["Data"].decode("utf-8", "ignore") response = json.loads(strData) Domoticz.Debug("JSON REPLY: " + str(response)) if (self.melcloud_state == "LOGIN"): if (response["ErrorId"] == None): Domoticz.Log("MELCloud login successfull") self.melcloud_key = response["LoginData"]["ContextKey"] self.melcloud_units_init() elif (response["ErrorId"] == 1): Domoticz.Log( "MELCloud login fail: check login and password") self.melcloud_state = "LOGIN_FAILED" else: Domoticz.Log("MELCloud failed with unknown error " + str(response["ErrorId"])) self.melcloud_state = "LOGIN_FAILED" elif (self.melcloud_state == "UNITS_INIT"): idoffset = 0 Domoticz.Log("Find " + str(len(response)) + " buildings") for building in response: Domoticz.Log("Find " + str(len(building["Structure"]["Areas"])) + " areas in building " + building["Name"]) Domoticz.Log("Find " + str(len(building["Structure"]["Floors"])) + " floors in building " + building["Name"]) Domoticz.Log("Find " + str(len(building["Structure"]["Devices"])) + " devices in building " + building["Name"]) #Search in devices for device in building["Structure"]["Devices"]: self.melcloud_add_unit(device, idoffset) idoffset += len(self.list_switchs) #Search in areas for area in building["Structure"]["Areas"]: for device in area["Devices"]: self.melcloud_add_unit(device, idoffset) idoffset += len(self.list_switchs) #Search in floors for floor in building["Structure"]["Floors"]: for device in floor["Devices"]: self.melcloud_add_unit(device, idoffset) idoffset += len(self.list_switchs) for area in floor["Areas"]: for device in area["Devices"]: self.melcloud_add_unit(device, idoffset) idoffset += len(self.list_switchs) self.melcloud_create_units() elif (self.melcloud_state == "UNIT_INFO"): for unit in self.list_units: if (unit['id'] == response['DeviceID']): Domoticz.Log("Update unit {0} information.".format( unit['name'])) unit['power'] = response['Power'] unit['op_mode'] = response['OperationMode'] unit['room_temp'] = response['RoomTemperature'] unit['set_temp'] = response['SetTemperature'] unit['set_fan'] = response['SetFanSpeed'] unit['vaneH'] = response['VaneHorizontal'] unit['vaneV'] = response['VaneVertical'] unit['next_comm'] = False Domoticz.Debug("Heartbeat unit info: " + str(unit)) self.domoticz_sync_switchs(unit) elif (self.melcloud_state == "SET"): for unit in self.list_units: if (unit['id'] == response['DeviceID']): date, time = response['NextCommunication'].split("T") hours, minutes, sec = time.split(":") sign = Parameters["Mode1"][0] value = Parameters["Mode1"][1:] Domoticz.Debug("TIME OFFSSET :" + sign + value) if (sign == "-"): hours = int(hours) - int(value) if (hours < 0): hours = hours + 24 else: hours = int(hours) + int(value) if (hours > 24): hours = hours - 24 next_comm = date + " " + str( hours) + ":" + minutes + ":" + sec unit[ 'next_comm'] = "Update for last command at " + next_comm Domoticz.Log("Next update for command: " + next_comm) self.domoticz_sync_switchs(unit) else: Domoticz.Log("State not implemented:" + self.melcloud_state) else: Domoticz.Log("MELCloud receive unknonw message with error code " + Data["Status"])
def getWeather(self): # Is the tree set? if self.tree == None: return False # Was the station set properly? if self.stationID == "": return False # Reset all the weather data self.resetWeatherValues() # Get the weather information from the station for station in self.tree.iterfind( 'weergegevens/actueel_weer/weerstations/weerstation[@id=\'' + self.stationID + '\']'): #self.observationDate = datetime.strptime(station.find('datum').text, '%m/%d/%Y %H:%M:%S') self.temperature = self.parseFloatValue( station.find('temperatuurGC').text) self.windSpeed = self.parseFloatValue( station.find('windsnelheidMS').text) self.windBearing = self.parseFloatValue( station.find('windrichtingGR').text) self.windSpeedGusts = self.parseFloatValue( station.find('windstotenMS').text) self.pressure = self.parseFloatValue( station.find('luchtdruk').text) self.humidity = self.parseIntValue( station.find('luchtvochtigheid').text) self.visibility = self.parseIntValue( station.find('zichtmeters').text) self.solarIrradiance = self.parseFloatValue( station.find('zonintensiteitWM2').text) self.rainRate = self.parseFloatValue( station.find('regenMMPU').text) if self.pressure == None and self.visibility == None: Domoticz.Log( "No Barometer and Visibility info found in your weather station, getting info from weather station De Bilt" ) elif self.pressure == None: Domoticz.Log( "No Barometer info found in your weather station, getting Barometer info from weather station De Bilt" ) elif self.visibility == None: Domoticz.Log( "No Visibility info found in your weather station, getting visibility info from weather station De Bilt" ) if self.pressure == None: for station in self.tree.iterfind( 'weergegevens/actueel_weer/weerstations/weerstation[@id=\'' + self.stationIDbackup + '\']'): self.pressure = self.parseFloatValue( station.find('luchtdruk').text) if self.visibility == None: for station in self.tree.iterfind( 'weergegevens/actueel_weer/weerstations/weerstation[@id=\'' + self.stationIDbackup + '\']'): self.visibility = self.parseFloatValue( station.find('zichtmeters').text) #Domoticz.Log("Observation: " + str(self.observationDate)) Domoticz.Log("Temperature: " + str(self.temperature)) Domoticz.Log("Wind Speed: " + str(self.windSpeed) + " | Wind Bearing: " + str(self.windBearing) + " | Wind Direction: " + self.getWindDirection() + " | Wind Speed Gusts: " + str(self.windSpeedGusts) + " | Wind Chill: " + str(self.getWindChill())) Domoticz.Log("Barometer: " + str(self.pressure) + " | Barometer Forecast: " + str(self.getBarometerForecast())) Domoticz.Log("Humidity: " + str(self.humidity) + " | Humidity status: " + str(self.getHumidityStatus())) Domoticz.Log("Visibility: " + str(self.visibility)) Domoticz.Log("Solar Irradiance: " + str(self.solarIrradiance)) Domoticz.Log("Rain rate: " + str(self.rainRate)) self.lastUpdate = datetime.now() #return True for prediction in self.tree.iterfind( 'weergegevens/verwachting_vandaag'): self.weatherForecast = prediction.find('titel').text self.weatherFCDateTime = prediction.find('tijdweerbericht').text Domoticz.Log("Weather prediction today: " + str(self.weatherForecast) + " (" + str(self.weatherFCDateTime) + ")") return True return False
def onCommand(self, Unit, Command, Level, Hue): Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level)) #~ Get switch function: mode, fan, temp ... switch_id = Unit while switch_id > 7: switch_id -= 7 switch_type = self.list_switchs[switch_id - 1]["name"] #~ Get the unit in units array current_unit = False for unit in self.list_units: if (unit['idoffset'] + self.list_switchs[switch_id - 1]["id"]) == Unit: current_unit = unit break if (switch_type == 'Mode'): if (Level == 0): flag = 1 current_unit['power'] = 'false' Domoticz.Log("Switch Off the unit " + current_unit['name'] + "with ID offset " + str(current_unit['idoffset'])) Devices[1 + current_unit['idoffset']].Update(nValue=0, sValue=str(Level), Image=9) Devices[2 + current_unit['idoffset']].Update( nValue=0, sValue=str(Devices[Unit + 1].sValue)) Devices[3 + current_unit['idoffset']].Update( nValue=0, sValue=str(Devices[Unit + 2].sValue)) Devices[4 + current_unit['idoffset']].Update( nValue=0, sValue=str(Devices[Unit + 3].sValue)) Devices[5 + current_unit['idoffset']].Update( nValue=0, sValue=str(Devices[Unit + 4].sValue)) Devices[6 + current_unit['idoffset']].Update( nValue=0, sValue=str(Devices[Unit + 5].sValue)) elif (Level == 10): Domoticz.Log("Set to WARM the unit " + current_unit['name']) Devices[1 + current_unit['idoffset']].Update(nValue=1, sValue=str(Level), Image=15) elif (Level == 20): Domoticz.Log("Set to COLD the unit " + current_unit['name']) Devices[1 + current_unit['idoffset']].Update(nValue=1, sValue=str(Level), Image=16) elif (Level == 30): Domoticz.Log("Set to Vent the unit " + current_unit['name']) Devices[1 + current_unit['idoffset']].Update(nValue=1, sValue=str(Level), Image=7) elif (Level == 40): Domoticz.Log("Set to Dry the unit " + current_unit['name']) Devices[1 + current_unit['idoffset']].Update(nValue=1, sValue=str(Level), Image=11) elif (Level == 50): Domoticz.Log("Set to Auto the unit " + current_unit['name']) Devices[1 + current_unit['idoffset']].Update(nValue=1, sValue=str(Level), Image=11) if (Level != 0): flag = 1 current_unit['power'] = 'true' self.melcloud_set(current_unit, flag) flag = 6 current_unit['power'] = 'true' current_unit['op_mode'] = self.domoticz_levels['mode'][str( Level)] Devices[2 + current_unit['idoffset']].Update( nValue=1, sValue=str(Devices[Unit + 1].sValue)) Devices[3 + current_unit['idoffset']].Update( nValue=1, sValue=str(Devices[Unit + 2].sValue)) Devices[4 + current_unit['idoffset']].Update( nValue=1, sValue=str(Devices[Unit + 3].sValue)) Devices[5 + current_unit['idoffset']].Update( nValue=1, sValue=str(Devices[Unit + 4].sValue)) Devices[6 + current_unit['idoffset']].Update( nValue=1, sValue=str(Devices[Unit + 5].sValue)) elif (switch_type == 'Fan'): flag = 8 current_unit['set_fan'] = self.domoticz_levels['fan'][str(Level)] Domoticz.Log("Change FAN to value {0} for {1} ".format( self.domoticz_levels['temp'][str(Level)], current_unit['name'])) Devices[Unit].Update(nValue=Devices[Unit].nValue, sValue=str(Level)) elif (switch_type == 'Temp'): flag = 4 setTemp = 16 if (Level != 0): setTemp = int(str(Level).strip("0")) + 16 Domoticz.Log("Change Temp to " + str(setTemp) + " for " + unit['name']) current_unit['set_temp'] = self.domoticz_levels['temp'][str(Level)] Devices[Unit].Update(nValue=Devices[Unit].nValue, sValue=str(Level)) elif (switch_type == 'Vane Horizontal'): flag = 256 current_unit['vaneH'] = self.domoticz_levels['vaneH'][str(Level)] Domoticz.Debug( "Change Vane Horizontal to value {0} for {1}".format( self.domoticz_levels['vaneH'][str(Level)], current_unit['name'])) Devices[Unit].Update(Devices[Unit].nValue, str(Level)) elif (switch_type == 'Vane Vertical'): flag = 16 current_unit['vaneV'] = self.domoticz_levels['vaneV'][str(Level)] Domoticz.Debug("Change Vane Vertical to value {0} for {1}".format( self.domoticz_levels['vaneV'][str(Level)], current_unit['name'])) Devices[Unit].Update(Devices[Unit].nValue, str(Level)) else: Domoticz.Log("Device not found") self.melcloud_set(current_unit, flag) return True
def onCommand(self, Unit, Command, Level, Hue): Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level))
def onDisconnect(self, Connection): self.melcloud_state = "Not Ready" Domoticz.Log("MELCloud has disconnected") self.melcloud_conn.Connect()
def onStop(self): Domoticz.Log("onStop called")
def onDisconnect(Connection): for Device in Devices: Devices[Device].Update(nValue=Devices[Device].nValue, sValue=Devices[Device].sValue, TimedOut=1) Domoticz.Log("Connection '"+Connection.Name+"' disconnected.") return
def onMessage(self, Connection, Data): Domoticz.Log("onMessage called")
def LogMessage(Message): if Parameters["Mode6"] == "File": f = open(Parameters["HomeFolder"]+"plugin.log","a") f.write(Message+"\r\n") f.close() Domoticz.Debug(Message)
def onDisconnect(self, Connection): Domoticz.Log("onDisconnect called")
def onMessage(Connection, Data): global hasConnected, nextCommand, fScale, summation strData = Data.decode("utf-8", "ignore") LogMessage(strData) xmltree = ET.fromstring(strData) if xmltree.tag == 'ConnectionStatus': strLog = "" if (xmltree.find('MeterMacId') != None): strLog = "MeterMacId: "+xmltree.find('MeterMacId').text+", " connectStatus = xmltree.find('Status').text strLog += "Connection Status = '"+connectStatus+"'" if (xmltree.find('Description') != None): strLog += " - "+xmltree.find('Description').text if (xmltree.find('LinkStrength') != None): strLog += ", Link Strength = "+str(int(xmltree.find('LinkStrength').text,16)) Domoticz.Log(strLog) if connectStatus == 'Initializing...': hasConnected = False elif (connectStatus == 'Connected') and (hasConnected == False): nextCommand = "get_device_info" hasConnected = True elif xmltree.tag == 'DeviceInfo': Domoticz.Log( "Manufacturer: %s, Device ID: %s, Install Code: %s" % (xmltree.find('Manufacturer').text, xmltree.find('DeviceMacId').text, xmltree.find('InstallCode').text) ) Domoticz.Log( "Hardware: Version %s, Firmware Version: %s, Model: %s" % (xmltree.find('HWVersion').text, xmltree.find('FWVersion').text, xmltree.find('ModelId').text) ) nextCommand = "get_network_info" elif xmltree.tag == 'NetworkInfo': LogMessage( "NetworkInfo response, Status = '%s' - %s, Link Strength = %d" % (xmltree.find('Status').text, xmltree.find('Description').text, int(xmltree.find('LinkStrength').text,16))) nextCommand = "get_meter_list" elif xmltree.tag == 'MeterList': nextCommand = "" for meter in xmltree.iter('MeterMacId'): LogMessage( "MeterMacId: %s, MeterList response" % meter.text) Connection.Send("<Command>\n <Name>get_meter_info</Name>\n <MeterMacId>"+meter.text+"</MeterMacId>\n</Command>\n") elif xmltree.tag == 'MeterInfo': LogMessage( "MeterMacId: %s, MeterInfo response, Enabled = %s" % (xmltree.find('MeterMacId').text, xmltree.find('Enabled').text)) Connection.Send("<Command>\n <Name>get_schedule</Name>\n <MeterMacId>"+xmltree.find('MeterMacId').text+"</MeterMacId>\n</Command>\n") elif xmltree.tag == 'ScheduleInfo': iFreq = int(xmltree.find('Frequency').text,16) LogMessage( "MeterMacId: %s, ScheduleInfo response: Type '%s', Frequency %d, Enabled %s" % (xmltree.find('MeterMacId').text, xmltree.find('Event').text, iFreq, xmltree.find('Enabled').text)) if (xmltree.find('Event').text == 'demand') and (iFreq != demandFreq): LogMessage( "MeterMacId: %s, Setting 'demand' schedule to: Frequency %d" % (xmltree.find('MeterMacId').text, demandFreq)) Connection.Send("<Command>\n <Name>set_schedule</Name>\n <MeterMacId>"+xmltree.find('MeterMacId').text+"</MeterMacId>\n <Event>demand</Event>\n <Frequency>" + str(hex(demandFreq)) + "</Frequency>\n <Enabled>Y</Enabled>\n</Command>\n") if (xmltree.find('Event').text == 'summation') and (iFreq != summaryFreq): LogMessage( "MeterMacId: %s, Setting 'summation' schedule to: Frequency %d" % (xmltree.find('MeterMacId').text, summaryFreq)) Connection.Send("<Command>\n <Name>set_schedule</Name>\n <MeterMacId>"+xmltree.find('MeterMacId').text+"</MeterMacId>\n <Event>summation</Event>\n <Frequency>" + str(hex(summaryFreq)) + "</Frequency>\n <Enabled>Y</Enabled>\n</Command>\n") if (xmltree.find('Event').text == 'summation'): Connection.Send("<Command>\n <Name>get_current_summation_delivered</Name>\n <MeterMacId>"+xmltree.find('MeterMacId').text+"</MeterMacId>\n <Refresh>Y</Refresh>\n</Command>\n") elif xmltree.tag == 'InstantaneousDemand': demand = float(getInstantDemandKWh(xmltree)) if (summation == 0.0): Domoticz.Log("MeterMacId: %s, Instantaneous Demand = %f, NO SUMMARY DATA" % (xmltree.find('MeterMacId').text, demand)) else: delta = fScale * demand summation = summation + delta Domoticz.Log( "MeterMacId: %s, Instantaneous Demand = %.3f, Summary Total = %.3f, Delta = %f" % (xmltree.find('MeterMacId').text, demand, summation, delta)) sValue = "%.3f;%.3f" % (demand,summation) Devices[1].Update(nValue=0, sValue=sValue.replace('.',''), TimedOut=0) elif xmltree.tag == 'CurrentSummationDelivered': total = float(getCurrentSummationKWh(xmltree)) if (total > summation): summation = total sValue = "%.3f" % (total) Devices[2].Update(nValue=0, sValue=sValue.replace('.',''), TimedOut=0) Domoticz.Log( "MeterMacId: %s, Current Summation = %.3f" % (xmltree.find('MeterMacId').text, total)) elif xmltree.tag == 'TimeCluster': Domoticz.Debug( xmltree.tag + " response" ) elif xmltree.tag == 'PriceCluster': Domoticz.Debug( xmltree.tag + " response" ) elif xmltree.tag == 'CurrentPeriodUsage': Domoticz.Debug( xmltree.tag + " response" ) elif xmltree.tag == 'LastPeriodUsage': Domoticz.Debug( xmltree.tag + " response" ) elif xmltree.tag == 'ProfileData': Domoticz.Debug( xmltree.tag + " response" ) else: Domoticz.Error("Unrecognised (not implemented) XML Fragment ("+xmltree.tag+").") return
def onConnect(self, Connection, Status, Description): if (Status == 0): Domoticz.Log("Successful connect to: "+Connection.Address+" which is surprising because ICMP is connectionless.") else: Domoticz.Log("Failed to connect to: "+Connection.Address+", Description: "+Description) self.icmpConn = None
def onStart(self): if Parameters["Mode6"] == "Debug": Domoticz.Debugging(1) Domoticz.Debug("onStart called")