예제 #1
0
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
예제 #2
0
파일: rules.py 프로젝트: chava33/Vesta
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
예제 #3
0
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")
예제 #4
0
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))
예제 #5
0
파일: rules.py 프로젝트: smeek/hubapp
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(?)
예제 #6
0
파일: rules.py 프로젝트: chava33/Vesta
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(?)
예제 #7
0
파일: rules.py 프로젝트: chava33/Vesta
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
예제 #8
0
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()
예제 #9
0
def CheckTimedRule(name, now):
    if variables.Get(name) == now.strftime("%H:%M"):
        rules.Run("time==" + name)  # Special rule for sunrise, sunset, etc.
예제 #10
0
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)
예제 #11
0
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")