コード例 #1
0
ファイル: telegesis.py プロジェクト: spikeygriffiths/Vesta
def TxReadAttrRsp(devKey, clstrId, attrId, attrType, attrVal):
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    if nwkId == None:
        return # Make sure it's a real device before continuing (it may have just been deleted)
    ep = database.GetDeviceItem(devKey, "endPoints")
    cmdRsp = ReadAttrRsp(nwkId, ep, clstrId, attrId, attrType, attrVal)
    queue.EnqueueCmd(devKey, cmdRsp)   # Queue up command for sending via devices.py
コード例 #2
0
ファイル: heating.py プロジェクト: spikeygriffiths/Vesta
def SetDaySchedule(devKey, scheduleType="Heating", dayOfWeek="Sun"):
    nwkId = CheckThermostat(devKey)
    if nwkId == None:
        return  # Make sure it's a real thermostat device before continuing
    ep = database.GetDeviceItem(devKey, "endPoints")
    frameCtl = "11"
    seqId = "00"
    dayOfWeekIndex = iottime.GetDowIndex(dayOfWeek)
    log.debug("From " + dayOfWeek + " get value of " + str(dayOfWeekIndex))
    dayBit = 2**dayOfWeekIndex  # ** is "raise to the power".  Assumes dayOfWeek is a int where 0=Sunday, 1=Monday, etc.
    scheduleStr = database.GetSchedule(scheduleType, dayOfWeek)
    try:
        scheduleList = eval(scheduleStr)
    except:
        return  # Bad list from database
    numSetpoints = len(scheduleList)
    scheduleStr = ""
    for index in range(0, numSetpoints):
        timeTemp = scheduleList[index]  # Get each time & temp from schedule
        timeStr = timeTemp[0]
        tempStr = timeTemp[1]
        time = datetime.strptime(timeStr, "%H:%M")
        minsSinceMidnight = (time.hour * 60) + time.minute
        htonMins = telegesis.ByteSwap(minsSinceMidnight)
        htonTemp = telegesis.ByteSwap(int(float(tempStr) * 100))
        scheduleStr = scheduleStr + "{:04X}".format(htonMins)
        scheduleStr = scheduleStr + "{:04X}".format(htonTemp)
    cmdRsp = ("AT+RAWZCL:" + nwkId + "," + ep + "," + zcl.Cluster.Thermostat +
              "," + frameCtl + seqId + zcl.Commands.SetSchedule +
              "{:02X}".format(numSetpoints) + "{:02X}".format(dayBit) + "01" +
              scheduleStr, "CWSCHEDULE")  #  Set heating(01) schedule
    queue.EnqueueCmd(devKey,
                     cmdRsp)  # Queue up command for sending via devices.py
コード例 #3
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
def Sat(devKey, satPercentage):
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if nwkId and ep:
        satStr = format(int(float(satPercentage / 100) * 254), 'X').zfill(2)
        queue.EnqueueCmd(devKey, [
            "AT+CCMVTOSAT:" + nwkId + "," + ep + ",0," + satStr + ",0001",
            "DFTREP"
        ])  # Fade over 100ms (in sec/10)
コード例 #4
0
ファイル: commands.py プロジェクト: spikeygriffiths/Vesta
 def do_devat(self, line):
     """devat name cmd
     Sends AT command to named device"""
     argList = line.split()
     if len(argList) >= 2:
         cmd = argList[1]
         devKey = devices.FindDev(argList[0])
         if devKey != None:
             queue.EnqueueCmd(devKey, ["AT" + cmd, "OK"])
コード例 #5
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
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)
コード例 #6
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
def Hue(devKey, hueDegree):
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if nwkId and ep:
        hueStr = format(int(float(hueDegree / 360) * 254), 'X').zfill(2)
        queue.EnqueueCmd(devKey, [
            "AT+CCMVTOHUE:" + nwkId + "," + ep + ",0," + hueStr + ",00,0001",
            "DFTREP"
        ])  # Fade over 100ms (in sec/10)
