class ConfigureReportingResponse(t.List(ConfigureReportingResponseRecord)): def serialize(self): failed = [record for record in self if record.status != Status.SUCCESS] if failed: return b"".join([ ConfigureReportingResponseRecord(i).serialize() for i in failed ]) return Status.SUCCESS.serialize()
async def test_write_attributes_cache_success(cluster, attributes, result): rsp_type = t.List(foundation.WriteAttributesStatusRecord) write_mock = CoroutineMock(return_value=[rsp_type.deserialize(result)[0]]) with mock.patch.object(cluster, "_write_attributes", write_mock): await cluster.write_attributes(attributes) assert cluster._write_attributes.call_count == 1 for attr_id in attributes: assert cluster._attr_cache[attr_id] == attributes[attr_id]
class MultistateInput(Cluster): cluster_id = 0x0012 ep_attribute = 'multistate_input' attributes = { 0x000e: ('state_text', t.List(t.LVBytes)), 0x001c: ('description', t.LVBytes), 0x004a: ('number_of_states', t.uint16_t), 0x0051: ('out_of_service', t.Bool), 0x0055: ('present_value', t.Single), # 0x0057: ('priority_array', TODO.array), # Array of 16 structures of (boolean, single precision) 0x0067: ('reliability', t.uint8_t), # enum8 0x006f: ('status_flags', t.uint8_t), # bitmap8 0x0100: ('application_type', t.uint32_t), } server_commands = {} client_commands = {}
class MultistateInput(Cluster): cluster_id = 0x0012 ep_attribute = "multistate_input" attributes = { 0x000E: ("state_text", t.List(t.CharacterString)), 0x001C: ("description", t.CharacterString), 0x004A: ("number_of_states", t.uint16_t), 0x0051: ("out_of_service", t.Bool), 0x0055: ("present_value", t.Single), # 0x0057: ('priority_array', TODO.array), # Array of 16 structures of (boolean, # single precision) 0x0067: ("reliability", t.enum8), 0x006F: ("status_flags", t.bitmap8), 0x0100: ("application_type", t.uint32_t), } server_commands = {} client_commands = {}
_fields = [ ('direction', t.uint8_t), ('attrid', t.uint16_t), ] class DiscoverAttributesResponseRecord(t.Struct): _fields = [ ('attrid', t.uint16_t), ('datatype', t.uint8_t), ] COMMANDS = { # id: (name, params, is_response) 0x00: ('Read attributes', (t.List(t.uint16_t), ), False), 0x01: ('Read attributes response', (t.List(ReadAttributeRecord), ), True), 0x02: ('Write attributes', (t.List(Attribute), ), False), 0x03: ('Write attributes undivided', (t.List(Attribute), ), False), 0x04: ('Write attributes response', (t.List(WriteAttributesStatusRecord), ), True), 0x05: ('Write attributes no response', (t.List(Attribute), ), False), 0x06: ('Configure reporting', (t.List(AttributeReportingConfig), ), False), 0x07: ('Configure reporting response', (t.List(ConfigureReportingResponseRecord), ), True), 0x08: ('Read reporting configuration', (t.List(ReadReportingConfigRecord), ), False), 0x09: ('Read reporting configuration response', (t.List(AttributeReportingConfig), ), True), 0x0a: ('Report attributes', (t.List(Attribute), ), False), 0x0b: ('Default response', (t.uint8_t, Status), True),
ZDOCmd.Mgmt_Leave_req: (("DeviceAddress", t.EUI64), ("Options", t.bitmap8)), ZDOCmd.Mgmt_Permit_Joining_req: ( ("PermitDuration", t.uint8_t), ("TC_Significant", t.Bool), ), # ... TODO optional stuff ... # Responses # Device and Service Discovery Server Responses ZDOCmd.NWK_addr_rsp: ( STATUS, IEEE, NWK, ("NumAssocDev", t.Optional(t.uint8_t)), ("StartIndex", t.Optional(t.uint8_t)), ("NWKAddressAssocDevList", t.Optional(t.List(t.NWK))), ), ZDOCmd.IEEE_addr_rsp: ( STATUS, IEEE, NWK, ("NumAssocDev", t.Optional(t.uint8_t)), ("StartIndex", t.Optional(t.uint8_t)), ("NWKAddrAssocDevList", t.Optional(t.List(t.NWK))), ), ZDOCmd.Node_Desc_rsp: ( STATUS, NWKI, ("NodeDescriptor", t.Optional(NodeDescriptor)), ), ZDOCmd.Power_Desc_rsp: (
class Thermostat(Cluster): """An interface for configuring and controlling the functionality of a thermostat.""" cluster_id = 0x0201 ep_attribute = 'thermostat' attributes = { # Thermostat Information 0x0000: ('local_temp', t.int16s), 0x0001: ('outdoor_temp', t.int16s), 0x0002: ('occupancy', t.bitmap8), 0x0003: ('abs_min_heat_setpoint_limit', t.int16s), 0x0004: ('abs_max_heat_setpoint_limit', t.int16s), 0x0005: ('abs_min_cool_setpoint_limit', t.int16s), 0x0006: ('abs_max_cool_setpoint_limit', t.int16s), 0x0007: ('pi_cooling_demand', t.uint8_t), 0x0008: ('pi_heating_demand', t.uint8_t), 0x0009: ('system_type_config', t.bitmap8), # Thermostat Settings 0x0010: ('local_temperature_calibration', t.int8s), 0x0011: ('occupied_cooling_setpoint', t.int16s), 0x0012: ('occupied_heating_setpoint', t.int16s), 0x0013: ('unoccupied_cooling_setpoint', t.int16s), 0x0014: ('unoccupied_heating_setpoint', t.int16s), 0x0015: ('min_heat_setpoint_limit', t.int16s), 0x0016: ('max_heat_setpoint_limit', t.int16s), 0x0017: ('min_cool_setpoint_limit', t.int16s), 0x0018: ('max_cool_setpoint_limit', t.int16s), 0x0019: ('min_setpoint_dead_band', t.int8s), 0x001a: ('remote_sensing', t.bitmap8), 0x001b: ('ctrl_seqe_of_oper', t.enum8), 0x001c: ('system_mode', t.enum8), 0x001d: ('alarm_mask', t.bitmap8), 0x001e: ('running_mode', t.enum8), # ... 0x0020: ('start_of_week', t.enum8), 0x0021: ('number_of_weekly_trans', t.uint8_t), 0x0022: ('number_of_daily_trans', t.uint8_t), 0x0023: ('temp_setpoint_hold', t.enum8), 0x0024: ('temp_setpoint_hold_duration', t.uint16_t), 0x0025: ('programing_oper_mode', t.bitmap8), 0x0029: ('running_state', t.bitmap16), 0x0030: ('setpoint_change_source', t.enum8), 0x0031: ('setpoint_change_amount', t.int16s), 0x0032: ('setpoint_change_source_time_stamp', t.uint32_t), 0x0040: ('ac_type', t.enum8), 0x0041: ('ac_capacity', t.uint16_t), 0x0042: ('ac_refrigerant_type', t.enum8), 0x0043: ('ac_compressor_type', t.enum8), 0x0044: ('ac_error_code', t.bitmap32), 0x0045: ('ac_louver_position', t.enum8), 0x0046: ('ac_coll_temp', t.int16s), 0x0047: ('ac_capacity_format', t.enum8), } server_commands = { 0x0000: ('setpoint_raise_lower', (t.enum8, t.int8s), False), 0x0001: ('set_weekly_schedule', (t.enum8, t.bitmap8, t.bitmap8, t.List(t.int16s)), False), 0x0002: ('get_weekly_schedule', (t.bitmap8, t.bitmap8), False), 0x0003: ('clear_weekly_schedule', (), False), 0x0004: ('get_relay_status_log', (), False), } client_commands = { 0x0000: ('get_weekly_schedule_response', (t.enum8, t.bitmap8, t.bitmap8, t.List(t.int16s)), True), 0x0001: ('get_relay_status_log_response', (t.uint16_t, t.bitmap8, t.int16s, t.uint8_t, t.int16s, t.uint16_t), True), }
# Bind Management Server Services Responses 0x0020: ('End_Device_Bind_req', (('BindingTarget', t.uint16_t), ('SrcAddress', t.EUI64), ('SrcEndpoint', t.uint8_t), ('ProfileID', t.uint8_t), ('InClusterList', t.LVList(t.uint8_t)), ('OutClusterList', t.LVList(t.uint8_t)))), 0x0021: ('Bind_req', (('SrcAddress', t.EUI64), ('SrcEndpoint', t.uint8_t), ('ClusterID', t.uint16_t), ('DstAddress', MultiAddress))), 0x0022: ('Unind_req', (('SrcAddress', t.EUI64), ('SrcEndpoint', t.uint8_t), ('ClusterID', t.uint16_t), ('DstAddress', MultiAddress))), # Network Management Server Services Requests # ... TODO optional stuff ... 0x0031: ('Mgmt_Lqi_req', (('StartIndex', t.uint8_t), )), 0x0032: ('Mgmt_Rtg_req', (('StartIndex', t.uint8_t), )), # ... TODO optional stuff ... 0x0034: ('Mgmt_Leave_req', (('DeviceAddress', t.EUI64), ('Options', t.bitmap8))), 0x0036: ('Mgmt_Permit_Joining_req', (('PermitDuration', t.uint8_t), ('TC_Significant', t.Bool))), # ... TODO optional stuff ... # Responses # Device and Service Discovery Server Responses 0x8000: ('NWK_addr_rsp', (STATUS, IEEE, NWK, ('NumAssocDev', t.uint8_t), ('StartIndex', t.uint8_t), ('NWKAddressAssocDevList', t.List(t.uint16_t)))), 0x8001: ('IEEE_addr_rsp', (STATUS, IEEE, NWK, ('NumAssocDev', t.uint8_t), ('StartIndex', t.uint8_t), ('NWKAddrAssocDevList', t.List(t.uint16_t)))), 0x8002: ('Node_Desc_rsp', (STATUS, NWKI, ('NodeDescriptor', NodeDescriptor))), 0x8003: ('Power_Desc_rsp', (STATUS, NWKI, ('PowerDescriptor', PowerDescriptor))), 0x8004: ('Simple_Desc_rsp', (STATUS, NWKI, ('SimpleDescriptor', SizePrefixedSimpleDescriptor))), 0x8005: ('Active_EP_rsp', (STATUS, NWKI, ('ActiveEPList', t.LVList(t.uint8_t)))), 0x8006: ('Match_Desc_rsp', (STATUS, NWKI, ('MatchList', t.LVList(t.uint8_t)))), # 0x8010: ('Complex_Desc_rsp', (STATUS, NWKI, ('Length', t.uint8_t), ('ComplexDescriptor', ComplexDescriptor))), 0x8011: ('User_Desc_rsp', (STATUS, NWKI, ('Length', t.uint8_t), ('UserDescriptor', t.fixed_list(16, t.uint8_t)))), 0x8012: ('Discovery_Cache_rsp', (STATUS, )), 0x8014: ('User_Desc_conf', (STATUS, NWKI)), 0x8015: ('System_Server_Discovery_rsp', (STATUS, ('ServerMask', t.uint16_t))), 0x8016: ('Discovery_Store_rsp', (STATUS, )), 0x8017: ('Node_Desc_store_rsp', (STATUS, )), 0x8018: ('Power_Desc_store_rsp', (STATUS, IEEE, ('PowerDescriptor', PowerDescriptor))), 0x8019: ('Active_EP_store_rsp', (STATUS, )),
Discover_Commands_Generated = 0x13 Discover_Commands_Generated_rsp = 0x14 Discover_Attribute_Extended = 0x15 Discover_Attribute_Extended_rsp = 0x16 @classmethod def deserialize(cls, data): try: return super().deserialize(data) except ValueError: return t.uint8_t.deserialize(data) COMMANDS = { # id: (params, is_response) Command.Configure_Reporting: ((t.List(AttributeReportingConfig), ), False), Command.Configure_Reporting_rsp: ( (t.List(ConfigureReportingResponseRecord), ), True, ), Command.Default_Response: ((t.uint8_t, Status), True), Command.Discover_Attributes: ((t.uint16_t, t.uint8_t), False), Command.Discover_Attributes_rsp: ( (t.Bool, t.List(DiscoverAttributesResponseRecord)), True, ), Command.Discover_Attribute_Extended: ((t.uint16_t, t.uint8_t), False), Command.Discover_Attribute_Extended_rsp: ( (t.Bool, t.List(DiscoverAttributesExtendedResponseRecord)), True, ),
class Thermostat(Cluster): """An interface for configuring and controlling the functionality of a thermostat.""" class ACCapacityFormat(t.enum8): BTUh = 0x00 class ACCompressorType(t.enum8): Reserved = 0x00 T1_max_working_43C = 0x01 T2_max_working_35C = 0x02 T3_max_working_52C = 0x03 class ACType(t.enum8): Reserved = 0x00 Cooling_fixed_speed = 0x01 Heat_Pump_fixed_speed = 0x02 Cooling_Inverter = 0x03 Heat_Pump_Inverter = 0x04 class ACRefrigerantType(t.enum8): Reserved = 0x00 R22 = 0x01 R410a = 0x02 R407c = 0x03 class ACErrorCode(t.bitmap32): No_Errors = 0x00000000 Commpressor_Failure = 0x00000001 Room_Temperature_Sensor_Failure = 0x00000002 Outdoor_Temperature_Sensor_Failure = 0x00000004 Indoor_Coil_Temperature_Sensor_Failure = 0x00000008 Fan_Failure = 0x00000010 class ACLouverPosition(t.enum8): Closed = 0x01 Open = 0x02 Qurter_Open = 0x03 Half_Open = 0x04 Three_Quarters_Open = 0x05 class AlarmMask(t.bitmap8): No_Alarms = 0x00 Initialization_failure = 0x01 Hardware_failure = 0x02 Self_calibration_failure = 0x04 class ControlSequenceOfOperation(t.enum8): Cooling_Only = 0x00 Cooling_With_Reheat = 0x01 Heating_Only = 0x02 Heating_With_Reheat = 0x03 Cooling_and_Heating = 0x04 Cooling_and_Heating_with_Reheat = 0x08 class SeqDayOfWeek(t.bitmap8): Sunday = 0x01 Monday = 0x02 Tuesday = 0x04 Wednesday = 0x08 Thursday = 0x10 Friday = 0x20 Saturday = 0x40 Away = 0x80 class SeqMode(t.bitmap8): Heat = 0x01 Cool = 0x02 class Occupancy(t.bitmap8): Unoccupied = 0x00 Occupied = 0x01 class ProgrammingOperationMode(t.bitmap8): Simple = 0x00 Schedule_programming_mode = 0x01 Auto_recovery_mode = 0x02 Economy_mode = 0x04 class RemoteSensing(t.bitmap8): all_local = 0x00 local_temperature_sensed_remotely = 0x01 outdoor_temperature_sensed_remotely = 0x02 occupancy_sensed_remotely = 0x04 class SetpointChangeSource(t.enum8): Manual = 0x00 Schedule = 0x01 External = 0x02 class SetpointMode(t.enum8): Heat = 0x00 Cool = 0x01 Both = 0x02 class StartOfWeek(t.enum8): Sunday = 0x00 Monday = 0x01 Tuesday = 0x02 Wednesday = 0x03 Thursday = 0x04 Friday = 0x05 Saturday = 0x06 class SystemMode(t.enum8): Off = 0x00 Auto = 0x01 Cool = 0x03 Heat = 0x04 Emergency_Heating = 0x05 Pre_cooling = 0x06 Fan_only = 0x07 Dry = 0x08 Sleep = 0x09 class SystemType(t.bitmap8): Heat_and_or_Cool_Stage_1 = 0x00 Cool_Stage_1 = 0x01 Cool_Stage_2 = 0x02 Heat_Stage_1 = 0x04 Heat_Stage_2 = 0x08 Heat_Pump = 0x10 Gas = 0x20 @property def cooling_system_stage(self) -> CoolingSystemStage: return CoolingSystemStage(self & 0x03) @property def heating_system_stage(self) -> HeatingSystemStage: return HeatingSystemStage((self >> 2) & 0x03) @property def heating_system_type(self) -> HeatingSystemType: return HeatingSystemType((self >> 4) & 0x01) @property def heating_fuel_source(self) -> HeatingFuelSource: return HeatingFuelSource((self >> 5) & 0x01) class TemperatureSetpointHold(t.enum8): Setpoint_Hold_Off = 0x00 Setpoint_Hold_On = 0x01 class RunningMode(t.enum8): Off = 0x00 Cool = 0x03 Heat = 0x04 class RunningState(t.bitmap16): Idle = 0x0000 Heat_State_On = 0x0001 Cool_State_On = 0x0002 Fan_State_On = 0x0004 Heat_2nd_Stage_On = 0x0008 Cool_2nd_Stage_On = 0x0010 Fan_2nd_Stage_On = 0x0020 Fan_3rd_Stage_On = 0x0040 cluster_id = 0x0201 ep_attribute = "thermostat" attributes = { # Thermostat Information 0x0000: ("local_temp", t.int16s), 0x0001: ("outdoor_temp", t.int16s), 0x0002: ("occupancy", Occupancy), 0x0003: ("abs_min_heat_setpoint_limit", t.int16s), 0x0004: ("abs_max_heat_setpoint_limit", t.int16s), 0x0005: ("abs_min_cool_setpoint_limit", t.int16s), 0x0006: ("abs_max_cool_setpoint_limit", t.int16s), 0x0007: ("pi_cooling_demand", t.uint8_t), 0x0008: ("pi_heating_demand", t.uint8_t), 0x0009: ("system_type_config", SystemType), # Thermostat Settings 0x0010: ("local_temperature_calibration", t.int8s), 0x0011: ("occupied_cooling_setpoint", t.int16s), 0x0012: ("occupied_heating_setpoint", t.int16s), 0x0013: ("unoccupied_cooling_setpoint", t.int16s), 0x0014: ("unoccupied_heating_setpoint", t.int16s), 0x0015: ("min_heat_setpoint_limit", t.int16s), 0x0016: ("max_heat_setpoint_limit", t.int16s), 0x0017: ("min_cool_setpoint_limit", t.int16s), 0x0018: ("max_cool_setpoint_limit", t.int16s), 0x0019: ("min_setpoint_dead_band", t.int8s), 0x001A: ("remote_sensing", RemoteSensing), 0x001B: ("ctrl_seqe_of_oper", ControlSequenceOfOperation), 0x001C: ("system_mode", SystemMode), 0x001D: ("alarm_mask", AlarmMask), 0x001E: ("running_mode", RunningMode), # ... 0x0020: ("start_of_week", StartOfWeek), 0x0021: ("number_of_weekly_trans", t.uint8_t), 0x0022: ("number_of_daily_trans", t.uint8_t), 0x0023: ("temp_setpoint_hold", TemperatureSetpointHold), 0x0024: ("temp_setpoint_hold_duration", t.uint16_t), 0x0025: ("programing_oper_mode", ProgrammingOperationMode), 0x0029: ("running_state", RunningState), 0x0030: ("setpoint_change_source", SetpointChangeSource), 0x0031: ("setpoint_change_amount", t.int16s), 0x0032: ("setpoint_change_source_time_stamp", t.uint32_t), 0x0040: ("ac_type", ACType), 0x0041: ("ac_capacity", t.uint16_t), 0x0042: ("ac_refrigerant_type", ACRefrigerantType), 0x0043: ("ac_compressor_type", ACCompressorType), 0x0044: ("ac_error_code", ACErrorCode), 0x0045: ("ac_louver_position", ACLouverPosition), 0x0046: ("ac_coll_temp", t.int16s), 0x0047: ("ac_capacity_format", ACCapacityFormat), } server_commands = { 0x0000: ("setpoint_raise_lower", (SetpointMode, t.int8s), False), 0x0001: ( "set_weekly_schedule", (t.enum8, SeqDayOfWeek, SeqMode, t.List(t.int16s)), False, ), 0x0002: ("get_weekly_schedule", (SeqDayOfWeek, SeqMode), False), 0x0003: ("clear_weekly_schedule", (), False), 0x0004: ("get_relay_status_log", (), False), } client_commands = { 0x0000: ( "get_weekly_schedule_response", (t.enum8, SeqDayOfWeek, SeqMode, t.List(t.int16s)), True, ), 0x0001: ( "get_relay_status_log_response", (t.uint16_t, t.bitmap8, t.int16s, t.uint8_t, t.int16s, t.uint16_t), True, ), }
class IasAce(Cluster): class AlarmStatus(t.enum8): """IAS ACE alarm status enum.""" No_Alarm = 0x00 Burglar = 0x01 Fire = 0x02 Emergency = 0x03 Police_Panic = 0x04 Fire_Panic = 0x05 Emergency_Panic = 0x06 class ArmMode(t.enum8): """IAS ACE arm mode enum.""" Disarm = 0x00 Arm_Day_Home_Only = 0x01 Arm_Night_Sleep_Only = 0x02 Arm_All_Zones = 0x03 class ArmNotification(t.enum8): """IAS ACE arm notification enum.""" All_Zones_Disarmed = 0x00 Only_Day_Home_Zones_Armed = 0x01 Only_Night_Sleep_Zones_Armed = 0x02 All_Zones_Armed = 0x03 Invalid_Arm_Disarm_Code = 0x04 Not_Ready_To_Arm = 0x05 Already_Disarmed = 0x06 class AudibleNotification( t.enum_factory(t.uint8_t, "manufacturer_specific")): """IAS ACE audible notification enum.""" Mute = 0x00 Default_Sound = 0x01 class BypassResponse(t.enum8): """Bypass result.""" Zone_bypassed = 0x00 Zone_not_bypassed = 0x01 Not_allowed = 0x02 Invalid_Zone_ID = 0x03 Unknown_Zone_ID = 0x04 Invalid_Code = 0x05 class PanelStatus(t.enum8): """IAS ACE panel status enum.""" Panel_Disarmed = 0x00 Armed_Stay = 0x01 Armed_Night = 0x02 Armed_Away = 0x03 Exit_Delay = 0x04 Entry_Delay = 0x05 Not_Ready_To_Arm = 0x06 In_Alarm = 0x07 Arming_Stay = 0x08 Arming_Night = 0x09 Arming_Away = 0x0A ZoneType = IasZone.ZoneType ZoneStatus = IasZone.ZoneStatus class ZoneStatusRsp(t.Struct): """Zone status response.""" _fields = [("zone_id", t.uint8_t), ("zone_status", IasZone.ZoneStatus)] cluster_id = 0x0501 name = "IAS Ancillary Control Equipment" ep_attribute = "ias_ace" attributes = {} server_commands = { 0x0000: ("arm", (ArmMode, t.CharacterString, t.uint8_t), False), 0x0001: ("bypass", (t.LVList(t.uint8_t), t.CharacterString), False), 0x0002: ("emergency", (), False), 0x0003: ("fire", (), False), 0x0004: ("panic", (), False), 0x0005: ("get_zone_id_map", (), False), 0x0006: ("get_zone_info", (t.uint8_t, ), False), 0x0007: ("get_panel_status", (), False), 0x0008: ("get_bypassed_zone_list", (), False), 0x0009: ("get_zone_status", (t.uint8_t, t.uint8_t, t.Bool, ZoneStatus), False), } client_commands = { 0x0000: ("arm_response", (ArmNotification, ), True), 0x0001: ("get_zone_id_map_response", (t.List(t.bitmap16), ), True), 0x0002: ( "get_zone_info_response", (t.uint8_t, ZoneType, t.EUI64, t.CharacterString), True, ), 0x0003: ( "zone_status_changed", (t.uint8_t, ZoneStatus, AudibleNotification, t.CharacterString), False, ), 0x0004: ( "panel_status_changed", (PanelStatus, t.uint8_t, AudibleNotification, AlarmStatus), False, ), 0x0005: ( "panel_status_response", (PanelStatus, t.uint8_t, AudibleNotification, AlarmStatus), True, ), 0x0006: ("set_bypassed_zone_list", (t.LVList(t.uint8_t), ), False), 0x0007: ("bypass_response", (t.LVList(BypassResponse), ), True), 0x0008: ("get_zone_status_response", (t.Bool, t.LVList(ZoneStatusRsp)), True), }
class Thermostat(Cluster): """An interface for configuring and controlling the functionality of a thermostat.""" cluster_id = 0x0201 ep_attribute = "thermostat" attributes = { # Thermostat Information 0x0000: ("local_temp", t.int16s), 0x0001: ("outdoor_temp", t.int16s), 0x0002: ("occupancy", t.bitmap8), 0x0003: ("abs_min_heat_setpoint_limit", t.int16s), 0x0004: ("abs_max_heat_setpoint_limit", t.int16s), 0x0005: ("abs_min_cool_setpoint_limit", t.int16s), 0x0006: ("abs_max_cool_setpoint_limit", t.int16s), 0x0007: ("pi_cooling_demand", t.uint8_t), 0x0008: ("pi_heating_demand", t.uint8_t), 0x0009: ("system_type_config", t.bitmap8), # Thermostat Settings 0x0010: ("local_temperature_calibration", t.int8s), 0x0011: ("occupied_cooling_setpoint", t.int16s), 0x0012: ("occupied_heating_setpoint", t.int16s), 0x0013: ("unoccupied_cooling_setpoint", t.int16s), 0x0014: ("unoccupied_heating_setpoint", t.int16s), 0x0015: ("min_heat_setpoint_limit", t.int16s), 0x0016: ("max_heat_setpoint_limit", t.int16s), 0x0017: ("min_cool_setpoint_limit", t.int16s), 0x0018: ("max_cool_setpoint_limit", t.int16s), 0x0019: ("min_setpoint_dead_band", t.int8s), 0x001A: ("remote_sensing", t.bitmap8), 0x001B: ("ctrl_seqe_of_oper", t.enum8), 0x001C: ("system_mode", t.enum8), 0x001D: ("alarm_mask", t.bitmap8), 0x001E: ("running_mode", t.enum8), # ... 0x0020: ("start_of_week", t.enum8), 0x0021: ("number_of_weekly_trans", t.uint8_t), 0x0022: ("number_of_daily_trans", t.uint8_t), 0x0023: ("temp_setpoint_hold", t.enum8), 0x0024: ("temp_setpoint_hold_duration", t.uint16_t), 0x0025: ("programing_oper_mode", t.bitmap8), 0x0029: ("running_state", t.bitmap16), 0x0030: ("setpoint_change_source", t.enum8), 0x0031: ("setpoint_change_amount", t.int16s), 0x0032: ("setpoint_change_source_time_stamp", t.uint32_t), 0x0040: ("ac_type", t.enum8), 0x0041: ("ac_capacity", t.uint16_t), 0x0042: ("ac_refrigerant_type", t.enum8), 0x0043: ("ac_compressor_type", t.enum8), 0x0044: ("ac_error_code", t.bitmap32), 0x0045: ("ac_louver_position", t.enum8), 0x0046: ("ac_coll_temp", t.int16s), 0x0047: ("ac_capacity_format", t.enum8), } server_commands = { 0x0000: ("setpoint_raise_lower", (t.enum8, t.int8s), False), 0x0001: ( "set_weekly_schedule", (t.enum8, t.bitmap8, t.bitmap8, t.List(t.int16s)), False, ), 0x0002: ("get_weekly_schedule", (t.bitmap8, t.bitmap8), False), 0x0003: ("clear_weekly_schedule", (), False), 0x0004: ("get_relay_status_log", (), False), } client_commands = { 0x0000: ( "get_weekly_schedule_response", (t.enum8, t.bitmap8, t.bitmap8, t.List(t.int16s)), True, ), 0x0001: ( "get_relay_status_log_response", (t.uint16_t, t.bitmap8, t.int16s, t.uint8_t, t.int16s, t.uint16_t), True, ), }
# ... TODO optional stuff ... ZDOCmd.Mgmt_Lqi_req: (('StartIndex', t.uint8_t), ), ZDOCmd.Mgmt_Rtg_req: (('StartIndex', t.uint8_t), ), # ... TODO optional stuff ... ZDOCmd.Mgmt_Leave_req: (('DeviceAddress', t.EUI64), ('Options', t.bitmap8)), ZDOCmd.Mgmt_Permit_Joining_req: (('PermitDuration', t.uint8_t), ('TC_Significant', t.Bool)), # ... TODO optional stuff ... # Responses # Device and Service Discovery Server Responses ZDOCmd.NWK_addr_rsp: (STATUS, IEEE, NWK, ('NumAssocDev', t.Optional(t.uint8_t)), ('StartIndex', t.Optional(t.uint8_t)), ('NWKAddressAssocDevList', t.Optional(t.List(t.NWK)))), ZDOCmd.IEEE_addr_rsp: (STATUS, IEEE, NWK, ('NumAssocDev', t.Optional(t.uint8_t)), ('StartIndex', t.Optional(t.uint8_t)), ('NWKAddrAssocDevList', t.Optional(t.List(t.NWK)))), ZDOCmd.Node_Desc_rsp: (STATUS, NWKI, ('NodeDescriptor', t.Optional(NodeDescriptor))), ZDOCmd.Power_Desc_rsp: (STATUS, NWKI, ('PowerDescriptor', t.Optional(PowerDescriptor))), ZDOCmd.Simple_Desc_rsp: (STATUS, NWKI, ('SimpleDescriptor', t.Optional(SizePrefixedSimpleDescriptor))), ZDOCmd.Active_EP_rsp: (STATUS, NWKI, ('ActiveEPList', t.LVList(t.uint8_t))), ZDOCmd.Match_Desc_rsp: (STATUS, NWKI, ('MatchList', t.LVList(t.uint8_t))), # ZDO.Complex_Desc_rsp: (STATUS, NWKI, ('Length', t.uint8_t), ('ComplexDescriptor', t.Optional(ComplexDescriptor))),
def test_list(): expected = list(map(ord, '\x0123')) assert t.List(t.uint8_t).deserialize(b'\x0123') == (expected, b'')
def test_list(): expected = list(map(ord, "\x0123")) assert t.List(t.uint8_t).deserialize(b"\x0123") == (expected, b"")
READ_REPORT = 0b101 READ_WRITE = 0b110 READ_WRITE_REPORT = 0b111 class DiscoverAttributesExtendedResponseRecord(t.Struct): _fields = [ ('attrid', t.uint16_t), ('datatype', t.uint8_t), ('acl', AttributeAccessControl), ] COMMANDS = { # id: (name, params, is_response) 0x00: ('Read attributes', (t.List(t.uint16_t), ), False), 0x01: ('Read attributes response', (t.List(ReadAttributeRecord), ), True), 0x02: ('Write attributes', (t.List(Attribute), ), False), 0x03: ('Write attributes undivided', (t.List(Attribute), ), False), 0x04: ('Write attributes response', (t.List(WriteAttributesStatusRecord), ), True), 0x05: ('Write attributes no response', (t.List(Attribute), ), False), 0x06: ('Configure reporting', (t.List(AttributeReportingConfig), ), False), 0x07: ('Configure reporting response', (t.List(ConfigureReportingResponseRecord), ), True), 0x08: ('Read reporting configuration', (t.List(ReadReportingConfigRecord), ), False), 0x09: ('Read reporting configuration response', (t.List(AttributeReportingConfig), ), True), 0x0a: ('Report attributes', (t.List(Attribute), ), False), 0x0b: ('Default response', (t.uint8_t, Status), True),
0x0022: ('Unind_req', (('SrcAddress', t.EUI64), ('SrcEndpoint', t.uint8_t), ('ClusterID', t.uint16_t), ('DstAddress', MultiAddress))), # Network Management Server Services Requests # ... TODO optional stuff ... 0x0034: ('Mgmt_Leave_req', (('DeviceAddress', t.EUI64), ('Options', t.uint8_t))), # bitmap8 0x0036: ('Mgmt_Permit_Joining_req', (('PermitDuration', t.uint8_t), ('TC_Significant', t.Bool))), # ... TODO optional stuff ... # Responses # Device and Service Discovery Server Responses 0x8000: ('NWK_addr_rsp', (STATUS, IEEE, NWK, ('NumAssocDev', t.uint8_t), ('StartIndex', t.uint8_t), ('NWKAddressAssocDevList', t.List(t.uint16_t)))), 0x8001: ('IEEE_addr_rsp', (STATUS, IEEE, NWK, ('NumAssocDev', t.uint8_t), ('StartIndex', t.uint8_t), ('NWKAddrAssocDevList', t.List(t.uint16_t)))), 0x8002: ('Node_Desc_rsp', (STATUS, NWKI, ('NodeDescriptor', NodeDescriptor))), 0x8003: ('Power_Desc_rsp', (STATUS, NWKI, ('PowerDescriptor', PowerDescriptor))), 0x8004: ('Simple_Desc_rsp', (STATUS, NWKI, ('SimpleDescriptor', SizePrefixedSimpleDescriptor))), 0x8005: ('Active_EP_rsp', (STATUS, NWKI, ('ActiveEPList', t.LVList(t.uint8_t)))), 0x8006: ('Match_Desc_rsp', (STATUS, NWKI, ('MatchList', t.LVList(t.uint8_t)))), # 0x8010: ('Complex_Desc_rsp', (STATUS, NWKI, ('Length', t.uint8_t), ('ComplexDescriptor', ComplexDescriptor))),