diff --git a/circuitmatter/__init__.py b/circuitmatter/__init__.py index d778c2d..1837ea5 100644 --- a/circuitmatter/__init__.py +++ b/circuitmatter/__init__.py @@ -81,7 +81,12 @@ class CircuitMatter: self._endpoints = {} self._next_endpoint = 0 self.root_node = RootNode( - random_source, self.mdns_server, self.UDP_PORT, vendor_id, product_id + random_source, + self.mdns_server, + self.UDP_PORT, + vendor_id, + product_id, + version=__version__, ) self.add_device(self.root_node) diff --git a/circuitmatter/clusters/device_management/general_diagnostics.py b/circuitmatter/clusters/device_management/general_diagnostics.py index d2937b6..65c71ff 100644 --- a/circuitmatter/clusters/device_management/general_diagnostics.py +++ b/circuitmatter/clusters/device_management/general_diagnostics.py @@ -3,4 +3,4 @@ from circuitmatter import data_model class GeneralDiagnosticsCluster(data_model.Cluster): CLUSTER_ID = 0x0033 - REVISION = 2 + cluster_revision = 2 diff --git a/circuitmatter/clusters/lighting/color_control.py b/circuitmatter/clusters/lighting/color_control.py index 9ae10a3..efad5d3 100644 --- a/circuitmatter/clusters/lighting/color_control.py +++ b/circuitmatter/clusters/lighting/color_control.py @@ -41,25 +41,42 @@ class ColorMode(data_model.Enum8): class ColorControl(data_model.Cluster): CLUSTER_ID = 0x0300 - REVISION = 6 + cluster_revision = 6 - CurrentHue = data_model.NumberAttribute(0x0000, signed=False, bits=8, default=0) - CurrentSaturation = data_model.NumberAttribute( + current_hue = data_model.NumberAttribute(0x0000, signed=False, bits=8, default=0) + current_saturation = data_model.NumberAttribute( 0x0001, signed=False, bits=8, default=0 ) - RemainingTime = data_model.NumberAttribute(0x0002, signed=False, bits=16, default=0) - CurrentX = data_model.NumberAttribute(0x0003, signed=False, bits=16, default=0) - CurrentY = data_model.NumberAttribute(0x0004, signed=False, bits=16, default=0) - DriftCompensation = data_model.NumberAttribute( + remaining_time = data_model.NumberAttribute( + 0x0002, signed=False, bits=16, default=0 + ) + current_x = data_model.NumberAttribute(0x0003, signed=False, bits=16, default=0) + current_y = data_model.NumberAttribute(0x0004, signed=False, bits=16, default=0) + drift_compensation = data_model.NumberAttribute( 0x0005, signed=False, bits=8, default=0 ) - CompensationText = data_model.UTF8StringAttribute(0x0006, default="") - ColorTemperature = data_model.NumberAttribute( + compensation_text = data_model.UTF8StringAttribute(0x0006, default="") + color_temperature = data_model.NumberAttribute( 0x0007, signed=False, bits=16, default=0 ) - ColorMode = data_model.EnumAttribute(0x0008, data_model.Enum8, default=0) - Options = data_model.BitmapAttribute(0x000F, OptionsBitmap, default=0) - ColorCapabilities = data_model.BitmapAttribute(0x400A, FeatureBitmap, default=0) + color_mode = data_model.EnumAttribute(0x0008, data_model.Enum8, default=0) + options = data_model.BitmapAttribute(0x000F, OptionsBitmap, default=0) + color_capabilities = data_model.BitmapAttribute(0x400A, FeatureBitmap, default=0) + + color_temp_physical_min_mireds = data_model.NumberAttribute( + 0x400B, + signed=False, + bits=16, + default=0, + feature=FeatureBitmap.COLOR_TEMPERATURE, + ) # maximum=0xfeff + color_temp_physical_max_mireds = data_model.NumberAttribute( + 0x400C, + signed=False, + bits=16, + default=0xFEFF, + feature=FeatureBitmap.COLOR_TEMPERATURE, + ) # maximum=0xfeff class MoveToHue(tlv.Structure): Hue = tlv.IntMember(0, signed=False, octets=1, maximum=254) diff --git a/circuitmatter/clusters/system_model/binding.py b/circuitmatter/clusters/system_model/binding.py index cd4e325..4b90b64 100644 --- a/circuitmatter/clusters/system_model/binding.py +++ b/circuitmatter/clusters/system_model/binding.py @@ -4,7 +4,7 @@ from circuitmatter import tlv class BindingCluster(data_model.Cluster): CLUSTER_ID = 0x001E - REVISION = 1 + cluster_revision = 1 class TargetStruct(tlv.Structure): Node = data_model.NodeId(1, optional=True) diff --git a/circuitmatter/clusters/system_model/user_label.py b/circuitmatter/clusters/system_model/user_label.py index 09a2857..c5e8902 100644 --- a/circuitmatter/clusters/system_model/user_label.py +++ b/circuitmatter/clusters/system_model/user_label.py @@ -4,7 +4,7 @@ from circuitmatter import tlv class UserLabelCluster(data_model.Cluster): CLUSTER_ID = 0x0041 - REVISION = 1 + cluster_revision = 1 class LabelStruct(tlv.Structure): Label = tlv.UTF8StringMember(0, 16, default="") diff --git a/circuitmatter/data_model.py b/circuitmatter/data_model.py index 7d6fc0c..5115e2e 100644 --- a/circuitmatter/data_model.py +++ b/circuitmatter/data_model.py @@ -57,6 +57,18 @@ class ClusterId(Uint16): pass +class AttributeId(Uint16): + pass + + +class EventId(Uint16): + pass + + +class CommandId(Uint16): + pass + + class DeviceTypeId(Uint32): pass @@ -302,13 +314,30 @@ class Command: class Cluster: + cluster_revision = NumberAttribute(0xFFFD, signed=False, bits=12, default=1) feature_map = NumberAttribute(0xFFFC, signed=False, bits=32, default=0) + attribute_list = ListAttribute(0xFFFB, AttributeId()) + event_list = ListAttribute(0xFFFA, EventId()) + accepted_command_list = ListAttribute(0xFFF9, CommandId()) + generated_command_list = ListAttribute(0xFFF8, CommandId()) def __init__(self): self._attribute_values = {} # Use random since this isn't for security or replayability. self.data_version = random.randint(0, 0xFFFFFFFF) + self.attribute_list = [] + for _, descriptor in self._attributes(): + self.attribute_list.append(descriptor.id) + + self.accepted_command_list = [] + self.generated_command_list = [] + self.event_list = [] + for _, descriptor in self._commands(): + self.accepted_command_list.append(descriptor.command_id) + if descriptor.response_id is not None: + self.generated_command_list.append(descriptor.response_id) + def __contains__(self, descriptor_id): return descriptor_id in self._attribute_values @@ -372,7 +401,7 @@ class Cluster: if path.Attribute is not None: break if not replies: - print("not found", path.Attribute) + print(f"\033[91mnot found 0x{path.Attribute:04x}\033[0m") return replies def set_attribute( diff --git a/circuitmatter/device_types/utility/root_node.py b/circuitmatter/device_types/utility/root_node.py index 3805372..da4bbcc 100644 --- a/circuitmatter/device_types/utility/root_node.py +++ b/circuitmatter/device_types/utility/root_node.py @@ -425,14 +425,24 @@ class RootNode(simple_device.SimpleDevice): DEVICE_TYPE_ID = 0x0011 REVISION = 2 - def __init__(self, random_source, mdns_server, port, vendor_id, product_id): + def __init__( + self, + random_source, + mdns_server, + port, + vendor_id, + product_id, + version="", + serial_number="1234", + ): super().__init__("root") basic_info = BasicInformationCluster() basic_info.vendor_id = vendor_id basic_info.product_id = product_id basic_info.product_name = "CircuitMatter" - basic_info.serial_number = "1234" + basic_info.serial_number = serial_number + basic_info.software_version_string = version self.servers.append(basic_info) access_control = AccessControlCluster() self.servers.append(access_control) diff --git a/circuitmatter/utility/mdns/avahi.py b/circuitmatter/utility/mdns/avahi.py index 8655199..b48a2f0 100644 --- a/circuitmatter/utility/mdns/avahi.py +++ b/circuitmatter/utility/mdns/avahi.py @@ -4,7 +4,6 @@ import subprocess class Avahi: def __init__(self): self.active_services = {} - self.publish_address = None def advertise_service( self, @@ -26,16 +25,7 @@ class Avahi: *txt_records, ] self.active_services[service_type + instance_name] = subprocess.Popen(command) - if self.publish_address is None: - command = [ - "avahi-publish-address", - "dalinar.local", - "fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", # "fe80::642:1aff:fe0c:9f2a", - ] - self.publish_address = subprocess.Popen(command) def __del__(self): for active_service in self.active_services.values(): active_service.kill() - if self.publish_address is not None: - self.publish_address.kill()