コード例 #7
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
def Identify(
    devKey, durationS
):  # Duration in seconds to flash the device's LED.  Use duration=0 to stop.
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if nwkId and ep:
        durationStr = format(int(durationS), 'X').zfill(4)
        queue.EnqueueCmd(devKey, [
            "AT+IDENTIFY:" + nwkId + "," + ep + ",0," + durationStr, "DFTREP"
        ])  # Identify for selected time
コード例 #8
0
def Sat(devKey, satPercentage):
    protocol = database.GetDeviceItem(devKey, "protocol")
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if protocol == "ZigbeeHA" and nwkId != None and ep != None:
        satStr = format(int(float(satPercentage / 100) * 254), 'X').zfill(2)
        queue.EnqueueCmd(devKey, [
            "AT+CCMVTOSAT:" + nwkId + "," + ep + ",0," + satStr + ",0001",
            "DFTREP"
        ])  # Fade over 100ms (in sec/10)
コード例 #9
0
def Hue(devKey, hueDegree):
    protocol = database.GetDeviceItem(devKey, "protocol")
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if protocol == "ZigbeeHA" and nwkId != None and ep != None:
        hueStr = format(int(float(hueDegree / 360) * 254), 'X').zfill(2)
        queue.EnqueueCmd(devKey, [
            "AT+CCMVTOHUE:" + nwkId + "," + ep + ",0," + hueStr + ",00,0001",
            "DFTREP"
        ])  # Fade over 100ms (in sec/10)
コード例 #10
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
def SwitchOn(devKey):
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    dimLevel = database.GetDeviceItem(devKey, "dimLevel")
    inClstr = database.GetDeviceItem(
        devKey, "inClusters")  # For checking whether we have LevelCtrl
    if nwkId and ep:
        #database.UpdateLoggedItem(devKey, "State", "SwitchOn") # So that we can access it from the rules later
        devices.SetTempVal(devKey, "JustSentOnOff", "True")
        devices.SetTempVal(devKey, "ExpectOnOff", "SwitchOn")
        queue.EnqueueCmd(devKey,
                         ["AT+RONOFF:" + nwkId + "," + ep + ",0,1", "OK"
                          ])  # Assume FFD if it supports OnOff cluster
        if zcl.Cluster.LevelCtrl in inClstr and dimLevel != 100:  # Queue up a dimming command if available and we're at a different dimness
            queue.EnqueueCmd(
                devKey,
                ["AT+LCMVTOLEV:" + nwkId + "," + ep + ",0,1,FE,0001", "OK"
                 ])  # Ensure fully bright ready to be turned on
            database.SetDeviceItem(
                devKey, "dimLevel",
                100)  # Assume the LevelCtrl command above works
コード例 #11
0
ファイル: telegesis.py プロジェクト: spikeygriffiths/Vesta
def EventHandler(eventId, eventArg):
    global ser, txBuf, rxBuf
    if eventId == events.ids.INIT:
        serPort = config.Get("tty", '/dev/ttyUSB0')
        serSpeed = config.Get("baud", '19200')
        ser = serial.Serial(serPort, int(serSpeed), timeout=0)
        ser.flushInput()
        if database.GetDevicesCount()==0: # If we have no devices yet, then...
            devices.Add("0000", "N/A", "COO") # ...make sure we add this device as the first item before we try to use it!
        queue.EnqueueCmd(0, ["ATS63=0007", "OK"]) # Request RSSI & LQI on every received message, also disable automatic checkIn responses
        queue.EnqueueCmd(0, ["ATS0F=0400", "OK"]) # Use 0600 to set bit 9 (bit 10 already set) to get rawzcl responses so we can see schedule responses from thermostat
        if database.GetDeviceItem(0, "modelName") == None:
            queue.EnqueueCmd(0, ["ATI", "OK"]) # Request our EUI, as well as our Telegesis version
        queue.EnqueueCmd(0, ["AT+N", "OK"]) # Get network information, to see whether to start new network or use existing one
    elif eventId == events.ids.SECONDS:
        HandleSerial(ser)
        while len(rxBuf):
            Parse(rxBuf.popleft())
    elif eventId == events.ids.RADIO_INFO:
        print(ourChannel+","+ourPowLvl+","+ourPan+","+ourExtPan) # Formatted to make it easy to extract in php
    elif eventId == events.ids.INFO:
        print("TxBuf: ", str(txBuf))
