def Prod(devKey): # Ask device a question, just to provoke a response nwkId = database.GetDeviceItem(devKey, "nwkId") ep = database.GetDeviceItem(devKey, "endPoints") if nwkId != None and ep != None: log.debug("Prodding devKey " + str(devKey) + " (nwkId:" + nwkId + ")") cmdRsp = telegesis.ReadAttr( nwkId, ep, zcl.Cluster.Basic, zcl.Attribute.Model_Name ) # Get Basic's Device Name in order to prod it into life queue.EnqueueCmd(devKey, cmdRsp)
def CheckPresence(): # Expected to be called infrequently - ie once/minute global info devIdx = 0 for device in info: if GetTempVal( devIdx, "AtCmdRsp" ) == None: # No pending command, so check whether device is present lastSeen = GetTempVal(devIdx, "LastSeen") if lastSeen != None: if datetime.now() > lastSeen + timedelta( seconds=900 ): # More than 15 minutes since we last heard from device devId = GetVal(devIdx, "devId") ep = GetVal(devIdx, "EP") if devId != None and ep != None: pendingAtCmd = telegesis.ReadAttr( devId, ep, zcl.Cluster.Basic, zcl.Attribute. Model_Name) # Get Basic's Device Name SetTempVal(devIdx, "AtCmdRsp", pendingAtCmd) if datetime.now() > lastSeen + timedelta( seconds=1800 ): # More than 30 minutes since we last heard from device SetStatus(devIdx, "Presence", "* Missing *") devIdx = devIdx + 1
def Check(devKey): global pendingBinding, msp_ota if devKey == 0: return # We don't need anything from the hub nwkId = database.GetDeviceItem(devKey, "nwkId") if None == nwkId: return # Make sure it's a real device before continuing (it may have just been deleted) ep = database.GetDeviceItem(devKey, "endPoints") if None == ep: return (["AT+ACTEPDESC:" + nwkId + "," + nwkId, "ActEpDesc"]) eui = database.GetDeviceItem(devKey, "eui64") if None == eui: return (["AT+EUIREQ:" + nwkId + "," + nwkId, "AddrResp"]) inClstr = database.GetDeviceItem( devKey, "inClusters", "[]") # Assume we have a list of clusters if we get this far if "[]" == inClstr: return ([ "AT+SIMPLEDESC:" + nwkId + "," + nwkId + "," + ep, "OutCluster" ]) outClstr = database.GetDeviceItem(devKey, "outClusters", "[]") binding = database.GetDeviceItem(devKey, "binding" "[]") if str(pendingBinding[devKey] ) == "": # Only try to add one binding per device at once if zcl.Cluster.PollCtrl in inClstr and zcl.Cluster.PollCtrl not in binding: return SetBinding( devKey, zcl.Cluster.PollCtrl, "01") # 01 is our endpoint we want CHECKIN messages to come to if zcl.Cluster.OnOff in outClstr and zcl.Cluster.OnOff not in binding: # If device sends OnOff commands (eg a Button) return SetBinding( devKey, zcl.Cluster.OnOff, "0A" ) # 0A is our endpoint we want messages to come to (so that we get TOGGLE, ON and OFF commands) if zcl.Cluster.Temperature in inClstr and zcl.Cluster.Temperature not in binding: return SetBinding( devKey, zcl.Cluster.Temperature, "01" ) # 01 is our endpoint we want Temperature reports to come to if zcl.Cluster.SimpleMetering in inClstr and zcl.Cluster.SimpleMetering not in binding: return SetBinding( devKey, zcl.Cluster.SimpleMetering, "01" ) # 01 is our endpoint we want SimpleMetering messages to come to if zcl.Cluster.Thermostat in inClstr and zcl.Cluster.Thermostat not in binding: return SetBinding( devKey, zcl.Cluster.Thermostat, "01" ) # 01 is our endpoint we want Thermostat messages to come to if zcl.Cluster.IAS_Zone in inClstr: if None == database.GetDeviceItem(devKey, "iasZoneType"): return telegesis.ReadAttr( nwkId, ep, zcl.Cluster.IAS_Zone, zcl.Attribute.Zone_Type ) # Get IAS device type (PIR or contact, etc.) if zcl.Cluster.Basic in inClstr: if None == database.GetDeviceItem(devKey, "modelName"): return telegesis.ReadAttr( nwkId, ep, zcl.Cluster.Basic, zcl.Attribute.Model_Name) # Get Basic's Device Name if None == database.GetDeviceItem(devKey, "manufName"): return telegesis.ReadAttr( nwkId, ep, zcl.Cluster.Basic, zcl.Attribute.Manuf_Name) # Get Basic's Manufacturer Name if zcl.Cluster.PowerConfig in inClstr and "SED" == database.GetDeviceItem( devKey, "devType"): checkBatt = GetTempVal(devKey, "GetNextBatteryAfter") if checkBatt != None: if datetime.now() > checkBatt: log.debug("Now = " + str(datetime.now()) + " and checkBatt = " + str(checkBatt)) return telegesis.ReadAttr( nwkId, ep, zcl.Cluster.PowerConfig, zcl.Attribute.Batt_Percentage) # Get Battery percentage if zcl.Cluster.PollCtrl in inClstr: if None == database.GetDeviceItem(devKey, "longPollInterval"): return telegesis.ReadAttr( nwkId, ep, zcl.Cluster.PollCtrl, zcl.Attribute. LongPollIntervalQs) # Get Poll Control's Long poll interval if zcl.Cluster.OTA in outClstr: if None == database.GetDeviceItem(devKey, "firmwareVersion"): return ("AT+READCATR:" + nwkId + "," + ep + ",0," + zcl.Cluster.OTA + "," + zcl.Attribute.firmwareVersion, "RESPATTR" ) # Get OTA's Version number as a string of hex digits if msp_ota != None and msp_ota in outClstr: if None == database.GetDeviceItem(devKey, "firmwareVersion"): return ("AT+READMCATR:" + nwkId + "," + ep + ",0," + config.Get(mfgId) + "," + msp_ota + "," + zcl.Attribute.firmwareVersion, "RESPMATTR" ) # Get OTA's Version number as a string of hex digits reporting = database.GetDeviceItem(devKey, "reporting", "[]") if zcl.Cluster.PowerConfig in binding and "SED" == database.GetDeviceItem( devKey, "devType"): atCmd = CheckReporting( devKey, reporting, "batteryReporting", zcl.Cluster.PowerConfig, zcl.Attribute.Batt_Percentage, zcl.AttributeTypes.Uint8, "43200,43200,2" ) # Default temperature reporting is "Every 12 hours" if atCmd != None: return atCmd if zcl.Cluster.Temperature in binding: atCmd = CheckReporting( devKey, reporting, "temperatureReporting", zcl.Cluster.Temperature, zcl.Attribute.Celsius, zcl.AttributeTypes.Uint16, "300,3600,100" ) # Default temperature reporting is "between 5 mins and 1 hr, or +/- 1.00'C" if atCmd != None: return atCmd if zcl.Cluster.SimpleMetering in binding: atCmd = CheckReporting( devKey, reporting, "powerReporting", zcl.Cluster.SimpleMetering, zcl.Attribute.InstantaneousDemand, zcl.AttributeTypes.Sint24, "-1,-1,10" ) # Default power reporting is "between 5 seconds and 15 minutes, or +/- 10W" if atCmd != None: return atCmd atCmd = CheckReporting( devKey, reporting, "energyConsumedReporting", zcl.Cluster.SimpleMetering, zcl.Attribute.CurrentSummationDelivered, zcl.AttributeTypes.Uint48, "-1,-1,100" ) # Default energy consumed reporting is "between 1 minute and 15 minutes, or +100Wh" if atCmd != None: return atCmd atCmd = CheckReporting( devKey, reporting, "energyGeneratedReporting", zcl.Cluster.SimpleMetering, zcl.Attribute.CurrentSummationReceived, zcl.AttributeTypes.Uint48, "-1,-1,0" ) # Default energy generated reporting is "never" (-1 as max) if atCmd != None: return atCmd if zcl.Cluster.Thermostat in binding: atCmd = CheckReporting( devKey, reporting, "targetTempReporting", zcl.Cluster.Thermostat, zcl.Attribute.OccupiedHeatingSetPoint, zcl.AttributeTypes.Sint16, "60,900,100" ) # Default target temperature reporting is "between 1 minute and 15 minutes, or +/-1.00'C" if atCmd != None: return atCmd if GetTempVal(devKey, "JustSentOnOff"): DelTempVal(devKey, "JustSentOnOff") return telegesis.ReadAttr( nwkId, ep, zcl.Cluster.OnOff, zcl.Attribute.OnOffState) # Get OnOff state after sending toggle return None
def Check(devIdx, consume): global pendingBinding, pendingRptAttrId devId = GetVal(devIdx, "devId") ep = GetVal(devIdx, "EP") eui = GetVal(devIdx, "EUI") if None == ep: return ("AT+ACTEPDESC:" + devId + "," + devId, "ActEpDesc") if None == eui: return ("AT+EUIREQ:" + devId + "," + devId, "AddrResp") if None == GetVal(devIdx, "InCluster") or None == GetVal( devIdx, "OutCluster"): SetVal(devIdx, "OutCluster", []) # Some devices have no outclusters... return ("AT+SIMPLEDESC:" + devId + "," + devId + "," + ep, "OutCluster") inClstr = GetVal( devIdx, "InCluster") # Assume we have a list of clusters if we get this far outClstr = GetVal(devIdx, "OutCluster") binding = GetVal(devIdx, "Binding") rprtg = GetVal(devIdx, "Reporting") if inClstr != None: if binding != None: if zcl.Cluster.PollCtrl in inClstr and zcl.Cluster.PollCtrl not in binding: return SetBinding( devIdx, zcl.Cluster.PollCtrl, "01") # 01 is our endpoint we want messages to come to if zcl.Cluster.OnOff in outClstr and zcl.Cluster.OnOff not in binding: # If device sends OnOff commands... return SetBinding( devIdx, zcl.Cluster.OnOff, "0A") # 0A is our endpoint we want messages to come to if zcl.Cluster.Temperature in inClstr and zcl.Cluster.Temperature not in binding: return SetBinding( devIdx, zcl.Cluster.Temperature, "01") # 01 is our endpoint we want messages to come to else: SetVal(devIdx, "Binding", []) if zcl.Cluster.IAS_Zone in inClstr: if None == GetAttrVal(devIdx, zcl.Cluster.IAS_Zone, zcl.Attribute.Zone_Type): return telegesis.ReadAttr( devId, ep, zcl.Cluster.IAS_Zone, zcl.Attribute.Zone_Type ) # Get IAS device type (PIR or contact, etc.) if zcl.Cluster.Basic in inClstr: if None == GetAttrVal(devIdx, zcl.Cluster.Basic, zcl.Attribute.Model_Name): return telegesis.ReadAttr( devId, ep, zcl.Cluster.Basic, zcl.Attribute.Model_Name) # Get Basic's Device Name if None == GetAttrVal(devIdx, zcl.Cluster.Basic, zcl.Attribute.Manuf_Name): return telegesis.ReadAttr( devId, ep, zcl.Cluster.Basic, zcl.Attribute.Manuf_Name) # Get Basic's Manufacturer Name if zcl.Cluster.PowerConfig in inClstr and "SED" == GetVal( devIdx, "DevType"): if None == GetAttrVal( devIdx, zcl.Cluster.PowerConfig, zcl.Attribute.Batt_Percentage ) or datetime.now() > GetTempVal(devIdx, "GetNextBatteryAfter"): return telegesis.ReadAttr( devId, ep, zcl.Cluster.PowerConfig, zcl.Attribute.Batt_Percentage) # Get Battery percentage if rprtg != None: if zcl.Cluster.Temperature in inClstr: tmpRpt = zcl.Cluster.Temperature + ":" + zcl.Attribute.Celsius if zcl.Cluster.Temperature in binding and tmpRpt not in rprtg: pendingRptAttrId = zcl.Attribute.Celsius return ( "AT+CFGRPT:" + devId + "," + ep + ",0," + zcl.Cluster.Temperature + ",0," + zcl.Attribute.Celsius + "," + zcl.AttributeTypes.Uint16 + ",012C,0E10,0064", "CFGRPTRP" ) # 012C is 300==5 mins, 0E10 is 3600==1 hour, 0064 is 100, being 1.00'C else: SetVal(devIdx, "Reporting", []) wantOnOff = GetTempVal(devIdx, "JustSentOnOff") if wantOnOff: DelTempVal(devIdx, "JustSentOnOff") return telegesis.ReadAttr( devId, ep, zcl.Cluster.OnOff, zcl.Attribute.OnOffState) # Get OnOff state after sending toggle pendingAtCmd = GetTempVal(devIdx, "AtCmdRsp") if pendingAtCmd: if consume: DelTempVal( devIdx, "AtCmdRsp" ) # Remove item if we're about to use it (presuming successful sending of command...) return pendingAtCmd