def set_poweron_afteroffon(self, key, OnOffMode=0xFF): # OSRAM/LEDVANCE # 0xfc0f --> Command 0x01 # 0xfc01 --> Command 0x01 # Tuya Blitzworl # 0x0006 / 0x8002 -> 0x00 Off ; 0x01 On ; 0x02 Previous state # Ikea / Philips/ Legrand # 0x0006 / 0x4003 -> 0x00 Off, 0x01 On, 0xff Previous self.log.logging("BasicOutput", "Debug", "set_PowerOn_OnOff for %s - OnOff: %s" % (key, OnOffMode), key) if key not in self.ListOfDevices: self.log.logging("BasicOutput", "Error", "set_PowerOn_OnOff for %s not found" % (key), key) return model_name = "" if "Model" in self.ListOfDevices[key]: model_name = self.ListOfDevices[key]["Model"] manuf_spec = "00" manuf_id = "0000" ListOfEp = getListOfEpForCluster(self, key, "0006") cluster_id = "0006" attribute = "4003" if model_name in ( "TS0121", "TS0115", "TS011F-multiprise", "TS011F-2Gang-switches", "TS011F-plug" ): attribute = "8002" if OnOffMode == 0xFF: OnOffMode = 0x02 data_type = "30" # ListOfEp = getListOfEpForCluster(self, key, "0006") for EPout in ListOfEp: data = "%02x" % OnOffMode self.log.logging( "BasicOutput", "Debug", "set_PowerOn_OnOff for %s/%s - OnOff: %s" % (key, EPout, OnOffMode), key ) if attribute in self.ListOfDevices[key]["Ep"][EPout]["0006"]: del self.ListOfDevices[key]["Ep"][EPout]["0006"][attribute] return write_attribute( self, key, ZIGATE_EP, EPout, cluster_id, manuf_id, manuf_spec, attribute, data_type, data, ackIsDisabled=True, )
def ScanDevicesForGroupMemberShip(self, DevicesToScan): self.logging("Debug", "ScanDevicesForGroupMemberShip : %s " % DevicesToScan) for NwkId in DevicesToScan: if NwkId == "0000": submitForGroupMemberShipScaner(self, NwkId, "01") continue if NwkId not in self.ListOfDevices: self.logging( "Debug", "ScanDevicesForGroupMemberShip : Skiping %s not existing" % NwkId) continue if not mainPoweredDevice: self.logging( "Debug", "ScanDevicesForGroupMemberShip : Skiping %s not main powered" % NwkId) continue ListEp = getListOfEpForCluster(self, NwkId, "0004") self.logging( "Debug", "ScanDevicesForGroupMemberShip : List of Ep %s for %s" % (str(ListEp), NwkId)) for Ep in ListEp: if [NwkId, Ep] not in self.ScanDevicesToBeDone: self.GroupStatus = "scan" submitForGroupMemberShipScaner(self, NwkId, Ep)
def set_PIROccupiedToUnoccupiedDelay(self, key, delay, ListOfEp=None): cluster_id = "0406" attribute = "0010" data_type = "21" manuf_id = "0000" manuf_spec = "00" if ListOfEp is None: ListOfEp = getListOfEpForCluster(self, key, cluster_id) for EPout in ListOfEp: data = "%04x" % delay self.log.logging( "BasicOutput", "Log", "set_PIROccupiedToUnoccupiedDelay for %s/%s - delay: %s" % (key, EPout, delay), key ) if attribute in self.ListOfDevices[key]["Ep"][EPout][cluster_id]: del self.ListOfDevices[key]["Ep"][EPout][cluster_id][attribute] return write_attribute( self, key, ZIGATE_EP, EPout, cluster_id, manuf_id, manuf_spec, attribute, data_type, data, ackIsDisabled=False, )
def ballast_Configuration_max_level(self, nwkid, value): ListOfEp = getListOfEpForCluster(self, nwkid, "0301") if ListOfEp: for EPout in ListOfEp: write_attribute( self, nwkid, ZIGATE_EP, EPout, "0301", "0000", "00", "0011", "20", "%02x" % value, ackIsDisabled=True ) read_attribute(self, nwkid, ZIGATE_EP, EPout, "0301", "00", "00", "0000", 1, "0011", ackIsDisabled=True)
def pollingDeviceStatus(self, NwkId): # """ # Purpose is to trigger ReadAttrbute 0x0006 and 0x0008 on attribute 0x0000 if applicable # """ if self.busy or self.ZigateComm.loadTransmit() > MAX_LOAD_ZIGATE: return True self.log.logging("Heartbeat", "Debug", "--------> pollingDeviceStatus Device %s" % NwkId, NwkId) if len(getListOfEpForCluster(self, NwkId, "0006")) != 0: ReadAttributeRequest_0006_0000(self, NwkId) self.log.logging("Heartbeat", "Debug", "++ pollingDeviceStatus - %s for ON/OFF" % (NwkId), NwkId) if len(getListOfEpForCluster(self, NwkId, "0008")) != 0: ReadAttributeRequest_0008_0000(self, NwkId) self.log.logging( "Heartbeat", "Debug", "++ pollingDeviceStatus - %s for LVLControl" % (NwkId), NwkId) if len(getListOfEpForCluster(self, NwkId, "0102")) != 0: ReadAttributeRequest_0102_0008(self, NwkId) self.log.logging( "Heartbeat", "Debug", "++ pollingDeviceStatus - %s for WindowCovering" % (NwkId), NwkId) if len(getListOfEpForCluster(self, NwkId, "0101")) != 0: ReadAttributeRequest_0101_0000(self, NwkId) self.log.logging( "Heartbeat", "Debug", "++ pollingDeviceStatus - %s for DoorLock" % (NwkId), NwkId) if len(getListOfEpForCluster(self, NwkId, "0201")) != 0: ReadAttributeRequest_0201_0012(self, NwkId) self.log.logging( "Heartbeat", "Debug", "++ pollingDeviceStatus - %s for Thermostat" % (NwkId), NwkId) return False
def danfoss_room_sensor_polling(self, NwkId): # This has been triggered because "DanfossRoomFreq" exist and > 0 # This is expected for a eTRV which belongs to a Room for which an external Temp sensor exist # External Temp Sensor will only have the "DanfossRoom" parameter self.log.logging( "Danfoss", "Debug", "danfoss_room_sensor_polling - Triggered for Nwkid: %s" % (NwkId, ), nwkid=NwkId, ) if "Param" not in self.ListOfDevices[NwkId]: return if "DanfossRoom" not in self.ListOfDevices[NwkId]["Param"]: return room = self.ListOfDevices[NwkId]["Param"]["DanfossRoom"] self.log.logging( "Danfoss", "Debug", "danfoss_room_sensor_polling - Triggered for Nwkid: %s - room: %s" % (NwkId, room), nwkid=NwkId, ) # Search for Temp Sensor for that Room for x in self.ListOfDevices: if x == NwkId: continue if "Param" not in self.ListOfDevices[x]: continue if "DanfossRoom" not in self.ListOfDevices[x]["Param"]: continue if self.ListOfDevices[x]["Param"]["DanfossRoom"] != room: continue ep_list = ListOfEp = getListOfEpForCluster(self, x, "0402") if ep_list == []: continue ep = ep_list[0] if "0000" not in self.ListOfDevices[x]["Ep"][ep]["0402"]: continue # At that stage we have found a Device which is in the same room and as the 0402 Cluster # Temp value is store in 0x0402/0x0000 is degrees temp_room = self.ListOfDevices[x]["Ep"][ep]["0402"]["0000"] danfoss_write_external_sensor_temp(self, NwkId, temp_room)
def danfoss_exercise_day_of_week(self, NwkId, week_num): # 0 = Sunday, 1 = Monday, … 6 = Saturday, 7 = undefined if week_num > 6: return manuf_id = "1246" manuf_spec = "01" cluster_id = "%04x" % 0x0201 EPout = ListOfEp = getListOfEpForCluster(self, NwkId, "0201") Hattribute = "%04x" % 0x4010 data_type = "30" # enum8 self.log.logging("Danfoss", "Debug", "Danfoss Aly Trigger_Week Num: %s" % week_num, nwkid=NwkId) Hdata = "%02x" % week_num self.log.logging( "Danfoss", "Debug", "danfoss_exercise_trigger_time - Week Num for %s with value %s / cluster: %s, attribute: %s type: %s" % (NwkId, Hdata, cluster_id, Hattribute, data_type), nwkid=NwkId, ) for ep in EPout: write_attribute(self, NwkId, "01", ep, cluster_id, manuf_id, manuf_spec, Hattribute, data_type, Hdata, ackIsDisabled=False) read_attribute(self, NwkId, ZIGATE_EP, ep, cluster_id, "00", manuf_spec, manuf_id, 1, Hattribute, ackIsDisabled=False)
def leaveRequest(self, ShortAddr=None, IEEE=None, RemoveChild=0x00, Rejoin=0x00): """ E_SL_MSG_LEAVE_REQUEST / 0x004C / ZPS_eAplZdoLeaveNetwork If you wish to move a whole network branch from under the requesting node to a different parent node, set bRemoveChildren to FALSE and bRejoin to TRUE. """ _ieee = None if IEEE: _ieee = IEEE else: if ShortAddr and ShortAddr in self.ListOfDevices and "IEEE" in self.ListOfDevices[ShortAddr]: _ieee = self.ListOfDevices[ShortAddr]["IEEE"] else: self.log.logging( "BasicOutput", "Error", "leaveRequest - Unable to determine IEEE address for %s %s" % (ShortAddr, IEEE), ShortAddr, {"Error code": "BOUTPUTS-LEAVE-01", "ListOfDevices": self.ListOfDevices}, ) return None if Rejoin == 0x00 and ShortAddr: ep_list = getListOfEpForCluster(self, ShortAddr, "0000") if ep_list: self.log.logging( "BasicOutput", "Log", "reset_device - Send a Device Reset to %s/%s" % (ShortAddr, ep_list[0]), ShortAddr ) reset_device(self, ShortAddr, ep_list[0]) _rmv_children = "%02X" % RemoveChild _rejoin = "%02X" % Rejoin #datas = _ieee + _rmv_children + _rejoin self.log.logging( "BasicOutput", "Debug", "---------> Sending a leaveRequest - NwkId: %s, IEEE: %s, RemoveChild: %s, Rejoin: %s" % (ShortAddr, IEEE, RemoveChild, Rejoin), ShortAddr, ) return zdp_management_leave_request(self, ShortAddr, _ieee, _rejoin, _rmv_children)
def get_group_identifiers_request(self, nwkid): cluster_frame = "19" sqn = get_and_inc_SQN(self, nwkid) command = "41" start_index = "00" cluster = "1000" ListOfEp = getListOfEpForCluster(self, nwkid, cluster) if len(ListOfEp) != 1: return payload = cluster_frame + sqn + command + start_index ep = ListOfEp[0] raw_APS_request( self, nwkid, ep, cluster, "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), highpriority=True, )
def thermostat_Setpoint_Danfoss(self, NwkId, setpoint): # Command Manufactuer Specific # Setpoint command sends: setpointType (enum8) + HeatingSetpoint (16bit) # if setpointType = 1 the actuator will make a large movement to minimize reaction time to UI. # If setpointType = 0 the behavior will be the same as setting the attribute "Occupied Heating Setpoint" to the same value. # if setpointType = 2 displayed setpoint is not effected but regulated setpoint will change. can be used for Forecast functionality self.log.logging( "Danfoss", "Debug", "thermostat_Setpoint_Danfoss - for %s with value %s " % (NwkId, setpoint), nwkid=NwkId, ) if "Param" not in self.ListOfDevices[NwkId]: return if "DanfossSetPointType" not in self.ListOfDevices[NwkId]["Param"]: return if not int(self.ListOfDevices[NwkId]["Param"]["DanfossSetPointType"]): return if int(self.ListOfDevices[NwkId]["Param"]["DanfossSetPointType"]) not in ( 1, 2): return self.log.logging( "Danfoss", "Debug", "thermostat_Setpoint_Danfoss - for %s with value %s and SetPointType: %s" % (NwkId, setpoint, int(self.ListOfDevices[NwkId]["Param"]["DanfossSetPointType"])), nwkid=NwkId, ) danfoss_setpoint_command = "40" danfoss_setpoint_type = "%02x" % int( self.ListOfDevices[NwkId]["Param"]["DanfossSetPointType"]) danfoss_setpoint_value = "%04x" % int( (setpoint * 2) / 2) # Round to 0.5 degrees EPout = getListOfEpForCluster(self, NwkId, "0201") # cluster_id = "%04x" % 0x0201 manuf_id = "1246" sqn = get_and_inc_SQN(self, NwkId) cluster_frame = build_fcf("1", "1", "0", "0") payload = cluster_frame + manuf_id[2:4] + manuf_id[ 0: 2] + sqn + danfoss_setpoint_command + danfoss_setpoint_type + danfoss_setpoint_value[ 2:4] + danfoss_setpoint_value[0:2] self.log.logging( "Danfoss", "Debug", "thermostat_Setpoint_Danfoss - for %s with cluster_frame: %s payload: %s " % (NwkId, cluster_frame, payload), nwkid=NwkId, ) for ep in EPout: raw_APS_request( self, NwkId, ep, cluster_id, "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, NwkId), )