def legrand_fc40(self, nwkid, Mode): # With the permission of @Thorgal789 who did the all reverse enginnering of this cluster CABLE_OUTLET_MODE = { "Confort": 0x00, "Confort -1": 0x01, "Confort -2": 0x02, "Eco": 0x03, "Frost Protection": 0x04, "Off": 0x05, } if Mode not in CABLE_OUTLET_MODE: Domoticz.Error(" Bad Mode : %s for %s" % (Mode, nwkid)) return Hattribute = "0000" data_type = "30" # 8bit Enum Hdata = CABLE_OUTLET_MODE[Mode] # manuf_id = "1021" # Legrand Code # manuf_spec = "01" # Manuf specific flag cluster_id = "%04x" % 0xFC40 EPout = "01" for tmpEp in self.ListOfDevices[nwkid]["Ep"]: if "fc40" in self.ListOfDevices[nwkid]["Ep"][tmpEp]: EPout = tmpEp self.log.logging( "Legrand", "Debug", "legrand %s Set Fil pilote mode - for %s with value %s / cluster: %s, attribute: %s type: %s" % (Mode, nwkid, Hdata, cluster_id, Hattribute, data_type), nwkid=nwkid, ) sqn = get_and_inc_SQN(self, nwkid) fcf = "15" # manufspec = "01" manufcode = "1021" cmd = "00" data = "%02x" % CABLE_OUTLET_MODE[Mode] payload = fcf + manufcode[2:4] + manufcode[0:2] + sqn + cmd + data raw_APS_request( self, nwkid, EPout, "fc40", "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), )
def send_default_response( self, Nwkid, srcEp, cluster, Direction, bDisableDefaultResponse, ManufacturerSpecific, u16ManufacturerCode, FrameType, response_to_command, sqn, ): # Response_To_Command # 0x01: Read Attributes Response # 0x02: Write Attribute # 0x03: Write Attributes Undivided # 0x04: Write Attributes Response # 0x05: Write Attributes No Response # 0x06: Configure Reporting # 0x07: Configure Reporting Response # 0x08: Read reporting Configuration # 0x09: Read Reporting Configuration Response # 0x0a: Report Attribute # 0x0b: Default response # 0x0c: Discover Attributes # 0x0d: Discober Attribute Response if Nwkid not in self.ListOfDevices: return # Take the reverse direction Direction = "%02x" % (not (int(Direction, 16))) fcf = build_fcf("00", ManufacturerSpecific, Direction, "01") cmd = "0b" # Default response command status = "00" payload = fcf + sqn if ManufacturerSpecific == "01": payload += u16ManufacturerCode[2:4] + u16ManufacturerCode[0:2] payload += cmd + response_to_command + status raw_APS_request( self, Nwkid, srcEp, cluster, "0104", payload, zigate_ep=ZIGATE_EP, highpriority=True, ackIsDisabled=True ) self.log.logging( "BasicOutput", "Debug", "send_default_response - [%s] %s/%s on cluster: %s with command: %s" % (sqn, Nwkid, srcEp, cluster, response_to_command), )
def ffad_send_manuf_specific_cmd(self, NwkId, payload): cluster_frame = "05" sqn = get_and_inc_SQN(self, NwkId) EPout = get_ffad_endpoint(self, NwkId) data = cluster_frame + CASAIA_MANUF_CODE_BE + sqn data += payload raw_APS_request(self, NwkId, EPout, "ffad", "0104", data, zigate_ep=ZIGATE_EP)
def profalux_stop(self, nwkid): # determine which Endpoint EPout = "01" for tmpEp in self.ListOfDevices[nwkid]["Ep"]: if "0008" in self.ListOfDevices[nwkid]["Ep"][tmpEp]: EPout = tmpEp cluster_frame = "01" sqn = get_and_inc_SQN(self, nwkid) cmd = "03" # Ask the Tilt Blind to stop moving payload = cluster_frame + sqn + cmd raw_APS_request(self, nwkid, EPout, "0008", "0104", payload, zigate_ep=ZIGATE_EP) self.log.logging("Profalux", "Debug", "profalux_stop ++++ %s/%s payload: %s" % (nwkid, EPout, payload), nwkid)
def AC211_ReadPairingCodeRequest(self, NwkId): # Command 0x00 # determine which Endpoint EPout = get_ffad_endpoint(self, NwkId) sqn = get_and_inc_SQN(self, NwkId) cluster_frame = "01" device_type = DEVICE_TYPE # Device type cmd = "00" payload = cluster_frame + sqn + cmd + device_type raw_APS_request(self, NwkId, EPout, "ffac", "0104", payload, zigate_ep=ZIGATE_EP) self.log.logging( "CasaIA", "Debug", "AC211_read_multi_pairing_code_request ++++ %s payload: %s" % (NwkId, payload), NwkId)
def profalux_MoveToLevelWithOnOff(self, nwkid, level): # determine which Endpoint EPout = "01" for tmpEp in self.ListOfDevices[nwkid]["Ep"]: if "0008" in self.ListOfDevices[nwkid]["Ep"][tmpEp]: EPout = tmpEp cluster_frame = "01" sqn = get_and_inc_SQN(self, nwkid) cmd = "04" # Ask the Tilt Blind to go to a certain Level payload = cluster_frame + sqn + cmd + "%02x" % level raw_APS_request(self, nwkid, EPout, "0008", "0104", payload, zigate_ep=ZIGATE_EP) self.log.logging( "Profalux", "Debug", "profalux_MoveToLevelWithOnOff ++++ %s/%s Level: %s payload: %s" % (nwkid, EPout, level, payload), nwkid, )
def zcl_raw_window_covering(self, nwkid, EPIn, EPout, command, level="00", percentage="00", groupaddrmode=False, ackIsDisabled=True): self.log.logging( "zclCommand", "Debug", "zcl_raw_window_covering %s %s %s %s %s" % (nwkid, EPout, command, level, percentage)) Cluster = "0102" WINDOW_COVERING_COMMANDS = { "Up": 0x00, "Down": 0x01, "Stop": 0x02, "GoToLiftValue": 0x04, "GoToLiftPercentage": 0x05, "GoToTiltValue": 0x07, "GoToTiltPercentage": 0x08 } if command not in WINDOW_COVERING_COMMANDS: return # Cluster Frame: # 0b xxxx xxxx # |- Frame Type: Cluster Specific (0x01) # |-- Manufacturer Specific False # |--- Command Direction: Client to Server (0) # | ---- Disable default response: True # |||- ---- Reserved : 0x000 # cluster_frame = 0b00010001 sqn = get_and_inc_SQN(self, nwkid) payload = "%02x" % cluster_frame + sqn + "%02x" % WINDOW_COVERING_COMMANDS[ command] if command in ("MovetoLevel", "MovetoLevelWithOnOff"): payload += level elif command == ("GoToLiftValue", "GoToTiltValue"): payload += percentage return raw_APS_request(self, nwkid, EPout, Cluster, "0104", payload, zigate_ep=EPIn, groupaddrmode=groupaddrmode, ackIsDisabled=ackIsDisabled)
def zdp_management_binding_table_request(self, nwkid, payload): return raw_APS_request( self, nwkid, "00", "0033", "0000", payload, zigate_ep="00", highpriority=False, ackIsDisabled=False, )
def AC201_read_learned_data_group_status_request(self, NwkId): # Command 0x11 EPout = get_ffad_endpoint(self, NwkId) sqn = get_and_inc_SQN(self, NwkId) device_type = "00" # Device type cluster_frame = "05" cmd = "11" payload = cluster_frame + CASAIA_MANUF_CODE_BE + sqn + cmd + device_type raw_APS_request(self, NwkId, EPout, "ffad", "0104", payload, zigate_ep=ZIGATE_EP) self.log.logging( "CasaIA", "Debug", "AC201_read_learned_data_group_status_request ++++ %s/%s payload: %s" % (NwkId, EPout, payload), NwkId, )
def rawaps_read_attribute_req(self, nwkid, EpIn, EpOut, Cluster, direction, manufacturer_spec, manufacturer, Attr, ackIsDisabled=True): self.log.logging( "zclCommand", "Debug", "rawaps_read_attribute_req %s %s %s %s %s %s %s %s" % (nwkid, EpIn, EpOut, Cluster, direction, manufacturer_spec, manufacturer, Attr)) cmd = "00" # Read Attribute Command Identifier # Cluster Frame: # 0b xxxx xxxx # |- Frame Type: Cluster Specific (0x00) # |-- Manufacturer Specific False # |--- Command Direction: Client to Server (0) # | ---- Disable default response: True # |||- ---- Reserved : 0x000 # cluster_frame = 0b00010000 if manufacturer_spec == "01": cluster_frame += 0b00000100 fcf = "%02x" % cluster_frame sqn = get_and_inc_SQN(self, nwkid) payload = fcf if manufacturer_spec == "01": payload += manufacturer_spec + manufacturer[4:2] + manufacturer[0:2] payload += sqn + cmd idx = 0 while idx < len(Attr): attribute = Attr[idx:idx + 4] idx += 4 payload += "%04x" % struct.unpack( ">H", struct.pack("H", int(attribute, 16)))[0] return raw_APS_request(self, nwkid, EpOut, Cluster, "0104", payload, zigate_ep=EpIn, ackIsDisabled=ackIsDisabled)
def rawaps_write_attribute_req(self, nwkid, EPin, EPout, cluster, manuf_id, manuf_spec, attribute, data_type, data, ackIsDisabled=True): self.log.logging( "zclCommand", "Debug", "rawaps_write_attribute_req %s %s %s %s %s %s %s %s %s" % (nwkid, EPin, EPout, cluster, manuf_id, manuf_spec, attribute, data_type, data)) cmd = "02" cluster_frame = 0b00010000 if manuf_spec == "01": cluster_frame += 0b00000100 fcf = "%02x" % cluster_frame sqn = get_and_inc_SQN(self, nwkid) payload = fcf if manuf_spec == "01": payload += manuf_spec + "%04x" % struct.unpack( ">H", struct.pack("H", int(manuf_id, 16)))[0] payload += sqn + cmd payload += "%04x" % struct.unpack(">H", struct.pack( "H", int(attribute, 16)))[0] payload += data_type if data_type in ("10", "18", "20", "28", "30"): payload += data elif data_type in ("09", "16", "21", "29", "31"): payload += "%04x" % struct.unpack(">H", struct.pack( "H", int(data, 16)))[0] elif data_type in ("22", "2a"): payload += "%06x" % struct.unpack(">i", struct.pack( "I", int(data, 16)))[0] elif data_type in ("23", "2b", "39"): payload += "%08x" % struct.unpack(">f", struct.pack( "I", int(data, 16)))[0] else: payload += data return raw_APS_request(self, nwkid, EPout, cluster, "0104", payload, zigate_ep=EPin, ackIsDisabled=ackIsDisabled)
def profalux_MoveWithOnOff(self, nwkid, OnOff): if OnOff not in [0x00, 0x01]: return # determine which Endpoint EPout = "01" for tmpEp in self.ListOfDevices[nwkid]["Ep"]: if "0008" in self.ListOfDevices[nwkid]["Ep"][tmpEp]: EPout = tmpEp cluster_frame = "11" sqn = get_and_inc_SQN(self, nwkid) cmd = "05" # Ask the Tilt Blind to open or Close payload = cluster_frame + sqn + cmd + "%02x" % OnOff raw_APS_request(self, nwkid, EPout, "0008", "0104", payload, zigate_ep=ZIGATE_EP) self.log.logging( "Profalux", "Debug", "profalux_MoveWithOnOff ++++ %s/%s OnOff: %s payload: %s" % (nwkid, EPout, OnOff, payload), nwkid, )
def zdp_raw_IEEE_address_request(self, nwkid, u8RequestType, u8StartIndex): Cluster = "0001" payload = get_and_inc_ZDP_SQM(self, nwkid) + "%04x" % struct.unpack( ">H", struct.pack("H", int(nwkid, 16)))[0] + u8RequestType + u8StartIndex return raw_APS_request( self, nwkid, "00", Cluster, "0000", payload, zigate_ep="00", groupaddrmode=False, ackIsDisabled=False, )
def raw_zcl_zcl_onoff(self, nwkid, EPIn, EpOut, command, effect="", groupaddrmode=False, ackIsDisabled=True): self.log.logging( "zclCommand", "Log", "raw_zcl_zcl_onoff %s %s %s %s %s %s" % (nwkid, EPIn, EpOut, command, effect, groupaddrmode)) Cluster = "0006" ONOFF_COMMANDS = { "Off": 0x00, "On": 0x01, "Toggle": 0x02, "OffWithEffect": 0x40, "OnWithRecallGlobalScene": 0x41, "OnWithTimedOff": 0x42, } if command not in ONOFF_COMMANDS: return # Cluster Frame: # 0b xxxx xxxx # |- Frame Type: Cluster Specific (0x01) # |-- Manufacturer Specific False # |--- Command Direction: Client to Server (0) # | ---- Disable default response: True # |||- ---- Reserved : 0x000 # cluster_frame = 0b00010001 sqn = get_and_inc_SQN(self, nwkid) payload = "%02x" % cluster_frame + sqn + "%02x" % ONOFF_COMMANDS[ command] + effect return raw_APS_request(self, nwkid, EpOut, Cluster, "0104", payload, zigate_ep=EPIn, groupaddrmode=groupaddrmode, ackIsDisabled=ackIsDisabled)
def rawaps_configure_reporting_req(self, nwkid, EpIn, EpOut, Cluster, direction, manufacturer_spec, manufacturer, attributelist, ackIsDisabled=True): self.log.logging( "zclCommand", "Debug", "rawaps_read_attribute_req %s %s %s %s %s %s %s %s" % (nwkid, EpIn, EpOut, Cluster, direction, manufacturer_spec, manufacturer, attributelist)) cmd = "06" # Configure Reporting Command Identifier # Cluster Frame: # 0b xxxx xxxx # |- Frame Type: Cluster Specific (0x00) # |-- Manufacturer Specific False # |--- Command Direction: Client to Server (0) # | ---- Disable default response: True # |||- ---- Reserved : 0x000 # cluster_frame = 0b00010000 if manufacturer_spec == "01": cluster_frame += 0b00000100 fcf = "%02x" % cluster_frame sqn = get_and_inc_SQN(self, nwkid) payload = fcf if manufacturer_spec == "01": payload += manufacturer_spec + manufacturer[4:2] + manufacturer[0:2] payload += sqn + cmd payload += build_payload_for_configure_reporting(attributelist) return raw_APS_request(self, nwkid, EpOut, Cluster, "0104", payload, zigate_ep=EpIn, ackIsDisabled=ackIsDisabled)
def zdp_power_descriptor_request(self, nwkid): self.log.logging("zdpCommand", "Log", "zdp_power_descriptor_request %s" % (nwkid, )) Cluster = "0003" payload = get_and_inc_ZDP_SQM(self, nwkid) + "%04x" % struct.unpack( ">H", struct.pack("H", int(nwkid, 16)))[0] return raw_APS_request( self, nwkid, "00", Cluster, "0000", payload, zigate_ep="00", groupaddrmode=False, ackIsDisabled=False, )
def profalux_MoveToLiftAndTilt(self, nwkid, level=None, tilt=None): def getLevel(self, nwkid): # Let's check if we can get the Level from Attribute level = None if ( "01" in self.ListOfDevices[nwkid]["Ep"] and "0008" in self.ListOfDevices[nwkid]["Ep"]["01"] and "0000" in self.ListOfDevices[nwkid]["Ep"]["01"]["0008"] ): level = int(self.ListOfDevices[nwkid]["Ep"]["01"]["0008"]["0000"], 16) return level def getTilt(self, nwkid): tilt = 45 if "Param" in self.ListOfDevices[nwkid] and "profaluxOrientBSO" in self.ListOfDevices[nwkid]["Param"]: tilt = self.ListOfDevices[nwkid]["Param"]["profaluxOrientBSO"] # Let's check if we can get the Tilt from Attribute if ( "01" in self.ListOfDevices[nwkid]["Ep"] and "fc21" in self.ListOfDevices[nwkid]["Ep"]["01"] and "0001" in self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"] ): tilt = int(self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"]["0001"], 16) return tilt def setLevel(self, nwkid, level): if "01" not in self.ListOfDevices[nwkid]["Ep"]: self.ListOfDevices[nwkid]["Ep"]["01"] = {} if "0008" not in self.ListOfDevices[nwkid]["Ep"]["01"]: self.ListOfDevices[nwkid]["Ep"]["01"]["0008"] = {} self.ListOfDevices[nwkid]["Ep"]["01"]["0008"]["0000"] = "%02x" % level def setTilt(self, nwkid, tilt): if "01" not in self.ListOfDevices[nwkid]["Ep"]: self.ListOfDevices[nwkid]["Ep"]["01"] = {} if "fc21" not in self.ListOfDevices[nwkid]["Ep"]["01"]: self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"] = {} self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"]["0001"] = "%02x" % tilt # Begin self.log.logging( "Profalux", "Debug", "profalux_MoveToLiftAndTilt Nwkid: %s Level: %s Tilt: %s" % (nwkid, level, tilt) ) if level is None and tilt is None: return # Disabled until 3.1c # checkAndTriggerConfigReporting( self, nwkid) if level is None: level = getLevel(self, nwkid) if tilt is None: tilt = getTilt(self, nwkid) self.log.logging( "Profalux", "Debug", "profalux_MoveToLiftAndTilt after update Nwkid: %s Level: %s Tilt: %s" % (nwkid, level, tilt), ) # determine which Endpoint EPout = "01" # Cluster Frame: # Frame Type: Cluster Command (1) # Manufacturer Specific True # Command Direction: Client to Server (0) # Disable default response: false # Reserved : 0x00 cluster_frame = "05" sqn = get_and_inc_SQN(self, nwkid) cmd = "10" # Propriatary Command: Ask the Tilt Blind to go to a Certain Position and Orientate to a certain angle # compute option 0x01 level, 0x02 tilt, 0x03 level + tilt if level is not None and tilt is not None: option = 0x03 elif tilt is not None: option = 0x02 level = 0x00 elif level is not None: option = 0x01 tilt = 0x00 setTilt(self, nwkid, tilt) setLevel(self, nwkid, level) # payload: 11 45 10 03 55 2d ffff # Option Parameter uint8 Bit0 Ask for lift action, Bit1 Ask fr a tilt action # Lift Parameter uint8 Lift value between 1 to 254 # Tilt Parameter uint8 Tilt value between 0 and 90 # Transition Time uint16 Transition Time between current and asked position ManfufacturerCode = "1110" payload = ( cluster_frame + ManfufacturerCode[2:4] + ManfufacturerCode[0:2] + sqn + cmd + "%02x" % option + "%02x" % level + "%02x" % tilt + "FFFF" ) self.log.logging( "Profalux", "Debug", "profalux_MoveToLiftAndTilt %s ++++ %s %s/%s level: %s tilt: %s option: %s payload: %s" % (cluster_frame, sqn, nwkid, EPout, level, tilt, option, payload), nwkid, ) raw_APS_request(self, nwkid, "01", "0008", "0104", payload, zigate_ep=ZIGATE_EP)
def sendFC01Command(self, sqn, nwkid, ep, ClusterID, cmd, data): self.log.logging("Legrand", "Debug", "sendFC01Command Cmd: %s Data: %s" % (cmd, data)) if cmd == "00": # Read Attribute received attribute = data[2:4] + data[0:2] if ClusterID == "0000" and attribute == "f000": # Respond to Time Of Operation cmd = "01" status = "00" cluster_frame = "1c" dataType = "23" # Uint32 PluginTimeOfOperation = "%08X" % (self.HeartbeatCount * HEARTBEAT) # Time since the plugin started payload = ( cluster_frame + sqn + cmd + attribute + status + dataType + PluginTimeOfOperation[6:8] + PluginTimeOfOperation[4:6] + PluginTimeOfOperation[0:2] + PluginTimeOfOperation[2:4] ) raw_APS_request( self, nwkid, ep, ClusterID, "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), highpriority=True, ) self.log.logging( "Legrand", "Log", "loggingLegrand - Nwkid: %s/%s Cluster: %s, Command: %s Payload: %s" % (nwkid, ep, ClusterID, cmd, data), ) return if cmd == "08": # Assign GroupId to a single remote manufspec = "2110" # Legrand Manuf Specific : 0x1021 cluster_frame = "1d" # Cliuster Specifi, Manuf Specifi payload = cluster_frame + manufspec + sqn + cmd + data raw_APS_request( self, nwkid, ep, ClusterID, "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), highpriority=True, ) self.log.logging( "Legrand", "Log", "loggingLegrand - Nwkid: %s/%s Cluster: %s, Command: %s Payload: %s" % (nwkid, ep, ClusterID, cmd, data), ) return if cmd == "0c": # Assign GroupId to a double remote manufspec = "2110" # Legrand Manuf Specific : 0x1021 cluster_frame = "1d" # Cliuster Specifi, Manuf Specifi payload = cluster_frame + manufspec + sqn + cmd + data raw_APS_request( self, nwkid, ep, ClusterID, "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), highpriority=True, ) self.log.logging( "Legrand", "Log", "loggingLegrand - Nwkid: %s/%s Cluster: %s, Command: %s Payload: %s" % (nwkid, ep, ClusterID, cmd, data), ) return
def zcl_raw_level_move_to_level(self, nwkid, EPIn, EPout, command, level="00", move_mode="00", rate="FF", step_mode="00", step_size="01", transition="0010", groupaddrmode=False, ackIsDisabled=True): self.log.logging( "zclCommand", "Debug", "zcl_raw_level_move_to_level %s %s %s %s %s %s %s %s %s %s" % (nwkid, EPIn, EPout, command, level, move_mode, rate, step_mode, step_size, transition)) Cluster = "0008" LEVEL_COMMANDS = { "MovetoLevel": 0x00, "Move": 0x01, "Step": 0x02, "Stop": 0x03, "MovetoLevelWithOnOff": 0x04, "MoveWithOnOff": 0x05, "StepWithOnOff": 0x06, "Stop2": 0x07 } if command not in LEVEL_COMMANDS: return # Cluster Frame: # 0b xxxx xxxx # |- Frame Type: Cluster Specific (0x01) # |-- Manufacturer Specific False # |--- Command Direction: Client to Server (0) # | ---- Disable default response: True # |||- ---- Reserved : 0x000 # cluster_frame = 0b00010001 sqn = get_and_inc_SQN(self, nwkid) payload = "%02x" % cluster_frame + sqn + "%02x" % LEVEL_COMMANDS[command] if command in ("MovetoLevel", "MovetoLevelWithOnOff"): payload += level + "%04x" % (struct.unpack( ">H", struct.pack("H", int(transition, 16)))[0]) elif command == ("Move", "MoveWithOnOff"): payload += move_mode + rate elif command == ("Step", "StepWithOnOff"): payload += step_mode + step_size + "%04x" % (struct.unpack( ">H", struct.pack("H", int(transition, 16)))[0]) return raw_APS_request(self, nwkid, EPout, Cluster, "0104", payload, zigate_ep=EPIn, groupaddrmode=groupaddrmode, ackIsDisabled=ackIsDisabled)