コード例 #12
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
def SwitchOff(devKey):
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if nwkId and ep:
        #database.UpdateLoggedItem(devKey, "State", "SwitchOff") # So that we can access it from the rules later
        devices.DelTempVal(
            devKey, "SwitchOff@"
        )  # Remove any pending "Off" events if we're turning the device off directly
        devices.SetTempVal(devKey, "JustSentOnOff", "True")
        devices.SetTempVal(devKey, "ExpectOnOff", "SwitchOff")
        queue.EnqueueCmd(devKey,
                         ["AT+RONOFF:" + nwkId + "," + ep + ",0,0", "OK"
                          ])  # Assume FFD if it supports OnOff cluster
        database.SetDeviceItem(devKey, "dimLevel", 0)  # Set dimness to 0
コード例 #13
0
ファイル: telegesis.py プロジェクト: spikeygriffiths/Vesta
def Parse(atLine):
    global expectOurEui
    global ourChannel, ourPowLvl, ourPan, ourExtPan
    if atLine == "":
        return # Ignore blank lines
    if atLine[0:2] == 'AT':
        return # Exit immediately if line starts with AT, indicating an echo
    log.debug("Parsing:"+ atLine)
    atLine = atLine.replace(':',',') # Replace colons with commas
    atList = atLine.split(',') # Split on commas
    if atList[0] == 'OK':
        events.Issue(events.ids.RXOK)
    elif expectOurEui == True and len(atList[0])==16: # If we're expecting an EUI and it's the correct length
        database.SetDeviceItem(0, "eui64", atList[0])
        expectOurEui = False
    elif atList[0] == "ERROR":
        errNo = None
        if len(atList) > 1:
            try:
                errNo = int(atList[1],16)   # Might be junk - have seen all sorts of nonsense from Telegesis stick here
            except ValueError:
                pass    # Just use default value of errNo
        events.Issue(events.ids.RXERROR, errNo) # See if anyone cares about the error
    elif atList[0] == "SED" or atList[0] == "FFD" or atList[0] == "ZED":
        events.Issue(events.ids.DEVICE_ANNOUNCE, atList) # Tell system that device has (re-)joined        
    elif atList[0] == 'CHECKIN':
        events.Issue(events.ids.CHECKIN, atList) # Tell devices that device is about to poll for data
    elif atList[0] == 'TOGGLE' or atList[0] == 'ON' or atList[0] == 'OFF':
        events.Issue(events.ids.BUTTON, atList) # Tell rules engine
    elif atList[0] == 'ZONESTATUS':
        events.Issue(events.ids.TRIGGER, atList) # Tell rules engine
    elif 0 == atList[0].find("Telegesis"):
        database.SetDeviceItem(0, "manufName", atList[0])
    elif 0 == atList[0].find("CICIE"):
        database.SetDeviceItem(0, "modelName", atList[0])
        expectOurEui = True # Following EUI has no prefix - we just have to know that it follows the CICIE line
    elif atList[0] == "+N=COO":
        ourChannel = atList[1]
        ourPowLvl = atList[2]
        ourPan = atList[3]
        ourExtPan = atList[4]
    elif atList[0] == "+N=NoPAN": # No PAN means we need to set up the network and add ourselves
        queue.EnqueueCmd(0, ["AT+EN", "OK"]) # Start new network
    elif atList[0] == "JPAN":  # After Establish Network (AT+EN) has finished
        ourChannel = atList[1]
        ourPan = atList[2]
        ourExtPan = atList[3]
    else:
        events.Issue(events.ids.RXMSG, atList)
