def GetDark(): sunrise = datetime.strptime(variables.Get("sunrise"), "%H:%M") sunset = datetime.strptime(variables.Get("sunset"), "%H:%M") now = datetime.strptime(datetime.now().strftime("%H:%M"), "%H:%M") # Just time of day cloudCover = variables.Get("cloudCover") if cloudCover != None: extraTime = int( cloudCover) # Just take percentage cloudiness as minutes else: extraTime = 0 # No weather, so assume cloudless and dry if extraTime < 30: extraTime = 30 # Minimum of half an hour of evening before sunset morning = sunrise + timedelta( minutes=extraTime ) # The more cloud, the later it gets light in the morning evening = sunset - timedelta( minutes=extraTime ) # The more cloud, the earlier it gets dark in the evening oldMorning = variables.Get( "morning" ) # if time is between variables.Get("morning") and newly calculated morning, then rules.Run("time==morning") oldEvening = variables.Get( "evening" ) # if time is between variables.Get("evening") and newly calculated evening, then rules.Run("time==evening") if IsTimeBetween(morning, now, oldMorning): rules.Run("time==morning") if IsTimeBetween(evening, now, oldEvening): rules.Run("time==evening") variables.Set("morning", morning.strftime("%H:%M"), True) variables.Set("evening", evening.strftime("%H:%M"), True) # Set up variables accordingly return not (IsTimeBetween(morning, now, evening) ) # True if dark, False if light
def Run( trigger ): # Run through the rules looking to see if we have a match for the trigger rules = database.GetRules( trigger) # Get a list of all rules that mention trigger log.debug("Running rule: " + trigger) delVar = False if "==" in trigger: sep = trigger.index("==") triggerType = trigger[:sep] triggerVal = trigger[sep + 2:] oldVal = variables.Get(triggerType) if oldVal == None: # Check to see if this variable already exists and leave it alone if so variables.Set(triggerType, triggerVal) delVar = True for line in rules: ruleId = line[0] rule = ' '.join( line[1].split() ) # Compact multiple spaces into single ones and make each line into a rule ruleList = rule.split(" ") # Make each rule into a list if ruleList[0].lower() == "if": doIndex = FindItemInList("do", ruleList) # Safely look for "do" if doIndex != None: if ParseCondition( ruleList[1:doIndex], trigger ) == True: # Parse condition from element 1 (ie immediately after "if") to "do" Action(ruleList[doIndex + 1:], ruleId) # Do action # else skip rest of line # else assume the line is a comment and skip it # end of rules if delVar: variables.Del( triggerType) # Make sure we don't re-run the same trigger
def Get(item): if ":" not in item: # If named item rather than HH:MM timestamp item = variables.Get( item) # Get time of day from variable (eg sunrise, etc.) if item == None: item = "00:00" # Null items become midnight return datetime.strptime(item, "%H:%M")
def MakeText(id): if weather.forecastPeriod=="": return None; reportDict = dict() reportDict["target"] = id minutes = datetime.now().minute #if minutes % 2 == 0: # reportDict["display"] = "off" #else: reportDict["display"] = "on" # For now at least reportDict["period"] = weather.forecastPeriod reportDict["icon"] = str(weather.symSym)[4:] reportDict["cloudText"] = weather.cloudText reportDict["maxTemp"] = str(round(weather.maxTemp))+"C" reportDict["minTemp"] = str(round(weather.minTemp))+"C" reportDict["windSpeed"] = str(round(weather.maxWind)) reportDict["windDir"] = str(weather.windDir) reportDict["windText"] = weather.windText now = datetime.now() reportDict["timeDigits"] = str(now.strftime("%H:%M")) reportDict["timeText"] = GetTimeInWords() reportDict["dayOfWeekText"] = str(now.strftime("%A")) reportDict["dayOfMonthText"] = str(int(now.strftime("%d"))) # Use int() to remove leading zero reportDict["monthText"] = str(now.strftime("%B")) powerMonitorName = config.Get("PowerMonitor") # House power monitoring device if powerMonitorName != None: devKey = devices.FindDev(powerMonitorName) if devKey != None: powerW = database.GetLatestLoggedItem(devKey, "PowerReadingW") if powerW != None: reportDict["powerNow"] = str(powerW[0]) energyToday = variables.Get("energyToday_kWh") if energyToday: reportDict["energyToday"] = energyToday tempMonitorName = config.Get("HouseTempDevice") # House temperature monitoring device if tempMonitorName != None: devKey = devices.FindDev(tempMonitorName) if devKey != None: houseTemp = database.GetLatestLoggedItem(devKey, "TemperatureCelsius") reportDict["houseTemp"] = '%.1f' % (houseTemp[0]) targetTemp = variables.Get("TargetTemp") if targetTemp != None: reportDict["TargetTemp"] = targetTemp #log.debug("ReportDict for:" +id + "=" + str(reportDict)) # Already reported in WiFiServer.py return (str(reportDict))
def GetConditionResult(test, condition): sep = condition.index( test) # Assume this has already been shown to return a valid answer varName = condition[:sep] # Variable must be on the left of the expression tstVal = condition[sep + len(test):] # Simple value must be on right varVal = variables.Get(varName) if varVal != None: if isNumber(tstVal): varVal = str(varVal) tstVal = str(tstVal) return eval(varVal + test + tstVal) else: return False # If we couldn't find the item requested, assume the condition fails(?)
def GetConditionResult(test, condition): sep = condition.index( test) # Assume this has already been shown to return a valid answer tstVal = condition[sep + len(test):] # Simple value must be on right varName = condition[:sep] # Variable must be on the left of the expression if "-" in varName: variables.GetVal(varName, "-") elif "+" in varName: variables.GetVal(varName, "+") else: varVal = variables.Get(varName) if varVal != None: if isNumber(tstVal): varVal = str(varVal) tstVal = str(tstVal) elif ":" in tstVal: varVal = iottime.Sanitise( varVal ) # Ensure timestamps are consistently formatted before comparing (to avoid "0:15" != "00:15") tstVal = iottime.Sanitise(tstVal) log.debug("Time test checks " + varVal + " against " + tstVal) else: varVal = "'" + varVal.lower() + "'" tstVal = "'" + tstVal.lower( ) + "'" # Surround strings with quotes to make string comparisons work (Tuesday==Tuesday fails, although 'Tuesday'=='Tuesday' works) condStr = varVal + test + tstVal try: answer = eval(condStr) except: synopsis.problem("BadRule", "Failed to evaluate '" + condition + "'") log.debug("Failed to evaluate '" + condition + "'") answer = False # Default answer to allow rest of rules to continue to run return answer else: return False # If we couldn't find the item requested, assume the condition fails(?)
def Action(actList, ruleId): log.debug("Action with: " + str(actList)) action = actList[0].lower() if action == "Log".lower(): log.debug("Rule says Log event for " + ' '.join(actList[1:])) elif action == "Play".lower(): call(["omxplayer", "-o", actList[1], actList[2]]) elif action == "Event".lower(): if actList[1].lower() == "TimeOfDay".lower(): events.IssueEvent(events.ids.TIMEOFDAY, actList[2]) elif actList[1].lower() == "Alarm".lower(): events.IssueEvent(events.ids.ALARM, actList[2]) # Could have other events here... elif action == "synopsis": # Was status emailAddress = config.Get("emailAddress") log.debug("About to send synopsis to " + emailAddress) if emailAddress != None: synopsis.BuildPage() # Create synopsis page on demand with open("synopsis.txt", "r") as fh: # Plain text of email emailText = fh.readlines() text = ''.join(emailText) with open("synopsis.html", "r") as fh: # HTML of email emailHtml = fh.readlines() html = ''.join(emailHtml) sendmail.email("Vesta Status", text, html) # See sendmail.py else: synopsis.problem( "NoEmail", "No emailAddress entry in config, needed to send synopsis") elif action == "email": # All args are body of the text. Fixed subject and email address emailAddress = config.Get("emailAddress") if emailAddress != None: emailBody = [] for item in actList[1:]: emailBody.append(item) plainText = " ".join(emailBody) log.debug("Sending email with '" + plainText + "'") result = sendmail.email("Vesta Alert!", plainText, None) if result != 0: synopsis.problem( "Email", "sendmail.email() failed with code " + str(result) + " when trying to send:" + plainText) else: synopsis.problem("NoEmail", "No emailAddress entry in config") elif action == "override": # Syntax is "Override <targetDevice> <targetDegC> <durationSecs>" devKey = devices.FindDev(actList[1]) target = actList[2] timeSecs = actList[3] if devKey != None: schedule.Override(devKey, target, timeSecs) elif action == "set": # Set a named variable to a value expression = "".join( actList[1:] ) # First recombine actList[1] onwards, with no spaces. Now expression should be of the form "<var>=<val>" if "--" in expression: sep = expression.index("--") varName = expression[:sep] varVal = variables.Get(varName) if isNumber(varVal): newVal = str(eval(varVal + "-1")) variables.Set(varName, newVal) Run( varName + "==" + newVal ) # Recurse! to see if any rules need running now that we've set a variable else: log.fault(varName + " not a number at " + expression) elif "++" in expression: sep = expression.index("++") varName = expression[:sep] varVal = variables.Get(varName) if isNumber(varVal): newVal = str(eval(varVal + "+1")) variables.Set(varName, newVal) Run( varName + "==" + newVal ) # Recurse! to see if any rules need running now that we've set a variable else: log.fault(varName + " not a number at " + expression) elif "=" in expression: sep = expression.index("=") varName = expression[:sep] varVal = expression[sep + 1:] variables.Set(varName, varVal) Run( varName + "==" + varVal ) # Recurse! to see if any rules need running now that we've set a variable else: log.fault("Badly formatted rule at " + expression) elif action == "unset": # Remove a named variable variables.Del(actList[1]) else: # Must be a command for a device, or group of devices if len(actList) >= 2: # Check that we have a second arg... name = actList[1] # Second arg is name if database.IsGroupName(name): # Check if name is a groupName devKeyList = GetGroupDevs(name) for devKey in devKeyList: CommandDev(action, devKey, actList, ruleId) # Command each device in list else: devKey = database.GetDevKey("userName", name) CommandDev(action, devKey, actList, ruleId) # Command one device
def EventHandler(eventId, eventArg): global oldMins, oldHours if eventId == events.ids.INIT: SetDayInfo() SetSunTimes() if variables.Get("sunrise") != None: variables.Set("morning", variables.Get("sunrise")) variables.Set("evening", variables.Get( "sunset")) # Set up defaults until we get a weather report variables.Set("dark", str(GetDark())) rules.Run("trigger==appstart") database.NewEvent(0, "App started") # 0 is always hub telegesis.SetTime() # Set time up for HA devices to synchronise to queue.EnqueueCmd(0, ["AT+SETATR:000A,0001,05", "OK" ]) # Set Master clock and timezone bits on CICIE queue.EnqueueCmd(0, ["AT+TIMERD", "OK"]) # Set CICIE as time server elif eventId == events.ids.SECONDS: now = datetime.now() if now.minute != oldMins: events.Issue(events.ids.MINUTES, now.minute) oldMins = now.minute # Ready for next time elif eventId == events.ids.MINUTES: now = datetime.now() if now.hour != oldHours: events.Issue(events.ids.HOURS, now.hour) oldHours = now.hour # Ready for next time variables.Set("time", str(now.strftime("%H:%M"))) rules.Run( "time==" + str(now.strftime("%H:%M"))) # Run timed rules once per minute rules.Run("trigger==time") # Run timed rules once per minute # Could alter above to rules.Run("trigger==minute") if variables.Get("sunrise") != None: CheckTimedRule("dawn", now) # Sky getting light before sunrise CheckTimedRule("sunrise", now) # Sun on horizon CheckTimedRule("morning", now) # Now proper daylight (depending on cloud) CheckTimedRule( "evening", now) # No longer proper daylight (depending on cloud) CheckTimedRule("sunset", now) # Sun on horizon CheckTimedRule("dusk", now) # Sky now getting dark after sunset dark = str(GetDark()) # Work out whether "dark" is True or False #log.debug("Old dark = " + variables.Get("dark") + " whereas new dark = " + dark) if dark != variables.Get("dark"): # Compare with previous variables.Set( "dark", dark ) # Update our idea of whether it's dark or light just now rules.Run("dark==" + variables.Get("dark") ) # This will also delete the variable afterwards variables.Set( "dark", dark ) # Re-instate the variable after the rule has deleted it if eventId == events.ids.HOURS: # Could add rules.Run("trigger==hour") if eventArg == 0: # Midnight, time to calculate sunrise and sunset for new day events.Issue(events.ids.NEWDAY) if eventArg == 4: # Re-synch Telegesis clock to local time at 4am every day to cope with DST telegesis.SetTime() # Set time up for HA devices to synchronise to if eventId == events.ids.NEWDAY: # Could add rules.Run("trigger==day") SetSunTimes() log.RollLogs() # Roll the logs, to avoid running out of disc space SetDayInfo() synopsis.BuildPage( ) # Create status page, once/day, based upon reported problems during the previous day synopsis.clearProblems()
def CheckTimedRule(name, now): if variables.Get(name) == now.strftime("%H:%M"): rules.Run("time==" + name) # Special rule for sunrise, sunset, etc.
def EventHandler(eventId, eventArg): global ephemera, globalDevKey, pendingBinding, pendingBindingTimeoutS, pendingRptAttrId, msp_ota if eventId == events.ids.PREINIT: keyList = database.GetAllDevKeys() # Get a list of all the device identifiers from the database for i in range(100): # Fudge to ensure we have enough pendingBinding entries pendingBinding.append("") # Problem is that the devKey indices aren't consecutive (removed devices) and so pendingBindingTimeoutS.append(0) # using the keyList isn't the same as for x in range(maxDevKey) for devKey in keyList: # Hub and devices Init(devKey) # Initialise dictionary and associated ephemera if database.GetDeviceItem(devKey, "nwkId") != "0000": # Ignore hub if database.GetDeviceItem(devKey, "protocol") != None: database.SetDeviceItem(devKey, "protocol", "ZigbeeHA") # Ensure all unknown devices are ZigbeeHA SetTempVal(devKey, "GetNextBatteryAfter", datetime.now()) # Ask for battery shortly after startup if eventId == events.ids.INIT: msp_ota = config.Get("MSP_OTA") if eventId == events.ids.NEWDAY: keyList = database.GetAllDevKeys() # Get a list of all the device identifiers from the database for devKey in keyList: # Hub and devices if GetTempVal(devKey, "wattSeconds"): SetTempVal(devKey, "wattSeconds", 0) # Clear down any accumulated energy at midnight SetTempVal(devKey, "lastRecorded_ws", 0) energyToday_kWh = variables.Get("energyToday_kWh") # Get today's energy consumed according to PowerClamp variables.Set("energyYesterday_kWh", energyToday_kWh) # Copy Today's energy into Yesterday's for comparison variables.Set("energyToday_kWh", "0") # Every midnight, clear down previous day's energy use if eventId == events.ids.MINUTES: keyList = database.GetAllDevKeys() # Get a list of all the device identifiers from the database for devKey in keyList: # Hub and devices recordEnergyMins = database.GetDeviceItem(devKey, "recordEnergyMins") if recordEnergyMins: minsSinceEnergy = GetTempVal(devKey, "minsSinceEnergy") if minsSinceEnergy == None: minsSinceEnergy = 0 minsSinceEnergy += 1 wattSeconds = GetTempVal(devKey, "wattSeconds") if minsSinceEnergy >= int(recordEnergyMins) and wattSeconds: # Make a recording of energy now, if we have any minsSinceEnergy = 0 lastRecorded_ws = GetTempVal(devKey, "lastRecorded_ws") if lastRecorded_ws == None: lastRecorded_ws = 0 energy_kWh = '%.3f' % ((wattSeconds - lastRecorded_ws) / 3600000) # Get kWh to 3 decimal places devName = database.GetDeviceItem(devKey, "userName") with open(log.logdir+'/'+devName+'_kWh.csv', 'a') as fh: fh.write(str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))+','+energy_kWh+'\n') # Append a line to the end of the csv file SetTempVal(devKey, "lastRecorded_ws", wattSeconds) # Make a note of last wattSeconds, so we can calculate energy next time SetTempVal(devKey, "minsSinceEnergy", minsSinceEnergy) if eventId == events.ids.DEVICE_ANNOUNCE: if len(eventArg) >= 3: eui64 = eventArg[1] nwkId = eventArg[2] devKey = GetKey(nwkId) if devKey == None: # Which will only be the case if we've not seen this short Id before devKey = database.GetDevKey("eui64", eui64) if devKey == None: # Which will be the case if we've not seen the long Id either devKey = Add(nwkId, eui64, eventArg[0]) log.debug("New key for new device is "+ str(devKey)) if eventArg[0] == "SED": SetTempVal(devKey,"PollingUntil", datetime.now()+timedelta(seconds=300)) events.Issue(events.ids.NEWDEVICE, devKey) # Tell everyone that a new device has been seen, so it can be initialised else: # Same long Id, but short Id needs updating after it has changed database.SetDeviceItem(devKey, "nwkId", nwkId) else: NoteMsgDetails(devKey, eventArg) SetTempVal(devKey, "GetNextBatteryAfter", datetime.now()) # Ask for battery shortly after Device Announce, either new or old one re-joining if eventId == events.ids.CHECKIN: # See if we have anything to ask the device... if len(eventArg) >= 3: endPoint = eventArg[2] seq = "00" # was seq = eventArg[3], but that's the RSSI devKey = GetKey(eventArg[1]) if devKey != None: EnsureInBinding(devKey, zcl.Cluster.PollCtrl) # Assume CheckIn means PollCtrl must be in binding, so make sure this is up-to-date NoteMsgDetails(devKey, eventArg) if database.GetDeviceItem(devKey, "endPoints") == None: database.SetDeviceItem(devKey, "endPoints", endPoint) # Note endpoint that CheckIn came from, unless we already know this nwkId = database.GetDeviceItem(devKey, "nwkId") cmdRsp = Check(devKey) # Check to see if we want to know anything about the device if cmdRsp != None: log.debug("Keep awake for 10 secs so we can send "+cmdRsp[0]) queue.Jump(devKey, ["AT+RAWZCL:"+nwkId+","+endPoint+",0020,11"+seq+"00012800", "DFTREP"]) # Tell device to enter Fast Poll for 40qs (==10s) SetTempVal(devKey,"PollingUntil", datetime.now()+timedelta(seconds=10)) queue.EnqueueCmd(devKey, cmdRsp) # This will go out after the Fast Poll Set else: SetTempVal(devKey,"PollingUntil", datetime.now()+timedelta(seconds=2)) # Say that it's polling for a short while, so that we can tell it to stop(!) queue.EnqueueCmd(devKey, ["AT+RAWZCL:"+nwkId+","+endPoint+",0020,11"+seq+"00000100", "DFTREP"]) # Tell device to stop Poll else: # Unknown device, so assume it's been deleted from our database telegesis.Leave(eventArg[1]) # Tell device to leave the network, since we don't know anything about it if eventId == events.ids.TRIGGER or eventId == events.ids.BUTTON: if len(eventArg) >= 2: devKey = GetKey(eventArg[1]) # Lookup device from network address in eventArg[1] if devKey != None: SetTempVal(devKey,"PollingUntil", datetime.now()+timedelta(seconds=1)) # Say that it's polling for a very short while so that we can try to set up a PollCtrl cluster if eventId == events.ids.RXMSG: if eventArg[0] == "AddrResp" and eventArg[1] == "00" and len(eventArg) >= 3: devKey = GetKey(eventArg[2]) if devKey != None: database.SetDeviceItem(devKey,"eui64",eventArg[1]) elif eventArg[0] == "ActEpDesc" and len(eventArg) >= 3: if "00" == eventArg[2]: devKey = GetKey(eventArg[1]) if devKey != None: database.SetDeviceItem(devKey, "endPoints", eventArg[3]) # Note first endpoint elif eventArg[0] == "SimpleDesc" and len(eventArg) >= 3: if "00" == eventArg[2]: globalDevKey = GetKey(eventArg[1]) # Is multi-line response, so expect rest of response and use this global index until it's all finished elif "82" == eventArg[2]: # 82 == Invalid endpoint devKey = GetKey(eventArg[1]) events.Issue(events.ids.RXERROR, int(eventArg[2],16)) # Tell system that we're aborting this command elif eventArg[0] == "InCluster" and len(eventArg) >= 2: if globalDevKey != None: database.SetDeviceItem(globalDevKey, "inClusters", str(eventArg[1:])) # Store whole list from arg[1] to arg[n] elif eventArg[0] == "OutCluster" and len(eventArg) >= 2: if globalDevKey != None: NoteMsgDetails(globalDevKey, eventArg) # Must do this so that we can remove RSSI and LQI if they're there, to avoid these values being interpreted as clusters database.SetDeviceItem(globalDevKey, "outClusters", str(eventArg[1:])) # Store whole list from arg[1] to arg[n] globalDevKey = None # We've finished with this global for now elif eventArg[0] == "RESPATTR" and len(eventArg) >= 7: devKey = GetKey(eventArg[1]) if devKey != None: NoteMsgDetails(devKey, eventArg) if len(eventArg) >= 7: # Check for number of args after possibly removing RSSI and LQI ep = eventArg[2] clusterId = eventArg[3] attrId = eventArg[4] if "00" == eventArg[5]: attrVal = eventArg[6] SetAttrVal(devKey, clusterId, attrId, attrVal) else: SetAttrVal(devKey, clusterId, attrId, "Failed (error "+eventArg[5]+")") # So that we don't keep asking elif eventArg[0] == "RESPMATTR" and len(eventArg) >= 8: devKey = GetKey(eventArg[1]) if devKey != None: NoteMsgDetails(devKey, eventArg) if len(eventArg) >= 8: # Check for number of args after possibly removing RSSI and LQI ep = eventArg[2] mfgId = eventArg[3] clusterId = eventArg[4] attrId = eventArg[5] if "00" == eventArg[6]: attrVal = eventArg[7] SetAttrVal(devKey, clusterId, attrId, attrVal) elif eventArg[0] == "REPORTATTR" and len(eventArg) >= 7: devKey = GetKey(eventArg[1]) if devKey != None: ep = eventArg[2] clusterId = eventArg[3] attrId = eventArg[4] attrType = eventArg[5] attrVal = eventArg[6] if clusterId == zcl.Cluster.MultistateInput and attrId == zcl.Attribute.PresentValue: args = [attrVal, eventArg[1]] events.Issue(events.ids.MULTISTATE, args) return # Ignore reports on Basic cluster (eg lumi.sensor_cube when it joins will send this) #if clusterId == zcl.Cluster.Basic: # return # Ignore reports on Basic cluster (eg lumi.sensor_cube when it joins will send this) NoteMsgDetails(devKey, eventArg) EnsureReporting(devKey, clusterId, attrId, attrVal) # Make sure reports are happening at the correct frequency and update device if not SetAttrVal(devKey, clusterId, attrId, attrVal) NoteReporting(devKey, clusterId, attrId) else: # Unknown device, so assume it's been deleted from our database telegesis.Leave(eventArg[1]) # Tell device to leave the network, since we don't know anything about it elif eventArg[0] == "Bind" and len(eventArg) >= 2: # Binding Response from device devKey = GetKey(eventArg[1]) if devKey != None: if pendingBinding[devKey]: binding = eval(database.GetDeviceItem(devKey, "binding", "[]")) if pendingBinding[devKey] not in binding: # Only put it in once, even if we get multiple responses binding.append(pendingBinding[devKey]) database.SetDeviceItem(devKey, "binding", str(binding)) pendingBinding[devKey] = None elif eventArg[0] == "CFGRPTRSP" and len(eventArg) >= 5: # Configure Report Response from device devKey = GetKey(eventArg[1]) status = eventArg[4] if devKey != None and status == "00": clusterId = eventArg[3] attrId = pendingRptAttrId # Need to remember this, since it doesn't appear in CFGRPTRSP NoteReporting(devKey, clusterId, attrId) pendingRptAttrId = None # Ready for the next report elif eventArg[0] == "CWSCHEDULE": heating.ParseCWShedule(eventArg) elif eventArg[0] == "DFTREP": devKey = GetKey(eventArg[1]) NoteMsgDetails(devKey, eventArg) if eventId == events.ids.RXERROR: globalDevKey = None # We've finished with this global if we get an error if eventId == events.ids.SECONDS: for devKey in devDict: # Go through devDict, pulling out each entry if devDict[devKey] >= 0: # Make sure device hasn't been deleted protocol = database.GetDeviceItem(devKey, "Protocol") if protocol == "ZigbeeHA" and IsListening(devKey): # True if FFD, ZED or Polling devIndex = GetIndexFromKey(devKey) if expRsp[devIndex] == None: # We don't have a message in flight if queue.IsEmpty(devKey): cmdRsp = Check(devKey) if cmdRsp: queue.EnqueueCmd(devKey, cmdRsp) # Queue up anything we ought to know cmdRsp = queue.DequeueCmd(devKey) # Pull first item from queue if cmdRsp != None: log.debug("Sending "+str(cmdRsp)) expRsp[devIndex] = cmdRsp[1] # Note response expRspTimeoutS[devIndex] = 2 # If we've not heard back after 2 seconds, it's probably got lost, so try again telegesis.TxCmd(cmdRsp[0]) # Send command directly else: # We're expecting a response, so time it out expRspTimeoutS[devIndex] = expRspTimeoutS[devIndex] - eventArg if expRspTimeoutS[devIndex] <= 0: expRsp[devIndex] = None if pendingBinding[devKey]: # Make sure we timeout pendingBinding pendingBindingTimeoutS[devKey] = pendingBindingTimeoutS[devKey] - eventArg if pendingBindingTimeoutS[devKey] <= 0: pendingBinding[devKey] = None offAt = GetTempVal(devKey, "SwitchOff@") if offAt: if datetime.now() >= offAt: DelTempVal(devKey, "SwitchOff@") devcmds.SwitchOff(devKey) fadeDownAt = GetTempVal(devKey, "FadeDown@") if fadeDownAt: if datetime.now() >= fadeDownAt: DelTempVal(devKey, "FadeDown@") devcmds.Dim(devKey, 0) devcmds.SwitchOff(devKey) # Switch off after dim command pirOffAt = GetTempVal(devKey, "PirInactive@") if pirOffAt: if datetime.now() >= pirOffAt: DelTempVal(devKey, "PirInactive@") newState = "inactive" database.NewEvent(devKey, newState) Rule(devKey, newState)
def Get(item): if ":" not in item: # If named item rather than HH:MM timestamp item = variables.Get(item) # Get time from variable (eg sunrise, etc.) return datetime.strptime(item, "%H:%M")