コード例 #14
0
ファイル: devcmds.py プロジェクト: chava33/Vesta
def Dim(devKey, level):
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    ep = database.GetDeviceItem(devKey, "endPoints")
    if nwkId and ep:
        if level > 1:  # Assume it's a percentage
            level = level / 100  # Convert to a fraction
        levelStr = format(int(level * 254), 'X').zfill(2)
        queue.EnqueueCmd(devKey, [
            "AT+LCMVTOLEV:" + nwkId + "," + ep + ",0,1," + levelStr + ",000A",
            "DFTREP"
        ])  # Fade over 1 sec (in 10ths)
        if level == 0:
            SwitchOff(devKey)
        database.SetDeviceItem(devKey, "dimLevel", level *
                               100)  # Assume the LevelCtrl command above works
コード例 #15
0
ファイル: heating.py プロジェクト: spikeygriffiths/Vesta
def GetDaySchedule(
        devKey,
        dayOfWeek="Sun"):  # Ask Thermostat/Boiler device for its schedule
    global thermoDevKey
    nwkId = CheckThermostat(devKey)
    if nwkId == None:
        return  # Make sure it's a real thermostat device before continuing
    thermoDevKey = devKey
    ep = database.GetDeviceItem(devKey, "endPoints")
    frameCtl = "11"
    seqId = "00"
    dayOfWeekIndex = iottime.GetDowIndex(dayOfWeek)
    dayBit = 2**dayOfWeekIndex  # ** is "raise to the power".  Assumes dayOfWeek is a int where 0=Sunday, 1=Monday, etc.
    cmdRsp = ("AT+RAWZCL:" + nwkId + "," + ep + "," + zcl.Cluster.Thermostat +
              "," + frameCtl + seqId + zcl.Commands.GetSchedule +
              "{:02X}".format(dayBit) + "01", "CWSCHEDULE"
              )  #  Get heating(01) schedule
    queue.EnqueueCmd(devKey,
                     cmdRsp)  # Queue up command for sending via devices.py
コード例 #16
0
ファイル: commands.py プロジェクト: spikeygriffiths/Vesta
 def do_at(self, line):
     """at cmd
     Sends AT command to Telegesis stick"""
     queue.EnqueueCmd(0, ["AT" + line, "OK"])
コード例 #17
0
 def do_open(self, line):
     """open
     Opens network (for 60s) to allow new device to join"""
     queue.EnqueueCmd(0, ["AT+PJOIN", "OK"])
コード例 #18
0
ファイル: telegesis.py プロジェクト: spikeygriffiths/Vesta
def SetTime(): # Set time up for HA devices to synchronise to
    timeVal = datetime.now()
    timeVal = time.mktime(timeVal.timetuple())
    zigBeeTime = iottime.ToZigbee(timeVal)   # Get local time in Unix epoch (1/Jan/1970) and convert it to Zigbee standard
    queue.EnqueueCmd(0, ["AT+SETTIME:{:08X}".format(int(zigBeeTime)), "OK"]) #  Set time in CICIE ready for setting up time server
コード例 #19
0
ファイル: commands.py プロジェクト: spikeygriffiths/Vesta
 def do_open(self, line):
     """open
     Opens network (for 60s) to allow new device to join"""
     log.debug("----- Got open command - sending AT+PJOIN ------")
     queue.EnqueueCmd(0, ["AT+PJOIN", "OK"])
コード例 #20
0
ファイル: devices.py プロジェクト: chava33/Vesta
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
                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.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)
        #else:   # Unrecognised message, but we still want to extract OOB info
        #    if len(eventArg) >= 2:
        #        devKey = GetKey(eventArg[1])    # Assume this is sensible
        #        if devKey != None:
        #            NoteMsgDetails(devKey, eventArg)
    #if eventId == events.ids.BUTTON:
    #    devKey = GetKey(eventArg[1]) # Lookup device from network address in 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
                if 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)
コード例 #21
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()