diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 03e3c76c625b7d..88588363d03ad4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -333,7 +333,7 @@ jobs: scripts/run_in_build_env.sh 'virtualenv pyenv' source pyenv/bin/activate pip3 install -r src/setup_payload/python/requirements.txt - python3 src/setup_payload/tests/run_python_setup_payload_gen_test.py out/chip-tool + python3 src/setup_payload/tests/run_python_setup_payload_test.py out/chip-tool build_linux_python_lighting_device: name: Build on Linux (python lighting-app) diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml index ad2a513209cc65..ba9c0f1d9f02c3 100644 --- a/.github/workflows/darwin.yaml +++ b/.github/workflows/darwin.yaml @@ -97,10 +97,10 @@ jobs: bootstrap-logs-framework-${{ matrix.options.flavor }} - name: Build example All Clusters Server run: | - scripts/examples/gn_build_example.sh examples/all-clusters-app/linux out/debug chip_config_network_layer_ble=false + scripts/examples/gn_build_example.sh examples/all-clusters-app/linux out/debug/all-clusters-app chip_config_network_layer_ble=false - name: Build example OTA Provider run: | - scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/debug chip_config_network_layer_ble=false + scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/debug/ota-provider-app chip_config_network_layer_ble=false - name: Build example OTA Requestor run: | scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/debug/ota-requestor-app chip_config_network_layer_ble=false non_spec_compliant_ota_action_delay_floor=0 @@ -113,13 +113,8 @@ jobs: run: | mkdir -p /tmp/darwin/framework-tests echo "This is a simple log" > /tmp/darwin/framework-tests/end_user_support_log.txt - ../../../out/debug/chip-all-clusters-app --interface-id -1 --end_user_support_log /tmp/darwin/framework-tests/end_user_support_log.txt > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) & - ../../../out/debug/chip-all-clusters-app --interface-id -1 --dac_provider ../../../credentials/development/commissioner_dut/struct_cd_origin_pid_vid_correct/test_case_vector.json --product-id 32768 --discriminator 3839 --secured-device-port 5539 --KVS /tmp/chip-all-clusters-app-kvs2 > >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid-err.log >&2) & - ../../../out/debug/chip-all-clusters-app --interface-id -1 --discriminator 101 --passcode 1001 --KVS /tmp/chip-all-clusters-app-kvs101 --secured-device-port 5531 & - ../../../out/debug/chip-all-clusters-app --interface-id -1 --discriminator 102 --passcode 1002 --KVS /tmp/chip-all-clusters-app-kvs102 --secured-device-port 5532 & - ../../../out/debug/chip-all-clusters-app --interface-id -1 --discriminator 103 --passcode 1003 --KVS /tmp/chip-all-clusters-app-kvs103 --secured-device-port 5533 & - ../../../out/debug/chip-all-clusters-app --interface-id -1 --discriminator 104 --passcode 1004 --KVS /tmp/chip-all-clusters-app-kvs104 --secured-device-port 5534 & - ../../../out/debug/chip-all-clusters-app --interface-id -1 --discriminator 105 --passcode 1005 --KVS /tmp/chip-all-clusters-app-kvs105 --secured-device-port 5535 & + ../../../out/debug/all-clusters-app/chip-all-clusters-app --interface-id -1 --end_user_support_log /tmp/darwin/framework-tests/end_user_support_log.txt > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) & + ../../../out/debug/all-clusters-app/chip-all-clusters-app --interface-id -1 --dac_provider ../../../credentials/development/commissioner_dut/struct_cd_origin_pid_vid_correct/test_case_vector.json --product-id 32768 --discriminator 3839 --secured-device-port 5539 --KVS /tmp/chip-all-clusters-app-kvs2 > >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid-err.log >&2) & export TEST_RUNNER_ASAN_OPTIONS=__CURRENT_VALUE__:detect_stack_use_after_return=1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4685948fd7bd12..bd5385580b9c22 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -98,7 +98,6 @@ jobs: --known-failure controller/ExamplePersistentStorage.cpp \ --known-failure controller/ExamplePersistentStorage.h \ --known-failure app/AttributeAccessToken.h \ - --known-failure app/CommandHandler.h \ --known-failure app/CommandHandlerInterface.h \ --known-failure app/CommandResponseSender.h \ --known-failure app/CommandSenderLegacyCallback.h \ diff --git a/.github/workflows/minimal-build.yaml b/.github/workflows/minimal-build.yaml index 46f1d0b1fce68e..ac11a145c7fa4e 100644 --- a/.github/workflows/minimal-build.yaml +++ b/.github/workflows/minimal-build.yaml @@ -26,7 +26,7 @@ concurrency: cancel-in-progress: true jobs: - minimal: + minimal-all-clusters: name: Linux / configure build of all-clusters-app if: github.actor != 'restyled-io[bot]' @@ -47,3 +47,25 @@ jobs: - name: Configure and build All Clusters App run: | CC=gcc CXX=g++ scripts/configure --project=examples/all-clusters-app/linux && ./ninja-build + + minimal-network-manager: + name: Linux / configure build of network-manager-app + + if: github.actor != 'restyled-io[bot]' + runs-on: ubuntu-latest + + container: + image: ghcr.io/project-chip/chip-build-minimal:50 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Checkout submodules # but don't bootstrap! + uses: ./.github/actions/checkout-submodules + with: + platform: linux + + - name: Configure and build Network Manager App + run: | + CC=gcc CXX=g++ scripts/configure --project=examples/network-manager-app/linux && ./ninja-build diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 57bc3971d44ea3..4dc5a4cc48218f 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -189,6 +189,7 @@ jobs: src/app/zap-templates/zcl/data-model/chip/wake-on-lan-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/washer-controls-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/wifi-network-diagnostics-cluster.xml \ + src/app/zap-templates/zcl/data-model/chip/wifi-network-management-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/window-covering.xml \ src/app/zap-templates/zcl/data-model/chip/temperature-control-cluster.xml \ src/app/zap-templates/zcl/data-model/chip/matter-devices.xml \ diff --git a/build/chip/linux/BUILD.gn b/build/chip/linux/BUILD.gn index c86f803a70f3d3..a530d5a611a25e 100644 --- a/build/chip/linux/BUILD.gn +++ b/build/chip/linux/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Project CHIP Authors +# Copyright (c) 2020-2024 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,4 +21,5 @@ pkg_config("glib") { "glib-2.0", "gio-unix-2.0", ] + optional = true # Only certain conditionally-compiled modules depend on glib } diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py index 4d6e773a00d666..f44667242de807 100755 --- a/build/config/linux/pkg-config.py +++ b/build/config/linux/pkg-config.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Copyright (c) 2020 Project CHIP Authors +# Copyright (c) 2020-2024 Project CHIP Authors # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -127,6 +127,7 @@ def RewritePath(path, strip_prefix, sysroot): def main(): parser = OptionParser() parser.add_option('-d', '--debug', action='store_true') + parser.add_option('-o', '--optional', action='store_true') parser.add_option('-p', action='store', dest='pkg_config', type='string', default='pkg-config') parser.add_option('-v', action='append', dest='strip_out', type='string') @@ -209,6 +210,10 @@ def main(): try: flag_string = subprocess.check_output(cmd).decode('utf-8') except Exception: + if options.optional: + sys.stderr.write('Ignoring failure to run pkg-config for optional library.\n') + print(json.dumps([False])) # Output a GN array indicating missing optional packages + return 0 sys.stderr.write('Could not run pkg-config.\n') return 1 @@ -248,10 +253,10 @@ def main(): else: cflags.append(flag) - # Output a GN array, the first one is the cflags, the second are the libs. The + # Output a GN array, indicating success and our output lists. # JSON formatter prints GN compatible lists when everything is a list of # strings. - print(json.dumps([includes, cflags, libs, lib_dirs])) + print(json.dumps([True, includes, cflags, libs, lib_dirs])) return 0 diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni index 016defafbc3617..d6892d97fb976f 100644 --- a/build/config/linux/pkg_config.gni +++ b/build/config/linux/pkg_config.gni @@ -1,5 +1,5 @@ # Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Copyright (c) 2020 Project CHIP Authors +# Copyright (c) 2020-2024 Project CHIP Authors # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -43,9 +43,14 @@ # # You can also use "extra args" to filter out results (see pkg-config.py): # extra_args = [ "-v, "foo" ] +# # To ignore libs and ldflags (only cflags/defines will be set, which is useful # when doing manual dynamic linking), set: # ignore_libs = true +# +# To allow the build to proceed if (any of) the requested packages are absent, set: +# optional = true +# In this case the resulting config object will be empty. import("//build_overrides/build.gni") import("${build_root}/config/sysroot.gni") @@ -109,37 +114,42 @@ template("pkg_config") { } else { args = pkg_config_args + invoker.packages } + if (defined(invoker.optional) && invoker.optional) { + args += [ "-o" ] + } if (defined(invoker.extra_args)) { args += invoker.extra_args } + # pkgresult = [present, includes, cflags, libs, lib_dirs] pkgresult = exec_script(pkg_config_script, args, "value") - cflags = pkgresult[1] + if (pkgresult[0]) { + cflags = pkgresult[2] - foreach(include, pkgresult[0]) { - cflags += [ "-I$include" ] - } + foreach(include, pkgresult[1]) { + cflags += [ "-I$include" ] + } - if (!defined(invoker.ignore_libs) || !invoker.ignore_libs) { - libs = pkgresult[2] - lib_dirs = pkgresult[3] - } + if (!defined(invoker.ignore_libs) || !invoker.ignore_libs) { + libs = pkgresult[3] + lib_dirs = pkgresult[4] + } - # Link libraries statically for OSS-Fuzz fuzzer build - if (oss_fuzz) { - libs = [] - ldflags = [ "-Wl,-Bstatic" ] - foreach(lib, pkgresult[2]) { - ldflags += [ "-l$lib" ] + # Link libraries statically for OSS-Fuzz fuzzer build + if (oss_fuzz) { + libs = [] + ldflags = [ "-Wl,-Bstatic" ] + foreach(lib, pkgresult[3]) { + ldflags += [ "-l$lib" ] + } + ldflags += [ "-Wl,-Bdynamic" ] + lib_dirs = pkgresult[4] } - ldflags += [ "-Wl,-Bdynamic" ] - lib_dirs = pkgresult[3] - } - forward_variables_from(invoker, - [ - "defines", - "visibility", - ]) + forward_variables_from(invoker, [ "defines" ]) + } } + + # Always forward visibility + forward_variables_from(invoker, [ "visibility" ]) } diff --git a/credentials/generate-revocation-set.py b/credentials/generate-revocation-set.py index 534edc15b0f203..bfc5ce560c1f80 100644 --- a/credentials/generate-revocation-set.py +++ b/credentials/generate-revocation-set.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # -# Copyright (c) 2023 Project CHIP Authors +# Copyright (c) 2023-2024 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import base64 import json +import logging import subprocess import sys from enum import Enum @@ -30,6 +31,16 @@ import requests from click_option_group import RequiredMutuallyExclusiveOptionGroup, optgroup from cryptography import x509 +from cryptography.hazmat.primitives.asymmetric import ec + +# Supported log levels, mapping string values required for argument +# parsing into logging constants +__LOG_LEVELS__ = { + 'debug': logging.DEBUG, + 'info': logging.INFO, + 'warn': logging.WARN, + 'fatal': logging.FATAL, +} class RevocationType(Enum): @@ -44,20 +55,144 @@ class RevocationType(Enum): TEST_NODE_URL_REST = "https://on.test-net.dcl.csa-iot.org" -def use_dcld(dcld, production, cmdlist): - return [dcld] + cmdlist + (['--node', PRODUCTION_NODE_URL] if production else []) - - def extract_single_integer_attribute(subject, oid): attribute_list = subject.get_attributes_for_oid(oid) if len(attribute_list) == 1: - if attribute_list[0].value.isdigit(): - return int(attribute_list[0].value) + return int(attribute_list[0].value, 16) return None +class DCLDClient: + ''' + A client for interacting with DCLD using either the REST API or command line interface (CLI). + + ''' + + def __init__(self, use_rest: bool, dcld_exe: str, production: bool, rest_node_url: str): + ''' + Initialize the client + + use_rest: bool + Use RESTful API with HTTPS against `rest_node_url` + dcld_exe: str + Path to `dcld` executable + production: bool + Use MainNet DCL URL with dcld executable + rest_node_url: str + RESTful API URL + ''' + + self.use_rest = use_rest + self.dcld_exe = dcld_exe + self.production = production + self.rest_node_url = rest_node_url + + def build_dcld_command_line(self, cmdlist: list[str]) -> list[str]: + ''' + Build command line for `dcld` executable. + + Parameters + ---------- + cmdlist: list[str] + List of command line arguments to append to some predefined arguments + + Returns + ------- + list[str] + The complete command list including the DCLD executable and node option if in production + ''' + + return [self.dcld_exe] + cmdlist + (['--node', PRODUCTION_NODE_URL] if self.production else []) + + def get_dcld_cmd_output_json(self, cmdlist: list[str]) -> dict: + ''' + Executes a DCLD CLI command and returns the JSON output. + + Parameters + ---------- + cmdlist: list[str] + List of command line arguments to append to some predefined arguments + + Returns + ------- + dict + The JSON output from the command + ''' + + # Set the output as JSON + subprocess.Popen([self.dcld_exe, 'config', 'output', 'json']) + + cmdpipe = subprocess.Popen(self.build_dcld_command_line(cmdlist), + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + return json.loads(cmdpipe.stdout.read()) + + def get_revocation_points(self) -> list[dict]: + ''' + Get revocation points from DCL + + Returns + ------- + list[dict] + List of revocation points + ''' + + if self.use_rest: + response = requests.get(f"{self.rest_node_url}/dcl/pki/revocation-points").json() + else: + response = self.get_dcld_cmd_output_json(['query', 'pki', 'all-revocation-points']) + + return response["PkiRevocationDistributionPoint"] + + def get_paa_cert_for_crl_issuer(self, crl_signer_issuer_name_b64, crl_signer_authority_key_id) -> str: + ''' + Get PAA certificate for CRL issuer + + Parameters + ---------- + crl_signer_issuer_name_b64: str + The issuer name of the CRL signer. + crl_signer_authority_key_id: str + The authority key ID of the CRL signer. + + Returns + ------- + str + PAA certificate in PEM format + ''' + if self.use_rest: + response = requests.get( + f"{self.rest_node_url}/dcl/pki/certificates/{crl_signer_issuer_name_b64}/{crl_signer_authority_key_id}").json() + else: + response = self.get_dcld_cmd_output_json( + ['query', 'pki', 'x509-cert', '-u', crl_signer_issuer_name_b64, '-k', crl_signer_authority_key_id]) + + return response["approvedCertificates"]["certs"][0]["pemCert"] + + def get_revocations_points_by_skid(self, issuer_subject_key_id) -> list[dict]: + ''' + Get revocation points by subject key ID + + Parameters + ---------- + issuer_subject_key_id: str + Subject key ID + + Returns + ------- + list[dict] + List of revocation points + ''' + if self.use_rest: + response = requests.get(f"{self.rest_node_url}/dcl/pki/revocation-points/{issuer_subject_key_id}").json() + else: + response = self.get_dcld_cmd_output_json(['query', 'pki', 'revocation-points', + '--issuer-subject-key-id', issuer_subject_key_id]) + + return response["pkiRevocationDistributionPointsByIssuerSubjectKeyID"]["points"] + + @click.command() @click.help_option('-h', '--help') @optgroup.group('Input data sources', cls=RequiredMutuallyExclusiveOptionGroup) @@ -66,9 +201,19 @@ def extract_single_integer_attribute(subject, oid): @optgroup.option('--use-main-net-http', is_flag=True, type=str, help="Use RESTful API with HTTPS against public MainNet observer.") @optgroup.option('--use-test-net-http', is_flag=True, type=str, help="Use RESTful API with HTTPS against public TestNet observer.") @optgroup.group('Optional arguments') -@optgroup.option('--output', default='sample_revocation_set_list.json', type=str, metavar='FILEPATH', help="Output filename (default: sample_revocation_set_list.json)") -def main(use_main_net_dcld, use_test_net_dcld, use_main_net_http, use_test_net_http, output): - """DCL PAA mirroring tools""" +@optgroup.option('--output', default='sample_revocation_set_list.json', type=str, metavar='FILEPATH', + help="Output filename (default: sample_revocation_set_list.json)") +@optgroup.option('--log-level', default='INFO', show_default=True, type=click.Choice(__LOG_LEVELS__.keys(), + case_sensitive=False), callback=lambda c, p, v: __LOG_LEVELS__[v], + help='Determines the verbosity of script output') +def main(use_main_net_dcld: str, use_test_net_dcld: str, use_main_net_http: bool, use_test_net_http: bool, output: str, log_level: str): + """Tool to construct revocation set from DCL""" + + logging.basicConfig( + level=log_level, + format='%(asctime)s %(name)s %(levelname)-7s %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' + ) production = False dcld = use_test_net_dcld @@ -83,28 +228,20 @@ def main(use_main_net_dcld, use_test_net_dcld, use_main_net_http, use_test_net_h rest_node_url = PRODUCTION_NODE_URL_REST if production else TEST_NODE_URL_REST - # TODO: Extract this to a helper function - if use_rest: - revocation_point_list = requests.get(f"{rest_node_url}/dcl/pki/revocation-points").json()["PkiRevocationDistributionPoint"] - else: - cmdlist = ['config', 'output', 'json'] - subprocess.Popen([dcld] + cmdlist) - - cmdlist = ['query', 'pki', 'all-revocation-points'] - - cmdpipe = subprocess.Popen(use_dcld(dcld, production, cmdlist), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + dcld_client = DCLDClient(use_rest, dcld, production, rest_node_url) - revocation_point_list = json.loads(cmdpipe.stdout.read())["PkiRevocationDistributionPoint"] + revocation_point_list = dcld_client.get_revocation_points() revocation_set = [] for revocation_point in revocation_point_list: # 1. Validate Revocation Type - if revocation_point["revocationType"] != RevocationType.CRL: + if revocation_point["revocationType"] != RevocationType.CRL.value: + logging.warning("Revocation Type is not CRL, continue...") continue # 2. Parse the certificate - crl_signer_certificate = x509.load_pem_x509_certificate(revocation_point["crlSignerCertificate"]) + crl_signer_certificate = x509.load_pem_x509_certificate(bytes(revocation_point["crlSignerCertificate"], 'utf-8')) vid = revocation_point["vid"] pid = revocation_point["pid"] @@ -119,12 +256,15 @@ def main(use_main_net_dcld, use_test_net_dcld, use_main_net_http, use_test_net_h if crl_vid is not None: if vid != crl_vid: # TODO: Need to log all situations where a continue is called + logging.warning("VID is not CRL VID, continue...") continue else: if crl_vid is None or vid != crl_vid: + logging.warning("VID is not CRL VID, continue...") continue if crl_pid is not None: if pid != crl_pid: + logging.warning("PID is not CRL PID, continue...") continue # 5. Validate the certification path containing CRLSignerCertificate. @@ -133,99 +273,110 @@ def main(use_main_net_dcld, use_test_net_dcld, use_main_net_http, use_test_net_h crl_signer_authority_key_id = crl_signer_certificate.extensions.get_extension_for_oid( x509.OID_AUTHORITY_KEY_IDENTIFIER).value.key_identifier - paa_certificate = None + # Convert CRL Signer AKID to colon separated hex + crl_signer_authority_key_id = crl_signer_authority_key_id.hex().upper() + crl_signer_authority_key_id = ':'.join([crl_signer_authority_key_id[i:i+2] + for i in range(0, len(crl_signer_authority_key_id), 2)]) - # TODO: Extract this to a helper function - if use_rest: - response = requests.get( - f"{rest_node_url}/dcl/pki/certificates/{crl_signer_issuer_name}/{crl_signer_authority_key_id}").json()["approvedCertificates"]["certs"][0] - paa_certificate = response["pemCert"] - else: - cmdlist = ['query', 'pki', 'x509-cert', '-u', crl_signer_issuer_name, '-k', crl_signer_authority_key_id] - cmdpipe = subprocess.Popen(use_dcld(dcld, production, cmdlist), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - paa_certificate = json.loads(cmdpipe.stdout.read())["approvedCertificates"]["certs"][0]["pemCert"] + paa_certificate = dcld_client.get_paa_cert_for_crl_issuer(crl_signer_issuer_name, crl_signer_authority_key_id) if paa_certificate is None: + logging.warning("PAA Certificate not found, continue...") continue - paa_certificate_object = x509.load_pem_x509_certificate(paa_certificate) + paa_certificate_object = x509.load_pem_x509_certificate(bytes(paa_certificate, 'utf-8')) + + # TODO: use verify_directly_issued_by() method when we upgrade cryptography to v40.0.0 + # Verify issuer matches with subject + if crl_signer_certificate.issuer != paa_certificate_object.subject: + logging.warning("CRL Signer Certificate issuer does not match with PAA Certificate subject, continue...") + continue + # Check crl signers AKID matches with SKID of paa_certificate_object's AKID + paa_skid = paa_certificate_object.extensions.get_extension_for_oid(x509.OID_SUBJECT_KEY_IDENTIFIER).value.key_identifier + crl_akid = crl_signer_certificate.extensions.get_extension_for_oid(x509.OID_AUTHORITY_KEY_IDENTIFIER).value.key_identifier + if paa_skid != crl_akid: + logging.warning("CRL Signer's AKID does not match with PAA Certificate SKID, continue...") + continue + + # verify if PAA singed the crl signer certificate try: - crl_signer_certificate.verify_directly_issued_by(paa_certificate_object) + paa_certificate_object.public_key().verify(crl_signer_certificate.signature, + crl_signer_certificate.tbs_certificate_bytes, + ec.ECDSA(crl_signer_certificate.signature_hash_algorithm)) except Exception: + logging.warning("CRL Signer Certificate is not signed by PAA Certificate, continue...") continue # 6. Obtain the CRL - r = requests.get(revocation_point["dataURL"]) - crl_file = x509.load_der_x509_crl(r.content) + logging.debug(f"Fetching CRL from {revocation_point['dataURL']}") + try: + r = requests.get(revocation_point["dataURL"], timeout=5) + except Exception: + logging.error('Failed to fetch CRL') + continue + + try: + crl_file = x509.load_der_x509_crl(r.content) + except Exception: + logging.error('Failed to load CRL') + continue # 7. Perform CRL File Validation crl_authority_key_id = crl_file.extensions.get_extension_for_oid(x509.OID_AUTHORITY_KEY_IDENTIFIER).value.key_identifier crl_signer_subject_key_id = crl_signer_certificate.extensions.get_extension_for_oid( x509.OID_SUBJECT_KEY_IDENTIFIER).value.key_identifier if crl_authority_key_id != crl_signer_subject_key_id: + logging.warning("CRL Authority Key ID is not CRL Signer Subject Key ID, continue...") continue issuer_subject_key_id = ''.join('{:02X}'.format(x) for x in crl_authority_key_id) - same_issuer_points = None + # b. + same_issuer_points = dcld_client.get_revocations_points_by_skid(issuer_subject_key_id) + count_with_matching_vid_issuer_skid = sum(item.get('vid') == vid for item in same_issuer_points) - # TODO: Extract this to a helper function - if use_rest: - response = requests.get( - f"{rest_node_url}/dcl/pki/revocation-points/{issuer_subject_key_id}").json()["pkiRevocationDistributionPointsByIssuerSubjectKeyID"] - same_issuer_points = response["points"] - else: - cmdlist = ['query', 'pki', 'revocation-points', '--issuer-subject-key-id', issuer_subject_key_id] - cmdpipe = subprocess.Popen(use_dcld(dcld, production, cmdlist), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - same_issuer_points = json.loads(cmdpipe.stdout.read())[ - "pkiRevocationDistributionPointsByIssuerSubjectKeyID"]["points"] - - matching_entries = False - for same_issuer_point in same_issuer_points: - if same_issuer_point["vid"] == vid: - matching_entries = True - break - - if matching_entries: + if count_with_matching_vid_issuer_skid > 1: try: issuing_distribution_point = crl_file.extensions.get_extension_for_oid( x509.OID_ISSUING_DISTRIBUTION_POINT).value except Exception: + logging.warning("CRL Issuing Distribution Point not found, continue...") continue uri_list = issuing_distribution_point.full_name if len(uri_list) == 1 and isinstance(uri_list[0], x509.UniformResourceIdentifier): if uri_list[0].value != revocation_point["dataURL"]: + logging.warning("CRL Issuing Distribution Point URI is not CRL URL, continue...") continue else: + logging.warning("CRL Issuing Distribution Point URI is not CRL URL, continue...") continue # 9. Assign CRL File Issuer certificate_authority_name = base64.b64encode(crl_file.issuer.public_bytes()).decode('utf-8') + logging.debug(f"CRL File Issuer: {certificate_authority_name}") serialnumber_list = [] # 10. Iterate through the Revoked Certificates List for revoked_cert in crl_file: + # a. try: revoked_cert_issuer = revoked_cert.extensions.get_extension_for_oid( x509.CRLEntryExtensionOID.CERTIFICATE_ISSUER).value.get_values_for_type(x509.DirectoryName).value if revoked_cert_issuer is not None: if revoked_cert_issuer != certificate_authority_name: + logging.warning("CRL Issuer is not CRL File Issuer, continue...") continue except Exception: pass # b. - try: - revoked_cert_authority_key_id = revoked_cert.extensions.get_extension_for_oid( - x509.OID_AUTHORITY_KEY_IDENTIFIER).value.key_identifier - - if revoked_cert_authority_key_id is None or revoked_cert_authority_key_id != crl_signer_subject_key_id: - continue - except Exception: - continue + # TODO: Verify that the certificate chain of the entry is linking to the same PAA + # that issued the CRLSignerCertificate for this entry, including path through + # CRLSignerDelegator if present. If the PAAs under which were issued the certificate + # and the CRLSignerCertificate are different, ignore the entry. # c. and d. serialnumber_list.append(bytes(str('{:02X}'.format(revoked_cert.serial_number)), 'utf-8').decode('utf-8')) diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md index 97f0f76b3b0436..10833e0c0c1ed7 100644 --- a/docs/QUICK_START.md +++ b/docs/QUICK_START.md @@ -10,7 +10,7 @@ and platforms. |
Controller / Admin
|
Node
| Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [**chip-tool**](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) (Linux / Mac)
Includes docs for all the cluster commands supported
| **all-clusters-app**
  • [M5Stack](https://github.com/project-chip/connectedhomeip/blob/master/examples/all-clusters-app/esp32/README.md) (ESP)
  • [Linux](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/linux) simulation | Use the command line tool on a laptop to pair with and control an embedded Wi-Fi platform. This demo supports the “all-clusters-app”, so it provides the basic onoff light test and more. | -| [**chip-device-ctrl.py**](https://github.com/project-chip/connectedhomeip/blob/master/src/controller/python/README.md) | **all-clusters-app**
  • [M5Stack](https://github.com/project-chip/connectedhomeip/blob/master/examples/all-clusters-app/esp32/README.md) (ESP)
  • [Linux](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/linux) simulation | Same as above, but uses the pychip tool as Controller Node. | +| [**chip-repl**](https://github.com/project-chip/connectedhomeip/blob/master/src/controller/python/README.md) | **all-clusters-app**
  • [M5Stack](https://github.com/project-chip/connectedhomeip/blob/master/examples/all-clusters-app/esp32/README.md) (ESP)
  • [Linux](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/linux) simulation | Same as above, but uses the Python CHIP REPL as Controller Node. | ## Thread Nodes diff --git a/docs/guides/python_chip_controller_advanced_usage.md b/docs/guides/python_chip_controller_advanced_usage.md index c3d3f55ddc5095..2eee5472fdda23 100644 --- a/docs/guides/python_chip_controller_advanced_usage.md +++ b/docs/guides/python_chip_controller_advanced_usage.md @@ -7,8 +7,9 @@ tool or Matter accessories on Linux.
    -- [Bluetooth LE virtualization on Linux](#bluetooth-le-virtualization-on-linux) -- [Debugging with gdb](#debugging-with-gdb) +- [Using Python CHIP Controller advanced features](#using-python-chip-controller-advanced-features) + - [Bluetooth LE virtualization on Linux](#bluetooth-le-virtualization-on-linux) + - [Debugging with gdb](#debugging-with-gdb)
    @@ -62,38 +63,38 @@ interfaces working as Bluetooth LE central and peripheral, respectively. TX bytes:3488 acl:95 sco:0 commands:110 errors:0 ``` -4. Run the Python CHIP Controller with Bluetooth LE adapter defined from a +4. Run the Python CHIP Controller REPL with Bluetooth LE adapter defined from a command line: - For example, add `--bluetooth-adapter=hci2` to use the virtual interface - `hci2` listed above. + For example, add `--ble-adapter=2` to use the virtual interface `hci2` + listed above. ``` - chip-device-ctrl --bluetooth-adapter=hci2 + chip-repl --ble-adapter=2 ```
    ## Debugging with gdb -You can run the chip-device-ctrl under GDB for debugging, however, since the -Matter core support library is a dynamic library, you cannot read the symbols -unless it is fully loaded. +You can run the chip-repl under GDB for debugging, however, since the Matter SDK +library is a dynamic library, you cannot read the symbols unless it is fully +loaded. The following block is a example debug session using GDB: ``` # GDB cannot run scripts directly -# so you need to run Python3 with the path of device controller -# Here, we use the feature from bash to get the path of chip-device-ctrl without typing it. -$ gdb --args python3 `which chip-device-ctrl` -GNU gdb (Ubuntu 10.1-2ubuntu2) 10.1.90.20210411-git -Copyright (C) 2021 Free Software Foundation, Inc. +# so you need to run Python3 with the path of device controller REPL +# Here, we use the feature from bash to get the path of chip-repl without typing it. +$ gdb --args python3 `which chip-repl` +GNU gdb (GDB) 14.2 +Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. -This GDB was configured as "aarch64-linux-gnu". +This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: . @@ -103,6 +104,12 @@ Find the GDB manual and other documentation resources online at: For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from python3... + +This GDB supports auto-downloading debuginfo from the following URLs: + +Enable debuginfod for this session? (y or [n]) n +Debuginfod has been disabled. +To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit. (No debugging symbols found in python3) (gdb) ``` @@ -119,38 +126,68 @@ library, let run the Matter device controller first. ``` (gdb) run -Starting program: /usr/bin/python3 /home/ubuntu/.local/bin/chip-device-ctrl +Starting program: /home/sag/projects/project-chip/connectedhomeip/out/venv/bin/python3 /home/sag/projects/project-chip/connectedhomeip/out/venv/bin/chip-repl [Thread debugging using libthread_db enabled] -Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1". -CHIP:DIS: Init admin pairing table with server storage. -CHIP:IN: local node id is 0x000000000001b669 -CHIP:DL: MDNS failed to join multicast group on wpan0 for address type IPv4: Inet Error 1016 (0x000003F8): Address not found -CHIP:ZCL: Using ZAP configuration... -CHIP:ZCL: deactivate report event -CHIP:CTL: Getting operational keys -CHIP:CTL: Generating operational certificate for the controller -CHIP:CTL: Getting root certificate for the controller from the issuer -CHIP:CTL: Generating credentials -CHIP:CTL: Loaded credentials successfully -CHIP:DL: Platform main loop started. -Chip Device Controller Shell +Using host libthread_db library "/usr/lib/libthread_db.so.1". +Python 3.11.9 (main, Apr 29 2024, 11:59:58) [GCC 13.2.1 20240417] +Type 'copyright', 'credits' or 'license' for more information +IPython 8.24.0 -- An enhanced Interactive Python. Type '?' for help. +[1716395111.775747][364405:364405] CHIP:CTL: Setting attestation nonce to random value +[1716395111.776196][364405:364405] CHIP:CTL: Setting CSR nonce to random value +InitBLE 0[1716395111.776809][364405:364405] CHIP:DL: writing settings to file (/tmp/chip_counters.ini-T7hX27) +[1716395111.776854][364405:364405] CHIP:DL: renamed tmp file to file (/tmp/chip_counters.ini) +[1716395111.776860][364405:364405] CHIP:DL: NVS set: chip-counters/reboot-count = 9 (0x9) +[1716395111.777261][364405:364405] CHIP:DL: Got Ethernet interface: eno2 +[1716395111.777555][364405:364405] CHIP:DL: Found the primary Ethernet interface:eno2 +[1716395111.777868][364405:364405] CHIP:DL: Got WiFi interface: wlp7s0 +[1716395111.777877][364405:364405] CHIP:DL: Failed to reset WiFi statistic counts +────────────────────────────────────────────────────────────────────────────────────────────────────────── Matter REPL ────────────────────────────────────────────────────────────────────────────────────────────────────────── + + + + Welcome to the Matter Python REPL! + + For help, please type matterhelp() + + To get more information on a particular object/class, you can pass + that into matterhelp() as well. + + +───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +2024-05-22 18:25:11 allenwind PersistentStorage[364405] WARNING Initializing persistent storage from file: /tmp/repl-storage.json +2024-05-22 18:25:11 allenwind PersistentStorage[364405] WARNING Loading configuration from /tmp/repl-storage.json... +2024-05-22 18:25:11 allenwind CertificateAuthorityManager[364405] WARNING Loading certificate authorities from storage... +2024-05-22 18:25:11 allenwind CertificateAuthority[364405] WARNING New CertificateAuthority at index 1 +2024-05-22 18:25:11 allenwind CertificateAuthority[364405] WARNING Loading fabric admins from storage... +2024-05-22 18:25:11 allenwind FabricAdmin[364405] WARNING New FabricAdmin: FabricId: 0x0000000000000001, VendorId = 0xFFF1 +2024-05-22 18:25:11 allenwind FabricAdmin[364405] WARNING Allocating new controller with CaIndex: 1, FabricId: 0x0000000000000001, NodeId: 0x000000000001B669, CatTags: [] + + +The following objects have been created: + certificateAuthorityManager: Manages a list of CertificateAuthority instances. + caList: The list of CertificateAuthority instances. + caList: A specific FabricAdmin object at index m for the nth CertificateAuthority instance. -chip-device-ctrl > + +Default CHIP Device Controller (NodeId: 112233): has been initialized to manage caList[0].adminList[0] (FabricId = 1), and is available as devCtrl + +In [1]: ``` -The prompt `chip-device-ctrl >` indicates that the Matter core library is loaded -by Python, you can browse the symbols in the Matter core library, setting -breakpoints on functions and many other functions provided by GDB. +The prompt `In [1]:` indicates that the Matter SDK library has been loaded and +initialized by the Python Controller REPL, you can browse the symbols in the +Matter core library, setting breakpoints on functions and many other functions +provided by GDB. -You can use `Ctrl-C` to send SIGINT to the controller anytime you want so you -can set breakpoints. +You can use `Ctrl-Z` to send `SIGTSTP` to the Python 3 REPL process anytime you +want so you can set breakpoints (unfortunately Ctrl+C seems to be captured by +the REPL). -> (`Ctrl-C` pressed here.) +In [1]: (`Ctrl-Z` pressed here.) ``` -Thread 1 "python3" received signal SIGINT, Interrupt. -0x0000fffff7db79ec in __GI___select (nfds=, readfds=0xffffffffe760, writefds=0x0, exceptfds=0x0, timeout=) at ../sysdeps/unix/sysv/linux/select.c:49 -49 ../sysdeps/unix/sysv/linux/select.c: No such file or directory. +Thread 1 "python3" received signal SIGTSTP, Stopped (user). +0x00007ffff7650ceb in kill () from /usr/lib/libc.so.6 (gdb) ``` @@ -159,40 +196,27 @@ command in GDB (`b` for short) ``` (gdb) b DeviceCommissioner::PairDevice -Breakpoint 1 at 0xfffff5b0f6b4 (2 locations) +Breakpoint 1 at 0x7fffed453943: DeviceCommissioner::PairDevice. (4 locations) (gdb) ``` -Type `continue` (`c` for short) to continue the device controller, you may need -another hit of `Enter` to see the prompt. +Type `signal SIGCONT` to continue the device controller after stopping it with +signal stop, you may need another hit of `Enter` to see the prompt. ``` -(gdb) c -Continuing. - -chip-device-ctrl > +(gdb) signal SIGCONT +Continuing with signal SIGCONT. +In [1]: ``` Let do pairing over IP to see the effect of the breakpoint we just set. ``` -chip-device-ctrl > connect -ip 192.168.50.5 20202021 1 -Device is assigned with nodeid = 1 - -Thread 1 "python3" hit Breakpoint 1, 0x0000fffff5b0f6b4 in chip::Controller::DeviceCommissioner::PairDevice(unsigned long, chip::RendezvousParameters&)@plt () - from /home/ubuntu/.local/lib/python3.9/site-packages/chip/_ChipDeviceCtrl.so -(gdb) -``` - -The `@plt` symbol means it is a symbol used by dynamic library loader, type `c` -(for `continue`) and it will break on the real function. +In [1]: devCtrl.CommissionWithCode("MT:-24J0AFN00KA0648G00", 1234) -``` -(gdb) c -Continuing. - -Thread 1 "python3" hit Breakpoint 1, chip::Controller::DeviceCommissioner::PairDevice (this=0xd28540, remoteDeviceId=1, params=...) at ../../src/controller/CHIPDeviceController.cpp:827 -827 { +Thread 5 "python3" hit Breakpoint 1.1, chip::Controller::DeviceCommissioner::PairDevice (this=0x7fffd8003a90, remoteDeviceId=1234, setUpCode=0x7ffff453d490 "MT:-24J0AFN00KA0648G00", params=..., + discoveryType=chip::Controller::DiscoveryType::kAll, resolutionData=...) at ../../src/controller/CHIPDeviceController.cpp:646 +646 { (gdb) ``` @@ -201,46 +225,44 @@ then you can use `bt` (for `backtrace`) to see the backtrace of the call stack. ``` (gdb) bt -#0 chip::Controller::DeviceCommissioner::PairDevice(unsigned long, chip::RendezvousParameters&) (this=0xd28540, remoteDeviceId=1, params=...) - at ../../src/controller/CHIPDeviceController.cpp:827 -#1 0x0000fffff5b3095c in pychip_DeviceController_ConnectIP(chip::Controller::DeviceCommissioner*, char const*, uint32_t, chip::NodeId) - (devCtrl=0xd28540, peerAddrStr=0xfffff467ace0 "192.168.50.5", setupPINCode=20202021, nodeid=1) at ../../src/controller/python/ChipDeviceController-ScriptBinding.cpp:234 -#2 0x0000fffff7639148 in () at /lib/aarch64-linux-gnu/libffi.so.8 -#3 0x0000fffff7638750 in () at /lib/aarch64-linux-gnu/libffi.so.8 -#4 0x0000fffff7665a44 in () at /usr/lib/python3.9/lib-dynload/_ctypes.cpython-39-aarch64-linux-gnu.so -#5 0x0000fffff7664c7c in () at /usr/lib/python3.9/lib-dynload/_ctypes.cpython-39-aarch64-linux-gnu.so -#6 0x00000000004a54f0 in _PyObject_MakeTpCall () -#7 0x000000000049cb10 in _PyEval_EvalFrameDefault () -#8 0x0000000000496d1c in () -#9 0x00000000004b1eb0 in _PyFunction_Vectorcall () -#10 0x0000000000498264 in _PyEval_EvalFrameDefault () -#11 0x00000000004b1cb8 in _PyFunction_Vectorcall () -#12 0x0000000000498418 in _PyEval_EvalFrameDefault () -#13 0x0000000000496d1c in () -#14 0x00000000004b1eb0 in _PyFunction_Vectorcall () -#15 0x0000000000498418 in _PyEval_EvalFrameDefault () -#16 0x00000000004b1cb8 in _PyFunction_Vectorcall () -#17 0x00000000004c6bc8 in () -#18 0x0000000000498264 in _PyEval_EvalFrameDefault () -#19 0x00000000004b1cb8 in _PyFunction_Vectorcall () -#20 0x0000000000498418 in _PyEval_EvalFrameDefault () -#21 0x00000000004966f8 in () -#22 0x00000000004b1f18 in _PyFunction_Vectorcall () -#23 0x0000000000498418 in _PyEval_EvalFrameDefault () -#24 0x00000000004b1cb8 in _PyFunction_Vectorcall () -#25 0x0000000000498264 in _PyEval_EvalFrameDefault () -#26 0x00000000004966f8 in () -#27 0x0000000000496490 in _PyEval_EvalCodeWithName () -#28 0x0000000000595b7c in PyEval_EvalCode () -#29 0x00000000005c6a5c in () -#30 0x00000000005c0a70 in () -#31 0x00000000005c69a8 in () -#32 0x00000000005c6148 in PyRun_SimpleFileExFlags () -#33 0x00000000005b60bc in Py_RunMain () -#34 0x0000000000585a08 in Py_BytesMain () -#35 0x0000fffff7d0c9d4 in __libc_start_main (main= - 0x5858fc <_start+60>, argc=2, argv=0xfffffffff498, init=, fini=, rtld_fini=, stack_end=) at ../csu/libc-start.c:332 -#36 0x00000000005858f8 in _start () +(gdb) bt +#0 chip::Controller::DeviceCommissioner::PairDevice + (this=0x7fffd8003a90, remoteDeviceId=1234, setUpCode=0x7fffef2555d0 "MT:-24J0AFN00KA0648G00", params=..., discoveryType=chip::Controller::DiscoveryType::kAll, resolutionData=...) + at ../../src/controller/CHIPDeviceController.cpp:646 +#1 0x00007fffed040825 in pychip_DeviceController_ConnectWithCode (devCtrl=0x7fffd8003a90, onboardingPayload=0x7fffef2555d0 "MT:-24J0AFN00KA0648G00", nodeid=1234, discoveryType=2 '\002') + at ../../src/controller/python/ChipDeviceController-ScriptBinding.cpp:395 +#2 0x00007ffff6ad5596 in ??? () at /usr/lib/libffi.so.8 +#3 0x00007ffff6ad200e in ??? () at /usr/lib/libffi.so.8 +#4 0x00007ffff6ad4bd3 in ffi_call () at /usr/lib/libffi.so.8 +#5 0x00007ffff6aeaffc in ??? () at /usr/lib/python3.11/lib-dynload/_ctypes.cpython-311-x86_64-linux-gnu.so +#6 0x00007ffff6aeb4b4 in ??? () at /usr/lib/python3.11/lib-dynload/_ctypes.cpython-311-x86_64-linux-gnu.so +#7 0x00007ffff794a618 in _PyObject_MakeTpCall () at /usr/lib/libpython3.11.so.1.0 +#8 0x00007ffff78f3d03 in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.11.so.1.0 +#9 0x00007ffff7adef90 in ??? () at /usr/lib/libpython3.11.so.1.0 +#10 0x00007ffff79ebc0b in _PyObject_FastCallDictTstate () at /usr/lib/libpython3.11.so.1.0 +#11 0x00007ffff79ebe02 in _PyObject_Call_Prepend () at /usr/lib/libpython3.11.so.1.0 +#12 0x00007ffff79ec114 in ??? () at /usr/lib/libpython3.11.so.1.0 +#13 0x00007ffff794a618 in _PyObject_MakeTpCall () at /usr/lib/libpython3.11.so.1.0 +#14 0x00007ffff78f3d03 in _PyEval_EvalFrameDefault () at /usr/lib/libpython3.11.so.1.0 +#15 0x00007ffff7adef90 in ??? () at /usr/lib/libpython3.11.so.1.0 +#16 0x00007ffff7955b97 in PyObject_Vectorcall () at /usr/lib/libpython3.11.so.1.0 +#17 0x00007ffff6aea174 in ??? () at /usr/lib/python3.11/lib-dynload/_ctypes.cpython-311-x86_64-linux-gnu.so +#18 0x00007ffff6aea28c in ??? () at /usr/lib/python3.11/lib-dynload/_ctypes.cpython-311-x86_64-linux-gnu.so +#19 0x00007ffff6ad5152 in ??? () at /usr/lib/libffi.so.8 +#20 0x00007ffff6ad57b8 in ??? () at /usr/lib/libffi.so.8 +#21 0x00007fffed5de848 in chip::DeviceLayer::Internal::GenericPlatformManagerImpl::_DispatchEvent + (this=0x7fffed88dc90 , event=0x7fffe6fffe30) at ../../src/include/platform/internal/GenericPlatformManagerImpl.ipp:304 +#22 0x00007fffed5dd90d in chip::DeviceLayer::PlatformManager::DispatchEvent (this=0x7fffed88dc80 , event=0x7fffe6fffe30) at ../../src/include/platform/PlatformManager.h:503 +#23 0x00007fffed5df45b in chip::DeviceLayer::Internal::GenericPlatformManagerImpl_POSIX::ProcessDeviceEvents + (this=0x7fffed88dc90 ) at ../../src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp:185 +#24 0x00007fffed5dee64 in chip::DeviceLayer::Internal::GenericPlatformManagerImpl_POSIX::_RunEventLoop (this=0x7fffed88dc90 ) +--Type for more, q to quit, c to continue without paging-- + at ../../src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp:227 +#25 0x00007fffed5dd888 in chip::DeviceLayer::PlatformManager::RunEventLoop (this=0x7fffed88dc80 ) at ../../src/include/platform/PlatformManager.h:403 +#26 0x00007fffed5df3fe in chip::DeviceLayer::Internal::GenericPlatformManagerImpl_POSIX::EventLoopTaskMain (arg=0x7fffed88dc90 ) + at ../../src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp:256 +#27 0x00007ffff76a6ded in ??? () at /usr/lib/libc.so.6 +#28 0x00007ffff772a0dc in ??? () at /usr/lib/libc.so.6 (gdb) ``` diff --git a/docs/guides/python_chip_controller_building.md b/docs/guides/python_chip_controller_building.md index c940f2c92575e7..8a7acc884ab2fa 100644 --- a/docs/guides/python_chip_controller_building.md +++ b/docs/guides/python_chip_controller_building.md @@ -1,25 +1,20 @@ -# Deprecation notice - -chip-device-ctrl is no longer maintained and should not be used. - -Matter-repl is the current python controller implementation. - # Working with Python CHIP Controller -The Python CHIP Controller is a tool that allows to commission a Matter device -into the network and to communicate with it using the Zigbee Cluster Library -(ZCL) messages. +The Python CHIP controller is a library that allows to create a Matter fabric +and commission Matter devices with it. -> The chip-device-ctrl tool will be deprecated, and will be replaced by -> chip-repl. Continue reading to see how to do the same thing with chip-repl. +The `chip-repl` is a REPl which sets up a Python CHIP Controller and allows to +explore the Python CHIP Controller API and communicate with devices from the +command line.
    - [Source files](#source-files) -- [Building Android CHIPTool](#building-and-installing) -- [Running the tool](#running-the-tool) -- [Using Python CHIP Controller for Matter accessory testing](#using-python-chip-controller-for-matter-accessory-testing) -- [List of commands](#list-of-commands) +- [Building Python CHIP Controller](#building-and-installing) +- [Running the CHIP REPL](#running-the-chip-repl) +- [Using Python CHIP Controller REPL for Matter accessory testing](#using-python-chip-controller-repl-for-matter-accessory-testing) +- [Example usage of the Python CHIP Controller REPL](#example-usage-of-the-python-chip-controller-repl) +- [Explore Clusters, Attributes and Commands](#explore-clusters-attributes-and-commands)
    @@ -85,35 +80,31 @@ To build and run the Python CHIP controller: scripts/build_python.sh -m platform -i separate ``` - > Note: To get more details about available build configurations, run the + > Note: This builds the Python CHIP Controller along with the CHIP REPL as + > Python wheels and installs it into a separate Python virtual environment. + > To get more details about available build configurations, run the > following command: `scripts/build_python.sh --help`
    -## Running the tool +## Running the CHIP REPL -1. Activate the Python virtual environment: +1. Activate the Python virtual environment with the Python CHIP Controller + installed: ``` source out/python_env/bin/activate ``` -2. Run the Python CHIP controller with root privileges, which is required to - obtain access to the Bluetooth interface: - - ``` - sudo out/python_env/bin/chip-device-ctrl - ``` - - You can also select the Bluetooth LE interface using command line argument: +2. Run the CHIP REPL to explore the API of the Python CHIP controller: ``` - sudo out/python_env/bin/chip-device-ctrl --bluetooth-adapter=hci2 + chip-repl ```
    -## Using Python CHIP Controller for Matter accessory testing +## Using Python CHIP Controller REPL for Matter accessory testing This section describes how to use Python CHIP controller to test the Matter accessory. Below steps depend on the application clusters that you implemented @@ -135,13 +126,14 @@ require physical trigger, for example pushing a button. Follow the documentation of the Matter accessory example to learn how Bluetooth LE advertising is enabled for the given example. -### Step 3: Discover Matter accessory device over Bluetooth LE +### Step 3: Discover commissionable Matter accessory device -An uncommissioned accessory device advertises over Bluetooth LE. Run the -following command to scan all advertised Matter devices: +An uncommissioned accessory device advertises over Bluetooth LE or via mDNS if +already on the network. Run the following command to scan all advertised Matter +devices: ``` -chip-device-ctrl > ble-scan +devCtrl.DiscoverCommissionableNodes() ``` ### Step 4: Set network pairing credentials @@ -177,11 +169,12 @@ network interface, such as Thread or Wi-Fi. datasets directly from the Thread Border Router, you might also use a different out-of-band method. -2. Set the previously obtained Active Operational Dataset as a hex-encoded value - using the following command: +2. Set the previously obtained Active Operational Dataset as a byte array using + the following command: ``` - chip-device-ctrl > set-pairing-thread-credential 0e080000000000010000000300001335060004001fffe002084fe76e9a8b5edaf50708fde46f999f0698e20510d47f5027a414ffeebaefa92285cc84fa030f4f70656e5468726561642d653439630102e49c0410b92f8c7fbb4f9f3e08492ee3915fbd2f0c0402a0fff8 + thread_dataset = bytes.fromhex("0e080000000000010000000300001335060004001fffe002084fe76e9a8b5edaf50708fde46f999f0698e20510d47f5027a414ffeebaefa92285cc84fa030f4f70656e5468726561642d653439630102e49c0410b92f8c7fbb4f9f3e08492ee3915fbd2f0c0402a0fff8") + devCtrl.SetThreadOperationalDataset(thread_dataset) ``` #### Setting Wi-Fi network credentials @@ -190,11 +183,9 @@ Assuming your Wi-Fi SSID is _TESTSSID_, and your Wi-Fi password is _P455W4RD_, set the credentials to the controller by executing the following command: ``` -chip-device-ctrl > set-pairing-wifi-credential TESTSSID P455W4RD +devCtrl.SetWiFiCredentials(, ) ``` -**REPL Command**: `devCtrl.SetWiFiCredentials(, )` - ### Step 5: Commission the Matter accessory device over Bluetooth LE The controller uses a 12-bit value called **discriminator** to discern between @@ -222,16 +213,26 @@ with the following assumptions for the Matter accessory device: - The temporary Node ID is _1234_ ``` -chip-device-ctrl > connect -ble 3840 20202021 1234 +devCtrl.ConnectBLE(3840, 20202021, 1234) ``` -**REPL Command:** -`devCtrl.ConnectBLE(, , )` - You can skip the last parameter, the Node ID, in the command. If you skip it, the controller will assign it randomly. In that case, note down the Node ID, because it is required later in the configuration process. +It is also possible to use the QR setup code instead. It typically is shown on +the terminal of the device as well. For example: + +``` +CHIP:SVR: SetupQRCode: [MT:-24J0AFN00KA0648G00] +``` + +Use the following command to commission the device with the QR code: + +``` +devCtrl.CommissionWithCode("MT:-24J0AFN00KA0648G00", 1234) +``` + After connecting the device over Bluetooth LE, the controller will go through the following stages: @@ -255,429 +256,155 @@ the following stages: finished and the Python CHIP controller is now using only the IPv6 traffic to reach the device. -### Step 6: Control application ZCL clusters. +### Step 6: Control application clusters. For the light bulb example, execute the following command to toggle the LED state: ``` -chip-device-ctrl > zcl OnOff Toggle 1234 1 0 +await devCtrl.SendCommand(1234, 1, Clusters.OnOff.Commands.Toggle()) ``` -**REPL Command:** -`await devCtrl.SendCommand(1234, 1, Clusters.OnOff.Commands.Toggle())` - To change the brightness of the LED, use the following command, with the level value somewhere between 0 and 255. ``` -chip-device-ctrl > zcl LevelControl MoveToLevel 1234 1 0 level=50 +commandToSend = LevelControl.Commands.MoveToLevel(level=50, transitionTime=Null, optionsMask=0, optionsOverride=0) +await devCtrl.SendCommand(1234, 1, commandToSend) ``` -**REPL Command:** -`await devCtrl.SendCommand(1234, 1, LevelControl.Commands.MoveToLevel(level=50, transitionTime=Null, optionsMask=0, optionsOverride=0))` - ### Step 7: Read basic information out of the accessory. Every Matter accessory device supports a Basic Information Cluster, which maintains collection of attributes that a controller can obtain from a device, -such as the vendor name, the product name, or software version. Use `zclread` -command to read those values from the device: +such as the vendor name, the product name, or software version. Use +`ReadAttribute()` command to read those values from the device: ``` -chip-device-ctrl > zclread BasicInformation VendorName 1234 1 0 -chip-device-ctrl > zclread BasicInformation ProductName 1234 1 0 -chip-device-ctrl > zclread BasicInformation SoftwareVersion 1234 1 0 +attributes = [ + (0, Clusters.BasicInformation.Attributes.VendorName), + (0, Clusters.BasicInformation.Attributes.ProductName), + (0, Clusters.BasicInformation.Attributes.SoftwareVersion), +] +await devCtrl.ReadAttribute(1234, attributes) ``` -**REPL Command:** -`await devCtrl.ReadAttribute(1234, [(1, Clusters.BasicInformation.Attributes.VendorName)])` - -> Use the `zcl ? BasicInformation` command to list all available commands for -> Basic Information Cluster. -> > In REPL, you can type `Clusters.BasicInformation.Attributes.` and then use the > TAB key.
    -## List of commands - -### `ble-adapter-print` +## Example usage of the Python CHIP Controller REPL -> BLE adapter operations is not yet supported in REPL +These section covers a few useful commands of the Python CHIP Controller along +with examples demonstrating how they can be called from the REPL. -Print the available Bluetooth adapters on device. Takes no arguments: - -``` -chip-device-ctrl > ble-adapter-print -2021-03-04 16:09:40,930 ChipBLEMgr INFO AdapterName: hci0 AdapterAddress: 00:AA:01:00:00:23 -``` +The +[CHIP Device Controller API documentation offer](https://project-chip.github.io/connectedhomeip-doc/testing/ChipDeviceCtrlAPI.html#chip-chipdevicectrl) +the full list of available commands. -### `ble-debug-log` - -> BLE adapter operations is not yet supported in REPL - -Enable the Bluetooth LE debug logs. - -``` -chip-device-ctrl > ble-debug-log 1 -``` - -### `ble-scan [-t ] [identifier]` - -> BLE adapter operations is not yet supported in REPL - -Start a scan action to search for valid CHIP devices over Bluetooth LE (for at -most _timeout_ seconds). Stop when the device is matching the identifier or the -counter times out. - -``` -chip-device-ctrl > ble-scan -2021-05-29 22:28:05,461 ChipBLEMgr INFO scanning started -2021-05-29 22:28:07,206 ChipBLEMgr INFO Name = ChipLight -2021-05-29 22:28:07,206 ChipBLEMgr INFO ID = f016e23d-0d00-35d5-93e7-588acdbc7e54 -2021-05-29 22:28:07,207 ChipBLEMgr INFO RSSI = -79 -2021-05-29 22:28:07,207 ChipBLEMgr INFO Address = E0:4D:84:3C:BB:C3 -2021-05-29 22:28:07,209 ChipBLEMgr INFO Pairing State = 0 -2021-05-29 22:28:07,209 ChipBLEMgr INFO Discriminator = 3840 -2021-05-29 22:28:07,209 ChipBLEMgr INFO Vendor Id = 9050 -2021-05-29 22:28:07,209 ChipBLEMgr INFO Product Id = 20044 -2021-05-29 22:28:07,210 ChipBLEMgr INFO Adv UUID = 0000fff6-0000-1000-8000-00805f9b34fb -2021-05-29 22:28:07,210 ChipBLEMgr INFO Adv Data = 00000f5a234c4e -2021-05-29 22:28:07,210 ChipBLEMgr INFO -2021-05-29 22:28:16,246 ChipBLEMgr INFO scanning stopped -``` - -### `set-pairing-thread-credential ` +### `SetThreadOperationalDataset()` Provides the controller with Thread network credentials that will be used in the device commissioning procedure to configure the device with a Thread interface. ``` -chip-device-ctrl > set-pairing-thread-credential 0e080000000000010000000300001335060004001fffe002084fe76e9a8b5edaf50708fde46f999f0698e20510d47f5027a414ffeebaefa92285cc84fa030f4f70656e5468726561642d653439630102e49c0410b92f8c7fbb4f9f3e08492ee3915fbd2f0c0402a0fff8 +thread_dataset = bytes.fromhex("0e080000000000010000000300001335060004001fffe002084fe76e9a8b5edaf50708fde46f999f0698e20510d47f5027a414ffeebaefa92285cc84fa030f4f70656e5468726561642d653439630102e49c0410b92f8c7fbb4f9f3e08492ee3915fbd2f0c0402a0fff8") +devCtrl.SetThreadOperationalDataset(thread_dataset) ``` -**REPL Commands:** -`devCtrl.SetThreadOperationalDataset(bytes.FromHex("0e080000000000010000000300001335060004001fffe002084fe76e9a8b5edaf50708fde46f999f0698e20510d47f5027a414ffeebaefa92285cc84fa030f4f70656e5468726561642d653439630102e49c0410b92f8c7fbb4f9f3e08492ee3915fbd2f0c0402a0fff8"))` - -### `set-pairing-wifi-credential ` +### `SetWiFiCredentials(: str, : str)` Provides the controller with Wi-Fi network credentials that will be used in the device commissioning procedure to configure the device with a Wi-Fi interface. ``` -chip-device-ctrl > set-pairing-wifi-credential TESTSSID P455W4RD +devCtrl.SetWiFiCredentials('TESTSSID', 'P455W4RD') ``` -**REPL Commands:** `devCtrl.SetWiFiCredentials('TESTSSID', 'P455W4RD')` - -### `connect -ip
    []` - -Do key exchange and establish a secure session between controller and device -using IP transport. - -The Node ID will be used by controller to distinguish multiple devices. This -does not match the spec and will be removed later. The nodeid will not be -persisted by controller / device. - -If no nodeid given, a random Node ID will be used. - -**REPL Commands:** -`devCtrl.CommissionIP(b'', , )` - -### `connect -ble []` - -Do key exchange and establish a secure session between controller and device -using Bluetooth LE transport. - -The Node ID will be used by controller to distinguish multiple devices. This -does not match the spec and will be removed later. The nodeid will not be -persisted by controller / device. - -If no nodeid given, a random Node ID will be used. - -**REPL Commands:** -`devCtrl.ConnectBLE(, , )` +### `CommissionWithCode(: str, : int, : DiscoveryType)` -### `close-session ` +Commission with the given nodeid from the setupPayload. setupPayload may be a QR +or the manual setup code. -If case there exists an open session (PASE or CASE) to the device with a given -Node ID, mark it as expired. - -**REPL Commands:** `devCtrl.CloseSession()` - -### `discover` - -> To be implemented in REPL - -Discover available Matter accessory devices: - -``` -chip-device-ctrl > discover -all ``` - -### `resolve ` - -> To be implemented in REPL - -Resolve DNS-SD name corresponding with the given Node ID and update address of -the node in the device controller: - -``` -chip-device-ctrl > resolve 1234 +devCtrl.CommissionWithCode("MT:-24J0AFN00KA0648G00", 1234) ``` -### `setup-payload generate [-v ] [-p ] [-cf ] [-dc ] [-dv ] [-ps ]` - -> To be implemented in REPL +### `SendCommand(: int, : int, Clusters..Commands.())` -Print the generated Onboarding Payload Contents in human-readable (Manual -Pairing Code) and machine-readable (QR Code) format: +Send a Matter command to the device. For example: +```python +commandToSend = Clusters.LevelControl.Commands.MoveWithOnOff(moveMode=1, rate=2, optionsMask=0, optionsOverride=0) +await devCtrl.SendCommand(1234, 1, commandToSend) ``` -chip-device-ctrl > setup-payload generate -v 9050 -p 65279 -cf 0 -dc 2 -dv 2976 -ps 34567890 -Manual pairing code: [26318621095] -SetupQRCode: [MT:YNJV7VSC00CMVH7SR00] -``` - -### `setup-payload parse-manual ` - -> To be implemented in REPL - -Print the commissioning information encoded in the Manual Pairing Code: - -``` -chip-device-ctrl > setup-payload parse-manual 34970112332 -Version: 0 -VendorID: 0 -ProductID: 0 -CommissioningFlow: 0 -RendezvousInformation: 0 -Discriminator: 3840 -SetUpPINCode: 20202021 -``` - -### `setup-payload parse-qr ` -> To be implemented in REPL - -Print the commissioning information encoded in the QR Code payload: +To see available arguments just create a command object without argument: ``` -chip-device-ctrl > setup-payload parse-qr "VP:vendorpayload%MT:W0GU2OTB00KA0648G00" -Version: 0 -VendorID: 9050 -ProductID: 20043 -CommissioningFlow: 0 -RendezvousInformation: 2 [BLE] -Discriminator: 3840 -SetUpPINCode: 20202021 +Clusters.LevelControl.Commands.MoveWithOnOff() ``` -### `zcl [arguments]` - -Send a ZCL command to the device. For example: +Shows which arguments are available: ``` -chip-device-ctrl > zcl LevelControl MoveWithOnOff 12344321 1 0 moveMode=1 rate=2 +MoveWithOnOff( +│ moveMode=0, +│ rate=Null, +│ optionsMask=0, +│ optionsOverride=0 +) ``` -**Format of arguments** +### `ReadAttribute(: int, [(: int, Clusters..Attributes.)])` -For any integer and char string (null terminated) types, just use `key=value`, -for example: `rate=2`, `string=123`, `string_2="123 456"` - -For byte string type, use `key=encoding:value`, currently, we support `str` and -`hex` encoding, the `str` encoding will encode a NULL terminated string. For -example, `networkId=hex:0123456789abcdef` (for -`[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]`), `ssid=str:Test` (for -`['T', 'e', 's', 't', 0x00]`). - -For boolean type, use `key=True` or `key=False`. - -**REPL Commands:** +Read the value of an attribute. For example: ```python -# await devCtrl.SendCommand(, , Clusters..Commands.()) -# e.g. -await devCtrl.SendCommand(12344321, 1, Clusters.LevelControl.Commands.MoveWithOnOff(moveMode=1, rate=2, optionsMask=0, optionsOverride=0)) -``` - -### `zcl ?` - -List available clusters: - -``` -chip-device-ctrl > zcl ? -AccountLogin -ApplicationBasic -ApplicationLauncher -AudioOutput -BarrierControl -BasicInformation -Binding -BridgedDeviceBasicInformation -ColorControl -ContentLaunch -Descriptor -DoorLock -EthernetNetworkDiagnostics -FixedLabel -GeneralCommissioning -GeneralDiagnostics -GroupKeyManagement -Groups -Identify -KeypadInput -LevelControl -LowPower -MediaInput -MediaPlayback -NetworkCommissioning -OnOff -OperationalCredentials -PumpConfigurationAndControl -RelativeHumidityMeasurement -ScenesManagement -SoftwareDiagnostics -Switch -Channel -TargetNavigator -TemperatureMeasurement -TestCluster -Thermostat -TrustedRootCertificates -WakeOnLan -WindowCovering -``` - -**REPL Commands** - -Type `Clusters.` and hit TAB - -### `zcl ? ` - -List available commands in cluster. For example, for _Basic Information_ -cluster: - -``` -chip-device-ctrl > zcl ? BasicInformation -DataModelRevision -VendorName -VendorID -ProductName -ProductID -UserLabel -Location -HardwareVersion -HardwareVersionString -SoftwareVersion -SoftwareVersionString -ManufacturingDate -PartNumber -ProductURL -ProductLabel -SerialNumber -LocalConfigDisabled -ClusterRevision -``` - -**REPL Commands** - -Type `Clusters.(cluster name).Commands.` and hit TAB - -### `zclread [arguments]` - -Read the value of ZCL attribute. For example: - -``` -chip-device-ctrl > zclread BasicInformation VendorName 1234 1 0 -``` - -**REPL Commands** - -```python -# devCtrl.ReadAttribute(, [(, Clusters..Attributes.)]) -# e.g. -await devCtrl.ReadAttribute(1234, [(1, Clusters.BasicInformation.Attributes.VendorName)]) -``` - -### `zclwrite ` - -Write the value to a ZCL attribute. For example: - -``` -chip-device-ctrl > zclwrite TestCluster Int8u 1 1 0 1 -chip-device-ctrl > zclwrite TestCluster Boolean 1 1 0 True -chip-device-ctrl > zclwrite TestCluster OctetString 1 1 0 str:123123 -chip-device-ctrl > zclwrite TestCluster CharString 1 1 0 233233 +await devCtrl.ReadAttribute(1234, [(0, Clusters.BasicInformation.Attributes.VendorName)]) ``` -Note: The format of the value is the same as the format of argument values for -ZCL cluster commands. +### `WriteAttribute(: int, [(: int, Clusters..Attributes.(value=))])` -**REPL Commands** +Write a value to an attribute. For example: ```python -# devCtrl.WriteAttribute(, [(, Clusters..Attributes.(value=))]) -# e.g. -await devCtrl.WriteAttribute(1, [(1, Clusters.UnitTesting.Attributes.Int8u(value=1))]) -await devCtrl.WriteAttribute(1, [(1, Clusters.UnitTesting.Attributes.Boolean(value=True))]) -await devCtrl.WriteAttribute(1, [(1, Clusters.UnitTesting.Attributes.OctetString(value=b'123123\x00'))]) -await devCtrl.WriteAttribute(1, [(1, Clusters.UnitTesting.Attributes.CharString(value='233233'))]) +await devCtrl.WriteAttribute(1234, [(1, Clusters.UnitTesting.Attributes.Int8u(value=1))]) +await devCtrl.WriteAttribute(1234, [(1, Clusters.UnitTesting.Attributes.Boolean(value=True))]) +await devCtrl.WriteAttribute(1234, [(1, Clusters.UnitTesting.Attributes.OctetString(value=b'123123\x00'))]) +await devCtrl.WriteAttribute(1234, [(1, Clusters.UnitTesting.Attributes.CharString(value='233233'))]) ``` -### `zclsubscribe ` +### `ReadAttribute(: int, [(: int, Clusters..Attributes.)], reportInterval=(: int, : int))` -Configure ZCL attribute reporting settings. For example: - -``` -chip-device-ctrl > zclsubscribe OccupancySensing Occupancy 1234 1 10 20 -``` - -**REPL Commands** +Configure Matter attribute reporting settings. For example: ```python -# devCtrl.ReadAttribute(, [(, Clusters..Attributes.)], reportInterval=(, )) -# e.g. -await devCtrl.ReadAttribute(1, [(1, Clusters.OccupancySensing.Attributes.Occupancy)], reportInterval=(10, 20)) +await devCtrl.ReadAttribute(1234, [(1, Clusters.OccupancySensing.Attributes.Occupancy)], reportInterval=(10, 20)) ``` -### `zclsubscribe -shutdown ` - -Shutdown an existing attribute subscription. +To shutdown an existing attribute subscription use the `Shutdown()` function on +the returned subscription object: -``` -chip-device-ctrl > zclsubscribe -shutdown 0xdeadbeefcafe +```python +sub = await devCtrl.ReadAttribute(1234, [(1, Clusters.OccupancySensing.Attributes.Occupancy)], reportInterval=(10, 20)) +sub.Shutdown() ``` -The subscription id can be obtained from previous subscription messages: +## Explore Clusters, Attributes and Commands -``` -chip-device-ctrl > zclsubscribe OnOff OnOff 1 1 10 20 -(omitted messages) -[1633922898.965587][1117858:1117866] CHIP:DMG: SubscribeResponse = -[1633922898.965599][1117858:1117866] CHIP:DMG: { -[1633922898.965610][1117858:1117866] CHIP:DMG: SubscriptionId = 0xdeadbeefcafe, -[1633922898.965622][1117858:1117866] CHIP:DMG: MinIntervalFloorSeconds = 0xa, -[1633922898.965633][1117858:1117866] CHIP:DMG: MaxIntervalCeilingSeconds = 0x14, -[1633922898.965644][1117858:1117866] CHIP:DMG: } -[1633922898.965662][1117858:1117866] CHIP:ZCL: SubscribeResponse: -[1633922898.965673][1117858:1117866] CHIP:ZCL: SubscriptionId: 0xdeadbeefcafe -[1633922898.965683][1117858:1117866] CHIP:ZCL: ApplicationIdentifier: 0 -[1633922898.965694][1117858:1117866] CHIP:ZCL: status: EMBER_ZCL_STATUS_SUCCESS (0x00) -[1633922898.965709][1117858:1117866] CHIP:ZCL: attributeValue: false -(omitted messages) -``` +In the Python REPL the Clusters and Attributes are classes. The `Clusters` +module contains all clusters. Tab completion can be used to explore available +clusters, attributes and commands. -The subscription id is `0xdeadbeefcafe` in this case +For example, to get a list of Clusters, type `Clusters.` and hit tab. Continue +to hit tab to cycle through the available Clusters. Pressing return will select +the Cluster. -**REPL Commands** +To explore Attributes, use the same technique but with the Attributes sub-class +of the Clusters class, for example, type `Clusters.(cluster name).Attributes.` +and hit tab. -```python -# SubscriptionTransaction.Shutdown() -# e.g. -sub = await devCtrl.ReadAttribute(1, [(1, Clusters.OccupancySensing.Attributes.Occupancy)], reportInterval=(10, 20)) -sub.Shutdown() -``` +The same is true for Commands, use the Commands sub-class. type +`Clusters.(cluster name).Commands.` and hit tab. diff --git a/docs/testing/yaml.md b/docs/testing/yaml.md index 107c761fbef71e..e7353d09697e30 100644 --- a/docs/testing/yaml.md +++ b/docs/testing/yaml.md @@ -279,6 +279,17 @@ function can be use. See [TestEqualities](https://github.com/project-chip/connectedhomeip/blob/master/src/app/tests/suites/TestEqualities.yaml) for an example of how to use this pseudo-cluster. +#### Setting step timeouts + +The timeout argument can be used for each individual test step to set the time +the runner will wait for a test step to complete before reporting a failure. + +Note that this timeout is different than the subscription report timeout and the +subscription report timeout is not currently adjustable in YAML. + +There several other options for configuring test steps as shown in the +[YAML schema](./yaml_schema.md) document. + ## Running YAML tests YAML scripts are parsed and run using a python-based runner program that parses @@ -304,6 +315,24 @@ There are several options for running tests locally. Because the YAML runner uses python, it is necessary to compile and install the chip python package before using any YAML runner script. +First activate the matter environment using either + +``` +. ./scripts/bootstrap.sh +``` + +or + +``` +. ./scripts/activate.sh +``` + +bootstrap.sh should be used for for the first setup, activate.sh may be used for +subsequent setups as it is faster. + +Next build the python wheels and create a venv (called `py` here, but any name +may be used) + ``` ./scripts/build_python.sh -i py source py/bin/activate diff --git a/docs/zap_clusters.md b/docs/zap_clusters.md index eedfb7190e2f27..a11a552bf023a6 100644 --- a/docs/zap_clusters.md +++ b/docs/zap_clusters.md @@ -112,6 +112,7 @@ Generally regenerate using one of: | 1069 | 0x42D | Pm10ConcentrationMeasurement | | 1070 | 0x42E | TotalVolatileOrganicCompoundsConcentrationMeasurement | | 1071 | 0x42F | RadonConcentrationMeasurement | +| 1105 | 0x451 | WiFiNetworkManagement | | 1283 | 0x503 | WakeOnLan | | 1284 | 0x504 | Channel | | 1285 | 0x505 | TargetNavigator | diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 59e79389113b79..804d1eae5fbd32 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -2609,7 +2609,7 @@ cluster BooleanState = 69 { } /** This cluster supports remotely monitoring and, where supported, changing the operational state of an Oven. */ -provisional cluster OvenCavityOperationalState = 72 { +cluster OvenCavityOperationalState = 72 { revision 1; enum ErrorStateEnum : enum8 { @@ -2675,7 +2675,7 @@ provisional cluster OvenCavityOperationalState = 72 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster OvenMode = 73 { +cluster OvenMode = 73 { revision 1; enum ModeTag : enum16 { @@ -3334,7 +3334,7 @@ cluster DishwasherAlarm = 93 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster MicrowaveOvenMode = 94 { +cluster MicrowaveOvenMode = 94 { revision 1; enum ModeTag : enum16 { @@ -3876,7 +3876,7 @@ cluster ValveConfigurationAndControl = 129 { } /** This cluster provides a mechanism for querying data about electrical power as measured by the server. */ -provisional cluster ElectricalPowerMeasurement = 144 { +cluster ElectricalPowerMeasurement = 144 { revision 1; enum MeasurementTypeEnum : enum16 { @@ -3981,7 +3981,7 @@ provisional cluster ElectricalPowerMeasurement = 144 { } /** This cluster provides a mechanism for querying data about the electrical energy imported or provided by the server. */ -provisional cluster ElectricalEnergyMeasurement = 145 { +cluster ElectricalEnergyMeasurement = 145 { revision 1; enum MeasurementTypeEnum : enum16 { @@ -4278,7 +4278,7 @@ provisional cluster DeviceEnergyManagement = 152 { } /** Electric Vehicle Supply Equipment (EVSE) is equipment used to charge an Electric Vehicle (EV) or Plug-In Hybrid Electric Vehicle. This cluster provides an interface to the functionality of Electric Vehicle Supply Equipment (EVSE) management. */ -provisional cluster EnergyEvse = 153 { +cluster EnergyEvse = 153 { revision 2; enum EnergyTransferStoppedReasonEnum : enum8 { @@ -4490,7 +4490,7 @@ provisional cluster EnergyPreference = 155 { } /** The Power Topology Cluster provides a mechanism for expressing how power is flowing between endpoints. */ -provisional cluster PowerTopology = 156 { +cluster PowerTopology = 156 { revision 1; bitmap Feature : bitmap32 { @@ -4511,7 +4511,7 @@ provisional cluster PowerTopology = 156 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster EnergyEvseMode = 157 { +cluster EnergyEvseMode = 157 { revision 1; enum ModeTag : enum16 { diff --git a/examples/android/CHIPTool/app/build.gradle b/examples/android/CHIPTool/app/build.gradle index 368930259ea66a..4502b7f7a18897 100644 --- a/examples/android/CHIPTool/app/build.gradle +++ b/examples/android/CHIPTool/app/build.gradle @@ -43,9 +43,6 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } - packagingOptions { - exclude 'META-INF/main.kotlin_module' - } buildFeatures { viewBinding = true diff --git a/examples/bridge-app/linux/main.cpp b/examples/bridge-app/linux/main.cpp index 3643f5ea1eb02a..a894b5d0150ca6 100644 --- a/examples/bridge-app/linux/main.cpp +++ b/examples/bridge-app/linux/main.cpp @@ -899,13 +899,11 @@ void ApplicationInit() // Setup Mock Devices Light1.SetReachable(true); Light2.SetReachable(true); - Light1.SetChangeCallback(&HandleDeviceOnOffStatusChanged); Light2.SetChangeCallback(&HandleDeviceOnOffStatusChanged); TempSensor1.SetReachable(true); - TempSensor1.SetReachable(true); - + TempSensor2.SetReachable(true); TempSensor1.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); TempSensor2.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); @@ -914,7 +912,6 @@ void ApplicationInit() ActionLight2.SetReachable(true); ActionLight3.SetReachable(true); ActionLight4.SetReachable(true); - ActionLight1.SetChangeCallback(&HandleDeviceOnOffStatusChanged); ActionLight2.SetChangeCallback(&HandleDeviceOnOffStatusChanged); ActionLight3.SetChangeCallback(&HandleDeviceOnOffStatusChanged); @@ -929,7 +926,6 @@ void ApplicationInit() ComposedTempSensor2.SetReachable(true); ComposedPowerSource.SetReachable(true); ComposedPowerSource.SetBatChargeLevel(58); - ComposedTempSensor1.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); ComposedTempSensor2.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); ComposedPowerSource.SetChangeCallback(&HandleDevicePowerSourceStatusChanged); diff --git a/examples/chef/common/chef-descriptor-namespace.h b/examples/chef/common/chef-descriptor-namespace.h new file mode 100644 index 00000000000000..e7e8e85df5a551 --- /dev/null +++ b/examples/chef/common/chef-descriptor-namespace.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// Please refer to https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/namespaces +constexpr const uint8_t kNamespaceCommonLevel = 5; +// Common Number Namespace: 5, tag 0 (Low) +constexpr const uint8_t kTagCommonLow = 0; +// Common Number Namespace: 5, tag 1 (Medium) +constexpr const uint8_t kTagCommonMedium = 1; +// Common Number Namespace: 5, tag 2 (High) +constexpr const uint8_t kTagCommonHigh = 2; + +constexpr const uint8_t kNamespaceCommonNumber = 7; +// Common Number Namespace: 7, tag 0 (Zero) +constexpr const uint8_t kTagCommonZero = 0; +// Common Number Namespace: 7, tag 1 (One) +constexpr const uint8_t kTagCommonOne = 1; +// Common Number Namespace: 7, tag 2 (Two) +constexpr const uint8_t kTagCommonTwo = 2; + +constexpr const uint8_t kNamespacePosition = 8; +// Common Position Namespace: 8, tag: 0 (Left) +constexpr const uint8_t kTagPositionLeft = 0; +// Common Position Namespace: 8, tag: 1 (Right) +constexpr const uint8_t kTagPositionRight = 1; +// Common Position Namespace: 8, tag: 2 (Top) +constexpr const uint8_t kTagPositionTop = 2; +// Common Position Namespace: 8, tag: 3 (Bottom) +constexpr const uint8_t kTagPositionBottom = 3; +// Common Position Namespace: 8, tag: 4 (Middle) +constexpr const uint8_t kTagPositionMiddle = 4; +// Common Position Namespace: 8, tag: 5 (Row) +constexpr const uint8_t kTagPositionRow = 5; +// Common Position Namespace: 8, tag: 6 (Column) +constexpr const uint8_t kTagPositionColumn = 6; diff --git a/examples/chef/common/chef-rpc-actions-worker.cpp b/examples/chef/common/chef-rpc-actions-worker.cpp new file mode 100644 index 00000000000000..98bba768e7f4d8 --- /dev/null +++ b/examples/chef/common/chef-rpc-actions-worker.cpp @@ -0,0 +1,158 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "chef-rpc-actions-worker.h" +#include +#include +#include +#include +#include +#include +#include + +using chip::app::DataModel::Nullable; + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::rpc; + +static std::map gActionsDelegateMap{}; + +ActionsDelegate * RpcFindActionsDelegate(ClusterId clusterId) +{ + if (gActionsDelegateMap.find(clusterId) != gActionsDelegateMap.end()) + { + return gActionsDelegateMap[clusterId]; + } + + return nullptr; +} + +static void RpcActionsTaskCallback(System::Layer * systemLayer, void * data) +{ + ChefRpcActionsWorker * worker = (ChefRpcActionsWorker *) data; + + worker->ProcessActionQueue(); +} + +bool ChefRpcActionsCallback(EndpointId endpointId, ClusterId clusterId, uint8_t type, uint32_t delayMs, uint32_t actionId, + std::vector args) +{ + ActionTask task(endpointId, clusterId, static_cast(type), delayMs, actionId, args); + + return ChefRpcActionsWorker::Instance().EnqueueAction(task); +} + +bool ChefRpcActionsWorker::EnqueueAction(ActionTask task) +{ + bool kickTimer = false; + + if (queue.empty()) + { + kickTimer = true; // kick timer when the first task is adding to the queue + } + + queue.push(task); + + if (kickTimer) + { + (void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(task.delayMs), RpcActionsTaskCallback, this); + } + return true; +} + +void ChefRpcActionsWorker::ProcessActionQueue() +{ + // Dequeue the first item + ActionTask task = queue.front(); + queue.pop(); + + ActionsDelegate * delegate = RpcFindActionsDelegate(task.clusterId); + if (nullptr == delegate) + { + ChipLogError(NotSpecified, + "Cannot run action due to not finding delegate: endpointId=%d, clusterId=%04lx, attributeId=%04lx", + task.endpointId, static_cast(task.clusterId), static_cast(task.actionId)); + return; + } + + ActionType type = static_cast(task.type); + + switch (type) + { + case ActionType::WRITE_ATTRIBUTE: { + ChipLogProgress(NotSpecified, "Writing Attribute: endpointId=%d, clusterId=%04lx, attributeId=%04lx, args.size=%lu", + task.endpointId, static_cast(task.clusterId), static_cast(task.actionId), + static_cast(task.args.size())); + delegate->AttributeWriteHandler(task.endpointId, static_cast(task.actionId), task.args); + } + break; + case ActionType::RUN_COMMAND: { + ChipLogProgress(NotSpecified, "Running Command: endpointId=%d, clusterId=%04lx, commandId=%04lx, args.size=%lu", + task.endpointId, static_cast(task.clusterId), static_cast(task.actionId), + static_cast(task.args.size())); + delegate->CommandHandler(task.endpointId, static_cast(task.actionId), task.args); + } + break; + case ActionType::EMIT_EVENT: { + ChipLogProgress(NotSpecified, "Emitting Event: endpointId=%d, clusterId=%04lx, eventIdId=%04lx, args.size=%lu", + task.endpointId, static_cast(task.clusterId), static_cast(task.actionId), + static_cast(task.args.size())); + delegate->EventHandler(task.endpointId, static_cast(task.actionId), task.args); + } + break; + default: + break; + } + + if (queue.empty()) + { + // Return due to no more actions in queue + return; + } + + // Run next action + task = queue.front(); + ChipLogProgress(NotSpecified, "StartTimer: endpointId=%d, clusterId=%04lx, eventIdId=%04lx, task.delyMs=%lu", task.endpointId, + static_cast(task.clusterId), static_cast(task.actionId), + static_cast(task.delayMs)); + (void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(task.delayMs), RpcActionsTaskCallback, this); +} + +void ChefRpcActionsWorker::RegisterRpcActionsDelegate(ClusterId clusterId, ActionsDelegate * delegate) +{ + // Register by cluster + if (nullptr == RpcFindActionsDelegate(clusterId)) + { + gActionsDelegateMap[clusterId] = delegate; + return; + } +} + +ChefRpcActionsWorker::ChefRpcActionsWorker() +{ + chip::rpc::SubscribeActions(ChefRpcActionsCallback); +} + +static ChefRpcActionsWorker instance; + +ChefRpcActionsWorker & ChefRpcActionsWorker::Instance() +{ + return instance; +} diff --git a/examples/chef/common/chef-rpc-actions-worker.h b/examples/chef/common/chef-rpc-actions-worker.h new file mode 100644 index 00000000000000..3ca16f4c8a716e --- /dev/null +++ b/examples/chef/common/chef-rpc-actions-worker.h @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Rpc.h" + +namespace chip { +namespace app { + +class ActionsDelegate +{ +public: + ActionsDelegate(ClusterId clusterId) : mClusterId(clusterId){}; + + virtual ~ActionsDelegate() = default; + + virtual void AttributeWriteHandler(chip::EndpointId endpointId, chip::AttributeId attributeId, std::vector args) = 0; + virtual void CommandHandler(chip::EndpointId endpointId, chip::CommandId commandId, std::vector args) = 0; + virtual void EventHandler(chip::EndpointId endpointId, chip::EventId eventId, std::vector args) = 0; + +protected: + ClusterId mClusterId; +}; + +struct ActionTask +{ + chip::EndpointId endpointId; + chip::ClusterId clusterId; + chip::rpc::ActionType type; // Aligned with Storage buf + uint32_t delayMs; + uint32_t actionId; + std::vector args; + ActionTask(chip::EndpointId endpoint, chip::ClusterId cluster, chip::rpc::ActionType actionType, uint32_t delay, uint32_t id, + std::vector arg) : + endpointId(endpoint), + clusterId(cluster), type(actionType), delayMs(delay), actionId(id), args(arg){}; + ~ActionTask(){}; +}; + +class ChefRpcActionsWorker +{ +public: + static ChefRpcActionsWorker & Instance(); + + ChefRpcActionsWorker(); + + bool EnqueueAction(ActionTask task); + void ProcessActionQueue(); + void RegisterRpcActionsDelegate(ClusterId clusterId, ActionsDelegate * delegate); + +private: + std::queue queue; +}; + +} // namespace app +} // namespace chip diff --git a/examples/chef/common/clusters/switch/SwitchEventHandler.cpp b/examples/chef/common/clusters/switch/SwitchEventHandler.cpp new file mode 100644 index 00000000000000..dd32e2b907bb5a --- /dev/null +++ b/examples/chef/common/clusters/switch/SwitchEventHandler.cpp @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifdef MATTER_DM_PLUGIN_SWITCH_SERVER +#include +#include +#include +#include + +#include "SwitchEventHandler.h" + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Switch; +using namespace chip::DeviceLayer; + +void SwitchEventHandler::OnSwitchLatched(EndpointId endpointId, uint8_t newPosition) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d", __func__, endpointId, newPosition); + + Clusters::SwitchServer::Instance().OnSwitchLatch(endpointId, newPosition); +} + +void SwitchEventHandler::OnInitialPress(EndpointId endpointId, uint8_t newPosition) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d", __func__, endpointId, newPosition); + + Clusters::SwitchServer::Instance().OnInitialPress(endpointId, newPosition); +} + +void SwitchEventHandler::OnLongPress(EndpointId endpointId, uint8_t newPosition) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d", __func__, endpointId, newPosition); + + Clusters::SwitchServer::Instance().OnLongPress(endpointId, newPosition); +} + +void SwitchEventHandler::OnShortRelease(EndpointId endpointId, uint8_t previousPosition) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, previousPosition=%d", __func__, endpointId, previousPosition); + + Clusters::SwitchServer::Instance().OnShortRelease(endpointId, previousPosition); +} + +void SwitchEventHandler::OnLongRelease(EndpointId endpointId, uint8_t previousPosition) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, previousPosition=%d", __func__, endpointId, previousPosition); + + Clusters::SwitchServer::Instance().OnLongRelease(endpointId, previousPosition); +} + +void SwitchEventHandler::OnMultiPressOngoing(EndpointId endpointId, uint8_t newPosition, uint8_t count) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d, count=%d", __func__, endpointId, newPosition, count); + + Clusters::SwitchServer::Instance().OnMultiPressOngoing(endpointId, newPosition, count); +} + +void SwitchEventHandler::OnMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uint8_t count) +{ + ChipLogDetail(NotSpecified, "%s: endpointId=%d, previousPosition=%d, count=%d", __func__, endpointId, previousPosition, count); + + Clusters::SwitchServer::Instance().OnMultiPressComplete(endpointId, previousPosition, count); +} +#endif // MATTER_DM_PLUGIN_SWITCH_SERVER diff --git a/examples/chef/common/clusters/switch/SwitchEventHandler.h b/examples/chef/common/clusters/switch/SwitchEventHandler.h new file mode 100644 index 00000000000000..1648e19cc829c5 --- /dev/null +++ b/examples/chef/common/clusters/switch/SwitchEventHandler.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace chip { +namespace app { +namespace Clusters { + +namespace Switch { + +class SwitchEventHandler +{ +public: + SwitchEventHandler(){}; + + /** + * Should be called when the latching switch is moved to a new position. + */ + void OnSwitchLatched(EndpointId endpointId, uint8_t newPosition); + + /** + * Should be called when the momentary switch starts to be pressed. + */ + void OnInitialPress(EndpointId endpointId, uint8_t newPosition); + + /** + * Should be called when the momentary switch has been pressed for a "long" time. + */ + void OnLongPress(EndpointId endpointId, uint8_t newPosition); + + /** + * Should be called when the momentary switch has been released. + */ + void OnShortRelease(EndpointId endpointId, uint8_t previousPosition); + + /** + * Should be called when the momentary switch has been released after having been pressed for a long time. + */ + void OnLongRelease(EndpointId endpointId, uint8_t previousPosition); + + /** + * Should be called to indicate how many times the momentary switch has been pressed in a multi-press + * sequence, during that sequence. + */ + void OnMultiPressOngoing(EndpointId endpointId, uint8_t newPosition, uint8_t count); + + /** + * Should be called to indicate how many times the momentary switch has been pressed in a multi-press + * sequence, after it has been detected that the sequence has ended. + */ + void OnMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uint8_t count); + +private: +}; + +} // namespace Switch +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/chef/common/clusters/switch/SwitchManager.cpp b/examples/chef/common/clusters/switch/SwitchManager.cpp new file mode 100644 index 00000000000000..45d39dd4bce1a4 --- /dev/null +++ b/examples/chef/common/clusters/switch/SwitchManager.cpp @@ -0,0 +1,172 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef MATTER_DM_PLUGIN_SWITCH_SERVER +#include "SwitchEventHandler.h" +#include +#include +#include +#include +#include +#include + +#include "chef-descriptor-namespace.h" +#include "chef-rpc-actions-worker.h" + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Switch; +using namespace chip::DeviceLayer; + +using namespace chip::rpc; +using namespace chip::app; + +class SwitchActionsDelegate : public chip::app::ActionsDelegate +{ +public: + SwitchActionsDelegate(ClusterId clusterId, SwitchEventHandler * eventHandler) : + ActionsDelegate(clusterId), mEventHandler(eventHandler){}; + ~SwitchActionsDelegate() override{}; + + void AttributeWriteHandler(chip::EndpointId endpointId, chip::AttributeId attributeId, std::vector args) override; + void CommandHandler(chip::EndpointId endpointId, chip::AttributeId attributeId, std::vector args) override{}; + void EventHandler(chip::EndpointId endpointId, chip::EventId eventId, std::vector args) override; + +private: + SwitchEventHandler * mEventHandler; +}; + +void SwitchActionsDelegate::AttributeWriteHandler(chip::EndpointId endpointId, chip::AttributeId attributeId, + std::vector args) +{ + if (args.empty()) + { + ChipLogError(NotSpecified, "Queue is empty "); + return; + } + + switch (attributeId) + { + case Switch::Attributes::NumberOfPositions::Id: { + uint8_t data = static_cast(args[0]); + app::Clusters::Switch::Attributes::NumberOfPositions::Set(endpointId, data); + } + break; + case Switch::Attributes::CurrentPosition::Id: { + uint8_t data = static_cast(args[0]); + app::Clusters::Switch::Attributes::CurrentPosition::Set(endpointId, data); + } + break; + case Switch::Attributes::MultiPressMax::Id: { + uint8_t data = static_cast(args[0]); + app::Clusters::Switch::Attributes::MultiPressMax::Set(endpointId, data); + } + break; + default: + break; + } +} + +void SwitchActionsDelegate::EventHandler(chip::EndpointId endpointId, chip::EventId eventId, std::vector args) +{ + if (args.empty()) + { + ChipLogError(NotSpecified, "Queue is empty "); + return; + } + switch (eventId) + { + case Events::SwitchLatched::Id: { + uint8_t newPosition = static_cast(args[0]); + mEventHandler->OnSwitchLatched(endpointId, newPosition); + } + break; + case Events::InitialPress::Id: { + uint8_t newPosition = static_cast(args[0]); + mEventHandler->OnInitialPress(endpointId, newPosition); + } + break; + case Events::LongPress::Id: { + uint8_t newPosition = static_cast(args[0]); + mEventHandler->OnLongPress(endpointId, newPosition); + } + break; + case Events::ShortRelease::Id: { + uint8_t previousPosition = static_cast(args[0]); + mEventHandler->OnShortRelease(endpointId, previousPosition); + } + break; + case Events::LongRelease::Id: { + uint8_t previousPosition = static_cast(args[0]); + mEventHandler->OnLongRelease(endpointId, previousPosition); + } + break; + case Events::MultiPressOngoing::Id: { + if (args.size() < 2) + { + ChipLogError(NotSpecified, "MultiPressOngoing has too few arguments"); + return; + } + uint8_t newPosition = static_cast(args[0]); + uint8_t currentNumberOfPressesCounted = static_cast(args[1]); + mEventHandler->OnMultiPressOngoing(endpointId, newPosition, currentNumberOfPressesCounted); + } + break; + case Events::MultiPressComplete::Id: { + if (args.size() < 2) + { + ChipLogError(NotSpecified, "MultiPressComplete has too few arguments"); + return; + } + uint8_t previousPosition = static_cast(args[0]); + uint8_t totalNumberOfPressesCounted = static_cast(args[1]); + mEventHandler->OnMultiPressComplete(endpointId, previousPosition, totalNumberOfPressesCounted); + } + break; + default: + break; + } +}; + +const Clusters::Descriptor::Structs::SemanticTagStruct::Type gLatchingSwitch[] = { + { .namespaceID = kNamespaceCommonLevel, + .tag = kTagCommonLow, + .label = chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("Low", 3)) }) }, + { .namespaceID = kNamespaceCommonLevel, + .tag = kTagCommonMedium, + .label = chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("Medium", 6)) }) }, + { .namespaceID = kNamespaceCommonLevel, + .tag = kTagCommonHigh, + .label = chip::Optional>( + { chip::app::DataModel::MakeNullable(chip::CharSpan("High", 4)) }) } +}; + +static SwitchEventHandler * gSwitchEventHandler = new SwitchEventHandler(); +static SwitchActionsDelegate * gSwitchActionsDelegate = new SwitchActionsDelegate(Clusters::Switch::Id, gSwitchEventHandler); + +void emberAfSwitchClusterInitCallback(EndpointId endpointId) +{ + ChipLogProgress(Zcl, "Chef: emberAfSwitchClusterInitCallback"); + + ChefRpcActionsWorker::Instance().RegisterRpcActionsDelegate(Clusters::Switch::Id, gSwitchActionsDelegate); + SetTagList(/* endpoint= */ 1, Span(gLatchingSwitch)); +} +#endif // MATTER_DM_PLUGIN_SWITCH_SERVER diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp index 5756aaa35b7e26..437dfe9e6221be 100644 --- a/examples/chef/common/stubs.cpp +++ b/examples/chef/common/stubs.cpp @@ -236,6 +236,16 @@ void emberAfWakeOnLanClusterInitCallback(EndpointId endpoint) } #endif +void ApplicationInit() +{ + ChipLogProgress(NotSpecified, "Chef Application Init !!!") +} + +void ApplicationShutdown() +{ + ChipLogProgress(NotSpecified, "Chef Application Down !!!") +} + // No-op function, used to force linking this file, // instead of the weak functions from other files extern "C" void chef_include_stubs_impl(void) {} diff --git a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter new file mode 100644 index 00000000000000..89319a4b61b4e2 --- /dev/null +++ b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter @@ -0,0 +1,1498 @@ +// This IDL was generated automatically by ZAP. +// It is for view/code review purposes only. + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 4; + + enum EffectIdentifierEnum : enum8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : enum8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : enum8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct IdentifyRequest { + int16u identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + /** Command description for Identify */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** Command description for TriggerEffect */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ +cluster Descriptor = 29 { + revision 2; + + bitmap Feature : bitmap32 { + kTagList = 0x1; + } + + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + struct SemanticTagStruct { + nullable vendor_id mfgCode = 0; + enum8 namespaceID = 1; + enum8 tag = 2; + optional nullable char_string label = 3; + } + + readonly attribute DeviceTypeStruct deviceTypeList[] = 0; + readonly attribute cluster_id serverList[] = 1; + readonly attribute cluster_id clientList[] = 2; + readonly attribute endpoint_no partsList[] = 3; + readonly attribute optional SemanticTagStruct tagList[] = 4; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The Access Control Cluster exposes a data model view of a + Node's Access Control List (ACL), which codifies the rules used to manage + and enforce Access Control for the Node's endpoints and their associated + cluster instances. */ +cluster AccessControl = 31 { + revision 1; // NOTE: Default/not specifically set + + enum AccessControlEntryAuthModeEnum : enum8 { + kPASE = 1; + kCASE = 2; + kGroup = 3; + } + + enum AccessControlEntryPrivilegeEnum : enum8 { + kView = 1; + kProxyView = 2; + kOperate = 3; + kManage = 4; + kAdminister = 5; + } + + enum ChangeTypeEnum : enum8 { + kChanged = 0; + kAdded = 1; + kRemoved = 2; + } + + struct AccessControlTargetStruct { + nullable cluster_id cluster = 0; + nullable endpoint_no endpoint = 1; + nullable devtype_id deviceType = 2; + } + + fabric_scoped struct AccessControlEntryStruct { + fabric_sensitive AccessControlEntryPrivilegeEnum privilege = 1; + fabric_sensitive AccessControlEntryAuthModeEnum authMode = 2; + nullable fabric_sensitive int64u subjects[] = 3; + nullable fabric_sensitive AccessControlTargetStruct targets[] = 4; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct AccessControlExtensionStruct { + fabric_sensitive octet_string<128> data = 1; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlEntryChanged = 0 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlEntryStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlExtensionChanged = 1 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlExtensionStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + attribute access(read: administer, write: administer) AccessControlEntryStruct acl[] = 0; + attribute access(read: administer, write: administer) optional AccessControlExtensionStruct extension[] = 1; + readonly attribute int16u subjectsPerAccessControlEntry = 2; + readonly attribute int16u targetsPerAccessControlEntry = 3; + readonly attribute int16u accessControlEntriesPerFabric = 4; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster provides attributes and events for determining basic information about Nodes, which supports both + Commissioning and operational determination of Node characteristics, such as Vendor ID, Product ID and serial number, + which apply to the whole Node. Also allows setting user device information such as location. */ +cluster BasicInformation = 40 { + revision 3; + + enum ColorEnum : enum8 { + kBlack = 0; + kNavy = 1; + kGreen = 2; + kTeal = 3; + kMaroon = 4; + kPurple = 5; + kOlive = 6; + kGray = 7; + kBlue = 8; + kLime = 9; + kAqua = 10; + kRed = 11; + kFuchsia = 12; + kYellow = 13; + kWhite = 14; + kNickel = 15; + kChrome = 16; + kBrass = 17; + kCopper = 18; + kSilver = 19; + kGold = 20; + } + + enum ProductFinishEnum : enum8 { + kOther = 0; + kMatte = 1; + kSatin = 2; + kPolished = 3; + kRugged = 4; + kFabric = 5; + } + + struct CapabilityMinimaStruct { + int16u caseSessionsPerFabric = 0; + int16u subscriptionsPerFabric = 1; + } + + struct ProductAppearanceStruct { + ProductFinishEnum finish = 0; + nullable ColorEnum primaryColor = 1; + } + + critical event StartUp = 0 { + int32u softwareVersion = 0; + } + + critical event ShutDown = 1 { + } + + info event Leave = 2 { + fabric_idx fabricIndex = 0; + } + + info event ReachableChanged = 3 { + boolean reachableNewValue = 0; + } + + readonly attribute int16u dataModelRevision = 0; + readonly attribute char_string<32> vendorName = 1; + readonly attribute vendor_id vendorID = 2; + readonly attribute char_string<32> productName = 3; + readonly attribute int16u productID = 4; + attribute access(write: manage) char_string<32> nodeLabel = 5; + attribute access(write: administer) char_string<2> location = 6; + readonly attribute int16u hardwareVersion = 7; + readonly attribute char_string<64> hardwareVersionString = 8; + readonly attribute int32u softwareVersion = 9; + readonly attribute char_string<64> softwareVersionString = 10; + readonly attribute optional char_string<16> manufacturingDate = 11; + readonly attribute optional char_string<32> partNumber = 12; + readonly attribute optional long_char_string<256> productURL = 13; + readonly attribute optional char_string<64> productLabel = 14; + readonly attribute optional char_string<32> serialNumber = 15; + attribute access(write: manage) optional boolean localConfigDisabled = 16; + readonly attribute optional boolean reachable = 17; + readonly attribute optional char_string<32> uniqueID = 18; + readonly attribute CapabilityMinimaStruct capabilityMinima = 19; + readonly attribute optional ProductAppearanceStruct productAppearance = 20; + readonly attribute int32u specificationVersion = 21; + readonly attribute int16u maxPathsPerInvoke = 22; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + command MfgSpecificPing(): DefaultSuccess = 0; +} + +/** This cluster is used to describe the configuration and capabilities of a physical power source that provides power to the Node. */ +cluster PowerSource = 47 { + revision 1; // NOTE: Default/not specifically set + + enum BatApprovedChemistryEnum : enum16 { + kUnspecified = 0; + kAlkaline = 1; + kLithiumCarbonFluoride = 2; + kLithiumChromiumOxide = 3; + kLithiumCopperOxide = 4; + kLithiumIronDisulfide = 5; + kLithiumManganeseDioxide = 6; + kLithiumThionylChloride = 7; + kMagnesium = 8; + kMercuryOxide = 9; + kNickelOxyhydride = 10; + kSilverOxide = 11; + kZincAir = 12; + kZincCarbon = 13; + kZincChloride = 14; + kZincManganeseDioxide = 15; + kLeadAcid = 16; + kLithiumCobaltOxide = 17; + kLithiumIon = 18; + kLithiumIonPolymer = 19; + kLithiumIronPhosphate = 20; + kLithiumSulfur = 21; + kLithiumTitanate = 22; + kNickelCadmium = 23; + kNickelHydrogen = 24; + kNickelIron = 25; + kNickelMetalHydride = 26; + kNickelZinc = 27; + kSilverZinc = 28; + kSodiumIon = 29; + kSodiumSulfur = 30; + kZincBromide = 31; + kZincCerium = 32; + } + + enum BatChargeFaultEnum : enum8 { + kUnspecified = 0; + kAmbientTooHot = 1; + kAmbientTooCold = 2; + kBatteryTooHot = 3; + kBatteryTooCold = 4; + kBatteryAbsent = 5; + kBatteryOverVoltage = 6; + kBatteryUnderVoltage = 7; + kChargerOverVoltage = 8; + kChargerUnderVoltage = 9; + kSafetyTimeout = 10; + } + + enum BatChargeLevelEnum : enum8 { + kOK = 0; + kWarning = 1; + kCritical = 2; + } + + enum BatChargeStateEnum : enum8 { + kUnknown = 0; + kIsCharging = 1; + kIsAtFullCharge = 2; + kIsNotCharging = 3; + } + + enum BatCommonDesignationEnum : enum16 { + kUnspecified = 0; + kAAA = 1; + kAA = 2; + kC = 3; + kD = 4; + k4v5 = 5; + k6v0 = 6; + k9v0 = 7; + k12AA = 8; + kAAAA = 9; + kA = 10; + kB = 11; + kF = 12; + kN = 13; + kNo6 = 14; + kSubC = 15; + kA23 = 16; + kA27 = 17; + kBA5800 = 18; + kDuplex = 19; + k4SR44 = 20; + k523 = 21; + k531 = 22; + k15v0 = 23; + k22v5 = 24; + k30v0 = 25; + k45v0 = 26; + k67v5 = 27; + kJ = 28; + kCR123A = 29; + kCR2 = 30; + k2CR5 = 31; + kCRP2 = 32; + kCRV3 = 33; + kSR41 = 34; + kSR43 = 35; + kSR44 = 36; + kSR45 = 37; + kSR48 = 38; + kSR54 = 39; + kSR55 = 40; + kSR57 = 41; + kSR58 = 42; + kSR59 = 43; + kSR60 = 44; + kSR63 = 45; + kSR64 = 46; + kSR65 = 47; + kSR66 = 48; + kSR67 = 49; + kSR68 = 50; + kSR69 = 51; + kSR516 = 52; + kSR731 = 53; + kSR712 = 54; + kLR932 = 55; + kA5 = 56; + kA10 = 57; + kA13 = 58; + kA312 = 59; + kA675 = 60; + kAC41E = 61; + k10180 = 62; + k10280 = 63; + k10440 = 64; + k14250 = 65; + k14430 = 66; + k14500 = 67; + k14650 = 68; + k15270 = 69; + k16340 = 70; + kRCR123A = 71; + k17500 = 72; + k17670 = 73; + k18350 = 74; + k18500 = 75; + k18650 = 76; + k19670 = 77; + k25500 = 78; + k26650 = 79; + k32600 = 80; + } + + enum BatFaultEnum : enum8 { + kUnspecified = 0; + kOverTemp = 1; + kUnderTemp = 2; + } + + enum BatReplaceabilityEnum : enum8 { + kUnspecified = 0; + kNotReplaceable = 1; + kUserReplaceable = 2; + kFactoryReplaceable = 3; + } + + enum PowerSourceStatusEnum : enum8 { + kUnspecified = 0; + kActive = 1; + kStandby = 2; + kUnavailable = 3; + } + + enum WiredCurrentTypeEnum : enum8 { + kAC = 0; + kDC = 1; + } + + enum WiredFaultEnum : enum8 { + kUnspecified = 0; + kOverVoltage = 1; + kUnderVoltage = 2; + } + + bitmap Feature : bitmap32 { + kWired = 0x1; + kBattery = 0x2; + kRechargeable = 0x4; + kReplaceable = 0x8; + } + + struct BatChargeFaultChangeType { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + struct BatFaultChangeType { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + struct WiredFaultChangeType { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event WiredFaultChange = 0 { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event BatFaultChange = 1 { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + info event BatChargeFaultChange = 2 { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + readonly attribute PowerSourceStatusEnum status = 0; + readonly attribute int8u order = 1; + readonly attribute char_string<60> description = 2; + readonly attribute optional nullable int32u wiredAssessedInputVoltage = 3; + readonly attribute optional nullable int16u wiredAssessedInputFrequency = 4; + readonly attribute optional WiredCurrentTypeEnum wiredCurrentType = 5; + readonly attribute optional nullable int32u wiredAssessedCurrent = 6; + readonly attribute optional int32u wiredNominalVoltage = 7; + readonly attribute optional int32u wiredMaximumCurrent = 8; + readonly attribute optional boolean wiredPresent = 9; + readonly attribute optional WiredFaultEnum activeWiredFaults[] = 10; + readonly attribute optional nullable int32u batVoltage = 11; + readonly attribute optional nullable int8u batPercentRemaining = 12; + readonly attribute optional nullable int32u batTimeRemaining = 13; + readonly attribute optional BatChargeLevelEnum batChargeLevel = 14; + readonly attribute optional boolean batReplacementNeeded = 15; + readonly attribute optional BatReplaceabilityEnum batReplaceability = 16; + readonly attribute optional boolean batPresent = 17; + readonly attribute optional BatFaultEnum activeBatFaults[] = 18; + readonly attribute optional char_string<60> batReplacementDescription = 19; + readonly attribute optional BatCommonDesignationEnum batCommonDesignation = 20; + readonly attribute optional char_string<20> batANSIDesignation = 21; + readonly attribute optional char_string<20> batIECDesignation = 22; + readonly attribute optional BatApprovedChemistryEnum batApprovedChemistry = 23; + readonly attribute optional int32u batCapacity = 24; + readonly attribute optional int8u batQuantity = 25; + readonly attribute optional BatChargeStateEnum batChargeState = 26; + readonly attribute optional nullable int32u batTimeToFullCharge = 27; + readonly attribute optional boolean batFunctionalWhileCharging = 28; + readonly attribute optional nullable int32u batChargingCurrent = 29; + readonly attribute optional BatChargeFaultEnum activeBatChargeFaults[] = 30; + readonly attribute endpoint_no endpointList[] = 31; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster is used to manage global aspects of the Commissioning flow. */ +cluster GeneralCommissioning = 48 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningErrorEnum : enum8 { + kOK = 0; + kValueOutsideRange = 1; + kInvalidAuthentication = 2; + kNoFailSafe = 3; + kBusyWithOtherAdmin = 4; + } + + enum RegulatoryLocationTypeEnum : enum8 { + kIndoor = 0; + kOutdoor = 1; + kIndoorOutdoor = 2; + } + + struct BasicCommissioningInfo { + int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; + } + + attribute access(write: administer) int64u breadcrumb = 0; + readonly attribute BasicCommissioningInfo basicCommissioningInfo = 1; + readonly attribute RegulatoryLocationTypeEnum regulatoryConfig = 2; + readonly attribute RegulatoryLocationTypeEnum locationCapability = 3; + readonly attribute boolean supportsConcurrentConnection = 4; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ArmFailSafeRequest { + int16u expiryLengthSeconds = 0; + int64u breadcrumb = 1; + } + + response struct ArmFailSafeResponse = 1 { + CommissioningErrorEnum errorCode = 0; + char_string<128> debugText = 1; + } + + request struct SetRegulatoryConfigRequest { + RegulatoryLocationTypeEnum newRegulatoryConfig = 0; + char_string<2> countryCode = 1; + int64u breadcrumb = 2; + } + + response struct SetRegulatoryConfigResponse = 3 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + response struct CommissioningCompleteResponse = 5 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + /** Arm the persistent fail-safe timer with an expiry time of now + ExpiryLengthSeconds using device clock */ + command access(invoke: administer) ArmFailSafe(ArmFailSafeRequest): ArmFailSafeResponse = 0; + /** Set the regulatory configuration to be used during commissioning */ + command access(invoke: administer) SetRegulatoryConfig(SetRegulatoryConfigRequest): SetRegulatoryConfigResponse = 2; + /** Signals the Server that the Client has successfully completed all steps of Commissioning/Recofiguration needed during fail-safe period. */ + fabric command access(invoke: administer) CommissioningComplete(): CommissioningCompleteResponse = 4; +} + +/** Functionality to configure, enable, disable network credentials and access on a Matter device. */ +cluster NetworkCommissioning = 49 { + revision 1; // NOTE: Default/not specifically set + + enum NetworkCommissioningStatusEnum : enum8 { + kSuccess = 0; + kOutOfRange = 1; + kBoundsExceeded = 2; + kNetworkIDNotFound = 3; + kDuplicateNetworkID = 4; + kNetworkNotFound = 5; + kRegulatoryError = 6; + kAuthFailure = 7; + kUnsupportedSecurity = 8; + kOtherConnectionFailure = 9; + kIPV6Failed = 10; + kIPBindFailed = 11; + kUnknownError = 12; + } + + enum WiFiBandEnum : enum8 { + k2G4 = 0; + k3G65 = 1; + k5G = 2; + k6G = 3; + k60G = 4; + k1G = 5; + } + + bitmap Feature : bitmap32 { + kWiFiNetworkInterface = 0x1; + kThreadNetworkInterface = 0x2; + kEthernetNetworkInterface = 0x4; + kPerDeviceCredentials = 0x8; + } + + bitmap ThreadCapabilitiesBitmap : bitmap16 { + kIsBorderRouterCapable = 0x1; + kIsRouterCapable = 0x2; + kIsSleepyEndDeviceCapable = 0x4; + kIsFullThreadDevice = 0x8; + kIsSynchronizedSleepyEndDeviceCapable = 0x10; + } + + bitmap WiFiSecurityBitmap : bitmap8 { + kUnencrypted = 0x1; + kWEP = 0x2; + kWPAPersonal = 0x4; + kWPA2Personal = 0x8; + kWPA3Personal = 0x10; + kWPA3MatterPDC = 0x20; + } + + struct NetworkInfoStruct { + octet_string<32> networkID = 0; + boolean connected = 1; + optional nullable octet_string<20> networkIdentifier = 2; + optional nullable octet_string<20> clientIdentifier = 3; + } + + struct ThreadInterfaceScanResultStruct { + int16u panId = 0; + int64u extendedPanId = 1; + char_string<16> networkName = 2; + int16u channel = 3; + int8u version = 4; + octet_string<8> extendedAddress = 5; + int8s rssi = 6; + int8u lqi = 7; + } + + struct WiFiInterfaceScanResultStruct { + WiFiSecurityBitmap security = 0; + octet_string<32> ssid = 1; + octet_string<6> bssid = 2; + int16u channel = 3; + WiFiBandEnum wiFiBand = 4; + int8s rssi = 5; + } + + readonly attribute access(read: administer) int8u maxNetworks = 0; + readonly attribute access(read: administer) NetworkInfoStruct networks[] = 1; + readonly attribute optional int8u scanMaxTimeSeconds = 2; + readonly attribute optional int8u connectMaxTimeSeconds = 3; + attribute access(write: administer) boolean interfaceEnabled = 4; + readonly attribute access(read: administer) nullable NetworkCommissioningStatusEnum lastNetworkingStatus = 5; + readonly attribute access(read: administer) nullable octet_string<32> lastNetworkID = 6; + readonly attribute access(read: administer) nullable int32s lastConnectErrorValue = 7; + readonly attribute optional WiFiBandEnum supportedWiFiBands[] = 8; + readonly attribute optional ThreadCapabilitiesBitmap supportedThreadFeatures = 9; + readonly attribute optional int16u threadVersion = 10; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ScanNetworksRequest { + optional nullable octet_string<32> ssid = 0; + optional int64u breadcrumb = 1; + } + + response struct ScanNetworksResponse = 1 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + optional WiFiInterfaceScanResultStruct wiFiScanResults[] = 2; + optional ThreadInterfaceScanResultStruct threadScanResults[] = 3; + } + + request struct AddOrUpdateWiFiNetworkRequest { + octet_string<32> ssid = 0; + octet_string<64> credentials = 1; + optional int64u breadcrumb = 2; + optional octet_string<140> networkIdentity = 3; + optional octet_string<20> clientIdentifier = 4; + optional octet_string<32> possessionNonce = 5; + } + + request struct AddOrUpdateThreadNetworkRequest { + octet_string<254> operationalDataset = 0; + optional int64u breadcrumb = 1; + } + + request struct RemoveNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct NetworkConfigResponse = 5 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string<512> debugText = 1; + optional int8u networkIndex = 2; + optional octet_string<140> clientIdentity = 3; + optional octet_string<64> possessionSignature = 4; + } + + request struct ConnectNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct ConnectNetworkResponse = 7 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + nullable int32s errorValue = 2; + } + + request struct ReorderNetworkRequest { + octet_string<32> networkID = 0; + int8u networkIndex = 1; + optional int64u breadcrumb = 2; + } + + request struct QueryIdentityRequest { + octet_string<20> keyIdentifier = 0; + optional octet_string<32> possessionNonce = 1; + } + + response struct QueryIdentityResponse = 10 { + octet_string<140> identity = 0; + optional octet_string<64> possessionSignature = 1; + } + + /** Detemine the set of networks the device sees as available. */ + command access(invoke: administer) ScanNetworks(ScanNetworksRequest): ScanNetworksResponse = 0; + /** Add or update the credentials for a given Wi-Fi network. */ + command access(invoke: administer) AddOrUpdateWiFiNetwork(AddOrUpdateWiFiNetworkRequest): NetworkConfigResponse = 2; + /** Add or update the credentials for a given Thread network. */ + command access(invoke: administer) AddOrUpdateThreadNetwork(AddOrUpdateThreadNetworkRequest): NetworkConfigResponse = 3; + /** Remove the definition of a given network (including its credentials). */ + command access(invoke: administer) RemoveNetwork(RemoveNetworkRequest): NetworkConfigResponse = 4; + /** Connect to the specified network, using previously-defined credentials. */ + command access(invoke: administer) ConnectNetwork(ConnectNetworkRequest): ConnectNetworkResponse = 6; + /** Modify the order in which networks will be presented in the Networks attribute. */ + command access(invoke: administer) ReorderNetwork(ReorderNetworkRequest): NetworkConfigResponse = 8; + /** Retrieve details about and optionally proof of possession of a network client identity. */ + command access(invoke: administer) QueryIdentity(QueryIdentityRequest): QueryIdentityResponse = 9; +} + +/** The cluster provides commands for retrieving unstructured diagnostic logs from a Node that may be used to aid in diagnostics. */ +cluster DiagnosticLogs = 50 { + revision 1; // NOTE: Default/not specifically set + + enum IntentEnum : enum8 { + kEndUserSupport = 0; + kNetworkDiag = 1; + kCrashLogs = 2; + } + + enum StatusEnum : enum8 { + kSuccess = 0; + kExhausted = 1; + kNoLogs = 2; + kBusy = 3; + kDenied = 4; + } + + enum TransferProtocolEnum : enum8 { + kResponsePayload = 0; + kBDX = 1; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct RetrieveLogsRequestRequest { + IntentEnum intent = 0; + TransferProtocolEnum requestedProtocol = 1; + optional char_string<32> transferFileDesignator = 2; + } + + response struct RetrieveLogsResponse = 1 { + StatusEnum status = 0; + long_octet_string logContent = 1; + optional epoch_us UTCTimeStamp = 2; + optional systime_us timeSinceBoot = 3; + } + + /** Retrieving diagnostic logs from a Node */ + command RetrieveLogsRequest(RetrieveLogsRequestRequest): RetrieveLogsResponse = 0; +} + +/** The General Diagnostics Cluster, along with other diagnostics clusters, provide a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster GeneralDiagnostics = 51 { + revision 2; + + enum BootReasonEnum : enum8 { + kUnspecified = 0; + kPowerOnReboot = 1; + kBrownOutReset = 2; + kSoftwareWatchdogReset = 3; + kHardwareWatchdogReset = 4; + kSoftwareUpdateCompleted = 5; + kSoftwareReset = 6; + } + + enum HardwareFaultEnum : enum8 { + kUnspecified = 0; + kRadio = 1; + kSensor = 2; + kResettableOverTemp = 3; + kNonResettableOverTemp = 4; + kPowerSource = 5; + kVisualDisplayFault = 6; + kAudioOutputFault = 7; + kUserInterfaceFault = 8; + kNonVolatileMemoryError = 9; + kTamperDetected = 10; + } + + enum InterfaceTypeEnum : enum8 { + kUnspecified = 0; + kWiFi = 1; + kEthernet = 2; + kCellular = 3; + kThread = 4; + } + + enum NetworkFaultEnum : enum8 { + kUnspecified = 0; + kHardwareFailure = 1; + kNetworkJammed = 2; + kConnectionFailed = 3; + } + + enum RadioFaultEnum : enum8 { + kUnspecified = 0; + kWiFiFault = 1; + kCellularFault = 2; + kThreadFault = 3; + kNFCFault = 4; + kBLEFault = 5; + kEthernetFault = 6; + } + + bitmap Feature : bitmap32 { + kDataModelTest = 0x1; + } + + struct NetworkInterface { + char_string<32> name = 0; + boolean isOperational = 1; + nullable boolean offPremiseServicesReachableIPv4 = 2; + nullable boolean offPremiseServicesReachableIPv6 = 3; + octet_string<8> hardwareAddress = 4; + octet_string IPv4Addresses[] = 5; + octet_string IPv6Addresses[] = 6; + InterfaceTypeEnum type = 7; + } + + critical event HardwareFaultChange = 0 { + HardwareFaultEnum current[] = 0; + HardwareFaultEnum previous[] = 1; + } + + critical event RadioFaultChange = 1 { + RadioFaultEnum current[] = 0; + RadioFaultEnum previous[] = 1; + } + + critical event NetworkFaultChange = 2 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + critical event BootReason = 3 { + BootReasonEnum bootReason = 0; + } + + readonly attribute NetworkInterface networkInterfaces[] = 0; + readonly attribute int16u rebootCount = 1; + readonly attribute optional int64u upTime = 2; + readonly attribute optional int32u totalOperationalHours = 3; + readonly attribute optional BootReasonEnum bootReason = 4; + readonly attribute optional HardwareFaultEnum activeHardwareFaults[] = 5; + readonly attribute optional RadioFaultEnum activeRadioFaults[] = 6; + readonly attribute optional NetworkFaultEnum activeNetworkFaults[] = 7; + readonly attribute boolean testEventTriggersEnabled = 8; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct TestEventTriggerRequest { + octet_string<16> enableKey = 0; + int64u eventTrigger = 1; + } + + response struct TimeSnapshotResponse = 2 { + systime_ms systemTimeMs = 0; + nullable posix_ms posixTimeMs = 1; + } + + request struct PayloadTestRequestRequest { + octet_string<16> enableKey = 0; + int8u value = 1; + int16u count = 2; + } + + response struct PayloadTestResponse = 4 { + octet_string payload = 0; + } + + /** Provide a means for certification tests to trigger some test-plan-specific events */ + command access(invoke: manage) TestEventTrigger(TestEventTriggerRequest): DefaultSuccess = 0; + /** Take a snapshot of system time and epoch time. */ + command TimeSnapshot(): TimeSnapshotResponse = 1; + /** Request a variable length payload response. */ + command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; +} + +/** This cluster exposes interactions with a switch device, for the purpose of using those interactions by other devices. +Two types of switch devices are supported: latching switch (e.g. rocker switch) and momentary switch (e.g. push button), distinguished with their feature flags. +Interactions with the switch device are exposed as attributes (for the latching switch) and as events (for both types of switches). An interested party MAY subscribe to these attributes/events and thus be informed of the interactions, and can perform actions based on this, for example by sending commands to perform an action such as controlling a light or a window shade. */ +cluster Switch = 59 { + revision 1; + + bitmap Feature : bitmap32 { + kLatchingSwitch = 0x1; + kMomentarySwitch = 0x2; + kMomentarySwitchRelease = 0x4; + kMomentarySwitchLongPress = 0x8; + kMomentarySwitchMultiPress = 0x10; + } + + info event SwitchLatched = 0 { + int8u newPosition = 0; + } + + info event InitialPress = 1 { + int8u newPosition = 0; + } + + info event LongPress = 2 { + int8u newPosition = 0; + } + + info event ShortRelease = 3 { + int8u previousPosition = 0; + } + + info event LongRelease = 4 { + int8u previousPosition = 0; + } + + info event MultiPressOngoing = 5 { + int8u newPosition = 0; + int8u currentNumberOfPressesCounted = 1; + } + + info event MultiPressComplete = 6 { + int8u previousPosition = 0; + int8u totalNumberOfPressesCounted = 1; + } + + readonly attribute int8u numberOfPositions = 0; + readonly attribute int8u currentPosition = 1; + readonly attribute optional int8u multiPressMax = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** Commands to trigger a Node to allow a new Administrator to commission it. */ +cluster AdministratorCommissioning = 60 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningWindowStatusEnum : enum8 { + kWindowNotOpen = 0; + kEnhancedWindowOpen = 1; + kBasicWindowOpen = 2; + } + + enum StatusCode : enum8 { + kBusy = 2; + kPAKEParameterError = 3; + kWindowNotOpen = 4; + } + + bitmap Feature : bitmap32 { + kBasic = 0x1; + } + + readonly attribute CommissioningWindowStatusEnum windowStatus = 0; + readonly attribute nullable fabric_idx adminFabricIndex = 1; + readonly attribute nullable vendor_id adminVendorId = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct OpenCommissioningWindowRequest { + int16u commissioningTimeout = 0; + octet_string PAKEPasscodeVerifier = 1; + int16u discriminator = 2; + int32u iterations = 3; + octet_string<32> salt = 4; + } + + request struct OpenBasicCommissioningWindowRequest { + int16u commissioningTimeout = 0; + } + + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using enhanced commissioning method. */ + timed command access(invoke: administer) OpenCommissioningWindow(OpenCommissioningWindowRequest): DefaultSuccess = 0; + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using basic commissioning method, if the node supports it. */ + timed command access(invoke: administer) OpenBasicCommissioningWindow(OpenBasicCommissioningWindowRequest): DefaultSuccess = 1; + /** This command is used by a current Administrator to instruct a Node to revoke any active Open Commissioning Window or Open Basic Commissioning Window command. */ + timed command access(invoke: administer) RevokeCommissioning(): DefaultSuccess = 2; +} + +/** This cluster is used to add or remove Operational Credentials on a Commissionee or Node, as well as manage the associated Fabrics. */ +cluster OperationalCredentials = 62 { + revision 1; // NOTE: Default/not specifically set + + enum CertificateChainTypeEnum : enum8 { + kDACCertificate = 1; + kPAICertificate = 2; + } + + enum NodeOperationalCertStatusEnum : enum8 { + kOK = 0; + kInvalidPublicKey = 1; + kInvalidNodeOpId = 2; + kInvalidNOC = 3; + kMissingCsr = 4; + kTableFull = 5; + kInvalidAdminSubject = 6; + kFabricConflict = 9; + kLabelConflict = 10; + kInvalidFabricIndex = 11; + } + + fabric_scoped struct FabricDescriptorStruct { + octet_string<65> rootPublicKey = 1; + vendor_id vendorID = 2; + fabric_id fabricID = 3; + node_id nodeID = 4; + char_string<32> label = 5; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct NOCStruct { + fabric_sensitive octet_string noc = 1; + nullable fabric_sensitive octet_string icac = 2; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: administer) NOCStruct NOCs[] = 0; + readonly attribute FabricDescriptorStruct fabrics[] = 1; + readonly attribute int8u supportedFabrics = 2; + readonly attribute int8u commissionedFabrics = 3; + readonly attribute octet_string trustedRootCertificates[] = 4; + readonly attribute int8u currentFabricIndex = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AttestationRequestRequest { + octet_string<32> attestationNonce = 0; + } + + response struct AttestationResponse = 1 { + octet_string<900> attestationElements = 0; + octet_string<64> attestationSignature = 1; + } + + request struct CertificateChainRequestRequest { + CertificateChainTypeEnum certificateType = 0; + } + + response struct CertificateChainResponse = 3 { + octet_string<600> certificate = 0; + } + + request struct CSRRequestRequest { + octet_string<32> CSRNonce = 0; + optional boolean isForUpdateNOC = 1; + } + + response struct CSRResponse = 5 { + octet_string NOCSRElements = 0; + octet_string attestationSignature = 1; + } + + request struct AddNOCRequest { + octet_string<400> NOCValue = 0; + optional octet_string<400> ICACValue = 1; + octet_string<16> IPKValue = 2; + int64u caseAdminSubject = 3; + vendor_id adminVendorId = 4; + } + + request struct UpdateNOCRequest { + octet_string NOCValue = 0; + optional octet_string ICACValue = 1; + } + + response struct NOCResponse = 8 { + NodeOperationalCertStatusEnum statusCode = 0; + optional fabric_idx fabricIndex = 1; + optional char_string<128> debugText = 2; + } + + request struct UpdateFabricLabelRequest { + char_string<32> label = 0; + } + + request struct RemoveFabricRequest { + fabric_idx fabricIndex = 0; + } + + request struct AddTrustedRootCertificateRequest { + octet_string rootCACertificate = 0; + } + + /** Sender is requesting attestation information from the receiver. */ + command access(invoke: administer) AttestationRequest(AttestationRequestRequest): AttestationResponse = 0; + /** Sender is requesting a device attestation certificate from the receiver. */ + command access(invoke: administer) CertificateChainRequest(CertificateChainRequestRequest): CertificateChainResponse = 2; + /** Sender is requesting a certificate signing request (CSR) from the receiver. */ + command access(invoke: administer) CSRRequest(CSRRequestRequest): CSRResponse = 4; + /** Sender is requesting to add the new node operational certificates. */ + command access(invoke: administer) AddNOC(AddNOCRequest): NOCResponse = 6; + /** Sender is requesting to update the node operational certificates. */ + fabric command access(invoke: administer) UpdateNOC(UpdateNOCRequest): NOCResponse = 7; + /** This command SHALL be used by an Administrative Node to set the user-visible Label field for a given Fabric, as reflected by entries in the Fabrics attribute. */ + fabric command access(invoke: administer) UpdateFabricLabel(UpdateFabricLabelRequest): NOCResponse = 9; + /** This command is used by Administrative Nodes to remove a given fabric index and delete all associated fabric-scoped data. */ + command access(invoke: administer) RemoveFabric(RemoveFabricRequest): NOCResponse = 10; + /** This command SHALL add a Trusted Root CA Certificate, provided as its CHIP Certificate representation. */ + command access(invoke: administer) AddTrustedRootCertificate(AddTrustedRootCertificateRequest): DefaultSuccess = 11; +} + +/** The Group Key Management Cluster is the mechanism by which group keys are managed. */ +cluster GroupKeyManagement = 63 { + revision 1; // NOTE: Default/not specifically set + + enum GroupKeySecurityPolicyEnum : enum8 { + kTrustFirst = 0; + kCacheAndSync = 1; + } + + bitmap Feature : bitmap32 { + kCacheAndSync = 0x1; + } + + fabric_scoped struct GroupInfoMapStruct { + group_id groupId = 1; + endpoint_no endpoints[] = 2; + optional char_string<16> groupName = 3; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct GroupKeyMapStruct { + group_id groupId = 1; + int16u groupKeySetID = 2; + fabric_idx fabricIndex = 254; + } + + struct GroupKeySetStruct { + int16u groupKeySetID = 0; + GroupKeySecurityPolicyEnum groupKeySecurityPolicy = 1; + nullable octet_string<16> epochKey0 = 2; + nullable epoch_us epochStartTime0 = 3; + nullable octet_string<16> epochKey1 = 4; + nullable epoch_us epochStartTime1 = 5; + nullable octet_string<16> epochKey2 = 6; + nullable epoch_us epochStartTime2 = 7; + } + + attribute access(write: manage) GroupKeyMapStruct groupKeyMap[] = 0; + readonly attribute GroupInfoMapStruct groupTable[] = 1; + readonly attribute int16u maxGroupsPerFabric = 2; + readonly attribute int16u maxGroupKeysPerFabric = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct KeySetWriteRequest { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetReadRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadResponse = 2 { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetRemoveRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadAllIndicesResponse = 5 { + int16u groupKeySetIDs[] = 0; + } + + /** Write a new set of keys for the given key set id. */ + fabric command access(invoke: administer) KeySetWrite(KeySetWriteRequest): DefaultSuccess = 0; + /** Read the keys for a given key set id. */ + fabric command access(invoke: administer) KeySetRead(KeySetReadRequest): KeySetReadResponse = 1; + /** Revoke a Root Key from a Group */ + fabric command access(invoke: administer) KeySetRemove(KeySetRemoveRequest): DefaultSuccess = 3; + /** Return the list of Group Key Sets associated with the accessing fabric */ + fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; +} + +endpoint 0 { + device type ma_rootdevice = 22, version 1; + + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster AccessControl { + emits event AccessControlEntryChanged; + emits event AccessControlExtensionChanged; + callback attribute acl; + callback attribute extension; + callback attribute subjectsPerAccessControlEntry; + callback attribute targetsPerAccessControlEntry; + callback attribute accessControlEntriesPerFabric; + callback attribute attributeList; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster BasicInformation { + emits event StartUp; + emits event ShutDown; + emits event Leave; + callback attribute dataModelRevision; + callback attribute vendorName; + callback attribute vendorID; + callback attribute productName; + callback attribute productID; + persist attribute nodeLabel; + callback attribute location; + callback attribute hardwareVersion; + callback attribute hardwareVersionString; + callback attribute softwareVersion; + callback attribute softwareVersionString; + callback attribute manufacturingDate; + callback attribute partNumber; + callback attribute productURL; + callback attribute productLabel; + callback attribute serialNumber; + persist attribute localConfigDisabled default = 0; + callback attribute uniqueID; + callback attribute capabilityMinima; + callback attribute specificationVersion; + callback attribute maxPathsPerInvoke; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + + server cluster GeneralCommissioning { + ram attribute breadcrumb default = 0x0000000000000000; + callback attribute basicCommissioningInfo; + callback attribute regulatoryConfig; + callback attribute locationCapability; + callback attribute supportsConcurrentConnection; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 0x0001; + + handle command ArmFailSafe; + handle command ArmFailSafeResponse; + handle command SetRegulatoryConfig; + handle command SetRegulatoryConfigResponse; + handle command CommissioningComplete; + handle command CommissioningCompleteResponse; + } + + server cluster NetworkCommissioning { + ram attribute maxNetworks; + callback attribute networks; + ram attribute scanMaxTimeSeconds; + ram attribute connectMaxTimeSeconds; + ram attribute interfaceEnabled; + ram attribute lastNetworkingStatus; + ram attribute lastNetworkID; + ram attribute lastConnectErrorValue; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 0x0001; + + handle command ScanNetworks; + handle command ScanNetworksResponse; + handle command AddOrUpdateWiFiNetwork; + handle command AddOrUpdateThreadNetwork; + handle command RemoveNetwork; + handle command NetworkConfigResponse; + handle command ConnectNetwork; + handle command ConnectNetworkResponse; + handle command ReorderNetwork; + } + + server cluster DiagnosticLogs { + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command RetrieveLogsRequest; + } + + server cluster GeneralDiagnostics { + emits event BootReason; + callback attribute networkInterfaces; + callback attribute rebootCount; + callback attribute upTime; + callback attribute totalOperationalHours; + callback attribute bootReason; + callback attribute activeHardwareFaults; + callback attribute activeRadioFaults; + callback attribute activeNetworkFaults; + callback attribute testEventTriggersEnabled default = false; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command TestEventTrigger; + handle command TimeSnapshot; + handle command TimeSnapshotResponse; + } + + server cluster AdministratorCommissioning { + callback attribute windowStatus; + callback attribute adminFabricIndex; + callback attribute adminVendorId; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 0x0001; + + handle command OpenCommissioningWindow; + handle command OpenBasicCommissioningWindow; + handle command RevokeCommissioning; + } + + server cluster OperationalCredentials { + callback attribute NOCs; + callback attribute fabrics; + callback attribute supportedFabrics; + callback attribute commissionedFabrics; + callback attribute trustedRootCertificates; + callback attribute currentFabricIndex; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 0x0001; + + handle command AttestationRequest; + handle command AttestationResponse; + handle command CertificateChainRequest; + handle command CertificateChainResponse; + handle command CSRRequest; + handle command CSRResponse; + handle command AddNOC; + handle command UpdateNOC; + handle command NOCResponse; + handle command UpdateFabricLabel; + handle command RemoveFabric; + handle command AddTrustedRootCertificate; + } + + server cluster GroupKeyManagement { + callback attribute groupKeyMap; + callback attribute groupTable; + callback attribute maxGroupsPerFabric; + callback attribute maxGroupKeysPerFabric; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command KeySetWrite; + handle command KeySetRead; + handle command KeySetReadResponse; + handle command KeySetRemove; + handle command KeySetReadAllIndices; + handle command KeySetReadAllIndicesResponse; + } +} +endpoint 1 { + device type ma_powersource = 17, version 1; + device type ma_genericswitch = 15, version 1; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute tagList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster PowerSource { + persist attribute status default = 1; + persist attribute order default = 1; + persist attribute description default = "Battery"; + persist attribute batVoltage; + persist attribute batPercentRemaining default = 100; + persist attribute batTimeRemaining; + persist attribute batChargeLevel; + ram attribute batReplacementNeeded; + ram attribute batReplaceability; + ram attribute batPresent; + ram attribute batReplacementDescription; + persist attribute batQuantity default = 1; + callback attribute endpointList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0x0A; + ram attribute clusterRevision default = 1; + } + + server cluster Switch { + emits event InitialPress; + emits event LongPress; + emits event ShortRelease; + emits event LongRelease; + persist attribute numberOfPositions default = 3; + persist attribute currentPosition default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0xE; + ram attribute clusterRevision default = 1; + } +} + + diff --git a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.zap b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.zap new file mode 100644 index 00000000000000..1f84a7aab45a71 --- /dev/null +++ b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.zap @@ -0,0 +1,2804 @@ +{ + "fileFormat": 2, + "featureLevel": 102, + "creator": "zap", + "keyValuePairs": [ + { + "key": "commandDiscovery", + "value": "1" + }, + { + "key": "defaultResponsePolicy", + "value": "always" + }, + { + "key": "manufacturerCodes", + "value": "0x1002" + } + ], + "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/zcl/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "category": "matter", + "version": "chip-v1" + } + ], + "endpointTypes": [ + { + "id": 1, + "name": "MA-rootdevice", + "deviceTypeRef": { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice" + }, + "deviceTypes": [ + { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 22 + ], + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ACL", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Extension", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SubjectsPerAccessControlEntry", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetsPerAccessControlEntry", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AccessControlEntriesPerFabric", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "AccessControlEntryChanged", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "AccessControlExtensionChanged", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DataModelRevision", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ManufacturingDate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartNumber", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductURL", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "long_char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductLabel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SerialNumber", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LocalConfigDisabled", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "NVM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UniqueID", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpecificationVersion", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxPathsPerInvoke", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "StartUp", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "ShutDown", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Leave", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocationCapability", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportsConcurrentConnection", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ScanNetworks", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ScanNetworksResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateWiFiNetwork", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateThreadNetwork", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveNetwork", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NetworkConfigResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ConnectNetwork", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ConnectNetworkResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ReorderNetwork", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ScanMaxTimeSeconds", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ConnectMaxTimeSeconds", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Diagnostic Logs", + "code": 50, + "mfgCode": null, + "define": "DIAGNOSTIC_LOGS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "RetrieveLogsRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshot", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshotResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TotalOperationalHours", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BootReason", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "BootReasonEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveHardwareFaults", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveRadioFaults", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveNetworkFaults", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "false", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "BootReason", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "OpenBasicCommissioningWindow", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminFabricIndex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "fabric_idx", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0001", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 15, + "profileId": 259, + "label": "MA-genericswitch", + "name": "MA-genericswitch" + }, + "deviceTypes": [ + { + "code": 15, + "profileId": 259, + "label": "MA-genericswitch", + "name": "MA-genericswitch" + }, + { + "code": 17, + "profileId": 259, + "label": "MA-powersource", + "name": "MA-powersource" + } + ], + "deviceVersions": [ + 1, + 1 + ], + "deviceIdentifiers": [ + 15, + 17 + ], + "deviceTypeName": "MA-genericswitch", + "deviceTypeCode": 15, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TagList", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Status", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerSourceStatusEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Order", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Description", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "Battery", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatVoltage", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPercentRemaining", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "100", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatTimeRemaining", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatChargeLevel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "BatChargeLevelEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementNeeded", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplaceability", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "BatReplaceabilityEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPresent", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementDescription", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatQuantity", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EndpointList", + "code": 31, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0A", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Switch", + "code": 59, + "mfgCode": null, + "define": "SWITCH_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "NumberOfPositions", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentPosition", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xE", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "InitialPress", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "LongPress", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "ShortRelease", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "LongRelease", + "code": 4, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0, + "parentEndpointIdentifier": null + } + ] +} \ No newline at end of file diff --git a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter index 8e2d0166cc44a9..cda268e6d211f0 100644 --- a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter +++ b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter @@ -256,6 +256,265 @@ cluster BasicInformation = 40 { command MfgSpecificPing(): DefaultSuccess = 0; } +/** This cluster is used to describe the configuration and capabilities of a physical power source that provides power to the Node. */ +cluster PowerSource = 47 { + revision 1; // NOTE: Default/not specifically set + + enum BatApprovedChemistryEnum : enum16 { + kUnspecified = 0; + kAlkaline = 1; + kLithiumCarbonFluoride = 2; + kLithiumChromiumOxide = 3; + kLithiumCopperOxide = 4; + kLithiumIronDisulfide = 5; + kLithiumManganeseDioxide = 6; + kLithiumThionylChloride = 7; + kMagnesium = 8; + kMercuryOxide = 9; + kNickelOxyhydride = 10; + kSilverOxide = 11; + kZincAir = 12; + kZincCarbon = 13; + kZincChloride = 14; + kZincManganeseDioxide = 15; + kLeadAcid = 16; + kLithiumCobaltOxide = 17; + kLithiumIon = 18; + kLithiumIonPolymer = 19; + kLithiumIronPhosphate = 20; + kLithiumSulfur = 21; + kLithiumTitanate = 22; + kNickelCadmium = 23; + kNickelHydrogen = 24; + kNickelIron = 25; + kNickelMetalHydride = 26; + kNickelZinc = 27; + kSilverZinc = 28; + kSodiumIon = 29; + kSodiumSulfur = 30; + kZincBromide = 31; + kZincCerium = 32; + } + + enum BatChargeFaultEnum : enum8 { + kUnspecified = 0; + kAmbientTooHot = 1; + kAmbientTooCold = 2; + kBatteryTooHot = 3; + kBatteryTooCold = 4; + kBatteryAbsent = 5; + kBatteryOverVoltage = 6; + kBatteryUnderVoltage = 7; + kChargerOverVoltage = 8; + kChargerUnderVoltage = 9; + kSafetyTimeout = 10; + } + + enum BatChargeLevelEnum : enum8 { + kOK = 0; + kWarning = 1; + kCritical = 2; + } + + enum BatChargeStateEnum : enum8 { + kUnknown = 0; + kIsCharging = 1; + kIsAtFullCharge = 2; + kIsNotCharging = 3; + } + + enum BatCommonDesignationEnum : enum16 { + kUnspecified = 0; + kAAA = 1; + kAA = 2; + kC = 3; + kD = 4; + k4v5 = 5; + k6v0 = 6; + k9v0 = 7; + k12AA = 8; + kAAAA = 9; + kA = 10; + kB = 11; + kF = 12; + kN = 13; + kNo6 = 14; + kSubC = 15; + kA23 = 16; + kA27 = 17; + kBA5800 = 18; + kDuplex = 19; + k4SR44 = 20; + k523 = 21; + k531 = 22; + k15v0 = 23; + k22v5 = 24; + k30v0 = 25; + k45v0 = 26; + k67v5 = 27; + kJ = 28; + kCR123A = 29; + kCR2 = 30; + k2CR5 = 31; + kCRP2 = 32; + kCRV3 = 33; + kSR41 = 34; + kSR43 = 35; + kSR44 = 36; + kSR45 = 37; + kSR48 = 38; + kSR54 = 39; + kSR55 = 40; + kSR57 = 41; + kSR58 = 42; + kSR59 = 43; + kSR60 = 44; + kSR63 = 45; + kSR64 = 46; + kSR65 = 47; + kSR66 = 48; + kSR67 = 49; + kSR68 = 50; + kSR69 = 51; + kSR516 = 52; + kSR731 = 53; + kSR712 = 54; + kLR932 = 55; + kA5 = 56; + kA10 = 57; + kA13 = 58; + kA312 = 59; + kA675 = 60; + kAC41E = 61; + k10180 = 62; + k10280 = 63; + k10440 = 64; + k14250 = 65; + k14430 = 66; + k14500 = 67; + k14650 = 68; + k15270 = 69; + k16340 = 70; + kRCR123A = 71; + k17500 = 72; + k17670 = 73; + k18350 = 74; + k18500 = 75; + k18650 = 76; + k19670 = 77; + k25500 = 78; + k26650 = 79; + k32600 = 80; + } + + enum BatFaultEnum : enum8 { + kUnspecified = 0; + kOverTemp = 1; + kUnderTemp = 2; + } + + enum BatReplaceabilityEnum : enum8 { + kUnspecified = 0; + kNotReplaceable = 1; + kUserReplaceable = 2; + kFactoryReplaceable = 3; + } + + enum PowerSourceStatusEnum : enum8 { + kUnspecified = 0; + kActive = 1; + kStandby = 2; + kUnavailable = 3; + } + + enum WiredCurrentTypeEnum : enum8 { + kAC = 0; + kDC = 1; + } + + enum WiredFaultEnum : enum8 { + kUnspecified = 0; + kOverVoltage = 1; + kUnderVoltage = 2; + } + + bitmap Feature : bitmap32 { + kWired = 0x1; + kBattery = 0x2; + kRechargeable = 0x4; + kReplaceable = 0x8; + } + + struct BatChargeFaultChangeType { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + struct BatFaultChangeType { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + struct WiredFaultChangeType { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event WiredFaultChange = 0 { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event BatFaultChange = 1 { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + info event BatChargeFaultChange = 2 { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + readonly attribute PowerSourceStatusEnum status = 0; + readonly attribute int8u order = 1; + readonly attribute char_string<60> description = 2; + readonly attribute optional nullable int32u wiredAssessedInputVoltage = 3; + readonly attribute optional nullable int16u wiredAssessedInputFrequency = 4; + readonly attribute optional WiredCurrentTypeEnum wiredCurrentType = 5; + readonly attribute optional nullable int32u wiredAssessedCurrent = 6; + readonly attribute optional int32u wiredNominalVoltage = 7; + readonly attribute optional int32u wiredMaximumCurrent = 8; + readonly attribute optional boolean wiredPresent = 9; + readonly attribute optional WiredFaultEnum activeWiredFaults[] = 10; + readonly attribute optional nullable int32u batVoltage = 11; + readonly attribute optional nullable int8u batPercentRemaining = 12; + readonly attribute optional nullable int32u batTimeRemaining = 13; + readonly attribute optional BatChargeLevelEnum batChargeLevel = 14; + readonly attribute optional boolean batReplacementNeeded = 15; + readonly attribute optional BatReplaceabilityEnum batReplaceability = 16; + readonly attribute optional boolean batPresent = 17; + readonly attribute optional BatFaultEnum activeBatFaults[] = 18; + readonly attribute optional char_string<60> batReplacementDescription = 19; + readonly attribute optional BatCommonDesignationEnum batCommonDesignation = 20; + readonly attribute optional char_string<20> batANSIDesignation = 21; + readonly attribute optional char_string<20> batIECDesignation = 22; + readonly attribute optional BatApprovedChemistryEnum batApprovedChemistry = 23; + readonly attribute optional int32u batCapacity = 24; + readonly attribute optional int8u batQuantity = 25; + readonly attribute optional BatChargeStateEnum batChargeState = 26; + readonly attribute optional nullable int32u batTimeToFullCharge = 27; + readonly attribute optional boolean batFunctionalWhileCharging = 28; + readonly attribute optional nullable int32u batChargingCurrent = 29; + readonly attribute optional BatChargeFaultEnum activeBatChargeFaults[] = 30; + readonly attribute endpoint_no endpointList[] = 31; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + /** This cluster is used to manage global aspects of the Commissioning flow. */ cluster GeneralCommissioning = 48 { revision 1; // NOTE: Default/not specifically set @@ -1166,6 +1425,7 @@ endpoint 0 { } } endpoint 1 { + device type ma_powersource = 17, version 1; device type ma_genericswitch = 15, version 1; @@ -1188,6 +1448,7 @@ endpoint 1 { callback attribute serverList; callback attribute clientList; callback attribute partsList; + callback attribute tagList; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -1196,9 +1457,31 @@ endpoint 1 { callback attribute clusterRevision; } + server cluster PowerSource { + persist attribute status default = 1; + persist attribute order default = 1; + persist attribute description default = "Battery"; + persist attribute batVoltage; + persist attribute batPercentRemaining default = 100; + persist attribute batTimeRemaining; + persist attribute batChargeLevel default = 0; + ram attribute batReplacementNeeded; + ram attribute batReplaceability; + ram attribute batPresent; + ram attribute batReplacementDescription; + persist attribute batQuantity default = 1; + callback attribute endpointList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0x0A; + ram attribute clusterRevision default = 1; + } + server cluster Switch { emits event SwitchLatched; - persist attribute numberOfPositions default = 2; + persist attribute numberOfPositions default = 5; persist attribute currentPosition default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; diff --git a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.zap b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.zap index 172c6d31772296..8e62878f7a4e40 100644 --- a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.zap +++ b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.zap @@ -1,6 +1,6 @@ { "fileFormat": 2, - "featureLevel": 100, + "featureLevel": 102, "creator": "zap", "keyValuePairs": [ { @@ -29,6 +29,7 @@ "pathRelativity": "relativeToZap", "path": "../../../src/app/zap-templates/app-templates.json", "type": "gen-templates-json", + "category": "matter", "version": "chip-v1" } ], @@ -1935,13 +1936,21 @@ "profileId": 259, "label": "MA-genericswitch", "name": "MA-genericswitch" + }, + { + "code": 17, + "profileId": 259, + "label": "MA-powersource", + "name": "MA-powersource" } ], "deviceVersions": [ + 1, 1 ], "deviceIdentifiers": [ - 15 + 15, + 17 ], "deviceTypeName": "MA-genericswitch", "deviceTypeCode": 15, @@ -2175,6 +2184,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "TagList", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "GeneratedCommandList", "code": 65528, @@ -2273,6 +2298,320 @@ } ] }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Status", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerSourceStatusEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Order", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Description", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "Battery", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatVoltage", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPercentRemaining", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "100", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatTimeRemaining", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatChargeLevel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "BatChargeLevelEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementNeeded", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplaceability", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "BatReplaceabilityEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatPresent", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatReplacementDescription", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatQuantity", + "code": 25, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EndpointList", + "code": 31, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0A", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Switch", "code": 59, @@ -2291,7 +2630,7 @@ "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "2", + "defaultValue": "5", "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/chef/esp32/main/CMakeLists.txt b/examples/chef/esp32/main/CMakeLists.txt index ac436a7919637b..c6b37a0675fa4c 100644 --- a/examples/chef/esp32/main/CMakeLists.txt +++ b/examples/chef/esp32/main/CMakeLists.txt @@ -70,6 +70,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/../common/clusters/low-power/" "${CMAKE_SOURCE_DIR}/../common/clusters/media-input/" "${CMAKE_SOURCE_DIR}/../common/clusters/media-playback/" + "${CMAKE_SOURCE_DIR}/../common/clusters/switch/" "${CMAKE_SOURCE_DIR}/../common/clusters/target-navigator/" "${CMAKE_SOURCE_DIR}/../common/clusters/wake-on-lan/" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/attributes" diff --git a/examples/chef/esp32/main/main.cpp b/examples/chef/esp32/main/main.cpp index c5f29dc0f847d8..b61fcf22bc1d19 100644 --- a/examples/chef/esp32/main/main.cpp +++ b/examples/chef/esp32/main/main.cpp @@ -152,6 +152,8 @@ void printQRCode() app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::ESPWiFiDriver::GetInstance())); +extern void ApplicationInit(); + void InitServer(intptr_t) { // Start IM server @@ -172,6 +174,10 @@ void InitServer(intptr_t) // Register a function to receive events from the CHIP device layer. Note that calls to // this function will happen on the CHIP event loop thread, not the app_main thread. PlatformMgr().AddEventHandler(DeviceEventCallback, reinterpret_cast(nullptr)); + + // Application code should always be initialised after the initialisation of + // server. + ApplicationInit(); } extern "C" void app_main(void) diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index 264ced698b62e8..ce0bed596850ef 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -47,6 +47,7 @@ executable("${sample_name}") { "${project_dir}/common/chef-laundry-washer-mode.cpp", "${project_dir}/common/chef-operational-state-delegate-impl.cpp", "${project_dir}/common/chef-resource-monitoring-delegates.cpp", + "${project_dir}/common/chef-rpc-actions-worker.cpp", "${project_dir}/common/chef-rvc-mode-delegate.cpp", "${project_dir}/common/chef-rvc-operational-state-delegate.cpp", "${project_dir}/common/clusters/audio-output/AudioOutputManager.cpp", @@ -58,6 +59,8 @@ executable("${sample_name}") { "${project_dir}/common/clusters/low-power/LowPowerManager.cpp", "${project_dir}/common/clusters/media-input/MediaInputManager.cpp", "${project_dir}/common/clusters/media-playback/MediaPlaybackManager.cpp", + "${project_dir}/common/clusters/switch/SwitchEventHandler.cpp", + "${project_dir}/common/clusters/switch/SwitchManager.cpp", "${project_dir}/common/clusters/target-navigator/TargetNavigatorManager.cpp", "${project_dir}/common/clusters/wake-on-lan/WakeOnLanManager.cpp", "${project_dir}/common/stubs.cpp", @@ -80,6 +83,7 @@ executable("${sample_name}") { if (chip_enable_pw_rpc) { defines = [ "PW_RPC_ENABLED", + "PW_RPC_ACTIONS_SERVICE=1", "PW_RPC_ATTRIBUTE_SERVICE=1", "PW_RPC_BOOLEAN_STATE_SERVICE=1", "PW_RPC_BUTTON_SERVICE=1", @@ -107,6 +111,7 @@ executable("${sample_name}") { "$dir_pw_trace_tokenized", "$dir_pw_trace_tokenized:trace_rpc_service", "${chip_root}/config/linux/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:actions_service.nanopb_rpc", "${chip_root}/examples/common/pigweed:attributes_service.nanopb_rpc", "${chip_root}/examples/common/pigweed:boolean_state_service.nanopb_rpc", "${chip_root}/examples/common/pigweed:button_service.nanopb_rpc", diff --git a/examples/chef/linux/main.cpp b/examples/chef/linux/main.cpp index d799b4da3b53e6..7f54490eccf0de 100644 --- a/examples/chef/linux/main.cpp +++ b/examples/chef/linux/main.cpp @@ -29,10 +29,6 @@ using namespace chip::Shell; using namespace chip::app; using namespace chip::app::Clusters; -void ApplicationInit() {} - -void ApplicationShutdown() {} - int main(int argc, char * argv[]) { if (ChipLinuxAppInit(argc, argv) != 0) diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt index 0e943cd90719f3..a22f6b6972bb15 100644 --- a/examples/chef/nrfconnect/CMakeLists.txt +++ b/examples/chef/nrfconnect/CMakeLists.txt @@ -99,6 +99,8 @@ target_sources(app PRIVATE ${CHEF}/common/clusters/low-power/LowPowerManager.cpp ${CHEF}/common/clusters/media-input/MediaInputManager.cpp ${CHEF}/common/clusters/media-playback/MediaPlaybackManager.cpp + ${CHEF}/common/clusters/switch/SwitchEventHandler.cpp + ${CHEF}/common/clusters/switch/SwitchManager.cpp ${CHEF}/common/clusters/target-navigator/TargetNavigatorManager.cpp ${CHEF}/common/clusters/wake-on-lan/WakeOnLanManager.cpp ${CHEF}/common/stubs.cpp diff --git a/examples/chef/nrfconnect/main.cpp b/examples/chef/nrfconnect/main.cpp index c79694e2e792a7..ca9d25655e3d52 100644 --- a/examples/chef/nrfconnect/main.cpp +++ b/examples/chef/nrfconnect/main.cpp @@ -64,6 +64,13 @@ chip::Crypto::PSAOperationalKeystore sPSAOperationalKeystore{}; #endif } // namespace +extern void ApplicationInit(); + +void InitServer(intptr_t) +{ + ApplicationInit(); +} + int main() { CHIP_ERROR err = CHIP_NO_ERROR; @@ -168,6 +175,8 @@ int main() cmd_app_server_init(); #endif + chip::DeviceLayer::PlatformMgr().ScheduleWork(InitServer); + #if CONFIG_CHIP_LIB_SHELL Engine::Root().RunMainLoop(); #endif diff --git a/examples/common/pigweed/BUILD.gn b/examples/common/pigweed/BUILD.gn index e056f2ef228a8a..c0178e419a1d5d 100644 --- a/examples/common/pigweed/BUILD.gn +++ b/examples/common/pigweed/BUILD.gn @@ -35,6 +35,14 @@ pw_proto_library("echo_service") { prefix = "echo_service" } +pw_proto_library("actions_service") { + sources = [ "protos/actions_service.proto" ] + inputs = [ "protos/actions_service.options" ] + deps = [ "$dir_pw_protobuf:common_protos" ] + strip_prefix = "protos" + prefix = "actions_service" +} + pw_proto_library("attributes_service") { sources = [ "protos/attributes_service.proto" ] inputs = [ "protos/attributes_service.options" ] diff --git a/examples/common/pigweed/protos/actions_service.options b/examples/common/pigweed/protos/actions_service.options new file mode 100644 index 00000000000000..24ce3e80648ae6 --- /dev/null +++ b/examples/common/pigweed/protos/actions_service.options @@ -0,0 +1 @@ +chip.rpc.ActionsRequest.actions max_count:16 // max action size diff --git a/examples/common/pigweed/protos/actions_service.proto b/examples/common/pigweed/protos/actions_service.proto new file mode 100644 index 00000000000000..dbf3a99ceb32ac --- /dev/null +++ b/examples/common/pigweed/protos/actions_service.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package chip.rpc; + +import 'pw_protobuf_protos/common.proto'; + +enum ActionType { + WRITE_ATTRIBUTE = 0x00; // Write an cluster Attribute + RUN_COMMAND = 0x01; // Run a cluster Command + EMIT_EVENT = 0x02; // Emit a cluster Events +} + +message Action { + ActionType type = 1; // ActionType above + uint32 delayMs = 2; // Delay and run action after xx ms + uint32 actionId = 3; // Align with Cluster Attribute/Event/Command ID + optional uint32 arg1 = 4; // 1st attribute + optional uint32 arg2 = 5; // 2nd attribute + optional uint32 arg3 = 6; // 3rd attribute +} + +message ActionsRequest { + uint32 endpoint_id = 1; + uint32 cluster_id = 2; + repeated Action actions = 3; // Actions including Attribute Write / Event / Command +} + +service Actions { + rpc Set(ActionsRequest) returns (pw.protobuf.Empty){} +} diff --git a/examples/common/pigweed/rpc_console/py/BUILD.gn b/examples/common/pigweed/rpc_console/py/BUILD.gn index a050fb64747302..a03dc980872739 100644 --- a/examples/common/pigweed/rpc_console/py/BUILD.gn +++ b/examples/common/pigweed/rpc_console/py/BUILD.gn @@ -39,6 +39,7 @@ pw_python_package("chip_rpc") { "$dir_pw_rpc/py", "$dir_pw_system/py", "$dir_pw_tokenizer/py", + "${chip_root}/examples/common/pigweed:actions_service.python", "${chip_root}/examples/common/pigweed:attributes_service.python", "${chip_root}/examples/common/pigweed:boolean_state_service.python", "${chip_root}/examples/common/pigweed:button_service.python", diff --git a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py index f5ed5b5ab4d582..1591722bfdbeab 100644 --- a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py +++ b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py @@ -46,6 +46,7 @@ # Protos # isort: off +from actions_service import actions_service_pb2 from attributes_service import attributes_service_pb2 from boolean_state_service import boolean_state_service_pb2 from button_service import button_service_pb2 @@ -128,6 +129,7 @@ def show_console(device: str, baudrate: int, # "set_wakeup_fd only works in main thread of the main interpreter" use_ipython=True, compiled_protos=[ + actions_service_pb2, attributes_service_pb2, boolean_state_service_pb2, button_service_pb2, diff --git a/examples/common/pigweed/rpc_services/Actions.h b/examples/common/pigweed/rpc_services/Actions.h new file mode 100644 index 00000000000000..a2cbba0cb49a7a --- /dev/null +++ b/examples/common/pigweed/rpc_services/Actions.h @@ -0,0 +1,127 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "actions_service/actions_service.rpc.pb.h" +#include "app/util/attribute-storage.h" +#include "pigweed/rpc_services/internal/StatusUtils.h" +#include +#include +#include + +namespace chip { +namespace rpc { + +class Actions final : public pw_rpc::nanopb::Actions::Service +{ + /* + * RPC Actions Service is a debugging interface for writting Attributes, emitting Events, or + * running Commands batchwisely. Each action will be execute one by one according to the + * delayed time in ms. + * + * An Action is a abstract type of Attribute, Command, Event + * type : this defines the action is either a Attribute, Command, or Event + * delayMs : this define the relative delayed time in ms after last action + * actionId : this defines the ID of Attribute, Command or Event + * arg1, arg2, arg3 : it has up to 3 optional arguments which could be mapped to Attribute/Command/Event aruments + * + * An Action Request is composed of a batch of Actions + * + * The usage of Actions Service: + * 1. Create an Action Request by protos.chip.rpc.ActionsWrite + * 2. Append Actions one by one to the action request + * 3. After all action added to the request, call rpcs.chip.rpc.Actions.Set to execute that + * + * e.g. In rpc_console: + * + * # Init a RPC Action request which is for endpoint 1 and Switch Cluster (0x003B) + * In [1]: request=protos.chip.rpc.ActionsWrite(endpoint_id=1, cluster_id=int("0x003B", 16)) + * + * # Add an action to write attribute id 0x1 (CurrentPosition) with data 2 after 1000 ms (meaning right away) + * In [2]: request.actions.append(protos.chip.rpc.Action(type=protos.chip.rpc.ActionType.WRITE_ATTRIBUTE, delayMs=1000, + * actionId=1, arg1=2)) + * + * # Define the follow action to emit an event id 0x1 (InitialPress) with data 2 (NewPosition) after 1000 ms + * In [3]: message.actions.append(protos.chip.rpc.Action(type=protos.chip.rpc.ActionType.EMIT_EVENT, delayMs=1000, + * actionId=1, arg1=2)) + * + * # Define the follow action to emit an event id 0x2 (LongPress) with data 2 (NewPosition) after 2000 ms + * In [4]: message.actions.append(protos.chip.rpc.Action(type=protos.chip.rpc.ActionType.EMIT_EVENT, delayMs=2000, + * actionId=2, arg1=2)) + * + * # Define an action to write attribute id 0x1 (CurrentPosition) with data 0 after 2000 ms (meaning button bouncing back) + * In [5]: message.actions.append(protos.chip.rpc.Action(type=protos.chip.rpc.ActionType.WRITE_ATTRIBUTE, delayMs=2000, + * actionId=1, arg1=0)) + * + * # Define the follow action to emit an event id 0x4 (LongRelease) with data 2 (PreviousPosition) after 1000 ms + * In [6]: message.actions.append(protos.chip.rpc.Action(type=protos.chip.rpc.ActionType.EMIT_EVENT, delayMs=1000, + * actionId=4, arg1=2)) + * + * # Set the actions to device + * In [7]: rpcs.chip.rpc.Actions.Set(message, pw_rpc_timeout_s=10000) + * + */ +public: + enum class Type : uint8_t + { + Attribute = 0, + Command = 1, + Event = 2, + }; + + ::pw::Status Set(const chip_rpc_ActionsRequest & request, ::pw_protobuf_Empty & response) + + { + DeviceLayer::StackLock lock; + ChipLogProgress(NotSpecified, " request.endpoint_id=%d, request.cluster_id=%d", request.endpoint_id, request.cluster_id); + + for (int i = 0; i < request.actions_count; i++) + { + chip_rpc_Action action = request.actions[i]; + std::vector args; + if (action.has_arg1) + args.push_back(action.arg1); + if (action.has_arg2) + args.push_back(action.arg2); + if (action.has_arg3) + args.push_back(action.arg3); + + mActionsSubscribeCallback(request.endpoint_id, request.cluster_id, static_cast(action.type), action.delayMs, + action.actionId, args); + } + + return pw::OkStatus(); + } + + using RpcActionsSubscribeCallback = bool (*)(EndpointId endpointId, ClusterId clusterId, uint8_t type, uint32_t delayMs, + uint32_t actionId, std::vector args); + + void SubscribeActions(RpcActionsSubscribeCallback subscriber) { mActionsSubscribeCallback = subscriber; }; + +private: + RpcActionsSubscribeCallback mActionsSubscribeCallback; +}; + +} // namespace rpc +} // namespace chip diff --git a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h index 447d2c2ae5ccf6..2deb7cfb4cac5e 100644 --- a/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h +++ b/examples/darwin-framework-tool/commands/clusters/ModelCommandBridge.h @@ -38,7 +38,7 @@ class ModelCommand : public CHIPCommandBridge /////////// CHIPCommand Interface ///////// CHIP_ERROR RunCommand() override; - chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); } + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(20); } virtual CHIP_ERROR SendCommand(MTRBaseDevice * _Nonnull device, chip::EndpointId endPointId) = 0; diff --git a/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm b/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm index c8594a6f4fa87c..9723199ed007a4 100644 --- a/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm +++ b/examples/darwin-framework-tool/commands/pairing/DeviceControllerDelegateBridge.mm @@ -22,7 +22,7 @@ @implementation CHIPToolDeviceControllerDelegate - (void)controller:(MTRDeviceController *)controller statusUpdate:(MTRCommissioningStatus)status { - NSLog(@"Pairing Status Update: %tu", status); + NSLog(@"Pairing Status Update: %ld", static_cast(status)); switch (status) { case MTRCommissioningStatusSuccess: ChipLogProgress(chipTool, "Secure Pairing Success"); diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index ea4e5db21a0b18..68db2eea271ec3 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -1237,7 +1237,7 @@ cluster GroupKeyManagement = 63 { } /** This cluster provides a mechanism for querying data about electrical power as measured by the server. */ -provisional cluster ElectricalPowerMeasurement = 144 { +cluster ElectricalPowerMeasurement = 144 { revision 1; enum MeasurementTypeEnum : enum16 { @@ -1342,7 +1342,7 @@ provisional cluster ElectricalPowerMeasurement = 144 { } /** This cluster provides a mechanism for querying data about the electrical energy imported or provided by the server. */ -provisional cluster ElectricalEnergyMeasurement = 145 { +cluster ElectricalEnergyMeasurement = 145 { revision 1; enum MeasurementTypeEnum : enum16 { @@ -1639,7 +1639,7 @@ provisional cluster DeviceEnergyManagement = 152 { } /** Electric Vehicle Supply Equipment (EVSE) is equipment used to charge an Electric Vehicle (EV) or Plug-In Hybrid Electric Vehicle. This cluster provides an interface to the functionality of Electric Vehicle Supply Equipment (EVSE) management. */ -provisional cluster EnergyEvse = 153 { +cluster EnergyEvse = 153 { revision 2; enum EnergyTransferStoppedReasonEnum : enum8 { @@ -1817,7 +1817,7 @@ provisional cluster EnergyEvse = 153 { } /** The Power Topology Cluster provides a mechanism for expressing how power is flowing between endpoints. */ -provisional cluster PowerTopology = 156 { +cluster PowerTopology = 156 { revision 1; bitmap Feature : bitmap32 { @@ -1838,7 +1838,7 @@ provisional cluster PowerTopology = 156 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster EnergyEvseMode = 157 { +cluster EnergyEvseMode = 157 { revision 1; enum ModeTag : enum16 { diff --git a/examples/lighting-app/infineon/cyw30739/README.md b/examples/lighting-app/infineon/cyw30739/README.md index 46589b1f1302e6..b1ff7aa5304902 100644 --- a/examples/lighting-app/infineon/cyw30739/README.md +++ b/examples/lighting-app/infineon/cyw30739/README.md @@ -214,19 +214,7 @@ Put the CYW30739 in to the recovery mode before running the flash script. [Openthread_border_router](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/openthread_border_router_pi.md) for more information on how to setup a border router on a raspberryPi. -- You can provision and control the Chip device using the python controller, - Chip tool standalone, Android or iOS app +- You can provision and control the device using the Python controller REPL, + chip-tool standalone, Android or iOS app [Python Controller](https://github.com/project-chip/connectedhomeip/blob/master/src/controller/python/README.md) - - Here is an example with the Python controller: - - ```bash - $ chip-device-ctrl - chip-device-ctrl > connect -ble 3840 20202021 1234 - chip-device-ctrl > zcl NetworkCommissioning AddThreadNetwork 1234 0 0 operationalDataset=hex:0e080000000000000000000300000b35060004001fffe00208dead00beef00cafe0708fddead00beef000005108e11d8ea8ffaa875713699f59e8807e0030a4f70656e5468726561640102c2980410edc641eb63b100b87e90a9980959befc0c0402a0fff8 breadcrumb=0 timeoutMs=1000 - chip-device-ctrl > zcl NetworkCommissioning EnableNetwork 1234 0 0 networkID=hex:dead00beef00cafe breadcrumb=0 timeoutMs=1000 - chip-device-ctrl > close-ble - chip-device-ctrl > resolve 1234 - chip-device-ctrl > zcl OnOff Toggle 1234 1 0 - ``` diff --git a/examples/lighting-app/python/README.md b/examples/lighting-app/python/README.md index 8e34e59dea5847..a935a165c93e4c 100644 --- a/examples/lighting-app/python/README.md +++ b/examples/lighting-app/python/README.md @@ -32,17 +32,6 @@ cd examples/lighting-app/python python lighting.py ``` -Control the Python lighting matter device: +Control the Python lighting matter device using the Python controller REPL: -```shell -source ./out/python_env/bin/activate - -chip-device-ctrl - -chip-device-ctrl > connect -ble 3840 20202021 12344321 -chip-device-ctrl > zcl NetworkCommissioning AddOrUpdateWiFiNetwork 12344321 0 0 ssid=str:YOUR_SSID credentials=str:YOUR_PASSWORD breadcrumb=0 -chip-device-ctrl > zcl NetworkCommissioning ConnectNetwork 12344321 0 0 networkID=str:YOUR_SSID breadcrumb=0 -chip-device-ctrl > close-ble -chip-device-ctrl > resolve 5544332211 1 (pass appropriate fabric ID and node ID, you can get this from get-fabricid) -chip-device-ctrl > zcl OnOff Toggle 12344321 1 0 -``` +[Python Controller](https://github.com/project-chip/connectedhomeip/blob/master/src/controller/python/README.md) diff --git a/examples/lighting-app/silabs/src/AppTask.cpp b/examples/lighting-app/silabs/src/AppTask.cpp index 338d6d85e2ef51..4f74ca7f348e78 100644 --- a/examples/lighting-app/silabs/src/AppTask.cpp +++ b/examples/lighting-app/silabs/src/AppTask.cpp @@ -24,7 +24,6 @@ #include "LEDWidget.h" #include -#include #include #include #include diff --git a/examples/lock-app/infineon/cyw30739/README.md b/examples/lock-app/infineon/cyw30739/README.md index 7f87af8792e6bc..2b7bd2094154df 100644 --- a/examples/lock-app/infineon/cyw30739/README.md +++ b/examples/lock-app/infineon/cyw30739/README.md @@ -214,19 +214,7 @@ Put the CYW30739 in to the recovery mode before running the flash script. [Openthread_border_router](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/openthread_border_router_pi.md) for more information on how to setup a border router on a raspberryPi. -- You can provision and control the Chip device using the python controller, - Chip tool standalone, Android or iOS app +- You can provision and control the device using the Python controller REPL, + chip-tool standalone, Android or iOS app [Python Controller](https://github.com/project-chip/connectedhomeip/blob/master/src/controller/python/README.md) - - Here is an example with the Python controller: - - ```bash - $ chip-device-ctrl - chip-device-ctrl > connect -ble 3840 20202021 1234 - chip-device-ctrl > zcl NetworkCommissioning AddThreadNetwork 1234 0 0 operationalDataset=hex:0e080000000000000000000300000b35060004001fffe00208dead00beef00cafe0708fddead00beef000005108e11d8ea8ffaa875713699f59e8807e0030a4f70656e5468726561640102c2980410edc641eb63b100b87e90a9980959befc0c0402a0fff8 breadcrumb=0 timeoutMs=1000 - chip-device-ctrl > zcl NetworkCommissioning EnableNetwork 1234 0 0 networkID=hex:dead00beef00cafe breadcrumb=0 timeoutMs=1000 - chip-device-ctrl > close-ble - chip-device-ctrl > resolve 1234 - chip-device-ctrl > zcl OnOff Toggle 1234 1 0 - ``` diff --git a/examples/lock-app/silabs/openthread.gni b/examples/lock-app/silabs/openthread.gni index 970d3a05c3aefc..3423049a9a8f79 100644 --- a/examples/lock-app/silabs/openthread.gni +++ b/examples/lock-app/silabs/openthread.gni @@ -28,7 +28,7 @@ openthread_external_platform = sl_enable_test_event_trigger = true # ICD Default configurations -chip_enable_icd_server = false +chip_enable_icd_server = true chip_subscription_timeout_resumption = false sl_use_subscription_syncing = true diff --git a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter index 40b3087bb836e3..bc4a43383fa2a9 100644 --- a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter +++ b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter @@ -1012,7 +1012,7 @@ cluster GroupKeyManagement = 63 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster MicrowaveOvenMode = 94 { +cluster MicrowaveOvenMode = 94 { revision 1; enum ModeTag : enum16 { @@ -1046,7 +1046,7 @@ provisional cluster MicrowaveOvenMode = 94 { } /** Attributes and commands for configuring the microwave oven control, and reporting cooking stats. */ -provisional cluster MicrowaveOvenControl = 95 { +cluster MicrowaveOvenControl = 95 { revision 1; // NOTE: Default/not specifically set bitmap Feature : bitmap32 { diff --git a/examples/network-manager-app/linux/main.cpp b/examples/network-manager-app/linux/main.cpp index 362ecb3100ad6a..ee6763a6d3d47d 100644 --- a/examples/network-manager-app/linux/main.cpp +++ b/examples/network-manager-app/linux/main.cpp @@ -16,13 +16,22 @@ */ #include +#include +#include +#include using namespace chip; using namespace chip::app; +using namespace chip::app::Clusters; void ApplicationInit() {} void ApplicationShutdown() {} +ByteSpan ByteSpanFromCharSpan(CharSpan span) +{ + return ByteSpan(Uint8::from_const_char(span.data()), span.size()); +} + int main(int argc, char * argv[]) { if (ChipLinuxAppInit(argc, argv) != 0) @@ -30,6 +39,9 @@ int main(int argc, char * argv[]) return -1; } + WiFiNetworkManagementServer::Instance().SetNetworkCredentials(ByteSpanFromCharSpan("MatterAP"_span), + ByteSpanFromCharSpan("Setec Astronomy"_span)); + ChipLinuxAppMainLoop(); return 0; } diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.matter b/examples/network-manager-app/network-manager-common/network-manager-app.matter index 8c935fbe9f9f08..935be20690a105 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.matter +++ b/examples/network-manager-app/network-manager-common/network-manager-app.matter @@ -1175,6 +1175,26 @@ cluster GroupKeyManagement = 63 { fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; } +/** Functionality to retrieve operational information about a managed Wi-Fi network. */ +cluster WiFiNetworkManagement = 1105 { + revision 1; + + readonly attribute nullable octet_string<32> ssid = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + response struct NetworkPassphraseResponse = 1 { + octet_string<64> passphrase = 0; + } + + /** Request the current WPA-Personal passphrase or PSK associated with the managed Wi-Fi network. */ + command access(invoke: administer) NetworkPassphraseRequest(): NetworkPassphraseResponse = 0; +} + endpoint 0 { device type ma_rootdevice = 22, version 1; @@ -1280,7 +1300,7 @@ endpoint 0 { callback attribute acceptedCommandList; callback attribute attributeList; callback attribute featureMap default = 0; - ram attribute clusterRevision default = 1; + callback attribute clusterRevision default = 0; } server cluster GeneralDiagnostics { @@ -1425,7 +1445,7 @@ endpoint 0 { } } endpoint 1 { - device type ma_network_infrastructure_manager = 4293984272, version 1; + device type ma_network_infrastructure_manager = 144, version 1; server cluster Descriptor { @@ -1440,6 +1460,19 @@ endpoint 1 { callback attribute featureMap; callback attribute clusterRevision; } + + server cluster WiFiNetworkManagement { + callback attribute ssid; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command NetworkPassphraseRequest; + handle command NetworkPassphraseResponse; + } } diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.zap b/examples/network-manager-app/network-manager-common/network-manager-app.zap index d144300c7dada7..46cb4b19598ca8 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.zap +++ b/examples/network-manager-app/network-manager-common/network-manager-app.zap @@ -1,6 +1,6 @@ { "fileFormat": 2, - "featureLevel": 100, + "featureLevel": 102, "creator": "zap", "keyValuePairs": [ { @@ -13,7 +13,7 @@ }, { "key": "manufacturerCodes", - "value": "0x1002" + "value": "0xFFF1" } ], "package": [ @@ -29,6 +29,7 @@ "pathRelativity": "relativeToZap", "path": "../../../src/app/zap-templates/app-templates.json", "type": "gen-templates-json", + "category": "matter", "version": "chip-v1" } ], @@ -1352,10 +1353,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "0", "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -3016,14 +3017,14 @@ "id": 2, "name": "Anonymous Endpoint Type", "deviceTypeRef": { - "code": 4293984272, + "code": 144, "profileId": 259, "label": "MA-network-infrastructure-manager", "name": "MA-network-infrastructure-manager" }, "deviceTypes": [ { - "code": 4293984272, + "code": 144, "profileId": 259, "label": "MA-network-infrastructure-manager", "name": "MA-network-infrastructure-manager" @@ -3033,10 +3034,10 @@ 1 ], "deviceIdentifiers": [ - 4293984272 + 144 ], "deviceTypeName": "MA-network-infrastructure-manager", - "deviceTypeCode": 4293984272, + "deviceTypeCode": 144, "deviceTypeProfileId": 259, "clusters": [ { @@ -3208,6 +3209,146 @@ "reportableChange": 0 } ] + }, + { + "name": "Wi-Fi Network Management", + "code": 1105, + "mfgCode": null, + "define": "WIFI_NETWORK_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "NetworkPassphraseRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NetworkPassphraseResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SSID", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] } ] } diff --git a/examples/platform/esp32/Rpc.cpp b/examples/platform/esp32/Rpc.cpp index 61efb842f089b7..a3b61830b5a46a 100644 --- a/examples/platform/esp32/Rpc.cpp +++ b/examples/platform/esp32/Rpc.cpp @@ -52,6 +52,10 @@ #include "pigweed/rpc_services/Device.h" #endif // defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE +#if defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE +#include "pigweed/rpc_services/Event.h" +#endif // defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + #if defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE #include "pigweed/rpc_services/Lighting.h" #endif // defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE @@ -275,6 +279,10 @@ static TaskHandle_t sRpcTaskHandle; StaticTask_t sRpcTaskBuffer; StackType_t sRpcTaskStack[RPC_TASK_STACK_SIZE]; +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +Actions actions_service; +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE Attributes attributes_service; #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -295,6 +303,10 @@ Descriptor descriptor_service; Esp32Device device_service; #endif // defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE +#if defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE +Event event_service; +#endif // defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + #if defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE Lighting lighting_service; #endif // defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE @@ -313,6 +325,10 @@ Esp32WiFi wifi_service; void RegisterServices(pw::rpc::Server & server) { +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + server.RegisterService(actions_service); +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE server.RegisterService(attributes_service); #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -333,6 +349,10 @@ void RegisterServices(pw::rpc::Server & server) server.RegisterService(device_service); #endif // defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE +#if defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + server.RegisterService(event_service); +#endif // defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + #if defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE server.RegisterService(lighting_service); #endif // defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE @@ -353,6 +373,13 @@ void RegisterServices(pw::rpc::Server & server) } // namespace +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +void SubscribeActions(RpcActionsSubscribeCallback subscriber) +{ + actions_service.SubscribeActions(subscriber); +} +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + void RunRpcService(void *) { Start(RegisterServices, &logger_mutex); diff --git a/examples/platform/esp32/Rpc.h b/examples/platform/esp32/Rpc.h index 9b73e5cafca96b..ff1a5f319ac975 100644 --- a/examples/platform/esp32/Rpc.h +++ b/examples/platform/esp32/Rpc.h @@ -20,6 +20,18 @@ namespace chip { namespace rpc { +enum class ActionType : uint8_t +{ + WRITE_ATTRIBUTE = 0x00, // Write an cluster Attribute + RUN_COMMAND = 0x01, // Run a cluster Command + EMIT_EVENT = 0x02, // Emit a cluster Events +}; + +using RpcActionsSubscribeCallback = bool (*)(EndpointId endpointId, ClusterId clusterId, uint8_t type, uint32_t delayMs, + uint32_t actionId, std::vector args); + +void SubscribeActions(RpcActionsSubscribeCallback subscriber); + void Init(); } // namespace rpc diff --git a/examples/platform/linux/Rpc.cpp b/examples/platform/linux/Rpc.cpp index da6b73b9135c13..6e20e2aecf61b9 100644 --- a/examples/platform/linux/Rpc.cpp +++ b/examples/platform/linux/Rpc.cpp @@ -20,8 +20,16 @@ #include "pw_rpc_system_server/rpc_server.h" #include "pw_rpc_system_server/socket.h" +#include #include +#include "Rpc.h" +#include + +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +#include "pigweed/rpc_services/Actions.h" +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE #include "pigweed/rpc_services/Attributes.h" #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -68,6 +76,10 @@ namespace chip { namespace rpc { namespace { +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +Actions actions_service; +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE Attributes attributes_service; #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -94,6 +106,10 @@ pw::trace::TraceService trace_service(pw::trace::GetTokenizedTracer()); void RegisterServices(pw::rpc::Server & server) { +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + server.RegisterService(actions_service); +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE server.RegisterService(attributes_service); #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -122,6 +138,13 @@ void RegisterServices(pw::rpc::Server & server) } // namespace +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +void SubscribeActions(RpcActionsSubscribeCallback subscriber) +{ + actions_service.SubscribeActions(subscriber); +} +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + void RunRpcService() { pw::rpc::system_server::Init(); diff --git a/examples/platform/linux/Rpc.h b/examples/platform/linux/Rpc.h index fbcfc6ed63f4f2..51f3f2e473bacb 100644 --- a/examples/platform/linux/Rpc.h +++ b/examples/platform/linux/Rpc.h @@ -18,9 +18,24 @@ #pragma once +#include +#include + namespace chip { namespace rpc { +enum class ActionType : uint8_t +{ + WRITE_ATTRIBUTE = 0x00, // Write an cluster Attribute + RUN_COMMAND = 0x01, // Run a cluster Command + EMIT_EVENT = 0x02, // Emit a cluster Events +}; + +using RpcActionsSubscribeCallback = bool (*)(EndpointId endpointId, ClusterId clusterId, uint8_t type, uint32_t delayMs, + uint32_t actionId, std::vector args); + +void SubscribeActions(RpcActionsSubscribeCallback subscriber); + int Init(uint16_t rpcServerPort); } // namespace rpc diff --git a/examples/platform/nrfconnect/Rpc.cpp b/examples/platform/nrfconnect/Rpc.cpp index 8b47215d6a0680..510b0ac8ac4c64 100644 --- a/examples/platform/nrfconnect/Rpc.cpp +++ b/examples/platform/nrfconnect/Rpc.cpp @@ -28,6 +28,10 @@ LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +#include "pigweed/rpc_services/Actions.h" +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE #include "pigweed/rpc_services/Attributes.h" #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -48,6 +52,10 @@ LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); #include "pigweed/rpc_services/Device.h" #endif // defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE +#if defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE +#include "pigweed/rpc_services/Event.h" +#endif // defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + #if defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE #include "pigweed/rpc_services/Lighting.h" #endif // defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE @@ -85,6 +93,10 @@ size_t pw_trace_GetTraceTimeTicksPerSecond() namespace chip { namespace rpc { +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +Actions actions_service; +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE namespace { @@ -159,6 +171,10 @@ Descriptor descriptor_service; NrfDevice device_service; #endif // defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE +#if defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE +Event event_service; +#endif // defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + #if defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE Lighting lighting_service; #endif // defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE @@ -181,6 +197,10 @@ pw::trace::TraceService trace_service(pw::trace::GetTokenizedTracer()); void RegisterServices(pw::rpc::Server & server) { +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + server.RegisterService(actions_service); +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + #if defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE server.RegisterService(attributes_service); #endif // defined(PW_RPC_ATTRIBUTE_SERVICE) && PW_RPC_ATTRIBUTE_SERVICE @@ -201,6 +221,10 @@ void RegisterServices(pw::rpc::Server & server) server.RegisterService(device_service); #endif // defined(PW_RPC_DEVICE_SERVICE) && PW_RPC_DEVICE_SERVICE +#if defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + server.RegisterService(event_service); +#endif // defined(PW_RPC_EVENT_SERVICE) && PW_RPC_EVENT_SERVICE + #if defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE server.RegisterService(lighting_service); #endif // defined(PW_RPC_LIGHTING_SERVICE) && PW_RPC_LIGHTING_SERVICE @@ -225,6 +249,13 @@ void RegisterServices(pw::rpc::Server & server) } // namespace +#if defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE +void SubscribeActions(RpcActionsSubscribeCallback subscriber) +{ + actions_service.SubscribeActions(subscriber); +} +#endif // defined(PW_RPC_ACTIONS_SERVICE) && PW_RPC_ACTIONS_SERVICE + void RunRpcService(void *, void *, void *) { Start(RegisterServices, &logger_mutex); diff --git a/examples/platform/nrfconnect/Rpc.h b/examples/platform/nrfconnect/Rpc.h index f0aeaf45b61fba..40efcb0750ca2b 100644 --- a/examples/platform/nrfconnect/Rpc.h +++ b/examples/platform/nrfconnect/Rpc.h @@ -23,6 +23,18 @@ namespace chip { namespace rpc { +enum class ActionType : uint8_t +{ + WRITE_ATTRIBUTE = 0x00, // Write an cluster Attribute + RUN_COMMAND = 0x01, // Run a cluster Command + EMIT_EVENT = 0x02, // Emit a cluster Events +}; + +using RpcActionsSubscribeCallback = bool (*)(EndpointId endpointId, ClusterId clusterId, uint8_t type, uint32_t delayMs, + uint32_t actionId, std::vector args); + +void SubscribeActions(RpcActionsSubscribeCallback subscriber); + class NrfButton; void RunRpcService(void *, void *, void *); diff --git a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp index a4a8d09396ae53..199ec7761be0c8 100644 --- a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp +++ b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp @@ -197,7 +197,7 @@ void ContentAppCommandDelegate::FormatResponseData(CommandHandlerInterface::Hand } else { - handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, launchResponse); + handlerContext.mCommandHandler.AddResponse(handlerContext.mRequestPath, launchResponse); } break; } @@ -211,7 +211,7 @@ void ContentAppCommandDelegate::FormatResponseData(CommandHandlerInterface::Hand } else { - handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, navigateTargetResponse); + handlerContext.mCommandHandler.AddResponse(handlerContext.mRequestPath, navigateTargetResponse); } break; } @@ -225,7 +225,7 @@ void ContentAppCommandDelegate::FormatResponseData(CommandHandlerInterface::Hand } else { - handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, playbackResponse); + handlerContext.mCommandHandler.AddResponse(handlerContext.mRequestPath, playbackResponse); } break; } @@ -244,7 +244,7 @@ void ContentAppCommandDelegate::FormatResponseData(CommandHandlerInterface::Hand } else { - handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, getSetupPINresponse); + handlerContext.mCommandHandler.AddResponse(handlerContext.mRequestPath, getSetupPINresponse); } break; } diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index 9a59e96c18355c..05ab2a03dbdb4f 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -52 : [NXP] Update K32W0 SDK to 2.6.14 \ No newline at end of file +53 : [Tizen] Add libatomic.so to QEMU Docker image diff --git a/integrations/docker/images/stage-3/chip-build-tizen-qemu/Dockerfile b/integrations/docker/images/stage-3/chip-build-tizen-qemu/Dockerfile index ff63e5c1940a01..8c38d19c1b3ed8 100644 --- a/integrations/docker/images/stage-3/chip-build-tizen-qemu/Dockerfile +++ b/integrations/docker/images/stage-3/chip-build-tizen-qemu/Dockerfile @@ -84,6 +84,7 @@ RUN set -x \ # Add extra libraries to the root image && guestfish --rw -a $TIZEN_IOT_IMAGE_ROOT -m /dev/sda copy-in \ $TIZEN_SDK_TOOLCHAIN/arm-tizen-linux-gnueabi/lib/libasan.so.* \ + $TIZEN_SDK_TOOLCHAIN/arm-tizen-linux-gnueabi/lib/libatomic.so.* \ $TIZEN_SDK_TOOLCHAIN/arm-tizen-linux-gnueabi/lib/libubsan.so.* \ $TIZEN_SDK_SYSROOT/usr/lib/libbluetooth-api.so.* \ $TIZEN_SDK_SYSROOT/usr/lib/libcapi-network-bluetooth.so.* \ diff --git a/ruff.toml b/ruff.toml index fec7608d707987..a33a97ef467d3c 100644 --- a/ruff.toml +++ b/ruff.toml @@ -15,5 +15,5 @@ line-length = 132 [lint] select = ["E4", "E7", "E9", "F"] ignore = [ - "E721" # We use is for good reasons + "E721" # We use it for good reasons ] diff --git a/scripts/rules.matterlint b/scripts/rules.matterlint index e876bae22094c6..037ed829a15a11 100644 --- a/scripts/rules.matterlint +++ b/scripts/rules.matterlint @@ -97,6 +97,7 @@ load "../src/app/zap-templates/zcl/data-model/chip/user-label-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/wake-on-lan-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/washer-controls-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/wifi-network-diagnostics-cluster.xml"; +load "../src/app/zap-templates/zcl/data-model/chip/wifi-network-management-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/window-covering.xml"; load "../src/app/zap-templates/zcl/data-model/chip/temperature-control-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/refrigerator-alarm.xml"; diff --git a/scripts/tools/bouffalolab/factory_qrcode.py b/scripts/tools/bouffalolab/factory_qrcode.py index 1a7f6303495775..0e12d8349d4c91 100644 --- a/scripts/tools/bouffalolab/factory_qrcode.py +++ b/scripts/tools/bouffalolab/factory_qrcode.py @@ -20,13 +20,13 @@ try: import qrcode - from generate_setup_payload import CommissioningFlow, SetupPayload + from SetupPayload import CommissioningFlow, SetupPayload except ImportError: SDK_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) sys.path.append(os.path.join(SDK_ROOT, "src/setup_payload/python")) try: import qrcode - from generate_setup_payload import CommissioningFlow, SetupPayload + from SetupPayload import CommissioningFlow, SetupPayload except ModuleNotFoundError or ImportError: no_onboarding_modules = True else: diff --git a/scripts/tools/generate_esp32_chip_factory_bin.py b/scripts/tools/generate_esp32_chip_factory_bin.py index 262be540a9bfed..eab2ec6b43c229 100755 --- a/scripts/tools/generate_esp32_chip_factory_bin.py +++ b/scripts/tools/generate_esp32_chip_factory_bin.py @@ -30,7 +30,7 @@ sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'scripts', 'tools', 'spake2p')) from spake2p import generate_verifier # noqa: E402 isort:skip sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'src', 'setup_payload', 'python')) -from generate_setup_payload import CommissioningFlow, SetupPayload # noqa: E402 isort:skip +from SetupPayload import CommissioningFlow, SetupPayload # noqa: E402 isort:skip if os.getenv('IDF_PATH'): sys.path.insert(0, os.path.join(os.getenv('IDF_PATH'), diff --git a/scripts/tools/linux_ip_namespace_setup.sh b/scripts/tools/linux_ip_namespace_setup.sh index 5d467b4b48c23e..f761eea3843fe8 100755 --- a/scripts/tools/linux_ip_namespace_setup.sh +++ b/scripts/tools/linux_ip_namespace_setup.sh @@ -124,7 +124,7 @@ function help() { echo "sudo /$file_name -r /" echo "" echo "Terminal 2:" - echo "/chip-device-ctrl" + echo "/chip-repl" echo "" echo "This script requires sudo for setup and requires access to ebtables-legacy" echo "to set up dual ipv4/ipv6 namespaces. Defaults to ipv6 only." diff --git a/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py b/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py index 78212cefd81e6e..ab70c69d7f9d53 100644 --- a/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py +++ b/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py @@ -32,13 +32,13 @@ try: import qrcode - from generate_setup_payload import CommissioningFlow, SetupPayload + from SetupPayload import CommissioningFlow, SetupPayload except ImportError: SDK_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) sys.path.append(os.path.join(SDK_ROOT, "src/setup_payload/python")) try: import qrcode - from generate_setup_payload import CommissioningFlow, SetupPayload + from SetupPayload import CommissioningFlow, SetupPayload except ModuleNotFoundError or ImportError: no_onboarding_modules = True else: diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 4bb4a05a555d39..f49a40f398842a 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -179,9 +179,6 @@ static_library("interaction-model") { "ReadClient.h", # TODO: cpp is only included conditionally. Needs logic # fixing "ReadPrepareParams.h", - "RequiredPrivilege.h", - "StatusResponse.cpp", - "StatusResponse.h", "SubscriptionResumptionStorage.h", "TimedHandler.cpp", "TimedHandler.h", @@ -210,6 +207,7 @@ static_library("interaction-model") { public_deps = [ ":app_config", + ":command-handler", ":constants", ":paths", ":subscription-info-provider", @@ -248,8 +246,6 @@ static_library("interaction-model") { "dynamic_server/AccessControl.cpp", "dynamic_server/AccessControl.h", "dynamic_server/DynamicDispatcher.cpp", - "util/privilege-storage.cpp", - "util/privilege-storage.h", ] public_deps += [ @@ -301,6 +297,62 @@ static_library("attribute-access") { ] } +source_set("required-privileges") { + sources = [ "RequiredPrivilege.h" ] + + public_deps = [ + ":paths", + "${chip_root}/src/access:types", + ] + + if (chip_build_controller_dynamic_server) { + sources += [ + "util/privilege-storage.cpp", + "util/privilege-storage.h", + ] + + public_deps += [ + ":global-attributes", + "${chip_root}/src/access", + "${chip_root}/src/app/dynamic_server:mock-codegen-includes", + ] + + public_configs = [ ":config-controller-dynamic-server" ] + } +} + +source_set("status-response") { + sources = [ + "StatusResponse.cpp", + "StatusResponse.h", + ] + public_deps = [ + ":constants", + "${chip_root}/src/app/MessageDef", + "${chip_root}/src/messaging", + ] +} + +source_set("command-handler") { + sources = [ + "CommandHandler.cpp", + "CommandHandler.h", + "CommandHandlerExchangeInterface.h", + ] + + public_deps = [ + ":paths", + ":required-privileges", + ":status-response", + "${chip_root}/src/access:types", + "${chip_root}/src/app/MessageDef", + "${chip_root}/src/app/data-model", + "${chip_root}/src/app/util:callbacks", + "${chip_root}/src/lib/support", + "${chip_root}/src/messaging", + ] +} + # Note to developpers, instead of continuously adding files in the app librabry, it is recommand to create smaller source_sets that app can depend on. # This way, we can have a better understanding of dependencies and other componenets can depend on the different source_sets without needing to depend on the entire app library. static_library("app") { @@ -312,8 +364,6 @@ static_library("app") { "AttributePersistenceProvider.h", "ChunkedWriteCallback.cpp", "ChunkedWriteCallback.h", - "CommandHandler.cpp", - "CommandHandlerExchangeInterface.h", "CommandResponseHelper.h", "CommandResponseSender.cpp", "DefaultAttributePersistenceProvider.cpp", @@ -338,7 +388,6 @@ static_library("app") { # (app depending on im and im including these headers): # Name with _ so that linter does not recognize it # "CommandResponseSender._h" - # "CommandHandler._h" # "ReadHandler._h", # "WriteHandler._h" ] diff --git a/src/app/CASESessionManager.cpp b/src/app/CASESessionManager.cpp index 162ae7021a9f9f..dc2656338d791a 100644 --- a/src/app/CASESessionManager.cpp +++ b/src/app/CASESessionManager.cpp @@ -29,6 +29,11 @@ CHIP_ERROR CASESessionManager::Init(chip::System::Layer * systemLayer, const CAS return AddressResolve::Resolver::Instance().Init(systemLayer); } +void CASESessionManager::Shutdown() +{ + AddressResolve::Resolver::Instance().Shutdown(); +} + void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, Callback::Callback * onFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES diff --git a/src/app/CASESessionManager.h b/src/app/CASESessionManager.h index 38b39108b43b7e..e536a62cf80908 100644 --- a/src/app/CASESessionManager.h +++ b/src/app/CASESessionManager.h @@ -59,7 +59,7 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess } CHIP_ERROR Init(chip::System::Layer * systemLayer, const CASESessionManagerConfig & params); - void Shutdown() {} + void Shutdown(); /** * Find an existing session for the given node ID, or trigger a new session diff --git a/src/app/CommandHandler.cpp b/src/app/CommandHandler.cpp index 86ef22ab886212..6077e0934721f7 100644 --- a/src/app/CommandHandler.cpp +++ b/src/app/CommandHandler.cpp @@ -15,21 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file - * This file defines object for a CHIP IM Invoke Command Handler - * - */ - -#include "CommandHandler.h" -#include "InteractionModelEngine.h" -#include "RequiredPrivilege.h" -#include "messaging/ExchangeContext.h" +#include #include #include #include +#include #include #include #include @@ -37,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/src/app/CommandHandler.h b/src/app/CommandHandler.h index cce19879a6c8a9..b06064c46a69be 100644 --- a/src/app/CommandHandler.h +++ b/src/app/CommandHandler.h @@ -30,9 +30,8 @@ #pragma once -#include "CommandPathRegistry.h" - #include +#include #include #include #include @@ -57,6 +56,32 @@ namespace chip { namespace app { +/// Defines an abstract class of something that can be encoded +/// into a TLV with a given data tag +class EncoderToTLV +{ +public: + virtual ~EncoderToTLV() = default; + + virtual CHIP_ERROR Encode(TLV::TLVWriter &, TLV::Tag tag) = 0; +}; + +/// An `EncoderToTLV` the uses `DataModel::Encode` to encode things. +/// +/// Generally useful to encode things like ::Commands::::Type +/// structures. +template +class DataModelEncoderToTLV : public EncoderToTLV +{ +public: + DataModelEncoderToTLV(const T & value) : mValue(value) {} + + virtual CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag) { return DataModel::Encode(writer, tag, mValue); } + +private: + const T & mValue; +}; + class CommandHandler { public: @@ -325,14 +350,37 @@ class CommandHandler * @param [in] aRequestCommandPath the concrete path of the command we are * responding to. * @param [in] aData the data for the response. + * + * NOTE: this is a convenience function for `AddResponseDataViaEncoder` */ template - CHIP_ERROR AddResponseData(const ConcreteCommandPath & aRequestCommandPath, const CommandData & aData) + inline CHIP_ERROR AddResponseData(const ConcreteCommandPath & aRequestCommandPath, const CommandData & aData) + { + DataModelEncoderToTLV encoder(aData); + return AddResponseDataViaEncoder(aRequestCommandPath, CommandData::GetCommandId(), encoder); + } + + /** + * API for adding a data response. The encoded is generally expected to encode + * a ClusterName::Commands::CommandName::Type struct, but any + * object should work. + * + * @param [in] aRequestCommandPath the concrete path of the command we are + * responding to. + * @param [in] commandId the command whose content is being encoded. + * @param [in] encoder - an encoder that places the command data structure for `commandId` + * into a TLV Writer. + * + * Most applications are likely to use `AddResponseData` as a more convenient + * one-call that auto-sets command ID and creates the underlying encoders. + */ + CHIP_ERROR AddResponseDataViaEncoder(const ConcreteCommandPath & aRequestCommandPath, CommandId commandId, + EncoderToTLV & encoder) { // Return early when response should not be sent out. VerifyOrReturnValue(ResponsesAccepted(), CHIP_NO_ERROR); - - return TryAddingResponse([&]() -> CHIP_ERROR { return TryAddResponseData(aRequestCommandPath, aData); }); + return TryAddingResponse( + [&]() -> CHIP_ERROR { return TryAddResponseDataViaEncoder(aRequestCommandPath, commandId, encoder); }); } /** @@ -350,9 +398,21 @@ class CommandHandler * @param [in] aData the data for the response. */ template - void AddResponse(const ConcreteCommandPath & aRequestCommandPath, const CommandData & aData) + inline void AddResponse(const ConcreteCommandPath & aRequestCommandPath, const CommandData & aData) { - if (AddResponseData(aRequestCommandPath, aData) != CHIP_NO_ERROR) + DataModelEncoderToTLV encoder(aData); + return AddResponseViaEncoder(aRequestCommandPath, CommandData::GetCommandId(), encoder); + } + + /** + * API for adding a response with a given encoder of TLV data. + * + * The encoder would generally encode a ClusterName::Commands::CommandName::Type with + * the corresponding `GetCommandId` call. + */ + void AddResponseViaEncoder(const ConcreteCommandPath & aRequestCommandPath, CommandId commandId, EncoderToTLV & encoder) + { + if (AddResponseDataViaEncoder(aRequestCommandPath, commandId, encoder) != CHIP_NO_ERROR) { AddStatus(aRequestCommandPath, Protocols::InteractionModel::Status::Failure); } @@ -630,7 +690,6 @@ class CommandHandler return PrepareInvokeResponseCommand(aResponseCommandPath, prepareParams); } - // TODO(#31627): It would be awesome if we could remove this template all together. /** * If this function fails, it may leave our TLV buffer in an inconsistent state. * Callers should snapshot as needed before calling this function, and roll back @@ -640,26 +699,14 @@ class CommandHandler * responding to. * @param [in] aData the data for the response. */ - template - CHIP_ERROR TryAddResponseData(const ConcreteCommandPath & aRequestCommandPath, const CommandData & aData) + CHIP_ERROR TryAddResponseDataViaEncoder(const ConcreteCommandPath & aRequestCommandPath, CommandId commandId, + EncoderToTLV & encoder) { - // This method, templated with CommandData, captures all the components needs - // from CommandData with as little code as possible. - // - // Previously, non-essential code was unnecessarily templated, leading to - // compilation and duplication N times. By isolating only the code segments - // that genuinely require templating, minimizes duplicate compiled code. - ConcreteCommandPath responseCommandPath = { aRequestCommandPath.mEndpointId, aRequestCommandPath.mClusterId, - CommandData::GetCommandId() }; + ConcreteCommandPath responseCommandPath = { aRequestCommandPath.mEndpointId, aRequestCommandPath.mClusterId, commandId }; ReturnErrorOnFailure(TryAddResponseDataPreEncode(aRequestCommandPath, responseCommandPath)); TLV::TLVWriter * writer = GetCommandDataIBTLVWriter(); VerifyOrReturnError(writer != nullptr, CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(DataModel::Encode(*writer, TLV::ContextTag(CommandDataIB::Tag::kFields), aData)); - - // FinishCommand technically should be refactored out as it is not a command that needs templating. - // But, because there is only a single function call, keeping it here takes less code. If there is - // ever more code between DataModel::Encode and the end of this function, it should be broken out into - // TryAddResponseDataPostEncode. + ReturnErrorOnFailure(encoder.Encode(*writer, TLV::ContextTag(CommandDataIB::Tag::kFields))); return FinishCommand(/* aEndDataStruct = */ false); } diff --git a/src/app/CommandHandlerInterface.h b/src/app/CommandHandlerInterface.h index 6ec2547befa1d0..d36a41e37f076c 100644 --- a/src/app/CommandHandlerInterface.h +++ b/src/app/CommandHandlerInterface.h @@ -23,8 +23,10 @@ #include #include #include // So we can encode lists +#include #include #include +#include namespace chip { namespace app { diff --git a/src/app/OperationalSessionSetup.cpp b/src/app/OperationalSessionSetup.cpp index 5733a423702226..9197a2edbddf70 100644 --- a/src/app/OperationalSessionSetup.cpp +++ b/src/app/OperationalSessionSetup.cpp @@ -792,6 +792,11 @@ CHIP_ERROR OperationalSessionSetup::ScheduleSessionSetupReattempt(System::Clock: // but in practice for old devices BUSY often sends some hardcoded value // that tells us nothing about when the other side will decide it has // timed out. + // + // Unfortunately, we do not have the MRP config for the other side here, + // but in practice if the other side is using its local config to + // compute Sigma2 response timeouts, then it's also returning useful + // values with BUSY, so we will wait long enough. auto additionalTimeout = CASESession::ComputeSigma2ResponseTimeout(GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig())); actualTimerDelay += additionalTimeout; } diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp index e8ada20a428c70..bb058e091858c7 100644 --- a/src/app/ReadClient.cpp +++ b/src/app/ReadClient.cpp @@ -938,24 +938,26 @@ CHIP_ERROR ReadClient::ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * // // To calculate the duration we're willing to wait for a report to come to us, we take into account the maximum interval of - // the subscription AND the time it takes for the report to make it to us in the worst case. This latter bit involves - // computing the Ack timeout from the publisher for the ReportData message being sent to us using our IDLE interval as the - // basis for that computation. + // the subscription AND the time it takes for the report to make it to us in the worst case. // - // Make sure to use the retransmission computation that includes backoff. For purposes of that computation, treat us as - // active now (since we are right now sending/receiving messages), and use the default "how long are we guaranteed to stay - // active" threshold for now. + // We have no way to estimate what the network latency will be, but we do know the other side will time out its ReportData + // after its computed round-trip timeout plus the processing time it gives us (app::kExpectedIMProcessingTime). Once it + // times out, assuming it sent the report at all, there's no point in us thinking we still have a subscription. // - // TODO: We need to find a good home for this logic that will correctly compute this based on transport. For now, this will - // suffice since we don't use TCP as a transport currently and subscriptions over BLE aren't really a thing. + // We can't use ComputeRoundTripTimeout() on the session for two reasons: we want the roundtrip timeout from the point of + // view of the peer, not us, and we want to start off with the assumption the peer will likely have, which is that we are + // idle, whereas ComputeRoundTripTimeout() uses the current activity state of the peer. // - const auto & localMRPConfig = GetLocalMRPConfig(); - const auto & defaultMRPConfig = GetDefaultMRPConfig(); - const auto & ourMrpConfig = localMRPConfig.ValueOr(defaultMRPConfig); - auto publisherTransmissionTimeout = - GetRetransmissionTimeout(ourMrpConfig.mActiveRetransTimeout, ourMrpConfig.mIdleRetransTimeout, - System::SystemClock().GetMonotonicTimestamp(), ourMrpConfig.mActiveThresholdTime); - *aTimeout = System::Clock::Seconds16(mMaxInterval) + publisherTransmissionTimeout; + // So recompute the round-trip timeout directly. Assume MRP, since in practice that is likely what is happening. + auto & peerMRPConfig = mReadPrepareParams.mSessionHolder->GetRemoteMRPConfig(); + // Peer will assume we are idle (hence we pass kZero to GetMessageReceiptTimeout()), but will assume we treat it as active + // for the response, so to match the retransmission timeout computation for the message back to the peeer, we should treat + // it as active. + auto roundTripTimeout = mReadPrepareParams.mSessionHolder->GetMessageReceiptTimeout(System::Clock::kZero) + + kExpectedIMProcessingTime + + GetRetransmissionTimeout(peerMRPConfig.mActiveRetransTimeout, peerMRPConfig.mIdleRetransTimeout, + System::SystemClock().GetMonotonicTimestamp(), peerMRPConfig.mActiveThresholdTime); + *aTimeout = System::Clock::Seconds16(mMaxInterval) + roundTripTimeout; return CHIP_NO_ERROR; } diff --git a/src/app/clusters/color-control-server/color-control-server.cpp b/src/app/clusters/color-control-server/color-control-server.cpp index 508f4b691bb0d1..784bca88b85955 100644 --- a/src/app/clusters/color-control-server/color-control-server.cpp +++ b/src/app/clusters/color-control-server/color-control-server.cpp @@ -431,15 +431,16 @@ ColorControlServer & ColorControlServer::Instance() return instance; } +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT chip::scenes::SceneHandler * ColorControlServer::GetSceneHandler() { - -#if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS +#if CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS return &sColorControlSceneHandler; #else return nullptr; -#endif // defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS +#endif // CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS } +#endif // ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT bool ColorControlServer::HasFeature(chip::EndpointId endpoint, Feature feature) { diff --git a/src/app/clusters/color-control-server/color-control-server.h b/src/app/clusters/color-control-server/color-control-server.h index 72dabb5600ff33..f453c6f02872e4 100644 --- a/src/app/clusters/color-control-server/color-control-server.h +++ b/src/app/clusters/color-control-server/color-control-server.h @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,10 @@ #include #include +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT +#include +#endif + /********************************************************** * Defines and Macros *********************************************************/ @@ -134,7 +137,9 @@ class ColorControlServer *********************************************************/ static ColorControlServer & Instance(); +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT chip::scenes::SceneHandler * GetSceneHandler(); +#endif bool HasFeature(chip::EndpointId endpoint, Feature feature); chip::Protocols::InteractionModel::Status stopAllColorTransitions(chip::EndpointId endpoint); @@ -272,7 +277,9 @@ class ColorControlServer EmberEventControl eventControls[kColorControlClusterServerMaxEndpointCount]; +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT friend class DefaultColorControlSceneHandler; +#endif }; /********************************************************** diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index b93bf50927c5eb..2ee9f2cfa54c04 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -608,14 +608,16 @@ Status MoveToLevel(EndpointId endpointId, const Commands::MoveToLevel::Decodable INVALID_STORED_LEVEL); // Don't revert to the stored level } +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT chip::scenes::SceneHandler * GetSceneHandler() { -#if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS +#if CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS return &sLevelControlSceneHandler; #else return nullptr; -#endif // defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS +#endif // CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS } +#endif // ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT } // namespace LevelControlServer diff --git a/src/app/clusters/level-control/level-control.h b/src/app/clusters/level-control/level-control.h index 95497cc117e6d2..0240c921acd8b4 100644 --- a/src/app/clusters/level-control/level-control.h +++ b/src/app/clusters/level-control/level-control.h @@ -28,9 +28,12 @@ #include #include -#include #include +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT +#include +#endif + /** @brief Level Control Cluster Server Post Init * * Following resolution of the Level Control state at startup for this endpoint, perform any @@ -53,6 +56,8 @@ chip::Protocols::InteractionModel::Status MoveToLevel(chip::EndpointId endpointId, const chip::app::Clusters::LevelControl::Commands::MoveToLevel::DecodableType & commandData); +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT chip::scenes::SceneHandler * GetSceneHandler(); +#endif } // namespace LevelControlServer diff --git a/src/app/clusters/on-off-server/on-off-server.cpp b/src/app/clusters/on-off-server/on-off-server.cpp index bc71044ae44075..aadac6c6e2e630 100644 --- a/src/app/clusters/on-off-server/on-off-server.cpp +++ b/src/app/clusters/on-off-server/on-off-server.cpp @@ -15,6 +15,8 @@ * limitations under the License. */ +#include + #include "on-off-server.h" #include @@ -299,15 +301,16 @@ OnOffServer & OnOffServer::Instance() return instance; } +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT chip::scenes::SceneHandler * OnOffServer::GetSceneHandler() { - -#if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS +#if CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS return &sOnOffSceneHandler; #else return nullptr; -#endif // defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS +#endif // CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS } +#endif // ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT bool OnOffServer::HasFeature(chip::EndpointId endpoint, Feature feature) { diff --git a/src/app/clusters/on-off-server/on-off-server.h b/src/app/clusters/on-off-server/on-off-server.h index 2cb5b62958a6c7..9bf8a5d4b03208 100644 --- a/src/app/clusters/on-off-server/on-off-server.h +++ b/src/app/clusters/on-off-server/on-off-server.h @@ -20,12 +20,15 @@ #include #include #include -#include #include #include #include #include +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT +#include +#endif + /********************************************************** * Defines and Macros *********************************************************/ @@ -50,7 +53,9 @@ class OnOffServer static OnOffServer & Instance(); +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT chip::scenes::SceneHandler * GetSceneHandler(); +#endif bool offCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath); bool onCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath); @@ -97,7 +102,9 @@ class OnOffServer static OnOffServer instance; chip::System::Clock::Timestamp nextDesiredOnWithTimedOffTimestamp; +#ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT friend class DefaultOnOffSceneHandler; +#endif }; struct OnOffEffect diff --git a/src/app/clusters/wifi-network-management-server/wifi-network-management-server.cpp b/src/app/clusters/wifi-network-management-server/wifi-network-management-server.cpp new file mode 100644 index 00000000000000..1a739e354bd3df --- /dev/null +++ b/src/app/clusters/wifi-network-management-server/wifi-network-management-server.cpp @@ -0,0 +1,176 @@ +/** + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wifi-network-management-server.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::WiFiNetworkManagement::Attributes; +using namespace chip::app::Clusters::WiFiNetworkManagement::Commands; +using namespace std::placeholders; + +namespace chip { +namespace app { +namespace Clusters { + +namespace { + +// TODO: Move this into lib/support somewhere and also use it network-commissioning.cpp +bool IsValidWpaPersonalCredential(ByteSpan credential) +{ + // As per spec section 11.9.7.3. AddOrUpdateWiFiNetwork Command + if (8 <= credential.size() && credential.size() <= 63) // passphrase + { + return true; + } + if (credential.size() == 64) // raw hex psk + { + return std::all_of(credential.begin(), credential.end(), [](auto c) { return std::isxdigit(c); }); + } + return false; +} + +Global gWiFiNetworkManagementServerInstance; + +} // namespace + +WiFiNetworkManagementServer & WiFiNetworkManagementServer::Instance() +{ + return gWiFiNetworkManagementServerInstance.get(); +} + +WiFiNetworkManagementServer::WiFiNetworkManagementServer() : + AttributeAccessInterface(NullOptional, WiFiNetworkManagement::Id), + CommandHandlerInterface(NullOptional, WiFiNetworkManagement::Id) +{} + +WiFiNetworkManagementServer::~WiFiNetworkManagementServer() +{ + unregisterAttributeAccessOverride(this); + InteractionModelEngine::GetInstance()->UnregisterCommandHandler(this); +} + +CHIP_ERROR WiFiNetworkManagementServer::Init(EndpointId endpoint) +{ + VerifyOrReturnError(endpoint != kInvalidEndpointId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(mEndpointId == kInvalidEndpointId, CHIP_ERROR_INCORRECT_STATE); + + mEndpointId = endpoint; + VerifyOrReturnError(registerAttributeAccessOverride(this), CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->RegisterCommandHandler(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiNetworkManagementServer::ClearNetworkCredentials() +{ + VerifyOrReturnError(HaveNetworkCredentials(), CHIP_NO_ERROR); + + mSsidLen = 0; + mPassphrase.SetLength(0); + MatterReportingAttributeChangeCallback(mEndpointId, WiFiNetworkManagement::Id, Ssid::Id); + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiNetworkManagementServer::SetNetworkCredentials(ByteSpan ssid, ByteSpan passphrase) +{ + VerifyOrReturnError(1 <= ssid.size() && ssid.size() <= sizeof(mSsid), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsValidWpaPersonalCredential(passphrase), CHIP_ERROR_INVALID_ARGUMENT); + + bool ssidChanged = !SsidSpan().data_equal(ssid); + bool passphraseChanged = !PassphraseSpan().data_equal(passphrase); + VerifyOrReturnError(ssidChanged || passphraseChanged, CHIP_NO_ERROR); + + memcpy(mSsid, ssid.data(), ssid.size()); + mSsidLen = static_cast(ssid.size()); + + VerifyOrDie(mPassphrase.SetLength(passphrase.size()) == CHIP_NO_ERROR); + memcpy(mPassphrase.Bytes(), passphrase.data(), passphrase.size()); + + // Note: The spec currently defines no way to signal a passphrase change + if (ssidChanged) + { + MatterReportingAttributeChangeCallback(mEndpointId, WiFiNetworkManagement::Id, Ssid::Id); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiNetworkManagementServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + switch (aPath.mAttributeId) + { + case Ssid::Id: + return HaveNetworkCredentials() ? aEncoder.Encode(SsidSpan()) : aEncoder.EncodeNull(); + } + return CHIP_NO_ERROR; +} + +void WiFiNetworkManagementServer::InvokeCommand(HandlerContext & ctx) +{ + switch (ctx.mRequestPath.mCommandId) + { + case NetworkPassphraseRequest::Id: + HandleCommand( + ctx, [this](HandlerContext & aCtx, const auto & req) { HandleNetworkPassphraseRequest(aCtx, req); }); + return; + } +} + +void WiFiNetworkManagementServer::HandleNetworkPassphraseRequest(HandlerContext & ctx, + const NetworkPassphraseRequest::DecodableType & req) +{ + if (HaveNetworkCredentials()) + { + NetworkPassphraseResponse::Type response; + response.passphrase = mPassphrase.Span(); + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); + } + else + { + // TODO: Status code TBC: https://github.com/CHIP-Specifications/connectedhomeip-spec/issues/9234 + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidInState); + } +} + +} // namespace Clusters +} // namespace app +} // namespace chip + +#if defined(MATTER_DM_WIFI_NETWORK_MANAGEMENT_CLUSTER_SERVER_ENDPOINT_COUNT) && \ + MATTER_DM_WIFI_NETWORK_MANAGEMENT_CLUSTER_SERVER_ENDPOINT_COUNT > 1 +#error Only a single Wi-Fi Network Management Cluster instance is supported. +#endif + +void MatterWiFiNetworkManagementPluginServerInitCallback() {} + +void emberAfWiFiNetworkManagementClusterServerInitCallback(EndpointId endpoint) +{ + // We could delay constructing the instance until this point; however it's not + // clear if this is inconvenient in terms of forcing the application to initialize + // the network credentials later than it otherwise would. + LogErrorOnFailure(chip::app::Clusters::WiFiNetworkManagementServer::Instance().Init(endpoint)); +} diff --git a/src/app/clusters/wifi-network-management-server/wifi-network-management-server.h b/src/app/clusters/wifi-network-management-server/wifi-network-management-server.h new file mode 100644 index 00000000000000..aa3cba89636a77 --- /dev/null +++ b/src/app/clusters/wifi-network-management-server/wifi-network-management-server.h @@ -0,0 +1,74 @@ +/** + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +void emberAfWiFiNetworkManagementClusterServerInitCallback(chip::EndpointId); + +namespace chip { +namespace app { +namespace Clusters { + +class WiFiNetworkManagementServer : private AttributeAccessInterface, private CommandHandlerInterface +{ +public: + static WiFiNetworkManagementServer & Instance(); + + CHIP_ERROR ClearNetworkCredentials(); + CHIP_ERROR SetNetworkCredentials(ByteSpan ssid, ByteSpan passphrase); + +private: + friend Global; + friend void ::emberAfWiFiNetworkManagementClusterServerInitCallback(chip::EndpointId); + + WiFiNetworkManagementServer(); + ~WiFiNetworkManagementServer(); + CHIP_ERROR Init(EndpointId endpoint); + + WiFiNetworkManagementServer(WiFiNetworkManagementServer const &) = delete; + WiFiNetworkManagementServer & operator=(WiFiNetworkManagementServer const &) = delete; + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + void InvokeCommand(HandlerContext & handlerContext) override; + + void HandleNetworkPassphraseRequest(HandlerContext & ctx, + const WiFiNetworkManagement::Commands::NetworkPassphraseRequest::DecodableType & req); + + EndpointId mEndpointId = kInvalidEndpointId; + + uint8_t mSsid[32]; + uint8_t mSsidLen = 0; + static_assert(std::numeric_limits::max() >= sizeof(mSsid)); + ByteSpan SsidSpan() const { return ByteSpan(mSsid, mSsidLen); } + + Crypto::SensitiveDataBuffer<64> mPassphrase; + ByteSpan PassphraseSpan() const { return mPassphrase.Span(); } + + bool HaveNetworkCredentials() { return mSsidLen > 0; } +}; + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index 875cdbcdbd1514..83d1b682153ed7 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -40,6 +40,7 @@ CommandHandlerInterfaceOnlyClusters: - Device Energy Management Mode - Electrical Power Measurement - Electrical Energy Measurement + - Wi-Fi Network Management # We need a more configurable way of deciding which clusters have which init functions.... # See https://github.com/project-chip/connectedhomeip/issues/4369 @@ -57,6 +58,7 @@ ClustersWithInitFunctions: - Mode Select - Sample MEI - Scenes Management + - Wi-Fi Network Management ClustersWithAttributeChangedFunctions: - Bridged Device Basic diff --git a/src/app/tests/suites/certification/Test_TC_CADMIN_1_5.yaml b/src/app/tests/suites/certification/Test_TC_CADMIN_1_5.yaml index 83c3617ab23343..8efb3b86885c5e 100644 --- a/src/app/tests/suites/certification/Test_TC_CADMIN_1_5.yaml +++ b/src/app/tests/suites/certification/Test_TC_CADMIN_1_5.yaml @@ -186,7 +186,7 @@ tests: [1663841939.843550][13897:13897] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1663841939.843617][13897:13897] CHIP:DL: Inet Layer shutdown - [1663841939.843673][13897:13897] CHIP:DL: BLE shutdown + [1663841939.843673][13897:13897] CHIP:DL: BLE Layer shutdown [1663841939.843727][13897:13897] CHIP:DL: System Layer shutdown [1663841939.844009][13897:13897] CHIP:TOO: Run command failure: ../../examples/chip-tool/commands/pairing/PairingCommand.cpp:151: CHIP Error 0x00000003: Incorrect state cluster: "LogCommands" diff --git a/src/app/tests/suites/certification/Test_TC_CADMIN_1_7.yaml b/src/app/tests/suites/certification/Test_TC_CADMIN_1_7.yaml index b7518730e87f65..f684e6090415ca 100644 --- a/src/app/tests/suites/certification/Test_TC_CADMIN_1_7.yaml +++ b/src/app/tests/suites/certification/Test_TC_CADMIN_1_7.yaml @@ -102,7 +102,7 @@ tests: [1663841939.843550][13897:13897] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1663841939.843617][13897:13897] CHIP:DL: Inet Layer shutdown - [1663841939.843673][13897:13897] CHIP:DL: BLE shutdown + [1663841939.843673][13897:13897] CHIP:DL: BLE Layer shutdown [1663841939.843727][13897:13897] CHIP:DL: System Layer shutdown [1663841939.844009][13897:13897] CHIP:TOO: Run command failure: ../../examples/chip-tool/commands/pairing/PairingCommand.cpp:151: CHIP Error 0x00000003: Incorrect state disabled: true @@ -161,7 +161,7 @@ tests: [1665481996.786704][4913:4913] CHIP:DL: renamed tmp file to file (/tmp/chip_counters.ini) [1665481996.786930][4913:4913] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1665481996.786999][4913:4913] CHIP:DL: Inet Layer shutdown - [1665481996.787065][4913:4913] CHIP:DL: BLE shutdown + [1665481996.787065][4913:4913] CHIP:DL: BLE Layer shutdown [1665481996.787123][4913:4913] CHIP:DL: System Layer shutdown [1665481996.787363][4913:4913] CHIP:TOO: Run command failure: ../../commands/pairing/PairingCommand.cpp:164: CHIP Error 0x00000003: Incorrect state disabled: true @@ -284,7 +284,7 @@ tests: [1678796869.645576][648903:648903] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1678796869.645584][648903:648903] CHIP:DL: Inet Layer shutdown - [1678796869.645589][648903:648903] CHIP:DL: BLE shutdown + [1678796869.645589][648903:648903] CHIP:DL: BLE Layer shutdown [1678796869.645596][648903:648903] CHIP:DL: System Layer shutdown [1678796869.645693][648903:648903] CHIP:TOO: Run command failure: ../../commands/pairing/PairingCommand.cpp:215: CHIP Error 0x00000003: Incorrect state disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_CADMIN_1_8.yaml b/src/app/tests/suites/certification/Test_TC_CADMIN_1_8.yaml index 4f26a7153f362a..f0a45e9bd04248 100644 --- a/src/app/tests/suites/certification/Test_TC_CADMIN_1_8.yaml +++ b/src/app/tests/suites/certification/Test_TC_CADMIN_1_8.yaml @@ -100,7 +100,7 @@ tests: [1663842366.887733][13938:13938] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1663842366.887797][13938:13938] CHIP:DL: Inet Layer shutdown - [1663842366.887851][13938:13938] CHIP:DL: BLE shutdown + [1663842366.887851][13938:13938] CHIP:DL: BLE Layer shutdown [1663842366.887905][13938:13938] CHIP:DL: System Layer shutdown [1663842366.888154][13938:13938] CHIP:TOO: Run command failure: ../../examples/chip-tool/commands/common/CHIPCommand.cpp:454: CHIP Error 0x00000032: Timeout disabled: true @@ -154,7 +154,7 @@ tests: verify you got the following message in the TH_CR2(CHIP-TOOL) log [1700552012.724377][27528:27528] CHIP:DL: Inet Layer shutdown - [1700552012.724405][27528:27528] CHIP:DL: BLE shutdown + [1700552012.724405][27528:27528] CHIP:DL: BLE Layer shutdown [1700552012.724445][27528:27528] CHIP:DL: System Layer shutdown [1700552012.725294][27528:27528] CHIP:TOO: Run command failure: ../../examples/chip-tool/commands/common/CHIPCommand.cpp:589: CHIP Error 0x00000032: Timeout disabled: true @@ -276,7 +276,7 @@ tests: Verify you got the following message in the TH_CR3(Chip-tool) log [1700552012.724377][27528:27528] CHIP:DL: Inet Layer shutdown - [1700552012.724405][27528:27528] CHIP:DL: BLE shutdown + [1700552012.724405][27528:27528] CHIP:DL: BLE Layer shutdown [1700552012.724445][27528:27528] CHIP:DL: System Layer shutdown [1700552012.725294][27528:27528] CHIP:TOO: Run command failure: ../../examples/chip-tool/commands/common/CHIPCommand.cpp:589: CHIP Error 0x00000032: Timeout disabled: true diff --git a/src/app/tests/suites/certification/Test_TC_CADMIN_1_9.yaml b/src/app/tests/suites/certification/Test_TC_CADMIN_1_9.yaml index a3d2de3641699e..5ee85f98a48a72 100644 --- a/src/app/tests/suites/certification/Test_TC_CADMIN_1_9.yaml +++ b/src/app/tests/suites/certification/Test_TC_CADMIN_1_9.yaml @@ -551,7 +551,7 @@ tests: [1665484807.015876][5399:5399] CHIP:DL: renamed tmp file to file (/tmp/chip_counters.ini) [1665484807.016042][5399:5399] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1665484807.016108][5399:5399] CHIP:DL: Inet Layer shutdown - [1665484807.016163][5399:5399] CHIP:DL: BLE shutdown + [1665484807.016163][5399:5399] CHIP:DL: BLE Layer shutdown [1665484807.016215][5399:5399] CHIP:DL: System Layer shutdown [1665484807.016460][5399:5399] CHIP:TOO: Run command failure: ../../commands/pairing/PairingCommand.cpp:164: CHIP Error 0x00000003: Incorrect state cluster: "LogCommands" @@ -589,7 +589,7 @@ tests: [1665484807.015876][5399:5399] CHIP:DL: renamed tmp file to file (/tmp/chip_counters.ini) [1665484807.016042][5399:5399] CHIP:DL: NVS set: chip-counters/total-operational-hours = 0 (0x0) [1665484807.016108][5399:5399] CHIP:DL: Inet Layer shutdown - [1665484807.016163][5399:5399] CHIP:DL: BLE shutdown + [1665484807.016163][5399:5399] CHIP:DL: BLE Layer shutdown [1665484807.016215][5399:5399] CHIP:DL: System Layer shutdown [1665484807.016460][5399:5399] CHIP:TOO: Run command failure: ../../commands/pairing/PairingCommand.cpp:164: CHIP Error 0x00000003: Incorrect state cluster: "LogCommands" diff --git a/src/app/zap-templates/zcl/data-model/all.xml b/src/app/zap-templates/zcl/data-model/all.xml index 86d2085718291d..9686aa74eed0d0 100644 --- a/src/app/zap-templates/zcl/data-model/all.xml +++ b/src/app/zap-templates/zcl/data-model/all.xml @@ -104,6 +104,7 @@ + diff --git a/src/app/zap-templates/zcl/data-model/chip/electrical-energy-measurement-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/electrical-energy-measurement-cluster.xml index 0a4039badf7c97..eb05052538d2de 100644 --- a/src/app/zap-templates/zcl/data-model/chip/electrical-energy-measurement-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/electrical-energy-measurement-cluster.xml @@ -16,7 +16,7 @@ limitations under the License. --> - + Electrical Energy Measurement Measurement & Sensing 0x0091 @@ -52,25 +52,25 @@ limitations under the License. PeriodicEnergyExported CumulativeEnergyReset - + CumulativeEnergyMeasured - + PeriodicEnergyMeasured - + - + diff --git a/src/app/zap-templates/zcl/data-model/chip/electrical-power-measurement-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/electrical-power-measurement-cluster.xml index 69be8e08570f39..7f49a643d1b1f9 100644 --- a/src/app/zap-templates/zcl/data-model/chip/electrical-power-measurement-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/electrical-power-measurement-cluster.xml @@ -16,7 +16,7 @@ limitations under the License. --> - + Electrical Power Measurement Measurement & Sensing 0x0090 @@ -82,18 +82,18 @@ limitations under the License. PowerFactor NeutralCurrent - + MeasurementPeriodRanges - + - + @@ -107,7 +107,7 @@ limitations under the License. - + diff --git a/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml index cbc0882ac1b3ac..5c22b8e93be8da 100644 --- a/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml @@ -14,7 +14,7 @@ limitations under the License. - + @@ -25,7 +25,7 @@ limitations under the License. - + @@ -34,7 +34,7 @@ limitations under the License. - + @@ -55,7 +55,7 @@ limitations under the License. - + @@ -86,7 +86,7 @@ limitations under the License. - + Energy EVSE Energy Management 0x0099 @@ -177,7 +177,7 @@ limitations under the License. Allows a client to disable the EVSE from charging and discharging. - + @@ -188,7 +188,7 @@ limitations under the License. Allows a client to enable the EVSE to discharge an EV. - + Allows a client to put the EVSE into a self-diagnostics mode. @@ -205,41 +205,41 @@ limitations under the License. The GetTargetsResponse is sent in response to the GetTargets Command. - + EVConnected - + - + EVNotDetected - - - - + + + + - + EnergyTransferStarted - - - + + + - + EnergyTransferStopped - - - - + + + + - + Fault - - - - + + + + - + RFID - + diff --git a/src/app/zap-templates/zcl/data-model/chip/energy-evse-mode-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/energy-evse-mode-cluster.xml index 22e5562ed33f7f..c4b702b701d174 100644 --- a/src/app/zap-templates/zcl/data-model/chip/energy-evse-mode-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/energy-evse-mode-cluster.xml @@ -24,7 +24,7 @@ limitations under the License. - + General Energy EVSE Mode 0x009D diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index 795f7a71cf54bc..83a462c4a64a4a 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -2420,11 +2420,12 @@ limitations under the License. CHIP Matter Network Infrastructure Manager 0x0103 - 0xFFF10010 + 0x0090 Simple Endpoint + diff --git a/src/app/zap-templates/zcl/data-model/chip/microwave-oven-control-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/microwave-oven-control-cluster.xml index 5567bc99461893..954bd898b6aa00 100644 --- a/src/app/zap-templates/zcl/data-model/chip/microwave-oven-control-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/microwave-oven-control-cluster.xml @@ -18,7 +18,7 @@ limitations under the License. - + Microwave Oven Control Appliances Attributes and commands for configuring the microwave oven control, and reporting cooking stats. @@ -47,8 +47,8 @@ limitations under the License. MinPower MaxPower PowerStep - SupportedWatts - SelectedWattIndex + SupportedWatts + SelectedWattIndex WattRating diff --git a/src/app/zap-templates/zcl/data-model/chip/microwave-oven-mode-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/microwave-oven-mode-cluster.xml index b26f022f3cc9b4..3e4e9cfe84d86c 100644 --- a/src/app/zap-templates/zcl/data-model/chip/microwave-oven-mode-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/microwave-oven-mode-cluster.xml @@ -23,7 +23,7 @@ limitations under the License. - + General Microwave Oven Mode 0x005E diff --git a/src/app/zap-templates/zcl/data-model/chip/operational-state-oven-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/operational-state-oven-cluster.xml index f121b6357d605b..83f2fc8b7984d4 100644 --- a/src/app/zap-templates/zcl/data-model/chip/operational-state-oven-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/operational-state-oven-cluster.xml @@ -16,7 +16,7 @@ limitations under the License. --> - + Appliances Oven Cavity Operational State 0x0048 diff --git a/src/app/zap-templates/zcl/data-model/chip/oven-mode-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/oven-mode-cluster.xml index 2508b4741602b3..41f95e81cdd248 100644 --- a/src/app/zap-templates/zcl/data-model/chip/oven-mode-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/oven-mode-cluster.xml @@ -30,7 +30,7 @@ limitations under the License. - + General Oven Mode 0x0049 diff --git a/src/app/zap-templates/zcl/data-model/chip/power-topology-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/power-topology-cluster.xml index 2fdddcbe3560da..3bca0bd43ee8af 100644 --- a/src/app/zap-templates/zcl/data-model/chip/power-topology-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/power-topology-cluster.xml @@ -17,7 +17,7 @@ limitations under the License. - + Measurement & Sensing Power Topology 0x009C diff --git a/src/app/zap-templates/zcl/data-model/chip/wifi-network-management-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/wifi-network-management-cluster.xml new file mode 100644 index 00000000000000..f05faad4dae4d2 --- /dev/null +++ b/src/app/zap-templates/zcl/data-model/chip/wifi-network-management-cluster.xml @@ -0,0 +1,44 @@ + + + + + + + Network Infrastructure + Wi-Fi Network Management + 0x0451 + WIFI_NETWORK_MANAGEMENT_CLUSTER + Functionality to retrieve operational information about a managed Wi-Fi network. + + true + true + + + + + SSID + + + Request the current WPA-Personal passphrase or PSK associated with the managed Wi-Fi network. + + + + This is the response to a NetworkPassphraseRequest. + + + + diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 7213b96cf0e012..f3aa6ef0b47f48 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -125,6 +125,7 @@ "wake-on-lan-cluster.xml", "washer-controls-cluster.xml", "wifi-network-diagnostics-cluster.xml", + "wifi-network-management-cluster.xml", "window-covering.xml", "matter-devices.xml", "sample-mei-cluster.xml", @@ -633,7 +634,8 @@ ], "Power Topology": ["FeatureMap"], "Valve Configuration and Control": ["RemainingDuration"], - "Boolean State Configuration": ["CurrentSensitivityLevel"] + "Boolean State Configuration": ["CurrentSensitivityLevel"], + "Wi-Fi Network Management": ["SSID"] }, "defaultReportingPolicy": "mandatory", "ZCLDataTypes": ["ARRAY", "BITMAP", "ENUM", "NUMBER", "STRING", "STRUCT"], diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 8a4159e98f7eb8..d85f850b2c9483 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -123,6 +123,7 @@ "wake-on-lan-cluster.xml", "washer-controls-cluster.xml", "wifi-network-diagnostics-cluster.xml", + "wifi-network-management-cluster.xml", "window-covering.xml", "matter-devices.xml", "sample-mei-cluster.xml", @@ -631,7 +632,8 @@ ], "Power Topology": ["FeatureMap"], "Valve Configuration and Control": ["RemainingDuration"], - "Boolean State Configuration": ["CurrentSensitivityLevel"] + "Boolean State Configuration": ["CurrentSensitivityLevel"], + "Wi-Fi Network Management": ["SSID"] }, "defaultReportingPolicy": "mandatory", "ZCLDataTypes": ["ARRAY", "BITMAP", "ENUM", "NUMBER", "STRING", "STRUCT"], diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index 2edfb272ad23e1..d86979f40adc9e 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -306,6 +306,7 @@ "LAUNDRY_WASHER_CONTROLS_CLUSTER": ["laundry-washer-controls-server"], "LAUNDRY_DRYER_CONTROLS_CLUSTER": ["laundry-dryer-controls-server"], "WIFI_NETWORK_DIAGNOSTICS_CLUSTER": ["wifi-network-diagnostics-server"], + "WIFI_NETWORK_MANAGEMENT_CLUSTER": ["wifi-network-management-server"], "WINDOW_COVERING_CLUSTER": ["window-covering-server"], "ZLL_COMMISSIONING_CLUSTER": [] } diff --git a/src/controller/README.md b/src/controller/README.md index e46c191f55489b..70a3fa5e8f8352 100644 --- a/src/controller/README.md +++ b/src/controller/README.md @@ -26,7 +26,7 @@ The POSIX CLI chip-tool is located in ### Python -The Python chip-device-ctrl is located in +The Python CHIP Controller library is located in [../controller/python/](../controller/python). ## Feature Overview diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index c559d1d0e9b129..e18d1cbe4a0193 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -2804,7 +2804,7 @@ provisional cluster Timer = 71 { } /** This cluster supports remotely monitoring and, where supported, changing the operational state of an Oven. */ -provisional cluster OvenCavityOperationalState = 72 { +cluster OvenCavityOperationalState = 72 { revision 1; enum ErrorStateEnum : enum8 { @@ -2870,7 +2870,7 @@ provisional cluster OvenCavityOperationalState = 72 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster OvenMode = 73 { +cluster OvenMode = 73 { revision 1; enum ModeTag : enum16 { @@ -3526,7 +3526,7 @@ cluster DishwasherAlarm = 93 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster MicrowaveOvenMode = 94 { +cluster MicrowaveOvenMode = 94 { revision 1; enum ModeTag : enum16 { @@ -3560,7 +3560,7 @@ provisional cluster MicrowaveOvenMode = 94 { } /** Attributes and commands for configuring the microwave oven control, and reporting cooking stats. */ -provisional cluster MicrowaveOvenControl = 95 { +cluster MicrowaveOvenControl = 95 { revision 1; // NOTE: Default/not specifically set bitmap Feature : bitmap32 { @@ -4112,7 +4112,7 @@ cluster ValveConfigurationAndControl = 129 { } /** This cluster provides a mechanism for querying data about electrical power as measured by the server. */ -provisional cluster ElectricalPowerMeasurement = 144 { +cluster ElectricalPowerMeasurement = 144 { revision 1; enum MeasurementTypeEnum : enum16 { @@ -4217,7 +4217,7 @@ provisional cluster ElectricalPowerMeasurement = 144 { } /** This cluster provides a mechanism for querying data about the electrical energy imported or provided by the server. */ -provisional cluster ElectricalEnergyMeasurement = 145 { +cluster ElectricalEnergyMeasurement = 145 { revision 1; enum MeasurementTypeEnum : enum16 { @@ -4803,7 +4803,7 @@ provisional cluster DeviceEnergyManagement = 152 { } /** Electric Vehicle Supply Equipment (EVSE) is equipment used to charge an Electric Vehicle (EV) or Plug-In Hybrid Electric Vehicle. This cluster provides an interface to the functionality of Electric Vehicle Supply Equipment (EVSE) management. */ -provisional cluster EnergyEvse = 153 { +cluster EnergyEvse = 153 { revision 2; enum EnergyTransferStoppedReasonEnum : enum8 { @@ -5015,7 +5015,7 @@ provisional cluster EnergyPreference = 155 { } /** The Power Topology Cluster provides a mechanism for expressing how power is flowing between endpoints. */ -provisional cluster PowerTopology = 156 { +cluster PowerTopology = 156 { revision 1; bitmap Feature : bitmap32 { @@ -5036,7 +5036,7 @@ provisional cluster PowerTopology = 156 { } /** Attributes and commands for selecting a mode from a list of supported options. */ -provisional cluster EnergyEvseMode = 157 { +cluster EnergyEvseMode = 157 { revision 1; enum ModeTag : enum16 { @@ -7654,6 +7654,26 @@ cluster RadonConcentrationMeasurement = 1071 { readonly attribute int16u clusterRevision = 65533; } +/** Functionality to retrieve operational information about a managed Wi-Fi network. */ +cluster WiFiNetworkManagement = 1105 { + revision 1; + + readonly attribute nullable octet_string<32> ssid = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + response struct NetworkPassphraseResponse = 1 { + octet_string<64> passphrase = 0; + } + + /** Request the current WPA-Personal passphrase or PSK associated with the managed Wi-Fi network. */ + command access(invoke: administer) NetworkPassphraseRequest(): NetworkPassphraseResponse = 0; +} + /** This cluster provides an interface for managing low power mode on a device that supports the Wake On LAN protocol. */ cluster WakeOnLan = 1283 { revision 1; diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index e22c50cd023788..ec522e367c60f4 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -262,7 +262,11 @@ kotlin_library("tlv") { "src/matter/tlv/values.kt", ] - kotlinc_flags = [ "-Xlint:deprecation" ] + kotlinc_flags = [ + "-Xlint:deprecation", + "-module-name", + "com.matter.tlv", + ] } kotlin_library("tlv_reader_test") { @@ -323,7 +327,11 @@ kotlin_library("jsontlv") { "src/matter/jsontlv/types.kt", ] - kotlinc_flags = [ "-Xlint:deprecation" ] + kotlinc_flags = [ + "-Xlint:deprecation", + "-module-name", + "com.matter.matterjson", + ] } kotlin_library("json_to_tlv_to_json_test") { @@ -363,6 +371,10 @@ kotlin_library("onboarding_payload") { "src/matter/onboardingpayload/Verhoeff.kt", "src/matter/onboardingpayload/Verhoeff10.kt", ] + kotlinc_flags = [ + "-module-name", + "com.matter.onboarding", + ] } kotlin_library("onboardingpayload_manual_code_test") { @@ -404,7 +416,11 @@ kotlin_library("chipcluster") { sources = structs_sources sources += eventstructs_sources - kotlinc_flags = [ "-Xlint:deprecation" ] + kotlinc_flags = [ + "-Xlint:deprecation", + "-module-name", + "com.matter.chipcluster", + ] } kotlin_library("chipcluster_test") { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 2e64d37cd62b11..7a6caeb9532993 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -52829,6 +52829,260 @@ public void onSuccess(byte[] tlv) { } } + public static class WiFiNetworkManagementCluster extends BaseChipCluster { + public static final long CLUSTER_ID = 1105L; + + private static final long SSID_ATTRIBUTE_ID = 1L; + private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L; + private static final long ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID = 65529L; + private static final long EVENT_LIST_ATTRIBUTE_ID = 65530L; + private static final long ATTRIBUTE_LIST_ATTRIBUTE_ID = 65531L; + private static final long FEATURE_MAP_ATTRIBUTE_ID = 65532L; + private static final long CLUSTER_REVISION_ATTRIBUTE_ID = 65533L; + + public WiFiNetworkManagementCluster(long devicePtr, int endpointId) { + super(devicePtr, endpointId, CLUSTER_ID); + } + + @Override + @Deprecated + public long initWithDevice(long devicePtr, int endpointId) { + return 0L; + } + + public void networkPassphraseRequest(NetworkPassphraseResponseCallback callback) { + networkPassphraseRequest(callback, 0); + } + + public void networkPassphraseRequest(NetworkPassphraseResponseCallback callback, int timedInvokeTimeoutMs) { + final long commandId = 0L; + + ArrayList elements = new ArrayList<>(); + StructType commandArgs = new StructType(elements); + invoke(new InvokeCallbackImpl(callback) { + @Override + public void onResponse(StructType invokeStructValue) { + final long passphraseFieldID = 0L; + byte[] passphrase = null; + for (StructElement element: invokeStructValue.value()) { + if (element.contextTagNum() == passphraseFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.ByteArray) { + ByteArrayType castingValue = element.value(ByteArrayType.class); + passphrase = castingValue.value(byte[].class); + } + } + } + callback.onSuccess(passphrase); + }}, commandId, commandArgs, timedInvokeTimeoutMs); + } + + public interface NetworkPassphraseResponseCallback extends BaseClusterCallback { + void onSuccess(byte[] passphrase); + } + + public interface SsidAttributeCallback extends BaseAttributeCallback { + void onSuccess(@Nullable byte[] value); + } + + public interface GeneratedCommandListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface AcceptedCommandListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface EventListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public interface AttributeListAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); + } + + public void readSsidAttribute( + SsidAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SSID_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + @Nullable byte[] value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, SSID_ATTRIBUTE_ID, true); + } + + public void subscribeSsidAttribute( + SsidAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SSID_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + @Nullable byte[] value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, SSID_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readGeneratedCommandListAttribute( + GeneratedCommandListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, GENERATED_COMMAND_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeGeneratedCommandListAttribute( + GeneratedCommandListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, GENERATED_COMMAND_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, GENERATED_COMMAND_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readAcceptedCommandListAttribute( + AcceptedCommandListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeAcceptedCommandListAttribute( + AcceptedCommandListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readEventListAttribute( + EventListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, EVENT_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, EVENT_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeEventListAttribute( + EventListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, EVENT_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, EVENT_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readAttributeListAttribute( + AttributeListAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ATTRIBUTE_LIST_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ATTRIBUTE_LIST_ATTRIBUTE_ID, true); + } + + public void subscribeAttributeListAttribute( + AttributeListAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ATTRIBUTE_LIST_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ATTRIBUTE_LIST_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readFeatureMapAttribute( + LongAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, FEATURE_MAP_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, FEATURE_MAP_ATTRIBUTE_ID, true); + } + + public void subscribeFeatureMapAttribute( + LongAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, FEATURE_MAP_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, FEATURE_MAP_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readClusterRevisionAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CLUSTER_REVISION_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, CLUSTER_REVISION_ATTRIBUTE_ID, true); + } + + public void subscribeClusterRevisionAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CLUSTER_REVISION_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, CLUSTER_REVISION_ATTRIBUTE_ID, minInterval, maxInterval); + } + } + public static class WakeOnLanCluster extends BaseChipCluster { public static final long CLUSTER_ID = 1283L; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index 3437b8a981e476..506d7386935c47 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -328,6 +328,9 @@ public static BaseCluster getCluster(long clusterId) { if (clusterId == RadonConcentrationMeasurement.ID) { return new RadonConcentrationMeasurement(); } + if (clusterId == WiFiNetworkManagement.ID) { + return new WiFiNetworkManagement(); + } if (clusterId == WakeOnLan.ID) { return new WakeOnLan(); } @@ -14313,6 +14316,108 @@ public long getCommandID(String name) throws IllegalArgumentException { return Command.valueOf(name).getID(); } } + public static class WiFiNetworkManagement implements BaseCluster { + public static final long ID = 1105L; + public long getID() { + return ID; + } + + public enum Attribute { + Ssid(1L), + GeneratedCommandList(65528L), + AcceptedCommandList(65529L), + EventList(65530L), + AttributeList(65531L), + FeatureMap(65532L), + ClusterRevision(65533L),; + private final long id; + Attribute(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Attribute value(long id) throws NoSuchFieldError { + for (Attribute attribute : Attribute.values()) { + if (attribute.getID() == id) { + return attribute; + } + } + throw new NoSuchFieldError(); + } + } + + public enum Event {; + private final long id; + Event(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Event value(long id) throws NoSuchFieldError { + for (Event event : Event.values()) { + if (event.getID() == id) { + return event; + } + } + throw new NoSuchFieldError(); + } + } + + public enum Command { + NetworkPassphraseRequest(0L),; + private final long id; + Command(long id) { + this.id = id; + } + + public long getID() { + return id; + } + + public static Command value(long id) throws NoSuchFieldError { + for (Command command : Command.values()) { + if (command.getID() == id) { + return command; + } + } + throw new NoSuchFieldError(); + } + }@Override + public String getAttributeName(long id) throws NoSuchFieldError { + return Attribute.value(id).toString(); + } + + @Override + public String getEventName(long id) throws NoSuchFieldError { + return Event.value(id).toString(); + } + + @Override + public String getCommandName(long id) throws NoSuchFieldError { + return Command.value(id).toString(); + } + + @Override + public long getAttributeID(String name) throws IllegalArgumentException { + return Attribute.valueOf(name).getID(); + } + + @Override + public long getEventID(String name) throws IllegalArgumentException { + return Event.valueOf(name).getID(); + } + + @Override + public long getCommandID(String name) throws IllegalArgumentException { + return Command.valueOf(name).getID(); + } + } public static class WakeOnLan implements BaseCluster { public static final long ID = 1283L; public long getID() { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 4ded328fad6ed5..d7c4134c812d9d 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -17299,6 +17299,133 @@ public void onError(Exception ex) { } } + + public static class DelegatedWiFiNetworkManagementClusterNetworkPassphraseResponseCallback implements ChipClusters.WiFiNetworkManagementCluster.NetworkPassphraseResponseCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(byte[] passphrase) { + Map responseValues = new LinkedHashMap<>(); + + CommandResponseInfo passphraseResponseValue = new CommandResponseInfo("passphrase", "byte[]"); + responseValues.put(passphraseResponseValue, passphrase); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception error) { + callback.onFailure(error); + } + } + public static class DelegatedWiFiNetworkManagementClusterSsidAttributeCallback implements ChipClusters.WiFiNetworkManagementCluster.SsidAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(@Nullable byte[] value) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("value", "byte[]"); + responseValues.put(commandResponseInfo, value); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedWiFiNetworkManagementClusterGeneratedCommandListAttributeCallback implements ChipClusters.WiFiNetworkManagementCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedWiFiNetworkManagementClusterAcceptedCommandListAttributeCallback implements ChipClusters.WiFiNetworkManagementCluster.AcceptedCommandListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedWiFiNetworkManagementClusterEventListAttributeCallback implements ChipClusters.WiFiNetworkManagementCluster.EventListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + + public static class DelegatedWiFiNetworkManagementClusterAttributeListAttributeCallback implements ChipClusters.WiFiNetworkManagementCluster.AttributeListAttributeCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(List valueList) { + Map responseValues = new LinkedHashMap<>(); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + responseValues.put(commandResponseInfo, valueList); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception ex) { + callback.onFailure(ex); + } + } + public static class DelegatedWakeOnLanClusterGeneratedCommandListAttributeCallback implements ChipClusters.WakeOnLanCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override @@ -21177,6 +21304,10 @@ public Map initializeClusterMap() { (ptr, endpointId) -> new ChipClusters.RadonConcentrationMeasurementCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("radonConcentrationMeasurement", radonConcentrationMeasurementClusterInfo); + ClusterInfo wiFiNetworkManagementClusterInfo = new ClusterInfo( + (ptr, endpointId) -> new ChipClusters.WiFiNetworkManagementCluster(ptr, endpointId), new HashMap<>()); + clusterMap.put("wiFiNetworkManagement", wiFiNetworkManagementClusterInfo); + ClusterInfo wakeOnLanClusterInfo = new ClusterInfo( (ptr, endpointId) -> new ChipClusters.WakeOnLanCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("wakeOnLan", wakeOnLanClusterInfo); @@ -21353,6 +21484,7 @@ public void combineCommand(Map destination, Map> getCommandMap() { commandMap.put("radonConcentrationMeasurement", radonConcentrationMeasurementClusterInteractionInfoMap); + Map wiFiNetworkManagementClusterInteractionInfoMap = new LinkedHashMap<>(); + + Map wiFiNetworkManagementnetworkPassphraseRequestCommandParams = new LinkedHashMap(); + InteractionInfo wiFiNetworkManagementnetworkPassphraseRequestInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster) + .networkPassphraseRequest((ChipClusters.WiFiNetworkManagementCluster.NetworkPassphraseResponseCallback) callback + ); + }, + () -> new DelegatedWiFiNetworkManagementClusterNetworkPassphraseResponseCallback(), + wiFiNetworkManagementnetworkPassphraseRequestCommandParams + ); + wiFiNetworkManagementClusterInteractionInfoMap.put("networkPassphraseRequest", wiFiNetworkManagementnetworkPassphraseRequestInteractionInfo); + + commandMap.put("wiFiNetworkManagement", wiFiNetworkManagementClusterInteractionInfoMap); + Map wakeOnLanClusterInteractionInfoMap = new LinkedHashMap<>(); commandMap.put("wakeOnLan", wakeOnLanClusterInteractionInfoMap); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index cc18af0810cc10..e75473bc0869b8 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -16529,6 +16529,87 @@ private static Map readRadonConcentrationMeasurementInt return result; } + private static Map readWiFiNetworkManagementInteractionInfo() { + Map result = new LinkedHashMap<>();Map readWiFiNetworkManagementSsidCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementSsidAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readSsidAttribute( + (ChipClusters.WiFiNetworkManagementCluster.SsidAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedWiFiNetworkManagementClusterSsidAttributeCallback(), + readWiFiNetworkManagementSsidCommandParams + ); + result.put("readSsidAttribute", readWiFiNetworkManagementSsidAttributeInteractionInfo); + Map readWiFiNetworkManagementGeneratedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementGeneratedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readGeneratedCommandListAttribute( + (ChipClusters.WiFiNetworkManagementCluster.GeneratedCommandListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedWiFiNetworkManagementClusterGeneratedCommandListAttributeCallback(), + readWiFiNetworkManagementGeneratedCommandListCommandParams + ); + result.put("readGeneratedCommandListAttribute", readWiFiNetworkManagementGeneratedCommandListAttributeInteractionInfo); + Map readWiFiNetworkManagementAcceptedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementAcceptedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readAcceptedCommandListAttribute( + (ChipClusters.WiFiNetworkManagementCluster.AcceptedCommandListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedWiFiNetworkManagementClusterAcceptedCommandListAttributeCallback(), + readWiFiNetworkManagementAcceptedCommandListCommandParams + ); + result.put("readAcceptedCommandListAttribute", readWiFiNetworkManagementAcceptedCommandListAttributeInteractionInfo); + Map readWiFiNetworkManagementEventListCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementEventListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readEventListAttribute( + (ChipClusters.WiFiNetworkManagementCluster.EventListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedWiFiNetworkManagementClusterEventListAttributeCallback(), + readWiFiNetworkManagementEventListCommandParams + ); + result.put("readEventListAttribute", readWiFiNetworkManagementEventListAttributeInteractionInfo); + Map readWiFiNetworkManagementAttributeListCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementAttributeListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readAttributeListAttribute( + (ChipClusters.WiFiNetworkManagementCluster.AttributeListAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedWiFiNetworkManagementClusterAttributeListAttributeCallback(), + readWiFiNetworkManagementAttributeListCommandParams + ); + result.put("readAttributeListAttribute", readWiFiNetworkManagementAttributeListAttributeInteractionInfo); + Map readWiFiNetworkManagementFeatureMapCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementFeatureMapAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readFeatureMapAttribute( + (ChipClusters.LongAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedLongAttributeCallback(), + readWiFiNetworkManagementFeatureMapCommandParams + ); + result.put("readFeatureMapAttribute", readWiFiNetworkManagementFeatureMapAttributeInteractionInfo); + Map readWiFiNetworkManagementClusterRevisionCommandParams = new LinkedHashMap(); + InteractionInfo readWiFiNetworkManagementClusterRevisionAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.WiFiNetworkManagementCluster) cluster).readClusterRevisionAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readWiFiNetworkManagementClusterRevisionCommandParams + ); + result.put("readClusterRevisionAttribute", readWiFiNetworkManagementClusterRevisionAttributeInteractionInfo); + + return result; + } private static Map readWakeOnLanInteractionInfo() { Map result = new LinkedHashMap<>();Map readWakeOnLanMACAddressCommandParams = new LinkedHashMap(); InteractionInfo readWakeOnLanMACAddressAttributeInteractionInfo = new InteractionInfo( @@ -20588,6 +20669,7 @@ public Map> getReadAttributeMap() { put("pm10ConcentrationMeasurement", readPm10ConcentrationMeasurementInteractionInfo()); put("totalVolatileOrganicCompoundsConcentrationMeasurement", readTotalVolatileOrganicCompoundsConcentrationMeasurementInteractionInfo()); put("radonConcentrationMeasurement", readRadonConcentrationMeasurementInteractionInfo()); + put("wiFiNetworkManagement", readWiFiNetworkManagementInteractionInfo()); put("wakeOnLan", readWakeOnLanInteractionInfo()); put("channel", readChannelInteractionInfo()); put("targetNavigator", readTargetNavigatorInteractionInfo()); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index 0e5a32b23f04c4..93f3a7790eb8fa 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -3636,6 +3636,8 @@ public Map> getWriteAttributeMap() { writeAttributeMap.put("totalVolatileOrganicCompoundsConcentrationMeasurement", writeTotalVolatileOrganicCompoundsConcentrationMeasurementInteractionInfo); Map writeRadonConcentrationMeasurementInteractionInfo = new LinkedHashMap<>(); writeAttributeMap.put("radonConcentrationMeasurement", writeRadonConcentrationMeasurementInteractionInfo); + Map writeWiFiNetworkManagementInteractionInfo = new LinkedHashMap<>(); + writeAttributeMap.put("wiFiNetworkManagement", writeWiFiNetworkManagementInteractionInfo); Map writeWakeOnLanInteractionInfo = new LinkedHashMap<>(); writeAttributeMap.put("wakeOnLan", writeWakeOnLanInteractionInfo); Map writeChannelInteractionInfo = new LinkedHashMap<>(); diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkManagementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkManagementCluster.kt new file mode 100644 index 00000000000000..5deb4b8317d3a4 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkManagementCluster.kt @@ -0,0 +1,786 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package matter.controller.cluster.clusters + +import java.time.Duration +import java.util.logging.Level +import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.InvokeRequest +import matter.controller.InvokeResponse +import matter.controller.MatterController +import matter.controller.ReadData +import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState +import matter.controller.cluster.structs.* +import matter.controller.model.AttributePath +import matter.controller.model.CommandPath +import matter.tlv.AnonymousTag +import matter.tlv.ContextSpecificTag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class WiFiNetworkManagementCluster( + private val controller: MatterController, + private val endpointId: UShort +) { + class NetworkPassphraseResponse(val passphrase: ByteArray) + + class SsidAttribute(val value: ByteArray?) + + sealed class SsidAttributeSubscriptionState { + data class Success(val value: ByteArray?) : SsidAttributeSubscriptionState() + + data class Error(val exception: Exception) : SsidAttributeSubscriptionState() + + object SubscriptionEstablished : SsidAttributeSubscriptionState() + } + + class GeneratedCommandListAttribute(val value: List) + + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + + class AcceptedCommandListAttribute(val value: List) + + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + + class EventListAttribute(val value: List) + + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + + class AttributeListAttribute(val value: List) + + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + + suspend fun networkPassphraseRequest( + timedInvokeTimeout: Duration? = null + ): NetworkPassphraseResponse { + val commandId: UInt = 0u + + val tlvWriter = TlvWriter() + tlvWriter.startStructure(AnonymousTag) + tlvWriter.endStructure() + + val request: InvokeRequest = + InvokeRequest( + CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), + tlvPayload = tlvWriter.getEncoded(), + timedRequest = timedInvokeTimeout + ) + + val response: InvokeResponse = controller.invoke(request) + logger.log(Level.FINE, "Invoke command succeeded: ${response}") + + val tlvReader = TlvReader(response.payload) + tlvReader.enterStructure(AnonymousTag) + val TAG_PASSPHRASE: Int = 0 + var passphrase_decoded: ByteArray? = null + + while (!tlvReader.isEndOfContainer()) { + val tag = tlvReader.peekElement().tag + + if (tag == ContextSpecificTag(TAG_PASSPHRASE)) { + passphrase_decoded = tlvReader.getByteArray(tag) + } else { + tlvReader.skipElement() + } + } + + if (passphrase_decoded == null) { + throw IllegalStateException("passphrase not found in TLV") + } + + tlvReader.exitContainer() + + return NetworkPassphraseResponse(passphrase_decoded) + } + + suspend fun readSsidAttribute(): SsidAttribute { + val ATTRIBUTE_ID: UInt = 1u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Ssid attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + return SsidAttribute(decodedValue) + } + + suspend fun subscribeSsidAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SsidAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Ssid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SsidAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SsidAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { + val ATTRIBUTE_ID: UInt = 65528u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Generatedcommandlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return GeneratedCommandListAttribute(decodedValue) + } + + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { + val ATTRIBUTE_ID: UInt = 65529u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Acceptedcommandlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return AcceptedCommandListAttribute(decodedValue) + } + + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readEventListAttribute(): EventListAttribute { + val ATTRIBUTE_ID: UInt = 65530u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Eventlist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return EventListAttribute(decodedValue) + } + + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAttributeListAttribute(): AttributeListAttribute { + val ATTRIBUTE_ID: UInt = 65531u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Attributelist attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + return AttributeListAttribute(decodedValue) + } + + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readFeatureMapAttribute(): UInt { + val ATTRIBUTE_ID: UInt = 65532u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Featuremap attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readClusterRevisionAttribute(): UShort { + val ATTRIBUTE_ID: UInt = 65533u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Clusterrevision attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + return decodedValue + } + + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + + companion object { + private val logger = Logger.getLogger(WiFiNetworkManagementCluster::class.java.name) + const val CLUSTER_ID: UInt = 1105u + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index f62cee23bdd5b3..e58b346b307ab7 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -341,5 +341,6 @@ matter_clusters_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/ValveConfigurationAndControlCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/WakeOnLanCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkDiagnosticsCluster.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkManagementCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/WindowCoveringCluster.kt", ] \ No newline at end of file diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 2400ba818c7cb9..ff10df38c79f9c 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -37156,6 +37156,170 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } break; } + case app::Clusters::WiFiNetworkManagement::Id: { + using namespace app::Clusters::WiFiNetworkManagement; + switch (aPath.mAttributeId) + { + case Attributes::Ssid::Id: { + using TypeInfo = Attributes::Ssid::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + if (cppValue.IsNull()) + { + value = nullptr; + } + else + { + jbyteArray valueByteArray = env->NewByteArray(static_cast(cppValue.Value().size())); + env->SetByteArrayRegion(valueByteArray, 0, static_cast(cppValue.Value().size()), + reinterpret_cast(cppValue.Value().data())); + value = valueByteArray; + } + return value; + } + case Attributes::GeneratedCommandList::Id: { + using TypeInfo = Attributes::GeneratedCommandList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::AcceptedCommandList::Id: { + using TypeInfo = Attributes::AcceptedCommandList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::EventList::Id: { + using TypeInfo = Attributes::EventList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::AttributeList::Id: { + using TypeInfo = Attributes::AttributeList::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); + } + return value; + } + case Attributes::FeatureMap::Id: { + using TypeInfo = Attributes::FeatureMap::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Long"; + std::string valueCtorSignature = "(J)V"; + jlong jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), + jnivalue, value); + return value; + } + case Attributes::ClusterRevision::Id: { + using TypeInfo = Attributes::ClusterRevision::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } + default: + *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; + break; + } + break; + } case app::Clusters::WakeOnLan::Id: { using namespace app::Clusters::WakeOnLan; switch (aPath.mAttributeId) diff --git a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp index 370e510894c121..7f210566b9aa37 100644 --- a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp @@ -7389,6 +7389,16 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & } break; } + case app::Clusters::WiFiNetworkManagement::Id: { + using namespace app::Clusters::WiFiNetworkManagement; + switch (aPath.mEventId) + { + default: + *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; + break; + } + break; + } case app::Clusters::WakeOnLan::Id: { using namespace app::Clusters::WakeOnLan; switch (aPath.mEventId) diff --git a/src/controller/python/BUILD.gn b/src/controller/python/BUILD.gn index 5fc2212098fea8..4676f89b362970 100644 --- a/src/controller/python/BUILD.gn +++ b/src/controller/python/BUILD.gn @@ -414,10 +414,7 @@ chip_python_wheel_action("chip-clusters") { } chip_python_wheel_action("chip-repl") { - py_scripts = [ - "chip-device-ctrl.py", - "chip-repl.py", - ] + py_scripts = [ "chip-repl.py" ] py_manifest_files = [ { diff --git a/src/controller/python/README.md b/src/controller/python/README.md index 34edea444650b1..e94a95e1585e0b 100644 --- a/src/controller/python/README.md +++ b/src/controller/python/README.md @@ -1,10 +1,14 @@ -# Python CHIP Device Controller +# Python CHIP Controller -The Python CHIP controller is a tool that allows to commission a Matter device -into the network and to communicate with it using the Zigbee Cluster Library -(ZCL) messages. The tool uses the generic [Chip Device Controller](../) library. +The Python CHIP controller is a library that allows to create a Matter fabric +and commission Matter devices with it, as well as communicate with commissioned +devices by reading/subscribing and writing Attributes and sending Commands. The +Python CHIP controller is based on the native [Chip Device Controller](../) +library. -To learn more about the tool, how to build it and use its commands and advanced +The Python CHIP Controller comes with a REPL which allows to explore and use the +Python CHIP controller library from a shell. To learn more about the Python CHIP +Controller and the REPL, how to build it and use its commands and advanced features, read the following guides: - [Working with Python CHIP Controller](../../../docs/guides/python_chip_controller_building.md) diff --git a/src/controller/python/chip-device-ctrl.py b/src/controller/python/chip-device-ctrl.py deleted file mode 100755 index 469fb2c49fdfc8..00000000000000 --- a/src/controller/python/chip-device-ctrl.py +++ /dev/null @@ -1,1202 +0,0 @@ -#!/usr/bin/env python - -# -# Copyright (c) 2020-2021 Project CHIP Authors -# Copyright (c) 2013-2018 Nest Labs, Inc. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# -# @file -# This file implements the Python-based Chip Device Controller Shell. -# - -from __future__ import absolute_import, print_function - -import argparse -import base64 -import ctypes -import logging -import os -import platform -import random -import shlex -import string -import sys -import textwrap -import time -import traceback -import warnings -from cmd import Cmd -from optparse import OptionParser, OptionValueError - -import chip.logging -import coloredlogs -from chip import ChipCommissionableNodeCtrl, ChipStack, exceptions, native -from chip.setup_payload import SetupPayload -from rich import pretty, print - -# Extend sys.path with one or more directories, relative to the location of the -# running script, in which the chip package might be found . This makes it -# possible to run the device manager shell from a non-standard install location, -# as well as directly from its location the CHIP source tree. -# -# Note that relative package locations are prepended to sys.path so as to give -# the local version of the package higher priority over any version installed in -# a standard location. -# -scriptDir = os.path.dirname(os.path.abspath(__file__)) -relChipPackageInstallDirs = [ - ".", - "../lib/python", - "../lib/python%s.%s" % (sys.version_info.major, sys.version_info.minor), - "../lib/Python%s%s" % (sys.version_info.major, sys.version_info.minor), -] -for relInstallDir in relChipPackageInstallDirs: - absInstallDir = os.path.realpath(os.path.join(scriptDir, relInstallDir)) - if os.path.isdir(os.path.join(absInstallDir, "chip")): - sys.path.insert(0, absInstallDir) - - -if platform.system() == 'Darwin': - from chip.ChipCoreBluetoothMgr import CoreBluetoothManager as BleManager -elif sys.platform.startswith('linux'): - from chip.ChipBluezMgr import BluezManager as BleManager - -# The exceptions for CHIP Device Controller CLI - - -class ChipDevCtrlException(exceptions.ChipStackException): - pass - - -class ParsingError(ChipDevCtrlException): - def __init__(self, msg=None): - self.msg = "Parsing Error: " + msg - - def __str__(self): - return self.msg - - -def DecodeBase64Option(option, opt, value): - try: - return base64.standard_b64decode(value) - except TypeError: - raise OptionValueError( - "option %s: invalid base64 value: %r" % (opt, value)) - - -def DecodeHexIntOption(option, opt, value): - try: - return int(value, 16) - except ValueError: - raise OptionValueError("option %s: invalid value: %r" % (opt, value)) - - -def ParseEncodedString(value): - if value.find(":") < 0: - raise ParsingError( - "value should be encoded in encoding:encodedvalue format") - enc, encValue = value.split(":", 1) - if enc == "str": - return encValue.encode("utf-8") + b'\x00' - elif enc == "hex": - return bytes.fromhex(encValue) - raise ParsingError("only str and hex encoding is supported") - - -def ParseValueWithType(value, type): - if type == 'int': - return int(value) - elif type == 'str': - return value - elif type == 'bytes': - return ParseEncodedString(value) - elif type == 'bool': - return (value.upper() not in ['F', 'FALSE', '0']) - else: - raise ParsingError('cannot recognize type: {}'.format(type)) - - -def FormatZCLArguments(args, command): - commandArgs = {} - for kvPair in args: - if kvPair.find("=") < 0: - raise ParsingError("Argument should in key=value format") - key, value = kvPair.split("=", 1) - valueType = command.get(key, None) - commandArgs[key] = ParseValueWithType(value, valueType) - return commandArgs - - -def ShowColoredWarnings(message, category, filename, lineno, file=None, line=None): - logging.warning(' %s:%s: %s:%s' % - (filename, lineno, category.__name__, message)) - return - - -class DeviceMgrCmd(Cmd): - def __init__(self, rendezvousAddr=None, controllerNodeId=1, bluetoothAdapter=None): - self.lastNetworkId = None - self.replHint = None - - pretty.install(indent_guides=True, expand_all=True) - - coloredlogs.install(level='DEBUG') - chip.logging.RedirectToPythonLogging() - - logging.getLogger().setLevel(logging.DEBUG) - warnings.showwarning = ShowColoredWarnings - - Cmd.__init__(self) - - Cmd.identchars = string.ascii_letters + string.digits + "-" - - if sys.stdin.isatty(): - self.prompt = "chip-device-ctrl > " - else: - self.use_rawinput = 0 - self.prompt = "" - - DeviceMgrCmd.command_names.sort() - - self.bleMgr = None - - self.chipStack = ChipStack.ChipStack( - bluetoothAdapter=bluetoothAdapter, persistentStoragePath='/tmp/chip-device-ctrl-storage.json') - self.certificateAuthorityManager = chip.CertificateAuthority.CertificateAuthorityManager(chipStack=self.chipStack) - self.certificateAuthority = self.certificateAuthorityManager.NewCertificateAuthority() - self.fabricAdmin = self.certificateAuthority.NewFabricAdmin(vendorId=0xFFF1, fabricId=1) - self.devCtrl = self.fabricAdmin.NewController( - nodeId=controllerNodeId, useTestCommissioner=True) - - self.commissionableNodeCtrl = ChipCommissionableNodeCtrl.ChipCommissionableNodeController( - self.chipStack) - - # If we are on Linux and user selects non-default bluetooth adapter. - if sys.platform.startswith("linux") and (bluetoothAdapter is not None): - try: - self.bleMgr = BleManager(self.devCtrl) - self.bleMgr.ble_adapter_select( - "hci{}".format(bluetoothAdapter)) - except Exception as ex: - traceback.print_exc() - print( - "Failed to initialize BLE, if you don't have BLE, run chip-device-ctrl with --no-ble") - raise ex - - self.historyFileName = os.path.expanduser( - "~/.chip-device-ctrl-history") - - try: - import readline - - if "libedit" in readline.__doc__: - readline.parse_and_bind("bind ^I rl_complete") - readline.set_completer_delims(" ") - try: - readline.read_history_file(self.historyFileName) - except IOError: - pass - except ImportError: - pass - - command_names = [ - "setup-payload", - - "ble-scan", - "ble-adapter-select", - "ble-adapter-print", - "ble-debug-log", - - "connect", - "close-ble", - "close-session", - "resolve", - "paseonly", - "commission", - "zcl", - "zclread", - "zclsubscribe", - - "discover", - - "set-pairing-wifi-credential", - "set-pairing-thread-credential", - - "open-commissioning-window", - - "get-fabricid", - ] - - def parseline(self, line): - cmd, arg, line = Cmd.parseline(self, line) - if cmd: - cmd = self.shortCommandName(cmd) - line = cmd + " " + arg - return cmd, arg, line - - def completenames(self, text, *ignored): - return [ - name + " " - for name in DeviceMgrCmd.command_names - if name.startswith(text) or self.shortCommandName(name).startswith(text) - ] - - def shortCommandName(self, cmd): - return cmd.replace("-", "") - - def precmd(self, line): - if not self.use_rawinput and line != "EOF" and line != "": - print(">>> " + line) - return line - - def postcmd(self, stop, line): - if self.replHint is not None: - print("Try the following command in repl: ") - print(self.replHint) - print("") - self.replHint = None - if not stop and self.use_rawinput: - self.prompt = "chip-device-ctrl > " - return stop - - def postloop(self): - try: - import readline - - try: - readline.write_history_file(self.historyFileName) - except IOError: - pass - except ImportError: - pass - - def do_help(self, line): - if line: - cmd, arg, unused = self.parseline(line) - try: - doc = getattr(self, "do_" + cmd).__doc__ - except AttributeError: - doc = None - if doc: - self.stdout.write("%s\n" % textwrap.dedent(doc)) - else: - self.stdout.write("No help on %s\n" % (line)) - else: - self.print_topics( - "\nAvailable commands (type help for more information):", - DeviceMgrCmd.command_names, - 15, - 80, - ) - - def do_closeble(self, line): - """ - close-ble - - Close the ble connection to the device. - """ - - warnings.warn( - "This method is being deprecated. " - "Please use the DeviceController.CloseBLEConnection method directly in the REPL", DeprecationWarning) - - args = shlex.split(line) - - if len(args) != 0: - print("Usage:") - self.do_help("close") - return - - try: - self.devCtrl.CloseBLEConnection() - except exceptions.ChipStackException as ex: - print(str(ex)) - - def do_setlogoutput(self, line): - """ - set-log-output [ none | error | progress | detail ] - - Set the level of Chip logging output. - """ - - warnings.warn( - "This method is being deprecated. " - "Please use the DeviceController.SetLogFilter method directly in the REPL", DeprecationWarning) - - args = shlex.split(line) - - if len(args) == 0: - print("Usage:") - self.do_help("set-log-output") - return - if len(args) > 1: - print("Unexpected argument: " + args[1]) - return - - category = args[0].lower() - if category == "none": - category = 0 - elif category == "error": - category = 1 - elif category == "progress": - category = 2 - elif category == "detail": - category = 3 - else: - print("Invalid argument: " + args[0]) - return - - try: - self.devCtrl.SetLogFilter(category) - except exceptions.ChipStackException as ex: - print(str(ex)) - return - - def do_setuppayload(self, line): - """ - setup-payload generate [options] - - Options: - -vr Version - -vi Vendor ID - -pi Product ID - -cf Custom Flow [Standard = 0, UserActionRequired = 1, Custom = 2] - -dc Discovery Capabilities [SoftAP = 1 | BLE = 2 | OnNetwork = 4] - -dv Discriminator Value - -ps Passcode - - setup-payload parse-manual - setup-payload parse-qr - """ - - warnings.warn( - "This method is being deprecated. " - "Please use the SetupPayload function in the chip.setup_payload package directly", DeprecationWarning) - - try: - arglist = shlex.split(line) - if arglist[0] not in ("generate", "parse-manual", "parse-qr"): - self.do_help("setup-payload") - return - - if arglist[0] == "generate": - parser = argparse.ArgumentParser() - parser.add_argument("-vr", type=int, default=0, dest='version') - parser.add_argument( - "-pi", type=int, default=0, dest='productId') - parser.add_argument( - "-vi", type=int, default=0, dest='vendorId') - parser.add_argument( - '-cf', type=int, default=0, dest='customFlow') - parser.add_argument( - "-dc", type=int, default=0, dest='capabilities') - parser.add_argument( - "-dv", type=int, default=0, dest='discriminator') - parser.add_argument("-ps", type=int, dest='passcode') - args = parser.parse_args(arglist[1:]) - - SetupPayload().PrintOnboardingCodes(args.passcode, args.vendorId, args.productId, - args.discriminator, args.customFlow, args.capabilities, args.version) - - if arglist[0] == "parse-manual": - SetupPayload().ParseManualPairingCode(arglist[1]).Print() - - if arglist[0] == "parse-qr": - SetupPayload().ParseQrCode(arglist[1]).Print() - - except exceptions.ChipStackException as ex: - print(str(ex)) - return - - def do_bleadapterselect(self, line): - """ - ble-adapter-select - - Start BLE adapter select, deprecated, you can select adapter by command line arguments. - """ - if sys.platform.startswith("linux"): - if not self.bleMgr: - self.bleMgr = BleManager(self.devCtrl) - - self.bleMgr.ble_adapter_select(line) - print( - "This change only applies to ble-scan\n" - "Please run device controller with --bluetooth-adapter= to select adapter\n" + - "e.g. chip-device-ctrl --bluetooth-adapter hci0" - ) - else: - print( - "ble-adapter-select only works in Linux, ble-adapter-select mac_address" - ) - - return - - def do_bleadapterprint(self, line): - """ - ble-adapter-print - - Print attached BLE adapter. - """ - if sys.platform.startswith("linux"): - if not self.bleMgr: - self.bleMgr = BleManager(self.devCtrl) - - self.bleMgr.ble_adapter_print() - else: - print("ble-adapter-print only works in Linux") - - return - - def do_bledebuglog(self, line): - """ - ble-debug-log 0:1 - 0: disable BLE debug log - 1: enable BLE debug log - """ - if not self.bleMgr: - self.bleMgr = BleManager(self.devCtrl) - - self.bleMgr.ble_debug_log(line) - - return - - def do_blescan(self, line): - """ - ble-scan - - Start BLE scanning operations. - """ - - if not self.bleMgr: - self.bleMgr = BleManager(self.devCtrl) - - self.bleMgr.scan(line) - - return - - def ConnectFromSetupPayload(self, setupPayload, nodeid): - # TODO(cecille): Get this from the C++ code? - ble = 1 << 1 - # Devices may be uncommissioned, or may already be on the network. Need to check both ways. - # TODO(cecille): implement soft-ap connection. - - # Any device that is already commissioned into a fabric needs to use on-network - # pairing, so look first on the network regardless of the QR code contents. - print("Attempting to find device on Network") - longDiscriminator = ctypes.c_uint16( - int(setupPayload.attributes['Discriminator'])) - self.devCtrl.DiscoverCommissionableNodesLongDiscriminator( - longDiscriminator) - print("Waiting for device responses...") - strlen = 100 - addrStrStorage = ctypes.create_string_buffer(strlen) - # If this device is on the network and we're looking specifically for 1 device, - # expect a quick response. - if self.wait_for_one_discovered_device(): - self.devCtrl.GetIPForDiscoveredDevice( - 0, addrStrStorage, strlen) - addrStr = addrStrStorage.value.decode('utf-8') - print("Connecting to device at " + addrStr) - pincode = ctypes.c_uint32( - int(setupPayload.attributes['SetUpPINCode'])) - try: - self.devCtrl.CommissionIP(addrStrStorage, pincode, nodeid) - print("Connected") - return 0 - except Exception as ex: - print(f"Unable to connect on network: {ex}") - else: - print("Unable to locate device on network") - - if int(setupPayload.attributes["RendezvousInformation"]) & ble: - print("Attempting to connect via BLE") - longDiscriminator = ctypes.c_uint16( - int(setupPayload.attributes['Discriminator'])) - pincode = ctypes.c_uint32( - int(setupPayload.attributes['SetUpPINCode'])) - try: - self.devCtrl.ConnectBLE(longDiscriminator, pincode, nodeid) - print("Connected") - return 0 - except Exception as ex: - print(f"Unable to connect: {ex}") - return -1 - - def do_paseonly(self, line): - """ - paseonly -ip [] - - TODO: Add more methods to connect to device (like cert for auth, and IP - for connection) - """ - - try: - args = shlex.split(line) - if len(args) <= 1: - print("Usage:") - self.do_help("paseonly") - return - nodeid = random.randint(1, 1000000) # Just a random number - if len(args) == 4: - nodeid = int(args[3]) - print("Device is assigned with nodeid = {}".format(nodeid)) - self.replHint = f"devCtrl.EstablishPASESessionIP({repr(args[1])}, {int(args[2])}, {nodeid})" - if args[0] == "-ip" and len(args) >= 3: - self.devCtrl.EstablishPASESessionIP(args[1], int(args[2]), nodeid) - else: - print("Usage:") - self.do_help("paseonly") - return - print( - "Device temporary node id (**this does not match spec**): {}".format(nodeid)) - except Exception as ex: - print(str(ex)) - return - - def do_commission(self, line): - """ - commission nodeid - - Runs commissioning on a device that has been connected with paseonly - """ - try: - args = shlex.split(line) - if len(args) != 1: - print("Usage:") - self.do_help("commission") - return - nodeid = int(args[0]) - self.replHint = f"devCtrl.Commission({nodeid})" - self.devCtrl.Commission(nodeid) - except Exception as ex: - print(str(ex)) - return - - def do_connect(self, line): - """ - connect -ip [] - connect -ble [] - connect -qr [] - connect -code [] - - connect command is used for establishing a rendezvous session to the device. - currently, only connect using setupPinCode is supported. - -qr option will connect to the first device with a matching long discriminator. - - TODO: Add more methods to connect to device (like cert for auth, and IP - for connection) - """ - - warnings.warn( - "This method is being deprecated. " - "Please use the DeviceController.[ConnectBLE|CommissionIP] methods directly in the REPL", DeprecationWarning) - - try: - args = shlex.split(line) - if len(args) <= 1: - print("Usage:") - self.do_help("connect SetupPinCode") - return - - nodeid = random.randint(1, 1000000) # Just a random number - if len(args) == 4: - nodeid = int(args[3]) - print("Device is assigned with nodeid = {}".format(nodeid)) - - if args[0] == "-ip" and len(args) >= 3: - self.replHint = f"devCtrl.CommissionIP({repr(args[1])}, {int(args[2])}, {nodeid})" - self.devCtrl.CommissionIP(args[1], int(args[2]), nodeid) - elif args[0] == "-ble" and len(args) >= 3: - self.replHint = f"devCtrl.ConnectBLE({int(args[1])}, {int(args[2])}, {nodeid})" - self.devCtrl.ConnectBLE(int(args[1]), int(args[2]), nodeid) - elif args[0] in ['-qr', '-code'] and len(args) >= 2: - if len(args) == 3: - nodeid = int(args[2]) - print("Parsing QR code {}".format(args[1])) - - setupPayload = None - if args[0] == '-qr': - setupPayload = SetupPayload().ParseQrCode(args[1]) - elif args[0] == '-code': - setupPayload = SetupPayload( - ).ParseManualPairingCode(args[1]) - - if not int(setupPayload.attributes.get("RendezvousInformation", 0)): - print("No rendezvous information provided, default to all.") - setupPayload.attributes["RendezvousInformation"] = 0b111 - setupPayload.Print() - self.replHint = f"devCtrl.CommissionWithCode(setupPayload={repr(setupPayload)}, nodeid={nodeid})" - self.ConnectFromSetupPayload(setupPayload, nodeid) - else: - print("Usage:") - self.do_help("connect SetupPinCode") - return - print( - "Device temporary node id (**this does not match spec**): {}".format(nodeid)) - except exceptions.ChipStackException as ex: - print(str(ex)) - return - - def do_closesession(self, line): - """ - close-session - - Close any session associated with a given node ID. - """ - try: - parser = argparse.ArgumentParser() - parser.add_argument('nodeid', type=int, help='Peer node ID') - args = parser.parse_args(shlex.split(line)) - self.replHint = f"devCtrl.CloseSession({args.nodeid})" - self.devCtrl.CloseSession(args.nodeid) - except exceptions.ChipStackException as ex: - print(str(ex)) - except Exception: - self.do_help("close-session") - - def do_resolve(self, line): - """ - resolve - - Resolve DNS-SD name corresponding with the given node ID and - update address of the node in the device controller. - """ - try: - args = shlex.split(line) - if len(args) == 1: - try: - self.replHint = f"devCtrl.ResolveNode({int(args[0])});devCtrl.GetAddressAndPort({int(args[0])})" - self.devCtrl.ResolveNode(int(args[0])) - address = self.devCtrl.GetAddressAndPort(int(args[0])) - address = "{}:{}".format( - *address) if address else "unknown" - print("Current address: " + address) - except exceptions.ChipStackException as ex: - print(str(ex)) - else: - self.do_help("resolve") - except exceptions.ChipStackException as ex: - print(str(ex)) - return - - def wait_for_one_discovered_device(self): - print("Waiting for device responses...") - strlen = 100 - addrStrStorage = ctypes.create_string_buffer(strlen) - count = 0 - maxWaitTime = 2 - while (not self.devCtrl.GetIPForDiscoveredDevice(0, addrStrStorage, strlen) and count < maxWaitTime): - time.sleep(0.2) - count = count + 0.2 - return count < maxWaitTime - - def wait_for_many_discovered_devices(self): - # Discovery happens through mdns, which means we need to wait for responses to come back. - # TODO(cecille): I suppose we could make this a command line arg. Or Add a callback when - # x number of responses are received. For now, just 2 seconds. We can all wait that long. - print("Waiting for device responses...") - time.sleep(2) - - def do_discover(self, line): - """ - discover -qr qrcode - discover -all - discover -l long_discriminator - discover -s short_discriminator - discover -v vendor_id - discover -t device_type - discover -c - - discover command is used to discover available devices. - """ - try: - arglist = shlex.split(line) - if len(arglist) < 1: - print("Usage:") - self.do_help("discover") - return - parser = argparse.ArgumentParser() - group = parser.add_mutually_exclusive_group() - group.add_argument( - '-all', help='discover all commissionable nodes and commissioners', action='store_true') - group.add_argument( - '-qr', help='discover commissionable nodes matching provided QR code', type=str) - group.add_argument( - '-l', help='discover commissionable nodes with given long discriminator', type=int) - group.add_argument( - '-s', help='discover commissionable nodes with given short discriminator', type=int) - group.add_argument( - '-v', help='discover commissionable nodes with given vendor ID', type=int) - group.add_argument( - '-t', help='discover commissionable nodes with given device type', type=int) - group.add_argument( - '-c', help='discover commissionable nodes in commissioning mode', action='store_true') - args = parser.parse_args(arglist) - if args.all: - self.commissionableNodeCtrl.DiscoverCommissioners() - self.wait_for_many_discovered_devices() - self.commissionableNodeCtrl.PrintDiscoveredCommissioners() - self.devCtrl.DiscoverAllCommissioning() - self.wait_for_many_discovered_devices() - elif args.qr is not None: - setupPayload = SetupPayload().ParseQrCode(args.qr) - longDiscriminator = ctypes.c_uint16( - int(setupPayload.attributes['Discriminator'])) - self.devCtrl.DiscoverCommissionableNodesLongDiscriminator( - longDiscriminator) - self.wait_for_one_discovered_device() - elif args.l is not None: - self.devCtrl.DiscoverCommissionableNodesLongDiscriminator( - ctypes.c_uint16(args.l)) - self.wait_for_one_discovered_device() - elif args.s is not None: - self.devCtrl.DiscoverCommissionableNodesShortDiscriminator( - ctypes.c_uint16(args.s)) - self.wait_for_one_discovered_device() - elif args.v is not None: - self.devCtrl.DiscoverCommissionableNodesVendor( - ctypes.c_uint16(args.v)) - self.wait_for_many_discovered_devices() - elif args.t is not None: - self.devCtrl.DiscoverCommissionableNodesDeviceType( - ctypes.c_uint16(args.t)) - self.wait_for_many_discovered_devices() - elif args.c is not None: - self.devCtrl.DiscoverCommissionableNodesCommissioningEnabled() - self.wait_for_many_discovered_devices() - else: - self.do_help("discover") - return - self.devCtrl.PrintDiscoveredDevices() - except exceptions.ChipStackException as ex: - print('exception') - print(str(ex)) - return - except Exception: - self.do_help("discover") - return - - def do_zcl(self, line): - """ - To send ZCL message to device: - zcl [key=value]... - To get a list of clusters: - zcl ? - To get a list of commands in cluster: - zcl ? - - Send ZCL command to device nodeid - """ - try: - args = shlex.split(line) - all_commands = self.devCtrl.ZCLCommandList() - if len(args) == 1 and args[0] == '?': - print('\n'.join(all_commands.keys())) - elif len(args) == 2 and args[0] == '?': - if args[1] not in all_commands: - raise exceptions.UnknownCluster(args[1]) - for commands in all_commands.get(args[1]).items(): - args = ", ".join(["{}: {}".format(argName, argType) - for argName, argType in commands[1].items()]) - print(commands[0]) - if commands[1]: - print(" ", args) - else: - print(" ") - elif len(args) > 4: - if args[0] not in all_commands: - raise exceptions.UnknownCluster(args[0]) - command = all_commands.get(args[0]).get(args[1], None) - # When command takes no arguments, (not command) is True - if command is None: - raise exceptions.UnknownCommand(args[0], args[1]) - req = eval(f"Clusters.{args[0]}.Commands.{args[1]}")(**FormatZCLArguments(args[5:], command)) - self.replHint = f"await devCtrl.SendCommand({int(args[2])}, {int(args[3])}, Clusters.{repr(req)})" - err, res = self.devCtrl.ZCLSend(args[0], args[1], int( - args[2]), int(args[3]), int(args[4]), FormatZCLArguments(args[5:], command), blocking=True) - if err != 0: - print("Failed to receive command response: {}".format(res)) - elif res is not None: - print("Received command status response:") - print(res) - else: - print("Success, no status code is attached with response.") - else: - self.do_help("zcl") - except exceptions.ChipStackException as ex: - print("An exception occurred during process ZCL command:") - print(str(ex)) - except Exception as ex: - print("An exception occurred during processing input:") - traceback.print_exc() - print(str(ex)) - - def do_zclread(self, line): - """ - To read ZCL attribute: - zclread - """ - try: - args = shlex.split(line) - all_attrs = self.devCtrl.ZCLAttributeList() - if len(args) == 1 and args[0] == '?': - print('\n'.join(all_attrs.keys())) - elif len(args) == 2 and args[0] == '?': - if args[1] not in all_attrs: - raise exceptions.UnknownCluster(args[1]) - print('\n'.join(all_attrs.get(args[1]).keys())) - elif len(args) == 5: - if args[0] not in all_attrs: - raise exceptions.UnknownCluster(args[0]) - self.replHint = (f"await devCtrl.ReadAttribute({int(args[2])}, [({int(args[3])}, " - f"Clusters.{args[0]}.Attributes.{args[1]})])") - res = self.devCtrl.ZCLReadAttribute(args[0], args[1], int( - args[2]), int(args[3]), int(args[4])) - if res is not None: - print(repr(res)) - else: - self.do_help("zclread") - except exceptions.ChipStackException as ex: - print("An exception occurred during reading ZCL attribute:") - print(str(ex)) - except Exception as ex: - print("An exception occurred during processing input:") - print(str(ex)) - - def do_zclwrite(self, line): - """ - To write ZCL attribute: - zclwrite - """ - try: - args = shlex.split(line) - all_attrs = self.devCtrl.ZCLAttributeList() - if len(args) == 1 and args[0] == '?': - print('\n'.join(all_attrs.keys())) - elif len(args) == 2 and args[0] == '?': - if args[1] not in all_attrs: - raise exceptions.UnknownCluster(args[1]) - cluster_attrs = all_attrs.get(args[1], {}) - print('\n'.join(["{}: {}".format(key, cluster_attrs[key]["type"]) - for key in cluster_attrs.keys() if cluster_attrs[key].get("writable", False)])) - elif len(args) == 6: - if args[0] not in all_attrs: - raise exceptions.UnknownCluster(args[0]) - attribute_type = all_attrs.get(args[0], {}).get( - args[1], {}).get("type", None) - self.replHint = ( - f"await devCtrl.WriteAttribute({int(args[2])}, [({int(args[3])}, " - f"Clusters.{args[0]}.Attributes.{args[1]}(value={repr(ParseValueWithType(args[5], attribute_type))}))])") - res = self.devCtrl.ZCLWriteAttribute(args[0], args[1], int( - args[2]), int(args[3]), int(args[4]), ParseValueWithType(args[5], attribute_type)) - print(repr(res)) - else: - self.do_help("zclwrite") - except exceptions.ChipStackException as ex: - print("An exception occurred during writing ZCL attribute:") - print(str(ex)) - except Exception as ex: - print("An exception occurred during processing input:") - print(str(ex)) - - def do_zclsubscribe(self, line): - """ - To subscribe ZCL attribute reporting: - zclsubscribe - - To shut down a subscription: - zclsubscribe -shutdown - """ - try: - args = shlex.split(line) - all_attrs = self.devCtrl.ZCLAttributeList() - if len(args) == 1 and args[0] == '?': - print('\n'.join(all_attrs.keys())) - elif len(args) == 2 and args[0] == '?': - if args[1] not in all_attrs: - raise exceptions.UnknownCluster(args[1]) - cluster_attrs = all_attrs.get(args[1], {}) - print('\n'.join([key for key in cluster_attrs.keys( - ) if cluster_attrs[key].get("reportable", False)])) - elif len(args) == 6: - if args[0] not in all_attrs: - raise exceptions.UnknownCluster(args[0]) - res = self.devCtrl.ZCLSubscribeAttribute(args[0], args[1], int( - args[2]), int(args[3]), int(args[4]), int(args[5])) - self.replHint = (f"sub = await devCtrl.ReadAttribute({int(args[2])}, [({int(args[3])}, " - f"Clusters.{args[0]}.Attributes.{args[1]})], reportInterval=({int(args[4])}, {int(args[5])}))") - print(res.GetAllValues()) - print(f"Subscription Established: {res}") - elif len(args) == 2 and args[0] == '-shutdown': - subscriptionId = int(args[1], base=0) - self.replHint = "You can call sub.Shutdown() (sub is the return value of ReadAttribute() called before)" - self.devCtrl.ZCLShutdownSubscription(subscriptionId) - else: - self.do_help("zclsubscribe") - except exceptions.ChipStackException as ex: - print("An exception occurred during configuring reporting of ZCL attribute:") - print(str(ex)) - except Exception as ex: - print("An exception occurred during processing input:") - print(str(ex)) - - def do_setpairingwificredential(self, line): - """ - set-pairing-wifi-credential ssid credentials - """ - try: - args = shlex.split(line) - if len(args) < 2: - print("Usage:") - self.do_help("set-pairing-wifi-credential") - return - self.devCtrl.SetWiFiCredentials( - args[0], args[1]) - self.replHint = f"devCtrl.SetWiFiCredentials({repr(args[0])}, {repr(args[1])})" - except Exception as ex: - print(str(ex)) - return - - def do_setpairingthreadcredential(self, line): - """ - set-pairing-thread-credential threadOperationalDataset - """ - try: - args = shlex.split(line) - if len(args) < 1: - print("Usage:") - self.do_help("set-pairing-thread-credential") - return - self.replHint = f"devCtrl.SetThreadOperationalDataset(bytes.fromhex({repr(args[0])}))" - self.devCtrl.SetThreadOperationalDataset(bytes.fromhex(args[0])) - except Exception as ex: - print(str(ex)) - return - - def do_opencommissioningwindow(self, line): - """ - open-commissioning-window [options] - - Options: - -t Timeout (in seconds) - -o Option [TokenWithRandomPIN = 1, TokenWithProvidedPIN = 2] - -d Discriminator Value - -i Iteration - - This command is used by a current Administrator to instruct a Node to go into commissioning mode - """ - try: - arglist = shlex.split(line) - - if len(arglist) <= 1: - print("Usage:") - self.do_help("open-commissioning-window") - return - parser = argparse.ArgumentParser() - parser.add_argument( - "-t", type=int, default=0, dest='timeout') - parser.add_argument( - "-o", type=int, default=1, dest='option') - parser.add_argument( - "-i", type=int, default=0, dest='iteration') - parser.add_argument( - "-d", type=int, default=0, dest='discriminator') - args = parser.parse_args(arglist[1:]) - - if args.option < 1 or args.option > 2: - print("Invalid option specified!") - raise ValueError("Invalid option specified") - - self.replHint = (f"devCtrl.OpenCommissioningWindow(nodeid={int(arglist[0])}, timeout={args.timeout}, " - f"iteration={args.iteration}, discriminator={args.discriminator}, option={args.option})") - - self.devCtrl.OpenCommissioningWindow( - int(arglist[0]), args.timeout, args.iteration, args.discriminator, args.option) - - except exceptions.ChipStackException as ex: - print(str(ex)) - return - except Exception: - self.do_help("open-commissioning-window") - return - - def do_getfabricid(self, line): - """ - get-fabricid - - Read the current Compressed Fabric Id of the controller device, return 0 if not available. - """ - try: - args = shlex.split(line) - - if (len(args) > 0): - print("Unexpected argument: " + args[1]) - return - - compressed_fabricid = self.devCtrl.GetCompressedFabricId() - raw_fabricid = self.devCtrl.fabricId - - self.replHint = "devCtrl.GetCompressedFabricId(), devCtrl.fabricId" - except exceptions.ChipStackException as ex: - print("An exception occurred during reading FabricID:") - print(str(ex)) - return - - print("Get fabric ID complete") - - print("Raw Fabric ID: 0x{:016x}".format(raw_fabricid) - + " (" + str(raw_fabricid) + ")") - - print("Compressed Fabric ID: 0x{:016x}".format(compressed_fabricid) - + " (" + str(compressed_fabricid) + ")") - - def do_history(self, line): - """ - history - - Show previously executed commands. - """ - - try: - import readline - - h = readline.get_current_history_length() - for n in range(1, h + 1): - print(readline.get_history_item(n)) - except ImportError: - pass - - def do_h(self, line): - self.do_history(line) - - def do_exit(self, line): - return True - - def do_quit(self, line): - return True - - def do_q(self, line): - return True - - def do_EOF(self, line): - print() - return True - - def emptyline(self): - pass - - -def main(): - optParser = OptionParser() - optParser.add_option( - "-r", - "--rendezvous-addr", - action="store", - dest="rendezvousAddr", - help="Device rendezvous address", - metavar="", - ) - optParser.add_option( - "-n", - "--controller-nodeid", - action="store", - dest="controllerNodeId", - default=1, - type='int', - help="Controller node ID", - metavar="", - ) - - if sys.platform.startswith("linux"): - optParser.add_option( - "-b", - "--bluetooth-adapter", - action="store", - dest="bluetoothAdapter", - default="hci0", - type="str", - help="Controller bluetooth adapter ID, use --no-ble to disable bluetooth functions.", - metavar="", - ) - optParser.add_option( - "--no-ble", - action="store_true", - dest="disableBluetooth", - help="Disable bluetooth, calling BLE related feature with this flag results in undefined behavior.", - ) - (options, remainingArgs) = optParser.parse_args(sys.argv[1:]) - - if len(remainingArgs) != 0: - print("Unexpected argument: %s" % remainingArgs[0]) - sys.exit(-1) - - adapterId = None - if sys.platform.startswith("linux"): - if options.disableBluetooth: - adapterId = None - elif not options.bluetoothAdapter.startswith("hci"): - print( - "Invalid bluetooth adapter: {}, adapter name looks like hci0, hci1 etc.") - sys.exit(-1) - else: - try: - adapterId = int(options.bluetoothAdapter[3:]) - except ValueError: - print( - "Invalid bluetooth adapter: {}, adapter name looks like hci0, hci1 etc.") - sys.exit(-1) - native.Init(bluetoothAdapter=adapterId) - try: - devMgrCmd = DeviceMgrCmd(rendezvousAddr=options.rendezvousAddr, - controllerNodeId=options.controllerNodeId, bluetoothAdapter=adapterId) - except Exception as ex: - print(ex) - print("Failed to bringup CHIPDeviceController CLI") - sys.exit(1) - - print("Chip Device Controller Shell") - if options.rendezvousAddr: - print("Rendezvous address set to %s" % options.rendezvousAddr) - - # Adapter ID will always be 0 - if adapterId != 0: - print("Bluetooth adapter set to hci{}".format(adapterId)) - print() - - try: - devMgrCmd.cmdloop() - except KeyboardInterrupt: - print("\nQuitting") - - sys.exit(0) - - -if __name__ == "__main__": - print(""" - chip-device-ctrl will be deprecated and will be removed in the future. Please try chip-repl, which provides a lot of features. - - - Multi-fabric support, - - Better complex type support for sending commands, - - Native command highlight, - - Parallel commands with asyncio, - - Writing complex logic inline. - - You can still use chip-device-ctrl as usual for now, and you will learn how to do the same thing in chip-repl. - - Feel free to file an issue if some features are not supported by chip-repl yet. - """) - main() diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index d63a3772e62dc6..4fb8fb28bcaf90 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -50,12 +50,9 @@ from .clusters import Attribute as ClusterAttribute from .clusters import ClusterObjects as ClusterObjects from .clusters import Command as ClusterCommand -from .clusters import Objects as GeneratedObjects from .clusters.CHIPClusters import ChipClusters from .crypto import p256keypair -from .exceptions import UnknownAttribute, UnknownCommand -from .interaction_model import InteractionModelError, SessionParameters, SessionParametersStruct -from .interaction_model import delegate as im +from .interaction_model import SessionParameters, SessionParametersStruct from .native import PyChipError __all__ = ["ChipDeviceController", "CommissioningParameters"] @@ -1170,33 +1167,26 @@ def _parseAttributePathTuple(self, pathTuple: typing.Union[ # Concrete path typing.Tuple[int, typing.Type[ClusterObjects.ClusterAttributeDescriptor]] ]): - endpoint = None - cluster = None - attribute = None - if pathTuple == ('*') or pathTuple == (): # Wildcard - pass + return ClusterAttribute.AttributePath() elif not isinstance(pathTuple, tuple): if isinstance(pathTuple, int): - endpoint = pathTuple + return ClusterAttribute.AttributePath(EndpointId=pathTuple) elif issubclass(pathTuple, ClusterObjects.Cluster): - cluster = pathTuple + return ClusterAttribute.AttributePath.from_cluster(EndpointId=None, Cluster=pathTuple) elif issubclass(pathTuple, ClusterObjects.ClusterAttributeDescriptor): - attribute = pathTuple + return ClusterAttribute.AttributePath.from_attribute(EndpointId=None, Attribute=pathTuple) else: raise ValueError("Unsupported Attribute Path") else: # endpoint + (cluster) attribute / endpoint + cluster - endpoint = pathTuple[0] if issubclass(pathTuple[1], ClusterObjects.Cluster): - cluster = pathTuple[1] + return ClusterAttribute.AttributePath.from_cluster(EndpointId=pathTuple[0], Cluster=pathTuple[1]) elif issubclass(pathTuple[1], ClusterAttribute.ClusterAttributeDescriptor): - attribute = pathTuple[1] + return ClusterAttribute.AttributePath.from_attribute(EndpointId=pathTuple[0], Attribute=pathTuple[1]) else: raise ValueError("Unsupported Attribute Path") - return ClusterAttribute.AttributePath( - EndpointId=endpoint, Cluster=cluster, Attribute=attribute) def _parseDataVersionFilterTuple(self, pathTuple: typing.List[typing.Tuple[int, typing.Type[ClusterObjects.Cluster], int]]): endpoint = None @@ -1209,7 +1199,7 @@ def _parseDataVersionFilterTuple(self, pathTuple: typing.List[typing.Tuple[int, else: raise ValueError("Unsupported Cluster Path") dataVersion = pathTuple[2] - return ClusterAttribute.DataVersionFilter( + return ClusterAttribute.DataVersionFilter.from_cluster( EndpointId=endpoint, Cluster=cluster, DataVersion=dataVersion) def _parseEventPathTuple(self, pathTuple: typing.Union[ @@ -1226,39 +1216,31 @@ def _parseEventPathTuple(self, pathTuple: typing.Union[ typing.Tuple[int, typing.Type[ClusterObjects.ClusterEvent], int] ]): - endpoint = None - cluster = None - event = None - urgent = False if pathTuple in [('*'), ()]: # Wildcard - pass + return ClusterAttribute.EventPath() elif not isinstance(pathTuple, tuple): logging.debug(type(pathTuple)) if isinstance(pathTuple, int): - endpoint = pathTuple + return ClusterAttribute.EventPath(EndpointId=pathTuple) elif issubclass(pathTuple, ClusterObjects.Cluster): - cluster = pathTuple + return ClusterAttribute.EventPath.from_cluster(EndpointId=None, Cluster=pathTuple) elif issubclass(pathTuple, ClusterObjects.ClusterEvent): - event = pathTuple + return ClusterAttribute.EventPath.from_event(EndpointId=None, Event=pathTuple) else: raise ValueError("Unsupported Event Path") else: if pathTuple[0] == '*': - urgent = pathTuple[-1] - pass + return ClusterAttribute.EventPath(Urgent=pathTuple[-1]) else: + urgent = bool(pathTuple[-1]) if len(pathTuple) > 2 else False # endpoint + (cluster) event / endpoint + cluster - endpoint = pathTuple[0] if issubclass(pathTuple[1], ClusterObjects.Cluster): - cluster = pathTuple[1] + return ClusterAttribute.EventPath.from_cluster(EndpointId=pathTuple[0], Cluster=pathTuple[1], Urgent=urgent) elif issubclass(pathTuple[1], ClusterAttribute.ClusterEvent): - event = pathTuple[1] + return ClusterAttribute.EventPath.from_event(EndpointId=pathTuple[0], Event=pathTuple[1], Urgent=urgent) else: raise ValueError("Unsupported Attribute Path") - urgent = bool(pathTuple[-1]) if len(pathTuple) > 2 else False - return ClusterAttribute.EventPath( - EndpointId=endpoint, Cluster=cluster, Event=event, Urgent=urgent) async def Read(self, nodeid: int, attributes: typing.List[typing.Union[ None, # Empty tuple, all wildcard @@ -1495,83 +1477,6 @@ async def ReadEvent(self, nodeid: int, events: typing.List[typing.Union[ else: return res.events - def ZCLSend(self, cluster, command, nodeid, endpoint, groupid, args, blocking=False): - ''' Wrapper over SendCommand that catches the exceptions - Returns a tuple of (errorCode, CommandResponse) - ''' - self.CheckIsActive() - - req = None - try: - req = eval( - f"GeneratedObjects.{cluster}.Commands.{command}")(**args) - except BaseException: - raise UnknownCommand(cluster, command) - try: - res = asyncio.run(self.SendCommand(nodeid, endpoint, req)) - logging.debug(f"CommandResponse {res}") - return (0, res) - except InteractionModelError as ex: - return (int(ex.status), None) - - def ZCLReadAttribute(self, cluster, attribute, nodeid, endpoint, groupid, blocking=True): - ''' Wrapper over ReadAttribute for a single attribute - Returns an AttributeReadResult - ''' - self.CheckIsActive() - - clusterType = getattr(GeneratedObjects, cluster) - - try: - attributeType = eval( - f"GeneratedObjects.{cluster}.Attributes.{attribute}") - except BaseException: - raise UnknownAttribute(cluster, attribute) - - result = asyncio.run(self.ReadAttribute( - nodeid, [(endpoint, attributeType)])) - path = ClusterAttribute.AttributePath( - EndpointId=endpoint, Attribute=attributeType) - return im.AttributeReadResult(path=im.AttributePath(nodeId=nodeid, endpointId=path.EndpointId, clusterId=path.ClusterId, attributeId=path.AttributeId), - status=0, value=result[endpoint][clusterType][attributeType], dataVersion=result[endpoint][clusterType][ClusterAttribute.DataVersion]) - - def ZCLWriteAttribute(self, cluster: str, attribute: str, nodeid, endpoint, groupid, value, dataVersion=0, blocking=True): - ''' Wrapper over WriteAttribute for a single attribute - return PyChipError - ''' - req = None - try: - req = eval( - f"GeneratedObjects.{cluster}.Attributes.{attribute}")(value) - except BaseException: - raise UnknownAttribute(cluster, attribute) - - return asyncio.run(self.WriteAttribute(nodeid, [(endpoint, req, dataVersion)])) - - def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterval, maxInterval, blocking=True, - keepSubscriptions=False, autoResubscribe=True): - ''' Wrapper over ReadAttribute for a single attribute - Returns a SubscriptionTransaction. See ReadAttribute for more information. - ''' - self.CheckIsActive() - - req = None - try: - req = eval(f"GeneratedObjects.{cluster}.Attributes.{attribute}") - except BaseException: - raise UnknownAttribute(cluster, attribute) - return asyncio.run(self.ReadAttribute(nodeid, [(endpoint, req)], None, False, reportInterval=(minInterval, maxInterval), - keepSubscriptions=keepSubscriptions, autoResubscribe=autoResubscribe)) - - def ZCLCommandList(self): - self.CheckIsActive() - return self._Cluster.ListClusterCommands() - - def ZCLAttributeList(self): - self.CheckIsActive() - - return self._Cluster.ListClusterAttributes() - def SetBlockingCB(self, blockingCB): self.CheckIsActive() diff --git a/src/controller/python/chip/ChipReplStartup.py b/src/controller/python/chip/ChipReplStartup.py index a49638cb99e56d..b75c77efcd5b2b 100644 --- a/src/controller/python/chip/ChipReplStartup.py +++ b/src/controller/python/chip/ChipReplStartup.py @@ -94,6 +94,8 @@ def main(): "-d", "--debug", help="Set default logging level to debug.", action="store_true") parser.add_argument( "-t", "--trust-store", help="Path to the PAA trust store.", action="store", default="./credentials/development/paa-root-certs") + parser.add_argument( + "-b", "--ble-adapter", help="Set the Bluetooth adapter index.", type=int, default=None) args = parser.parse_args() if not os.path.exists(args.trust_store): @@ -128,7 +130,7 @@ def main(): # nothing we can do ... things will NOT work return - chip.native.Init() + chip.native.Init(bluetoothAdapter=args.ble_adapter) global certificateAuthorityManager global chipStack diff --git a/src/controller/python/chip/clusters/Attribute.py b/src/controller/python/chip/clusters/Attribute.py index 0b4601f9daa3bf..1471999c6232ae 100644 --- a/src/controller/python/chip/clusters/Attribute.py +++ b/src/controller/python/chip/clusters/Attribute.py @@ -54,62 +54,43 @@ class EventPriority(Enum): CRITICAL = 2 -@dataclass +@dataclass(frozen=True) class AttributePath: EndpointId: int = None ClusterId: int = None AttributeId: int = None - def __init__(self, EndpointId: int = None, Cluster=None, Attribute=None, ClusterId=None, AttributeId=None): - self.EndpointId = EndpointId - if Cluster is not None: - # Wildcard read for a specific cluster - if (Attribute is not None) or (ClusterId is not None) or (AttributeId is not None): - raise Warning( - "Attribute, ClusterId and AttributeId is ignored when Cluster is specified") - self.ClusterId = Cluster.id - return - if Attribute is not None: - if (ClusterId is not None) or (AttributeId is not None): - raise Warning( - "ClusterId and AttributeId is ignored when Attribute is specified") - self.ClusterId = Attribute.cluster_id - self.AttributeId = Attribute.attribute_id - return - self.ClusterId = ClusterId - self.AttributeId = AttributeId + @staticmethod + def from_cluster(EndpointId: int, Cluster: Cluster) -> AttributePath: + if Cluster is None: + raise ValueError("Cluster cannot be None") + return AttributePath(EndpointId=EndpointId, ClusterId=Cluster.id) + + @staticmethod + def from_attribute(EndpointId: int, Attribute: ClusterAttributeDescriptor) -> AttributePath: + if Attribute is None: + raise ValueError("Attribute cannot be None") + return AttributePath(EndpointId=EndpointId, ClusterId=Attribute.cluster_id, AttributeId=Attribute.attribute_id) def __str__(self) -> str: return f"{self.EndpointId}/{self.ClusterId}/{self.AttributeId}" - def __hash__(self): - return str(self).__hash__() - -@dataclass +@dataclass(frozen=True) class DataVersionFilter: EndpointId: int = None ClusterId: int = None DataVersion: int = None - def __init__(self, EndpointId: int = None, Cluster=None, ClusterId=None, DataVersion=None): - self.EndpointId = EndpointId - if Cluster is not None: - # Wildcard read for a specific cluster - if (ClusterId is not None): - raise Warning( - "Attribute, ClusterId and AttributeId is ignored when Cluster is specified") - self.ClusterId = Cluster.id - else: - self.ClusterId = ClusterId - self.DataVersion = DataVersion + @staticmethod + def from_cluster(EndpointId: int, Cluster: Cluster, DataVersion: int = None) -> AttributePath: + if Cluster is None: + raise ValueError("Cluster cannot be None") + return DataVersionFilter(EndpointId=EndpointId, ClusterId=Cluster.id, DataVersion=DataVersion) def __str__(self) -> str: return f"{self.EndpointId}/{self.ClusterId}/{self.DataVersion}" - def __hash__(self): - return str(self).__hash__() - @dataclass class TypedAttributePath: @@ -165,44 +146,28 @@ def __init__(self, ClusterType: Cluster = None, AttributeType: ClusterAttributeD self.AttributeId = self.AttributeType.attribute_id -@dataclass +@dataclass(frozen=True) class EventPath: EndpointId: int = None ClusterId: int = None EventId: int = None Urgent: int = None - def __init__(self, EndpointId: int = None, Cluster=None, Event=None, ClusterId=None, EventId=None, Urgent=None): - self.EndpointId = EndpointId - self.Urgent = Urgent - if Cluster is not None: - # Wildcard read for a specific cluster - if (Event is not None) or (ClusterId is not None) or (EventId is not None): - raise Warning( - "Event, ClusterId and AttributeId is ignored when Cluster is specified") - self.ClusterId = Cluster.id - return - if Event is not None: - if (ClusterId is not None) or (EventId is not None): - raise Warning( - "ClusterId and EventId is ignored when Event is specified") - self.ClusterId = Event.cluster_id - self.EventId = Event.event_id - return - self.ClusterId = ClusterId - self.EventId = EventId + @staticmethod + def from_cluster(EndpointId: int, Cluster: Cluster, EventId: int = None, Urgent: int = None) -> "EventPath": + if Cluster is None: + raise ValueError("Cluster cannot be None") + return EventPath(EndpointId=EndpointId, ClusterId=Cluster.id, EventId=EventId, Urgent=Urgent) + + @staticmethod + def from_event(EndpointId: int, Event: ClusterEvent, Urgent: int = None) -> "EventPath": + if Event is None: + raise ValueError("Event cannot be None") + return EventPath(EndpointId=EndpointId, ClusterId=Event.cluster_id, EventId=Event.event_id, Urgent=Urgent) def __str__(self) -> str: return f"{self.EndpointId}/{self.ClusterId}/{self.EventId}/{self.Urgent}" - def __hash__(self): - return str(self).__hash__() - - -@dataclass -class AttributePathWithListIndex(AttributePath): - ListIndex: int = None - @dataclass class EventHeader: @@ -698,7 +663,7 @@ def SetClientObjPointers(self, pReadClient, pReadCallback): def GetAllEventValues(self): return self._events - def handleAttributeData(self, path: AttributePathWithListIndex, dataVersion: int, status: int, data: bytes): + def handleAttributeData(self, path: AttributePath, dataVersion: int, status: int, data: bytes): try: imStatus = chip.interaction_model.Status(status) diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 3bc715829f27db..6acd5596b06d50 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -11535,6 +11535,62 @@ class ChipClusters: }, }, } + _WI_FI_NETWORK_MANAGEMENT_CLUSTER_INFO = { + "clusterName": "WiFiNetworkManagement", + "clusterId": 0x00000451, + "commands": { + 0x00000000: { + "commandId": 0x00000000, + "commandName": "NetworkPassphraseRequest", + "args": { + }, + }, + }, + "attributes": { + 0x00000001: { + "attributeName": "Ssid", + "attributeId": 0x00000001, + "type": "bytes", + "reportable": True, + }, + 0x0000FFF8: { + "attributeName": "GeneratedCommandList", + "attributeId": 0x0000FFF8, + "type": "int", + "reportable": True, + }, + 0x0000FFF9: { + "attributeName": "AcceptedCommandList", + "attributeId": 0x0000FFF9, + "type": "int", + "reportable": True, + }, + 0x0000FFFA: { + "attributeName": "EventList", + "attributeId": 0x0000FFFA, + "type": "int", + "reportable": True, + }, + 0x0000FFFB: { + "attributeName": "AttributeList", + "attributeId": 0x0000FFFB, + "type": "int", + "reportable": True, + }, + 0x0000FFFC: { + "attributeName": "FeatureMap", + "attributeId": 0x0000FFFC, + "type": "int", + "reportable": True, + }, + 0x0000FFFD: { + "attributeName": "ClusterRevision", + "attributeId": 0x0000FFFD, + "type": "int", + "reportable": True, + }, + }, + } _WAKE_ON_LAN_CLUSTER_INFO = { "clusterName": "WakeOnLan", "clusterId": 0x00000503, @@ -14638,6 +14694,7 @@ class ChipClusters: 0x0000042D: _PM10_CONCENTRATION_MEASUREMENT_CLUSTER_INFO, 0x0000042E: _TOTAL_VOLATILE_ORGANIC_COMPOUNDS_CONCENTRATION_MEASUREMENT_CLUSTER_INFO, 0x0000042F: _RADON_CONCENTRATION_MEASUREMENT_CLUSTER_INFO, + 0x00000451: _WI_FI_NETWORK_MANAGEMENT_CLUSTER_INFO, 0x00000503: _WAKE_ON_LAN_CLUSTER_INFO, 0x00000504: _CHANNEL_CLUSTER_INFO, 0x00000505: _TARGET_NAVIGATOR_CLUSTER_INFO, @@ -14759,6 +14816,7 @@ class ChipClusters: "Pm10ConcentrationMeasurement": _PM10_CONCENTRATION_MEASUREMENT_CLUSTER_INFO, "TotalVolatileOrganicCompoundsConcentrationMeasurement": _TOTAL_VOLATILE_ORGANIC_COMPOUNDS_CONCENTRATION_MEASUREMENT_CLUSTER_INFO, "RadonConcentrationMeasurement": _RADON_CONCENTRATION_MEASUREMENT_CLUSTER_INFO, + "WiFiNetworkManagement": _WI_FI_NETWORK_MANAGEMENT_CLUSTER_INFO, "WakeOnLan": _WAKE_ON_LAN_CLUSTER_INFO, "Channel": _CHANNEL_CLUSTER_INFO, "TargetNavigator": _TARGET_NAVIGATOR_CLUSTER_INFO, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index cd411b93d43301..c2db68c0ecfd4c 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -40230,6 +40230,175 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'uint' = 0 +@dataclass +class WiFiNetworkManagement(Cluster): + id: typing.ClassVar[int] = 0x00000451 + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="ssid", Tag=0x00000001, Type=typing.Union[Nullable, bytes]), + ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="attributeList", Tag=0x0000FFFB, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="featureMap", Tag=0x0000FFFC, Type=uint), + ClusterObjectFieldDescriptor(Label="clusterRevision", Tag=0x0000FFFD, Type=uint), + ]) + + ssid: 'typing.Union[Nullable, bytes]' = None + generatedCommandList: 'typing.List[uint]' = None + acceptedCommandList: 'typing.List[uint]' = None + eventList: 'typing.List[uint]' = None + attributeList: 'typing.List[uint]' = None + featureMap: 'uint' = None + clusterRevision: 'uint' = None + + class Commands: + @dataclass + class NetworkPassphraseRequest(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000451 + command_id: typing.ClassVar[int] = 0x00000000 + is_client: typing.ClassVar[bool] = True + response_type: typing.ClassVar[str] = 'NetworkPassphraseResponse' + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ]) + + @dataclass + class NetworkPassphraseResponse(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000451 + command_id: typing.ClassVar[int] = 0x00000001 + is_client: typing.ClassVar[bool] = False + response_type: typing.ClassVar[str] = None + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="passphrase", Tag=0, Type=bytes), + ]) + + passphrase: 'bytes' = b"" + + class Attributes: + @dataclass + class Ssid(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000001 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Union[Nullable, bytes]) + + value: 'typing.Union[Nullable, bytes]' = NullValue + + @dataclass + class GeneratedCommandList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFF8 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class AcceptedCommandList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFF9 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class EventList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFA + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class AttributeList(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFB + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) + + value: 'typing.List[uint]' = field(default_factory=lambda: []) + + @dataclass + class FeatureMap(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFC + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + @dataclass + class ClusterRevision(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000451 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x0000FFFD + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=uint) + + value: 'uint' = 0 + + @dataclass class WakeOnLan(Cluster): id: typing.ClassVar[int] = 0x00000503 diff --git a/src/controller/python/test/test_scripts/cluster_objects.py b/src/controller/python/test/test_scripts/cluster_objects.py index 53516c1dc75e9b..37f6819cbe66a4 100644 --- a/src/controller/python/test/test_scripts/cluster_objects.py +++ b/src/controller/python/test/test_scripts/cluster_objects.py @@ -164,7 +164,7 @@ async def TestWriteRequest(cls, devCtrl): ] ) expectedRes = [ - AttributeStatus(Path=AttributePath( + AttributeStatus(Path=AttributePath.from_attribute( EndpointId=1, Attribute=Clusters.UnitTesting.Attributes.ListLongOctetString), Status=chip.interaction_model.Status.Success), ] diff --git a/src/crypto/tests/TestChipCryptoPAL.cpp b/src/crypto/tests/TestChipCryptoPAL.cpp index c7ad4f3f290522..b4e0fbb2558057 100644 --- a/src/crypto/tests/TestChipCryptoPAL.cpp +++ b/src/crypto/tests/TestChipCryptoPAL.cpp @@ -2804,8 +2804,8 @@ TEST_F(TestChipCryptoPAL, TestVIDPID_x509Extraction) AttestationCertVidPid vidpid; CHIP_ERROR result = ExtractVIDPIDFromX509Cert(testCase.cert, vidpid); EXPECT_EQ(result, testCase.expectedResult); - EXPECT_EQ(vidpid.mVendorId.HasValue(), testCase.expectedVidPresent); - EXPECT_EQ(vidpid.mProductId.HasValue(), testCase.expectedPidPresent); + ASSERT_EQ(vidpid.mVendorId.HasValue(), testCase.expectedVidPresent); + ASSERT_EQ(vidpid.mProductId.HasValue(), testCase.expectedPidPresent); // If present, make sure the VID matches expectation. if (testCase.expectedVidPresent) diff --git a/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm b/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm index 1e44b4a04ef702..62deb58f5008e6 100644 --- a/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm +++ b/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm @@ -77,7 +77,7 @@ - (NSString *)description std::lock_guard lock(_lock); return [NSString - stringWithFormat:@"MTRAsyncCallbackWorkQueue context: %@ items count: %lu", self.context, (unsigned long) self.items.count]; + stringWithFormat:@"MTRAsyncCallbackWorkQueue context: %@ items count: %lu", self.context, static_cast(self.items.count)]; } - (void)enqueueWorkItem:(MTRAsyncCallbackQueueWorkItem *)item diff --git a/src/darwin/Framework/CHIP/MTRAsyncWorkQueue.mm b/src/darwin/Framework/CHIP/MTRAsyncWorkQueue.mm index 7220b6f72fc208..4d82fded930b87 100644 --- a/src/darwin/Framework/CHIP/MTRAsyncWorkQueue.mm +++ b/src/darwin/Framework/CHIP/MTRAsyncWorkQueue.mm @@ -84,7 +84,7 @@ - (void)setDuplicateTypeID:(NSUInteger)opaqueDuplicateTypeID handler:(MTRAsyncWo - (void)assertMutable { - NSAssert(_state == MTRAsyncWorkItemMutable, @"work item is not mutable (%ld)", (long) _state); + NSAssert(_state == MTRAsyncWorkItemMutable, @"work item is not mutable (%ld)", static_cast(_state)); } #pragma mark Management by the work queue (queue lock held) @@ -109,7 +109,7 @@ - (NSInteger)retryCount - (void)callReadyHandlerWithContext:(id)context completion:(MTRAsyncWorkCompletionBlock)completion { - NSAssert(_state >= MTRAsyncWorkItemEnqueued, @"work item is not enqueued (%ld)", (long) _state); + NSAssert(_state >= MTRAsyncWorkItemEnqueued, @"work item is not enqueued (%ld)", static_cast(_state)); NSInteger retryCount = 0; if (_state == MTRAsyncWorkItemEnqueued) { _state = MTRAsyncWorkItemRunning; @@ -161,7 +161,7 @@ - (BOOL)isComplete - (void)markComplete { - NSAssert(_state >= MTRAsyncWorkItemEnqueued, @"work item was not enqueued (%ld)", (long) _state); + NSAssert(_state >= MTRAsyncWorkItemEnqueued, @"work item was not enqueued (%ld)", static_cast(_state)); _state = MTRAsyncWorkItemComplete; // Clear all handlers in case any of them captured this object. @@ -185,7 +185,7 @@ - (NSString *)description state = @"enqueued"; break; default: - return [NSString stringWithFormat:@"<%@ %llu running retry: %tu>", self.class, _uniqueID, self.retryCount]; + return [NSString stringWithFormat:@"<%@ %llu running retry: %ld>", self.class, _uniqueID, static_cast(self.retryCount)]; } return [NSString stringWithFormat:@"<%@ %llu %@>", self.class, _uniqueID, state]; } @@ -236,7 +236,7 @@ - (NSString *)description { ContextSnapshot context(self); std::lock_guard lock(_lock); - return [NSString stringWithFormat:@"<%@ context: %@, items count: %tu>", self.class, context.description, _items.count]; + return [NSString stringWithFormat:@"<%@ context: %@, items count: %lu>", self.class, context.description, static_cast(_items.count)]; } - (void)enqueueWorkItem:(MTRAsyncWorkItem *)item @@ -268,9 +268,9 @@ - (void)enqueueWorkItem:(MTRAsyncWorkItem *)item // Logging the description once is enough because other log messages // related to the work item (execution, completion etc) can easily be // correlated using the unique id. - MTR_LOG("MTRAsyncWorkQueue<%@, items count: %tu> enqueued work item [%llu]: %@", context.description, _items.count, item.uniqueID, description); + MTR_LOG("MTRAsyncWorkQueue<%@, items count: %lu> enqueued work item [%llu]: %@", context.description, static_cast(_items.count), item.uniqueID, description); } else { - MTR_LOG("MTRAsyncWorkQueue<%@, items count: %tu> enqueued work item [%llu]", context.description, _items.count, item.uniqueID); + MTR_LOG("MTRAsyncWorkQueue<%@, items count: %lu> enqueued work item [%llu]", context.description, static_cast(_items.count), item.uniqueID); } [self _callNextReadyWorkItemWithContext:context]; @@ -280,7 +280,7 @@ - (void)invalidate { ContextSnapshot context(self); // outside of lock std::lock_guard lock(_lock); - MTR_LOG("MTRAsyncWorkQueue<%@> invalidate %tu items", context.description, _items.count); + MTR_LOG("MTRAsyncWorkQueue<%@> invalidate %lu items", context.description, static_cast(_items.count)); for (MTRAsyncWorkItem * item in _items) { [item cancel]; } @@ -316,7 +316,7 @@ - (void)_postProcessWorkItem:(MTRAsyncWorkItem *)workItem [workItem markComplete]; [_items removeObjectAtIndex:indexOfWorkItem]; - MTR_LOG("MTRAsyncWorkQueue<%@, items count: %tu> completed work item [%llu]", context.description, _items.count, workItem.uniqueID); + MTR_LOG("MTRAsyncWorkQueue<%@, items count: %lu> completed work item [%llu]", context.description, static_cast(_items.count), workItem.uniqueID); // sanity check running work item count is positive if (_runningWorkItemCount == 0) { diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.mm b/src/darwin/Framework/CHIP/MTRBaseDevice.mm index 0712e779c525e6..331d61129b9daf 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice.mm +++ b/src/darwin/Framework/CHIP/MTRBaseDevice.mm @@ -571,7 +571,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue return _MakeDataValueDictionary(typeName, array, dataVersion); } default: - MTR_LOG_ERROR("Error: Unsupported TLV type for conversion: %u", (unsigned) data->GetType()); + MTR_LOG_ERROR("Error: Unsupported TLV type for conversion: %u", static_cast(data->GetType())); return nil; } } diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index 735982a9b72a42..4e916d14b101c8 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -376,7 +376,11 @@ @implementation MTRDevice { #ifdef DEBUG NSUInteger _unitTestAttributesReportedSinceLastCheck; #endif - BOOL _delegateDeviceCachePrimedCalled; + + // _deviceCachePrimed is true if we have the data that comes from an initial + // subscription priming report (whether it came from storage or from our + // subscription). + BOOL _deviceCachePrimed; // _persistedClusterData stores data that we have already persisted (when we have // cluster data persistence enabled). Nil when we have no persistence enabled. @@ -736,11 +740,6 @@ - (void)setDelegate:(id)delegate queue:(dispatch_queue_t)queu _weakDelegate = [MTRWeakReference weakReferenceWithObject:delegate]; _delegateQueue = queue; - // If Check if cache is already primed and client hasn't been informed yet, call the -deviceCachePrimed: callback - if (!_delegateDeviceCachePrimedCalled && [self _isCachePrimedWithInitialConfigurationData]) { - [self _callDelegateDeviceCachePrimed]; - } - if (setUpSubscription) { _initialSubscribeStart = [NSDate now]; if ([self _deviceUsesThread]) { @@ -915,7 +914,7 @@ - (BOOL)_callDelegateWithBlock:(void (^)(id))block - (void)_callDelegateDeviceCachePrimed { os_unfair_lock_assert_owner(&self->_lock); - _delegateDeviceCachePrimedCalled = [self _callDelegateWithBlock:^(id delegate) { + [self _callDelegateWithBlock:^(id delegate) { if ([delegate respondsToSelector:@selector(deviceCachePrimed:)]) { [delegate deviceCachePrimed:self]; } @@ -994,11 +993,6 @@ - (void)_handleSubscriptionEstablished [self _changeInternalState:MTRInternalDeviceStateInitialSubscriptionEstablished]; } - // As subscription is established, check if the delegate needs to be informed - if (!_delegateDeviceCachePrimedCalled) { - [self _callDelegateDeviceCachePrimed]; - } - [self _changeState:MTRDeviceStateReachable]; // No need to monitor connectivity after subscription establishment @@ -1480,6 +1474,13 @@ - (void)_scheduleClusterDataPersistence return; } + // If we have nothing stored at all yet, store directly, so we move into a + // primed state. + if (!_deviceCachePrimed) { + [self _persistClusterData]; + return; + } + // Ensure there is an array to keep the most recent report times if (!_mostRecentReportTimes) { _mostRecentReportTimes = [NSMutableArray array]; @@ -1525,7 +1526,7 @@ - (void)_scheduleClusterDataPersistence // Set current multiplier to [1, MaxMultiplier] _reportToPersistenceDelayCurrentMultiplier = 1 + (proportionTowardMinThreshold * (_storageBehaviorConfiguration.reportToPersistenceDelayMaxMultiplier - 1)); - MTR_LOG("%@ storage behavior: device reporting frequently - setting delay multiplied to %lf", self, _reportToPersistenceDelayCurrentMultiplier); + MTR_LOG("%@ storage behavior: device reporting frequently - setting delay multiplier to %lf", self, _reportToPersistenceDelayCurrentMultiplier); } else { _reportToPersistenceDelayCurrentMultiplier = 1; } @@ -1601,6 +1602,19 @@ - (void)_handleReportEnd _deviceConfigurationChanged = NO; } + // Do this after the _deviceConfigurationChanged check, so that we don't + // call deviceConfigurationChanged: immediately after telling our delegate + // we are now primed. + // + // TODO: Maybe we shouldn't dispatch deviceConfigurationChanged: for the + // initial priming bits? + if (!_deviceCachePrimed) { + // This is the end of the priming sequence of data reports, so we have + // all the data for the device now. + _deviceCachePrimed = YES; + [self _callDelegateDeviceCachePrimed]; + } + // For unit testing only #ifdef DEBUG id delegate = _weakDelegate.strongObject; @@ -2158,7 +2172,7 @@ - (void)_setupSubscription return; } - MTR_LOG("%@ Subscribe with data version list size %lu, reduced by %lu", self, (unsigned long) dataVersions.count, (unsigned long) dataVersionFilterListSizeReduction); + MTR_LOG("%@ Subscribe with data version list size %lu, reduced by %lu", self, static_cast(dataVersions.count), static_cast(dataVersionFilterListSizeReduction)); // Callback and ClusterStateCache and ReadClient will be deleted // when OnDone is called. @@ -2388,8 +2402,8 @@ static BOOL AttributeHasChangesOmittedQuality(MTRAttributePath * attributePath) auto readItem = readRequestsNext.firstObject; [readRequestsNext removeObjectAtIndex:0]; [readRequestsCurrent addObject:readItem]; - MTR_LOG("Batching read attribute work item [%llu]: added %@ (now %tu requests total) [0x%016llX:%@:0x%llx:0x%llx]", - workItemID, readItem, readRequestsCurrent.count, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + MTR_LOG("Batching read attribute work item [%llu]: added %@ (now %lu requests total) [0x%016llX:%@:0x%llx:0x%llx]", + workItemID, readItem, static_cast(readRequestsCurrent.count), nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); outcome = MTRBatchedPartially; } NSCAssert(readRequestsNext.count == 0, @"should have batched everything or returned early"); @@ -2516,7 +2530,7 @@ - (void)writeAttributeWithEndpointID:(NSNumber *)endpointID if (writeRequestsCurrent.count != 1) { // Very unexpected! - MTR_LOG_ERROR("Batching write attribute work item [%llu]: Unexpected write request count %tu", workItemID, writeRequestsCurrent.count); + MTR_LOG_ERROR("Batching write attribute work item [%llu]: Unexpected write request count %lu", workItemID, static_cast(writeRequestsCurrent.count)); return MTRNotBatched; } @@ -2551,7 +2565,7 @@ - (void)writeAttributeWithEndpointID:(NSNumber *)endpointID MTRBaseDevice * baseDevice = [self newBaseDevice]; // Make sure to use writeRequests here, because that's what our batching // handler will modify as needed. - NSCAssert(writeRequests.count == 1, @"Incorrect number of write requests: %tu", writeRequests.count); + NSCAssert(writeRequests.count == 1, @"Incorrect number of write requests: %lu", static_cast(writeRequests.count)); auto * request = writeRequests[0]; MTRAttributePath * path = request[MTRDeviceWriteRequestFieldPathIndex]; @@ -3165,10 +3179,9 @@ - (void)setPersistedClusterData:(NSDictionary_lock); - - // Check if root node descriptor exists - MTRDeviceDataValueDictionary rootDescriptorPartsListDataValue = [self _cachedAttributeValueForPath:[MTRAttributePath attributePathWithEndpointID:@(kRootEndpointId) clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributePartsListID)]]; - if (!rootDescriptorPartsListDataValue || ![MTRArrayValueType isEqualToString:rootDescriptorPartsListDataValue[MTRTypeKey]]) { - return NO; - } - NSArray * partsList = rootDescriptorPartsListDataValue[MTRValueKey]; - if (![partsList isKindOfClass:[NSArray class]] || !partsList.count) { - MTR_LOG_ERROR("%@ unexpected type %@ for parts list %@", self, [partsList class], partsList); - return NO; - } - - // Check if we have cached descriptor clusters for each listed endpoint - for (NSDictionary * endpointDictionary in partsList) { - NSDictionary * endpointDataValue = endpointDictionary[MTRDataKey]; - if (![endpointDataValue isKindOfClass:[NSDictionary class]]) { - MTR_LOG_ERROR("%@ unexpected parts list dictionary %@ data value class %@", self, endpointDictionary, [endpointDataValue class]); - continue; - } - if (![MTRUnsignedIntegerValueType isEqual:endpointDataValue[MTRTypeKey]]) { - MTR_LOG_ERROR("%@ unexpected parts list data value %@ item type %@", self, endpointDataValue, endpointDataValue[MTRTypeKey]); - continue; - } - NSNumber * endpoint = endpointDataValue[MTRValueKey]; - if (![endpoint isKindOfClass:[NSNumber class]]) { - MTR_LOG_ERROR("%@ unexpected parts list item value class %@", self, [endpoint class]); - continue; - } - MTRDeviceDataValueDictionary descriptorDeviceTypeListDataValue = [self _cachedAttributeValueForPath:[MTRAttributePath attributePathWithEndpointID:endpoint clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID)]]; - if (![MTRArrayValueType isEqualToString:descriptorDeviceTypeListDataValue[MTRTypeKey]] || !descriptorDeviceTypeListDataValue[MTRValueKey]) { - return NO; - } - } - - return YES; -} - - (MTRBaseDevice *)newBaseDevice { return [MTRBaseDevice deviceWithNodeID:self.nodeID controller:self.deviceController]; diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 5047b97ef3cef0..303cc2679e60d1 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -265,14 +265,14 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory concurrentSubscriptionPoolSize = static_cast(subscriptionPoolSizeOverride); } - MTR_LOG(" *** Overriding pool size of MTRDeviceController with: %tu", concurrentSubscriptionPoolSize); + MTR_LOG(" *** Overriding pool size of MTRDeviceController with: %lu", static_cast(concurrentSubscriptionPoolSize)); } if (!concurrentSubscriptionPoolSize) { concurrentSubscriptionPoolSize = 1; } - MTR_LOG("Setting up pool size of MTRDeviceController with: %tu", concurrentSubscriptionPoolSize); + MTR_LOG("Setting up pool size of MTRDeviceController with: %lu", static_cast(concurrentSubscriptionPoolSize)); _concurrentSubscriptionPool = [[MTRAsyncWorkQueue alloc] initWithContext:self width:concurrentSubscriptionPoolSize]; @@ -1842,7 +1842,7 @@ - (MTRBaseDevice *)getDeviceBeingCommissioned:(uint64_t)deviceId error:(NSError - (BOOL)openPairingWindow:(uint64_t)deviceID duration:(NSUInteger)duration error:(NSError * __autoreleasing *)error { if (duration > UINT16_MAX) { - MTR_LOG_ERROR("Error: Duration %tu is too large. Max value %d", duration, UINT16_MAX); + MTR_LOG_ERROR("Error: Duration %lu is too large. Max value %d", static_cast(duration), UINT16_MAX); if (error) { *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_INTEGER_VALUE]; } @@ -1868,7 +1868,7 @@ - (NSString *)openPairingWindowWithPIN:(uint64_t)deviceID error:(NSError * __autoreleasing *)error { if (duration > UINT16_MAX) { - MTR_LOG_ERROR("Error: Duration %tu is too large. Max value %d", duration, UINT16_MAX); + MTR_LOG_ERROR("Error: Duration %lu is too large. Max value %d", static_cast(duration), UINT16_MAX); if (error) { *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_INTEGER_VALUE]; } @@ -1876,7 +1876,7 @@ - (NSString *)openPairingWindowWithPIN:(uint64_t)deviceID } if (discriminator > 0xfff) { - MTR_LOG_ERROR("Error: Discriminator %tu is too large. Max value %d", discriminator, 0xfff); + MTR_LOG_ERROR("Error: Discriminator %lu is too large. Max value %d", static_cast(discriminator), 0xfff); if (error) { *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_INTEGER_VALUE]; } diff --git a/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm b/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm index a547321d88c2e0..a9d1fcdc18ba67 100644 --- a/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm +++ b/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm @@ -102,7 +102,7 @@ - (BOOL)_populateCppOperationalDataset - (BOOL)_checkDataLength:(NSData *)data expectedLength:(size_t)expectedLength { if (data.length != expectedLength) { - MTR_LOG_ERROR("Length Check Failed. Length:%tu is incorrect, must be %tu", data.length, expectedLength); + MTR_LOG_ERROR("Length Check Failed. Length:%lu is incorrect, must be %tu", static_cast(data.length), expectedLength); return NO; } return YES; diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index 5c5439003862b9..97199ad7bda19a 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -9687,3 +9687,7 @@ - release: "Future" versions: "future" + provisional: + clusters: + # Targeting Fall 2024 + - WiFiNetworkManagement diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm index cb98d807f3495d..a6ab1d6beee61c 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm @@ -5288,6 +5288,36 @@ static BOOL AttributeIsSpecifiedInRadonConcentrationMeasurementCluster(Attribute } } } +static BOOL AttributeIsSpecifiedInWiFiNetworkManagementCluster(AttributeId aAttributeId) +{ + using namespace Clusters::WiFiNetworkManagement; + switch (aAttributeId) { + case Attributes::Ssid::Id: { + return YES; + } + case Attributes::GeneratedCommandList::Id: { + return YES; + } + case Attributes::AcceptedCommandList::Id: { + return YES; + } + case Attributes::EventList::Id: { + return YES; + } + case Attributes::AttributeList::Id: { + return YES; + } + case Attributes::FeatureMap::Id: { + return YES; + } + case Attributes::ClusterRevision::Id: { + return YES; + } + default: { + return NO; + } + } +} static BOOL AttributeIsSpecifiedInWakeOnLANCluster(AttributeId aAttributeId) { using namespace Clusters::WakeOnLan; @@ -6804,6 +6834,9 @@ BOOL MTRAttributeIsSpecified(ClusterId aClusterId, AttributeId aAttributeId) case Clusters::RadonConcentrationMeasurement::Id: { return AttributeIsSpecifiedInRadonConcentrationMeasurementCluster(aAttributeId); } + case Clusters::WiFiNetworkManagement::Id: { + return AttributeIsSpecifiedInWiFiNetworkManagementCluster(aAttributeId); + } case Clusters::WakeOnLan::Id: { return AttributeIsSpecifiedInWakeOnLANCluster(aAttributeId); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index bae1643f3beb39..f5b2ca3d7dd743 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -15219,6 +15219,33 @@ static id _Nullable DecodeAttributeValueForRadonConcentrationMeasurementCluster( *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; return nil; } +static id _Nullable DecodeAttributeValueForWiFiNetworkManagementCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +{ + using namespace Clusters::WiFiNetworkManagement; + switch (aAttributeId) { + case Attributes::Ssid::Id: { + using TypeInfo = Attributes::Ssid::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSData * _Nullable value; + if (cppValue.IsNull()) { + value = nil; + } else { + value = AsData(cppValue.Value()); + } + return value; + } + default: { + break; + } + } + + *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; + return nil; +} static id _Nullable DecodeAttributeValueForWakeOnLANCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { using namespace Clusters::WakeOnLan; @@ -19593,6 +19620,9 @@ id _Nullable MTRDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::T case Clusters::RadonConcentrationMeasurement::Id: { return DecodeAttributeValueForRadonConcentrationMeasurementCluster(aPath.mAttributeId, aReader, aError); } + case Clusters::WiFiNetworkManagement::Id: { + return DecodeAttributeValueForWiFiNetworkManagementCluster(aPath.mAttributeId, aReader, aError); + } case Clusters::WakeOnLan::Id: { return DecodeAttributeValueForWakeOnLANCluster(aPath.mAttributeId, aReader, aError); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 3c7624201d0484..d5e7efa37f08bd 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -12989,6 +12989,82 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) @end +/** + * Cluster Wi-Fi Network Management + * + * Functionality to retrieve operational information about a managed Wi-Fi network. + */ +MTR_PROVISIONALLY_AVAILABLE +@interface MTRBaseClusterWiFiNetworkManagement : MTRGenericBaseCluster + +/** + * Command NetworkPassphraseRequest + * + * Request the current WPA-Personal passphrase or PSK associated with the managed Wi-Fi network. + */ +- (void)networkPassphraseRequestWithParams:(MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams * _Nullable)params completion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)networkPassphraseRequestWithCompletion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion + MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeSSIDWithCompletion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeSSIDWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSData * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeSSIDWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface MTRBaseClusterWiFiNetworkManagement (Availability) + +/** + * For all instance methods (reads, writes, commands) that take a completion, + * the completion will be called on the provided queue. + */ +- (instancetype _Nullable)initWithDevice:(MTRBaseDevice *)device + endpointID:(NSNumber *)endpointID + queue:(dispatch_queue_t)queue MTR_PROVISIONALLY_AVAILABLE; + +@end + /** * Cluster Wake on LAN * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index b375488f292fc8..8155fed2e794f1 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -92894,6 +92894,291 @@ + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheC @end +@implementation MTRBaseClusterWiFiNetworkManagement + +- (void)networkPassphraseRequestWithCompletion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion +{ + [self networkPassphraseRequestWithParams:nil completion:completion]; +} +- (void)networkPassphraseRequestWithParams:(MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams * _Nullable)params completion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion +{ + if (params == nil) { + params = [[MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(response, error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams.class + queue:self.callbackQueue + completion:responseHandler]; +} + +- (void)readAttributeSSIDWithCompletion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::Ssid::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeSSIDWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSData * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::Ssid::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeSSIDWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::Ssid::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::GeneratedCommandList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::GeneratedCommandList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::GeneratedCommandList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::AcceptedCommandList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::AcceptedCommandList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::AcceptedCommandList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::EventList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::EventList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::EventList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::AttributeList::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::AttributeList::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::AttributeList::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::FeatureMap::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::FeatureMap::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::FeatureMap::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::ClusterRevision::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = WiFiNetworkManagement::Attributes::ClusterRevision::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = WiFiNetworkManagement::Attributes::ClusterRevision::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +@end + @implementation MTRBaseClusterWakeOnLAN - (void)readAttributeMACAddressWithCompletion:(void (^)(NSString * _Nullable value, NSError * _Nullable error))completion diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index 5c3f6a080fdd7b..0627e1d7937536 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -184,6 +184,7 @@ typedef NS_ENUM(uint32_t, MTRClusterIDType) { MTRClusterIDTypePM10ConcentrationMeasurementID MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0x0000042D, MTRClusterIDTypeTotalVolatileOrganicCompoundsConcentrationMeasurementID MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0x0000042E, MTRClusterIDTypeRadonConcentrationMeasurementID MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0x0000042F, + MTRClusterIDTypeWiFiNetworkManagementID MTR_PROVISIONALLY_AVAILABLE = 0x00000451, MTRClusterIDTypeWakeOnLANID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000503, MTRClusterIDTypeChannelID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000504, MTRClusterIDTypeTargetNavigatorID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000505, @@ -4361,6 +4362,15 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterRadonConcentrationMeasurementAttributeFeatureMapID MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = MTRAttributeIDTypeGlobalAttributeFeatureMapID, MTRAttributeIDTypeClusterRadonConcentrationMeasurementAttributeClusterRevisionID MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster WiFiNetworkManagement attributes + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeSSIDID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeAcceptedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeAttributeListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAttributeListID, + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, + MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster WakeOnLan deprecated attribute names MTRClusterWakeOnLanAttributeMACAddressID MTR_DEPRECATED("Please use MTRAttributeIDTypeClusterWakeOnLANAttributeMACAddressID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) @@ -6575,6 +6585,10 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { MTRCommandIDTypeClusterColorControlCommandMoveColorTemperatureID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000004B, MTRCommandIDTypeClusterColorControlCommandStepColorTemperatureID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000004C, + // Cluster WiFiNetworkManagement commands + MTRCommandIDTypeClusterWiFiNetworkManagementCommandNetworkPassphraseRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRCommandIDTypeClusterWiFiNetworkManagementCommandNetworkPassphraseResponseID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + // Cluster Channel deprecated command id names MTRClusterChannelCommandChangeChannelID MTR_DEPRECATED("Please use MTRCommandIDTypeClusterChannelCommandChangeChannelID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4)) diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm index 474c5cacf47679..7b8402cabc2fda 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm @@ -318,6 +318,9 @@ case MTRClusterIDTypeRadonConcentrationMeasurementID: result = @"RadonConcentrationMeasurement"; break; + case MTRClusterIDTypeWiFiNetworkManagementID: + result = @"WiFiNetworkManagement"; + break; case MTRClusterIDTypeWakeOnLANID: result = @"WakeOnLAN"; break; @@ -7212,6 +7215,44 @@ break; } + case MTRClusterIDTypeWiFiNetworkManagementID: + + switch (attributeID) { + + // Cluster WiFiNetworkManagement attributes + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeSSIDID: + result = @"SSID"; + break; + + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeGeneratedCommandListID: + result = @"GeneratedCommandList"; + break; + + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeAcceptedCommandListID: + result = @"AcceptedCommandList"; + break; + + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeEventListID: + result = @"EventList"; + break; + + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeAttributeListID: + result = @"AttributeList"; + break; + + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeFeatureMapID: + result = @"FeatureMap"; + break; + + case MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeClusterRevisionID: + result = @"ClusterRevision"; + break; + + default: + result = [NSString stringWithFormat:@"", attributeID]; + break; + } + case MTRClusterIDTypeWakeOnLANID: switch (attributeID) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 6e4e0f80b44d00..34d469730f1c94 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -5993,6 +5993,48 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) @end +/** + * Cluster Wi-Fi Network Management + * Functionality to retrieve operational information about a managed Wi-Fi network. + */ +MTR_PROVISIONALLY_AVAILABLE +@interface MTRClusterWiFiNetworkManagement : MTRGenericCluster + +- (void)networkPassphraseRequestWithParams:(MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)networkPassphraseRequestWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion + MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeSSIDWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface MTRClusterWiFiNetworkManagement (Availability) + +/** + * For all instance methods that take a completion (i.e. command invocations), + * the completion will be called on the provided queue. + */ +- (instancetype _Nullable)initWithDevice:(MTRDevice *)device + endpointID:(NSNumber *)endpointID + queue:(dispatch_queue_t)queue MTR_PROVISIONALLY_AVAILABLE; + +@end + /** * Cluster Wake on LAN * This cluster provides an interface for managing low power mode on a device that supports the Wake On LAN protocol. diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index db279250cac8bf..2605a37007449c 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -16768,6 +16768,76 @@ @implementation MTRClusterRadonConcentrationMeasurement @end +@implementation MTRClusterWiFiNetworkManagement + +- (void)networkPassphraseRequestWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion +{ + [self networkPassphraseRequestWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; +} +- (void)networkPassphraseRequestWithParams:(MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable data, NSError * _Nullable error))completion +{ + if (params == nil) { + params = [[MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(response, error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Type; + [self.device _invokeKnownCommandWithEndpointID:self.endpointID + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + expectedValues:expectedValues + expectedValueInterval:expectedValueIntervalMs + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams.class + queue:self.callbackQueue + completion:responseHandler]; +} + +- (NSDictionary * _Nullable)readAttributeSSIDWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeSSIDID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeGeneratedCommandListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeAcceptedCommandListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeEventListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeAttributeListID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeFeatureMapID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeWiFiNetworkManagementID) attributeID:@(MTRAttributeIDTypeClusterWiFiNetworkManagementAttributeClusterRevisionID) params:params]; +} + +@end + @implementation MTRClusterWakeOnLAN - (NSDictionary * _Nullable)readAttributeMACAddressWithParams:(MTRReadParams * _Nullable)params diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 1d1552200b5b1c..cfd06dee343cc0 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -8512,6 +8512,53 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams : NSObject +/** + * Controls whether the command is a timed command (using Timed Invoke). + * + * If nil (the default value), a regular invoke is done for commands that do + * not require a timed invoke and a timed invoke with some default timed request + * timeout is done for commands that require a timed invoke. + * + * If not nil, a timed invoke is done, with the provided value used as the timed + * request timeout. The value should be chosen small enough to provide the + * desired security properties but large enough that it will allow a round-trip + * from the sever to the client (for the status response and actual invoke + * request) within the timeout window. + * + */ +@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; + +/** + * Controls how much time, in seconds, we will allow for the server to process the command. + * + * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * + * If nil, the framework will try to select an appropriate timeout value itself. + */ +@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +@end + +MTR_PROVISIONALLY_AVAILABLE +@interface MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams : NSObject + +@property (nonatomic, copy) NSData * _Nonnull passphrase MTR_PROVISIONALLY_AVAILABLE; + +/** + * Initialize an MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams with a response-value dictionary + * of the sort that MTRDeviceResponseHandler would receive. + * + * Will return nil and hand out an error if the response-value dictionary is not + * a command data response or is not the right command response. + * + * Will return nil and hand out an error if the data response does not match the known + * schema for this command. + */ +- (nullable instancetype)initWithResponseValue:(NSDictionary *)responseValue + error:(NSError * __autoreleasing *)error MTR_PROVISIONALLY_AVAILABLE; +@end + MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRChannelClusterChangeChannelParams : NSObject diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 3105c9a9d21f80..af9752c200df41 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -23968,6 +23968,158 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end +@implementation MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams +- (instancetype)init +{ + if (self = [super init]) { + _timedInvokeTimeoutMs = nil; + _serverSideProcessingTimeout = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams alloc] init]; + + other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; + other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])]; + return descriptionString; +} + +@end + +@implementation MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams (InternalMethods) + +- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +{ + chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Type encodableStruct; + ListFreer listFreer; + + auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); + if (buffer.IsNull()) { + return CHIP_ERROR_NO_MEMORY; + } + + chip::System::PacketBufferTLVWriter writer; + // Commands never need chained buffers, since they cannot be chunked. + writer.Init(std::move(buffer), /* useChainedBuffers = */ false); + + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); + + ReturnErrorOnFailure(writer.Finalize(&buffer)); + + reader.Init(std::move(buffer)); + return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); +} + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error +{ + chip::System::PacketBufferTLVReader reader; + CHIP_ERROR err = [self _encodeToTLVReader:reader]; + if (err != CHIP_NO_ERROR) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:err]; + } + return nil; + } + + auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); + if (decodedObj == nil) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + } + } + return decodedObj; +} +@end + +@implementation MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams +- (instancetype)init +{ + if (self = [super init]) { + + _passphrase = [NSData data]; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams alloc] init]; + + other.passphrase = self.passphrase; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: passphrase:%@; >", NSStringFromClass([self class]), [_passphrase base64EncodedStringWithOptions:0]]; + return descriptionString; +} + +- (nullable instancetype)initWithResponseValue:(NSDictionary *)responseValue + error:(NSError * __autoreleasing *)error +{ + if (!(self = [super init])) { + return nil; + } + + using DecodableType = chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType; + chip::System::PacketBufferHandle buffer = [MTRBaseDevice _responseDataForCommand:responseValue + clusterID:DecodableType::GetClusterId() + commandID:DecodableType::GetCommandId() + error:error]; + if (buffer.IsNull()) { + return nil; + } + + chip::TLV::TLVReader reader; + reader.Init(buffer->Start(), buffer->DataLength()); + + CHIP_ERROR err = reader.Next(chip::TLV::AnonymousTag()); + if (err == CHIP_NO_ERROR) { + DecodableType decodedStruct; + err = chip::app::DataModel::Decode(reader, decodedStruct); + if (err == CHIP_NO_ERROR) { + err = [self _setFieldsFromDecodableStruct:decodedStruct]; + if (err == CHIP_NO_ERROR) { + return self; + } + } + } + + NSString * errorStr = [NSString stringWithFormat:@"Command payload decoding failed: %s", err.AsString()]; + MTR_LOG_ERROR("%s", errorStr.UTF8String); + if (error != nil) { + NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : NSLocalizedString(errorStr, nil) }; + *error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeSchemaMismatch userInfo:userInfo]; + } + return nil; +} + +@end + +@implementation MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams (InternalMethods) + +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType &)decodableStruct +{ + { + self.passphrase = AsData(decodableStruct.passphrase); + } + return CHIP_NO_ERROR; +} + +@end + @implementation MTRChannelClusterChangeChannelParams - (instancetype)init { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h index 2579d3bc49a9bd..2b629efdc5a24d 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h @@ -1570,6 +1570,18 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams (InternalMethods) + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; + +@end + +@interface MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams (InternalMethods) + +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType &)decodableStruct; + +@end + @interface MTRChannelClusterChangeChannelParams (InternalMethods) - (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm index 685ca8f4f035a9..0ea5a38336bb2a 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm @@ -956,6 +956,15 @@ static BOOL CommandNeedsTimedInvokeInRadonConcentrationMeasurementCluster(Attrib } } } +static BOOL CommandNeedsTimedInvokeInWiFiNetworkManagementCluster(AttributeId aAttributeId) +{ + using namespace Clusters::WiFiNetworkManagement; + switch (aAttributeId) { + default: { + return NO; + } + } +} static BOOL CommandNeedsTimedInvokeInWakeOnLANCluster(AttributeId aAttributeId) { using namespace Clusters::WakeOnLan; @@ -1419,6 +1428,9 @@ BOOL MTRCommandNeedsTimedInvoke(NSNumber * _Nonnull aClusterID, NSNumber * _Nonn case Clusters::RadonConcentrationMeasurement::Id: { return CommandNeedsTimedInvokeInRadonConcentrationMeasurementCluster(commandID); } + case Clusters::WiFiNetworkManagement::Id: { + return CommandNeedsTimedInvokeInWiFiNetworkManagementCluster(commandID); + } case Clusters::WakeOnLan::Id: { return CommandNeedsTimedInvokeInWakeOnLANCluster(commandID); } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm index 46427cba7fab3b..06042f32f9f1d8 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm @@ -71,6 +71,7 @@ { 0x0000007A, DeviceTypeClass::Simple, "Matter Extractor Hood" }, { 0x0000007B, DeviceTypeClass::Simple, "Matter Oven" }, { 0x0000007C, DeviceTypeClass::Simple, "Matter Laundry Dryer" }, + { 0x00000090, DeviceTypeClass::Simple, "Matter Network Infrastructure Manager" }, { 0x00000100, DeviceTypeClass::Simple, "Matter On/Off Light" }, { 0x00000101, DeviceTypeClass::Simple, "Matter Dimmable Light" }, { 0x00000103, DeviceTypeClass::Simple, "Matter On/Off Light Switch" }, @@ -96,7 +97,6 @@ { 0x00000510, DeviceTypeClass::Utility, "Matter Electrical Sensor" }, { 0x00000840, DeviceTypeClass::Simple, "Matter Control Bridge" }, { 0x00000850, DeviceTypeClass::Simple, "Matter On/Off Sensor" }, - { 0xFFF10010, DeviceTypeClass::Simple, "Matter Network Infrastructure Manager" }, }; static_assert(ExtractVendorFromMEI(0xFFF10001) != 0, "Must have class defined for \"Matter Orphan Clusters\" if it's a standard device type"); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm index 3e36773ffebd99..9fc3cd16b8235a 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm @@ -4035,6 +4035,18 @@ static id _Nullable DecodeEventPayloadForRadonConcentrationMeasurementCluster(Ev *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; return nil; } +static id _Nullable DecodeEventPayloadForWiFiNetworkManagementCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +{ + using namespace Clusters::WiFiNetworkManagement; + switch (aEventId) { + default: { + break; + } + } + + *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; + return nil; +} static id _Nullable DecodeEventPayloadForWakeOnLANCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { using namespace Clusters::WakeOnLan; @@ -4836,6 +4848,9 @@ id _Nullable MTRDecodeEventPayload(const ConcreteEventPath & aPath, TLV::TLVRead case Clusters::RadonConcentrationMeasurement::Id: { return DecodeEventPayloadForRadonConcentrationMeasurementCluster(aPath.mEventId, aReader, aError); } + case Clusters::WiFiNetworkManagement::Id: { + return DecodeEventPayloadForWiFiNetworkManagementCluster(aPath.mEventId, aReader, aError); + } case Clusters::WakeOnLan::Id: { return DecodeEventPayloadForWakeOnLANCluster(aPath.mEventId, aReader, aError); } diff --git a/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m b/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m index 4253625af80ff7..047ce4f8588816 100644 --- a/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m +++ b/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m @@ -34,13 +34,8 @@ static const uint16_t kTestProductId2 = 0x8001u; static const uint16_t kTestDiscriminator1 = 3840u; static const uint16_t kTestDiscriminator2 = 3839u; -static const uint16_t kTestDiscriminator3 = 101u; -static const uint16_t kTestDiscriminator4 = 102u; -static const uint16_t kTestDiscriminator5 = 103u; -static const uint16_t kTestDiscriminator6 = 104u; -static const uint16_t kTestDiscriminator7 = 105u; static const uint16_t kDiscoverDeviceTimeoutInSeconds = 10; -static const uint16_t kExpectedDiscoveredDevicesCount = 7; +static const uint16_t kExpectedDiscoveredDevicesCount = 2; // Singleton controller we use. static MTRDeviceController * sController = nil; @@ -102,7 +97,7 @@ - (void)controller:(MTRDeviceController *)controller didFindCommissionableDevice XCTAssertEqual(instanceName.length, 16); // The instance name is random, so just ensure the len is right. XCTAssertEqualObjects(vendorId, @(kTestVendorId)); XCTAssertTrue([productId isEqual:@(kTestProductId1)] || [productId isEqual:@(kTestProductId2)]); - XCTAssertTrue([discriminator isEqual:@(kTestDiscriminator1)] || [discriminator isEqual:@(kTestDiscriminator2)] || [discriminator isEqual:@(kTestDiscriminator3)] || [discriminator isEqual:@(kTestDiscriminator4)] || [discriminator isEqual:@(kTestDiscriminator5)] || [discriminator isEqual:@(kTestDiscriminator6)] || [discriminator isEqual:@(kTestDiscriminator7)]); + XCTAssertTrue([discriminator isEqual:@(kTestDiscriminator1)] || [discriminator isEqual:@(kTestDiscriminator2)]); XCTAssertEqual(commissioningMode, YES); NSLog(@"Found Device (%@) with discriminator: %@ (vendor: %@, product: %@)", instanceName, discriminator, vendorId, productId); diff --git a/src/darwin/Framework/CHIPTests/MTRControllerTests.m b/src/darwin/Framework/CHIPTests/MTRControllerTests.m index b5ca63135703b3..436a0df230e3d9 100644 --- a/src/darwin/Framework/CHIPTests/MTRControllerTests.m +++ b/src/darwin/Framework/CHIPTests/MTRControllerTests.m @@ -1557,6 +1557,10 @@ - (void)testSetMRPParameters // Can be called before starting the factory XCTAssertFalse(MTRDeviceControllerFactory.sharedInstance.running); MTRSetMessageReliabilityParameters(@2000, @2000, @2000, @2000); + + // Now reset back to the default state, so timings in other tests are not + // affected. + MTRSetMessageReliabilityParameters(nil, nil, nil, nil); } @end diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index b0254fbde38ad4..f0d6aee1a8556b 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -36,6 +36,7 @@ #import "MTRTestStorage.h" #import // For INFINITY +#import // system dependencies #import @@ -3668,7 +3669,7 @@ - (void)test035_TestMTRDeviceSubscriptionNotEstablishedOverXPC XCTAssertEqual([device _getInternalState], MTRInternalDeviceStateUnsubscribed); } -- (NSArray *> *)testAttributeReportWithValue:(unsigned int)testValue +- (NSArray *> *)_testAttributeReportWithValue:(unsigned int)testValue { return @[ @{ MTRAttributePathKey : [MTRAttributePath attributePathWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeLevelControlID) attributeID:@(MTRAttributeIDTypeClusterLevelControlAttributeCurrentLevelID)], @@ -3695,7 +3696,7 @@ - (void)test036_TestStorageBehaviorConfiguration __block NSDate * reportEndTime = nil; __block NSDate * dataPersistedTime = nil; - XCTestExpectation * dataPersisted1 = [self expectationWithDescription:@"data persisted 1"]; + XCTestExpectation * dataPersistedInitial = [self expectationWithDescription:@"data persisted initial"]; delegate.onReportEnd = ^() { os_unfair_lock_lock(&lock); if (!reportEndTime) { @@ -3710,7 +3711,7 @@ - (void)test036_TestStorageBehaviorConfiguration dataPersistedTime = [NSDate now]; } os_unfair_lock_unlock(&lock); - [dataPersisted1 fulfill]; + [dataPersistedInitial fulfill]; }; // Do not subscribe - only inject sequence of reports to control the timing @@ -3731,11 +3732,29 @@ - (void)test036_TestStorageBehaviorConfiguration [device setDelegate:delegate queue:queue]; - // Use a mutable dictionary so the data value can be easily changed between reports + // Use a counter that will be incremented for each report as the value. unsigned int currentTestValue = 1; + // Initial setup: Inject report and see that the attribute persisted. No delay is + // expected for the first (priming) report. + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + + [self waitForExpectations:@[ dataPersistedInitial ] timeout:60]; + + XCTestExpectation * dataPersisted1 = [self expectationWithDescription:@"data persisted 1"]; + delegate.onClusterDataPersisted = ^{ + os_unfair_lock_lock(&lock); + if (!dataPersistedTime) { + dataPersistedTime = [NSDate now]; + } + os_unfair_lock_unlock(&lock); + [dataPersisted1 fulfill]; + }; + // Test 1: Inject report and see that the attribute persisted, with a delay - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + reportEndTime = nil; + dataPersistedTime = nil; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; [self waitForExpectations:@[ dataPersisted1 ] timeout:60]; @@ -3761,20 +3780,20 @@ - (void)test036_TestStorageBehaviorConfiguration // Test 2: Inject multiple reports with delay and see that the attribute persisted eventually reportEndTime = nil; dataPersistedTime = nil; - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; double frequentReportMultiplier = 0.5; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; usleep((useconds_t) (baseTestDelayTime * frequentReportMultiplier * USEC_PER_SEC)); - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; // At this point, the threshold for reportToPersistenceDelayTimeMax should have hit, and persistence // should have happened with timer running down to persist again with the 5th report above. Need to @@ -3816,7 +3835,7 @@ - (void)test036_TestStorageBehaviorConfiguration ]]]; // Inject final report that makes MTRDevice recalculate delay with multiplier - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; [self waitForExpectations:@[ dataPersisted3 ] timeout:60]; @@ -3855,13 +3874,13 @@ - (void)test036_TestStorageBehaviorConfiguration ]]]; // Inject report that makes MTRDevice detect the device is reporting excessively - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; // Now keep reporting excessively for base delay time max times max multiplier, plus a bit more NSDate * excessiveStartTime = [NSDate now]; for (;;) { usleep((useconds_t) (baseTestDelayTime * 0.1 * USEC_PER_SEC)); - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; NSTimeInterval elapsed = -[excessiveStartTime timeIntervalSinceNow]; if (elapsed > (baseTestDelayTime * 2 * 5 * 1.2)) { break; @@ -3878,7 +3897,7 @@ - (void)test036_TestStorageBehaviorConfiguration // And inject a report to trigger MTRDevice to recalculate that this device is no longer // reporting excessively - [device unitTestInjectAttributeReport:[self testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; + [device unitTestInjectAttributeReport:[self _testAttributeReportWithValue:currentTestValue++] fromSubscription:YES]; [self waitForExpectations:@[ dataPersisted4 ] timeout:60]; diff --git a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m index cc27efecd2cca7..52b1ae36673b28 100644 --- a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m @@ -29,6 +29,7 @@ #import "MTRTestKeys.h" #import "MTRTestPerControllerStorage.h" #import "MTRTestResetCommissioneeHelper.h" +#import "MTRTestServerAppRunner.h" static const uint16_t kPairingTimeoutInSeconds = 10; static const uint16_t kTimeoutInSeconds = 3; @@ -1436,32 +1437,29 @@ - (void)doDataStoreMTRDeviceTestWithStorageDelegate:(id * dataStoreClusterData = [controller.controllerDataStore getStoredClusterDataForNodeID:deviceID]; @@ -1500,18 +1498,13 @@ - (void)doDataStoreMTRDeviceTestWithStorageDelegate:(id *)deviceOnboardingPayloads { __auto_type * factory = [MTRDeviceControllerFactory sharedInstance]; XCTAssertNotNil(factory); @@ -2190,15 +2194,7 @@ - (void)doTestSubscriptionPoolWithSize:(NSInteger)subscriptionPoolSize XCTAssertEqualObjects(controller.controllerNodeID, nodeID); - // QRCodes generated for discriminators 101~105 and passcodes 1001~1005 NSArray * orderedDeviceIDs = @[ @(101), @(102), @(103), @(104), @(105) ]; - NSDictionary * deviceOnboardingPayloads = @{ - @(101) : @"MT:00000EBQ15IZC900000", - @(102) : @"MT:00000MNY16-AD900000", - @(103) : @"MT:00000UZ427GOD900000", - @(104) : @"MT:00000CQM00Z.D900000", - @(105) : @"MT:00000K0V01FDE900000", - }; // Commission 5 devices for (NSNumber * deviceID in orderedDeviceIDs) { @@ -2279,8 +2275,27 @@ - (void)doTestSubscriptionPoolWithSize:(NSInteger)subscriptionPoolSize - (void)testSubscriptionPool { - [self doTestSubscriptionPoolWithSize:1]; - [self doTestSubscriptionPoolWithSize:2]; + // QRCodes generated for discriminators 1111~1115 and passcodes 1001~1005 + NSDictionary * deviceOnboardingPayloads = @{ + @(101) : @"MT:00000UZ427U0D900000", + @(102) : @"MT:00000CQM00BED900000", + @(103) : @"MT:00000K0V01TRD900000", + @(104) : @"MT:00000SC11293E900000", + @(105) : @"MT:00000-O913RGE900000", + }; + + // Start our helper apps. + __auto_type * sortedKeys = [[deviceOnboardingPayloads allKeys] sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber * deviceID in sortedKeys) { + __auto_type * appRunner = [[MTRTestServerAppRunner alloc] initWithAppName:@"all-clusters" + arguments:@[] + payload:deviceOnboardingPayloads[deviceID] + testcase:self]; + XCTAssertNotNil(appRunner); + } + + [self doTestSubscriptionPoolWithSize:1 deviceOnboardingPayloads:deviceOnboardingPayloads]; + [self doTestSubscriptionPoolWithSize:2 deviceOnboardingPayloads:deviceOnboardingPayloads]; } @end diff --git a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestServerAppRunner.m b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestServerAppRunner.m index 83912e9eb2dc0b..18424ed332a6af 100644 --- a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestServerAppRunner.m +++ b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestServerAppRunner.m @@ -90,7 +90,7 @@ - (instancetype)initWithAppName:(NSString *)name arguments:(NSArray [testcase launchTask:_appTask]; - NSLog(@"Started %@ with arguments %@ stdout=%@ and stderr=%@", name, allArguments, outFile, errorFile); + NSLog(@"Started chip-%@-app with arguments %@ stdout=%@ and stderr=%@", name, allArguments, outFile, errorFile); return self; #endif // HAVE_NSTASK diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.ipp b/src/include/platform/internal/GenericPlatformManagerImpl.ipp index 64878f5928cd9b..589dd4ccbe4584 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.ipp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.ipp @@ -139,7 +139,7 @@ exit: template void GenericPlatformManagerImpl::_Shutdown() { - ChipLogError(DeviceLayer, "Inet Layer shutdown"); + ChipLogProgress(DeviceLayer, "Inet Layer shutdown"); UDPEndPointManager()->Shutdown(); #if INET_CONFIG_ENABLE_TCP_ENDPOINT @@ -147,11 +147,11 @@ void GenericPlatformManagerImpl::_Shutdown() #endif #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE - ChipLogError(DeviceLayer, "BLE shutdown"); + ChipLogProgress(DeviceLayer, "BLE Layer shutdown"); BLEMgr().Shutdown(); #endif - ChipLogError(DeviceLayer, "System Layer shutdown"); + ChipLogProgress(DeviceLayer, "System Layer shutdown"); SystemLayer().Shutdown(); } diff --git a/src/messaging/tests/MessagingContext.cpp b/src/messaging/tests/MessagingContext.cpp index 61565da1cd4ac0..909bc90f443575 100644 --- a/src/messaging/tests/MessagingContext.cpp +++ b/src/messaging/tests/MessagingContext.cpp @@ -58,7 +58,7 @@ CHIP_ERROR MessagingContext::Init(TransportMgrBase * transport, IOContext * ioCo ReturnErrorOnFailure(mExchangeManager.Init(&mSessionManager)); ReturnErrorOnFailure(mMessageCounterManager.Init(&mExchangeManager)); - if (sInitializeNodes) + if (mInitializeNodes) { ReturnErrorOnFailure(CreateAliceFabric()); ReturnErrorOnFailure(CreateBobFabric()); @@ -112,8 +112,6 @@ using namespace System::Clock::Literals; constexpr chip::System::Clock::Timeout MessagingContext::kResponsiveIdleRetransTimeout; constexpr chip::System::Clock::Timeout MessagingContext::kResponsiveActiveRetransTimeout; -bool MessagingContext::sInitializeNodes = true; - void MessagingContext::SetMRPMode(MRPMode mode) { if (mode == MRPMode::kDefault) diff --git a/src/messaging/tests/MessagingContext.h b/src/messaging/tests/MessagingContext.h index bd9b0b981926e6..51525f967d1475 100644 --- a/src/messaging/tests/MessagingContext.h +++ b/src/messaging/tests/MessagingContext.h @@ -101,7 +101,7 @@ class MessagingContext : public PlatformMemoryUser ~MessagingContext() { VerifyOrDie(mInitialized == false); } // Whether Alice and Bob are initialized, must be called before Init - static void ConfigInitializeNodes(bool initializeNodes) { sInitializeNodes = initializeNodes; } + void ConfigInitializeNodes(bool initializeNodes) { mInitializeNodes = initializeNodes; } /// Initialize the underlying layers and test suite pointer CHIP_ERROR Init(TransportMgrBase * transport, IOContext * io); @@ -178,7 +178,7 @@ class MessagingContext : public PlatformMemoryUser System::Layer & GetSystemLayer() { return mIOContext->GetSystemLayer(); } private: - static bool sInitializeNodes; + bool mInitializeNodes = true; bool mInitialized; FabricTable mFabricTable; diff --git a/src/platform/Linux/DiagnosticDataProviderImpl.cpp b/src/platform/Linux/DiagnosticDataProviderImpl.cpp index 5ee5558064afeb..bebe5827163fa9 100644 --- a/src/platform/Linux/DiagnosticDataProviderImpl.cpp +++ b/src/platform/Linux/DiagnosticDataProviderImpl.cpp @@ -74,8 +74,10 @@ enum class WiFiStatsCountType kWiFiOverrunCount }; +#if defined(__GLIBC__) // Static variable to store the maximum heap size static size_t maxHeapHighWatermark = 0; +#endif CHIP_ERROR GetEthernetStatsCount(EthernetStatsCountType type, uint64_t & count) { @@ -223,9 +225,7 @@ DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree) { -#ifndef __GLIBC__ - return CHIP_ERROR_NOT_IMPLEMENTED; -#else +#if defined(__GLIBC__) struct mallinfo mallocInfo = mallinfo(); // Get the current amount of heap memory, in bytes, that are not being utilized @@ -233,14 +233,14 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeap currentHeapFree = mallocInfo.fordblks; return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; #endif } CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeapUsed) { -#ifndef __GLIBC__ - return CHIP_ERROR_NOT_IMPLEMENTED; -#else +#if defined(__GLIBC__) struct mallinfo mallocInfo = mallinfo(); // Get the current amount of heap memory, in bytes, that are being used by @@ -253,14 +253,14 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeap maxHeapHighWatermark = currentHeapUsed; } return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; #endif } CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) { -#ifndef __GLIBC__ - return CHIP_ERROR_NOT_IMPLEMENTED; -#else +#if defined(__GLIBC__) struct mallinfo mallocInfo = mallinfo(); // The usecase of this function is embedded devices,on which we would need to intercept @@ -279,6 +279,8 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & cu currentHeapHighWatermark = maxHeapHighWatermark; return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; #endif } @@ -287,10 +289,12 @@ CHIP_ERROR DiagnosticDataProviderImpl::ResetWatermarks() // If implemented, the server SHALL set the value of the CurrentHeapHighWatermark attribute to the // value of the CurrentHeapUsed. +#if defined(__GLIBC__) // Get the current amount of heap memory, in bytes, that are being used by // the current running program and reset the max heap high watermark to current heap amount. struct mallinfo mallocInfo = mallinfo(); maxHeapHighWatermark = mallocInfo.uordblks; +#endif return CHIP_NO_ERROR; } diff --git a/src/platform/Linux/bluez/BluezConnection.cpp b/src/platform/Linux/bluez/BluezConnection.cpp index 722cb2478d1665..eeb1e7fb8f1343 100644 --- a/src/platform/Linux/bluez/BluezConnection.cpp +++ b/src/platform/Linux/bluez/BluezConnection.cpp @@ -335,7 +335,7 @@ void BluezConnection::SubscribeCharacteristicDone(GObject * aObject, GAsyncResul auto * pC2 = reinterpret_cast(aObject); GAutoPtr error; - gboolean success = bluez_gatt_characteristic1_call_write_value_finish(pC2, aResult, &error.GetReceiver()); + gboolean success = bluez_gatt_characteristic1_call_start_notify_finish(pC2, aResult, &error.GetReceiver()); VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: SubscribeCharacteristic : %s", error->message)); @@ -367,7 +367,7 @@ void BluezConnection::UnsubscribeCharacteristicDone(GObject * aObject, GAsyncRes auto * pC2 = reinterpret_cast(aObject); GAutoPtr error; - gboolean success = bluez_gatt_characteristic1_call_write_value_finish(pC2, aResult, &error.GetReceiver()); + gboolean success = bluez_gatt_characteristic1_call_stop_notify_finish(pC2, aResult, &error.GetReceiver()); VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnsubscribeCharacteristic : %s", error->message)); diff --git a/src/platform/android/java/chip/platform/NsdManagerServiceBrowser.java b/src/platform/android/java/chip/platform/NsdManagerServiceBrowser.java index 28fc6988a9dbbd..e4ac8a673b5db2 100644 --- a/src/platform/android/java/chip/platform/NsdManagerServiceBrowser.java +++ b/src/platform/android/java/chip/platform/NsdManagerServiceBrowser.java @@ -172,7 +172,11 @@ public void onStopDiscoveryFailed(String serviceType, int errorCode) { @Override public void onDiscoveryStopped(String serviceType) { Log.w(TAG, "Successfully stopped discovery service '" + serviceType); - this.handleServiceBrowse(chipMdnsCallback); + new Handler(Looper.getMainLooper()) + .post( + () -> { + this.handleServiceBrowse(chipMdnsCallback); + }); } public void handleServiceBrowse(ChipMdnsCallback chipMdnsCallback) { diff --git a/src/platform/android/java/chip/platform/NsdServiceFinderAndResolver.java b/src/platform/android/java/chip/platform/NsdServiceFinderAndResolver.java index 70ffdbc0102a62..c1a187680c5c73 100644 --- a/src/platform/android/java/chip/platform/NsdServiceFinderAndResolver.java +++ b/src/platform/android/java/chip/platform/NsdServiceFinderAndResolver.java @@ -21,6 +21,8 @@ import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; import android.net.wifi.WifiManager.MulticastLock; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import androidx.annotation.Nullable; import java.util.concurrent.Executors; @@ -118,20 +120,24 @@ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { Log.w( TAG, "Failed to resolve service '" + serviceInfo.getServiceName() + "': " + errorCode); - chipMdnsCallback.handleServiceResolve( - serviceInfo.getServiceName(), - // Use the target service info since the resolved service info sometimes appends a - // "." at the front likely because it is trying to strip the service name out of it - // and something is missed. - // The target service info service type should be effectively the same as the - // resolved service info. - NsdServiceFinderAndResolver.this.targetServiceInfo.getServiceType(), - null, - null, - 0, - null, - callbackHandle, - contextHandle); + new Handler(Looper.getMainLooper()) + .post( + () -> { + chipMdnsCallback.handleServiceResolve( + serviceInfo.getServiceName(), + // Use the target service info since the resolved service info sometimes + // appends a "." at the front likely because it is trying to strip the + // service name out of it and something is missed. + // The target service info service type should be effectively the same as + // the resolved service info. + NsdServiceFinderAndResolver.this.targetServiceInfo.getServiceType(), + null, + null, + 0, + null, + callbackHandle, + contextHandle); + }); if (multicastLock.isHeld()) { multicastLock.release(); @@ -153,21 +159,28 @@ public void onServiceResolved(NsdServiceInfo serviceInfo) { + serviceInfo.getHost() + ", type : " + serviceInfo.getServiceType()); - // TODO: Find out if DNS-SD results for Android should contain interface ID - chipMdnsCallback.handleServiceResolve( - serviceInfo.getServiceName(), - // Use the target service info since the resolved service info sometimes appends a - // "." at the front likely because it is trying to strip the service name out of it - // and something is missed. - // The target service info service type should be effectively the same as the - // resolved service info. - NsdServiceFinderAndResolver.this.targetServiceInfo.getServiceType(), - serviceInfo.getHost().getHostName(), - serviceInfo.getHost().getHostAddress(), - serviceInfo.getPort(), - serviceInfo.getAttributes(), - callbackHandle, - contextHandle); + final String hostName = serviceInfo.getHost().getHostName(); + final String address = serviceInfo.getHost().getHostAddress(); + final int port = serviceInfo.getPort(); + new Handler(Looper.getMainLooper()) + .post( + () -> { + // TODO: Find out if DNS-SD results for Android should contain interface ID + chipMdnsCallback.handleServiceResolve( + serviceInfo.getServiceName(), + // Use the target service info since the resolved service info sometimes + // appends a "." at the front likely because it is trying to strip the + // service name out of it and something is missed. + // The target service info service type should be effectively the same as + // the resolved service info. + NsdServiceFinderAndResolver.this.targetServiceInfo.getServiceType(), + hostName, + address, + port, + serviceInfo.getAttributes(), + callbackHandle, + contextHandle); + }); if (multicastLock.isHeld()) { multicastLock.release(); diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index ccc2bc2188d176..b0642a966890fd 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -2362,21 +2362,36 @@ CHIP_ERROR CASESession::OnMessageReceived(ExchangeContext * ec, const PayloadHea return err; } -System::Clock::Timeout CASESession::ComputeSigma1ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig) +namespace { +System::Clock::Timeout ComputeRoundTripTimeout(ExchangeContext::Timeout serverProcessingTime, + const ReliableMessageProtocolConfig & remoteMrpConfig) { + // TODO: This is duplicating logic from Session::ComputeRoundTripTimeout. Unfortunately, it's called by + // consumers who do not have a session. + const auto & maybeLocalMRPConfig = GetLocalMRPConfig(); + const auto & defaultMRRPConfig = GetDefaultMRPConfig(); + const auto & localMRPConfig = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig); return GetRetransmissionTimeout(remoteMrpConfig.mActiveRetransTimeout, remoteMrpConfig.mIdleRetransTimeout, - // Assume peer is idle, since that's what we - // will assume for our initial message. + // Assume peer is idle, as a worst-case assumption (probably true for + // Sigma1, since that will be our initial message on the session, but less + // so for Sigma2). System::Clock::kZero, remoteMrpConfig.mActiveThresholdTime) + - kExpectedSigma1ProcessingTime; + serverProcessingTime + + GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout, + // Peer will assume we are active, since it's + // responding to our message. + System::SystemClock().GetMonotonicTimestamp(), localMRPConfig.mActiveThresholdTime); +} +} // anonymous namespace + +System::Clock::Timeout CASESession::ComputeSigma1ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig) +{ + return ComputeRoundTripTimeout(kExpectedSigma1ProcessingTime, remoteMrpConfig); } System::Clock::Timeout CASESession::ComputeSigma2ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig) { - return GetRetransmissionTimeout(remoteMrpConfig.mActiveRetransTimeout, remoteMrpConfig.mIdleRetransTimeout, - // Assume peer is idle, as a worst-case assumption. - System::Clock::kZero, remoteMrpConfig.mActiveThresholdTime) + - kExpectedHighProcessingTime; + return ComputeRoundTripTimeout(kExpectedHighProcessingTime, remoteMrpConfig); } bool CASESession::InvokeBackgroundWorkWatchdog() diff --git a/src/protocols/secure_channel/tests/TestCASESession.cpp b/src/protocols/secure_channel/tests/TestCASESession.cpp index 5fc6a37f72f4ab..68d6ddd177eeb8 100644 --- a/src/protocols/secure_channel/tests/TestCASESession.cpp +++ b/src/protocols/secure_channel/tests/TestCASESession.cpp @@ -64,6 +64,13 @@ class TestContext : public Test::LoopbackMessagingContext static void SetUpTestSuite(); // Performs shared teardown for all tests in the test suite static void TearDownTestSuite(); + + virtual void SetUp() override + { + ConfigInitializeNodes(false); + chip::Test::LoopbackMessagingContext::SetUp(); + } + virtual void TearDown() override { chip::Test::LoopbackMessagingContext::TearDown(); } }; void ServiceEvents(TestContext & ctx) @@ -329,7 +336,6 @@ CHIP_ERROR InitCredentialSets() void TestContext::SetUpTestSuite() { - ConfigInitializeNodes(false); CHIP_ERROR err = CHIP_NO_ERROR; LoopbackMessagingContext::SetUpTestSuite(); // TODO: use ASSERT_EQ, once transition to pw_unit_test is complete diff --git a/src/protocols/secure_channel/tests/TestPASESession.cpp b/src/protocols/secure_channel/tests/TestPASESession.cpp index d610b304cec481..896f721579334d 100644 --- a/src/protocols/secure_channel/tests/TestPASESession.cpp +++ b/src/protocols/secure_channel/tests/TestPASESession.cpp @@ -89,11 +89,16 @@ class TestContext : public chip::Test::LoopbackMessagingContext { public: // Performs shared setup for all tests in the test suite - static void SetUpTestSuite() + static void SetUpTestSuite() { chip::Test::LoopbackMessagingContext::SetUpTestSuite(); } + static void TearDownTestSuite() { chip::Test::LoopbackMessagingContext::TearDownTestSuite(); } + + void SetUp() override { ConfigInitializeNodes(false); - chip::Test::LoopbackMessagingContext::SetUpTestSuite(); + chip::Test::LoopbackMessagingContext::SetUp(); } + + void TearDown() override { chip::Test::LoopbackMessagingContext::TearDown(); } }; class PASETestLoopbackTransportDelegate : public Test::LoopbackTransportDelegate diff --git a/src/pybindings/pycontroller/build-chip-wheel.py b/src/pybindings/pycontroller/build-chip-wheel.py index a61b591d5c5368..61bdf373e8615c 100644 --- a/src/pybindings/pycontroller/build-chip-wheel.py +++ b/src/pybindings/pycontroller/build-chip-wheel.py @@ -60,7 +60,6 @@ def __init__(self, name): chipPackageVer = args.build_number installScripts = [ - # InstalledScriptInfo('chip-device-ctrl.py'), # InstalledScriptInfo('chip-repl.py'), ] diff --git a/src/python_testing/TC_IDM_1_4.py b/src/python_testing/TC_IDM_1_4.py index 507b5d74254abf..34d75f7d8f6184 100644 --- a/src/python_testing/TC_IDM_1_4.py +++ b/src/python_testing/TC_IDM_1_4.py @@ -74,7 +74,11 @@ async def test_TC_IDM_1_4(self): cap_for_batch_commands = 100 number_of_commands_to_send = min(max_paths_per_invoke + 1, cap_for_batch_commands) - invalid_command_id = 0xffff_ffff + # Use a valid (according to MEI definition) command-id (in this case belonging to Test Vendor MC with prefix 0xfff4) + # which should never be existing on a prodiction device. We use this decodable id to prevent hitting issues with the + # specification being not clearly defined in respect to decoding vs processing the invoke requests. + invalid_command_id = 0xfff4_00ff + list_of_commands_to_send = [] for endpoint_index in range(number_of_commands_to_send): # Using Toggle command to form the base as it is a command that doesn't take diff --git a/src/setup_payload/python/Base38.py b/src/setup_payload/python/Base38.py index 23113f7ed25c8d..834ae9e1d520e7 100644 --- a/src/setup_payload/python/Base38.py +++ b/src/setup_payload/python/Base38.py @@ -24,6 +24,7 @@ RADIX = len(CODES) BASE38_CHARS_NEEDED_IN_CHUNK = [2, 4, 5] MAX_BYTES_IN_CHUNK = 3 +MAX_ENCODED_BYTES_IN_CHUNK = 5 def encode(bytes): @@ -47,3 +48,25 @@ def encode(bytes): base38_chars_needed -= 1 return qrcode + + +def decode(qrcode): + total_chars = len(qrcode) + decoded_bytes = bytearray() + + for i in range(0, total_chars, MAX_ENCODED_BYTES_IN_CHUNK): + if (i + MAX_ENCODED_BYTES_IN_CHUNK) > total_chars: + chars_in_chunk = total_chars - i + else: + chars_in_chunk = MAX_ENCODED_BYTES_IN_CHUNK + + value = 0 + for j in range(i + chars_in_chunk - 1, i - 1, -1): + value = value * RADIX + CODES.index(qrcode[j]) + + bytes_in_chunk = BASE38_CHARS_NEEDED_IN_CHUNK.index(chars_in_chunk) + 1 + for k in range(0, bytes_in_chunk): + decoded_bytes.append(value & 0xFF) + value = value >> 8 + + return decoded_bytes diff --git a/src/setup_payload/python/README.md b/src/setup_payload/python/README.md index 068bf553fb7e6b..a39496104300d1 100644 --- a/src/setup_payload/python/README.md +++ b/src/setup_payload/python/README.md @@ -1,19 +1,22 @@ -## Python tool to generate Matter onboarding codes +## Python tool to generate and parse Matter onboarding codes -Generates Manual Pairing Code and QR Code +Generates and parses Manual Pairing Code and QR Code #### example usage: +- Parse + ``` -./generate_setup_payload.py -h -./generate_setup_payload.py -d 3840 -p 20202021 -cf 0 -dm 2 -vid 65521 -pid 32768 +./SetupPayload.py parse MT:U9VJ0OMV172PX813210 +./SetupPayload.py parse 34970112332 ``` -- Output +- Generate ``` -Manualcode : 34970112332 -QRCode : MT:Y.K9042C00KA0648G00 +./SetupPayload.py generate --help +./SetupPayload.py generate -d 3840 -p 20202021 +./SetupPayload.py generate -d 3840 -p 20202021 --vendor-id 65521 --product-id 32768 -cf 0 -dm 2 ``` For more details please refer Matter Specification diff --git a/src/setup_payload/python/SetupPayload.py b/src/setup_payload/python/SetupPayload.py new file mode 100755 index 00000000000000..82a58d957eff08 --- /dev/null +++ b/src/setup_payload/python/SetupPayload.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import enum + +import Base38 +import click +from bitarray import bitarray +from bitarray.util import int2ba, zeros +from construct import BitsInteger, BitStruct, Enum +from stdnum.verhoeff import calc_check_digit + +# Format for constructing manualcode +manualcode_format = BitStruct( + 'version' / BitsInteger(1), + 'vid_pid_present' / BitsInteger(1), + 'discriminator' / BitsInteger(4), + 'pincode_lsb' / BitsInteger(14), + 'pincode_msb' / BitsInteger(13), + 'vid' / BitsInteger(16), + 'pid' / BitsInteger(16), + 'padding' / BitsInteger(7), # this is intentional as BitStruct only takes 8-bit aligned data +) + +# Format for constructing qrcode +# qrcode bytes are packed as lsb....msb, hence the order is reversed +qrcode_format = BitStruct( + 'padding' / BitsInteger(4), + 'pincode' / BitsInteger(27), + 'discriminator' / BitsInteger(12), + 'discovery' / BitsInteger(8), + 'flow' / Enum(BitsInteger(2), + Standard=0, UserIntent=1, Custom=2), + 'pid' / BitsInteger(16), + 'vid' / BitsInteger(16), + 'version' / BitsInteger(3), +) + + +class CommissioningFlow(enum.IntEnum): + Standard = 0, + UserIntent = 1, + Custom = 2 + + +class SetupPayload: + def __init__(self, discriminator, pincode, rendezvous=4, flow=CommissioningFlow.Standard, vid=0, pid=0): + self.long_discriminator = discriminator + self.short_discriminator = discriminator >> 8 + self.pincode = pincode + self.discovery = rendezvous + self.flow = flow + self.vid = vid + self.pid = pid + + def p_print(self): + print('{:<{}} :{}'.format('Flow', 24, self.flow)) + print('{:<{}} :{}'.format('Pincode', 24, self.pincode)) + print('{:<{}} :{}'.format('Short Discriminator', 24, self.short_discriminator)) + if self.long_discriminator: + print('{:<{}} :{}'.format('Long Discriminator', 24, self.long_discriminator)) + if self.discovery: + print('{:<{}} :{}'.format('Discovery Capabilities', 24, self.discovery)) + if self.vid is not None and self.pid is not None: + print('{:<{}} :{:<{}} (0x{:04x})'.format('Vendor Id', 24, self.vid, 6, self.vid)) + print('{:<{}} :{:<{}} (0x{:04x})'.format('Product Id', 24, self.pid, 6, self.pid)) + + def qrcode_dict(self): + return { + 'version': 0, + 'vid': self.vid, + 'pid': self.pid, + 'flow': int(self.flow), + 'discovery': self.discovery, + 'discriminator': self.long_discriminator, + 'pincode': self.pincode, + 'padding': 0, + } + + def manualcode_dict(self): + return { + 'version': 0, + 'vid_pid_present': 0 if self.flow == CommissioningFlow.Standard else 1, + 'discriminator': self.short_discriminator, + 'pincode_lsb': self.pincode & 0x3FFF, # 14 ls-bits + 'pincode_msb': self.pincode >> 14, # 13 ms-bits + 'vid': 0 if self.flow == CommissioningFlow.Standard else self.vid, + 'pid': 0 if self.flow == CommissioningFlow.Standard else self.pid, + 'padding': 0, + } + + def generate_qrcode(self): + data = qrcode_format.build(self.qrcode_dict()) + b38_encoded = Base38.encode(data[::-1]) # reversing + return 'MT:{}'.format(b38_encoded) + + def generate_manualcode(self): + CHUNK1_START = 0 + CHUNK1_LEN = 4 + CHUNK2_START = CHUNK1_START + CHUNK1_LEN + CHUNK2_LEN = 16 + CHUNK3_START = CHUNK2_START + CHUNK2_LEN + CHUNK3_LEN = 13 + + bytes = manualcode_format.build(self.manualcode_dict()) + bits = bitarray() + bits.frombytes(bytes) + + chunk1 = str(int(bits[CHUNK1_START:CHUNK1_START + CHUNK1_LEN].to01(), 2)).zfill(1) + chunk2 = str(int(bits[CHUNK2_START:CHUNK2_START + CHUNK2_LEN].to01(), 2)).zfill(5) + chunk3 = str(int(bits[CHUNK3_START:CHUNK3_START + CHUNK3_LEN].to01(), 2)).zfill(4) + chunk4 = str(self.vid).zfill(5) if self.flow != CommissioningFlow.Standard else '' + chunk5 = str(self.pid).zfill(5) if self.flow != CommissioningFlow.Standard else '' + payload = '{}{}{}{}{}'.format(chunk1, chunk2, chunk3, chunk4, chunk5) + return '{}{}'.format(payload, calc_check_digit(payload)) + + @staticmethod + def from_container(container, is_qrcode): + payload = None + if is_qrcode: + payload = SetupPayload(container['discriminator'], container['pincode'], + container['discovery'], CommissioningFlow(container['flow'].__int__()), + container['vid'], container['pid']) + else: + payload = SetupPayload(discriminator=container['discriminator'], + pincode=(container['pincode_msb'] << 14) | container['pincode_lsb'], + vid=container['vid'] if container['vid_pid_present'] else None, + pid=container['pid'] if container['vid_pid_present'] else None) + payload.short_discriminator = container['discriminator'] + payload.long_discriminator = None + payload.discovery = None + payload.flow = 2 if container['vid_pid_present'] else 0 + + return payload + + @staticmethod + def parse_qrcode(payload): + payload = payload[3:] # remove 'MT:' + b38_decoded = Base38.decode(payload)[::-1] + container = qrcode_format.parse(b38_decoded) + return SetupPayload.from_container(container, is_qrcode=True) + + @staticmethod + def parse_manualcode(payload): + payload_len = len(payload) + if payload_len != 11 and payload_len != 21: + print('Invalid length') + return None + + # if first digit is greater than 7 the its not v1 + if int(str(payload)[0]) > 7: + print('incorrect first digit') + return None + + if calc_check_digit(payload[:-1]) != str(payload)[-1]: + print('check digit mismatch') + return None + + # vid_pid_present bit position + is_long = int(str(payload)[0]) & (1 << 2) + + bits = int2ba(int(payload[0]), length=4) + bits += int2ba(int(payload[1:6]), length=16) + bits += int2ba(int(payload[6:10]), length=13) + bits += int2ba(int(payload[10:15]), length=16) if is_long else zeros(16) + bits += int2ba(int(payload[15:20]), length=16) if is_long else zeros(16) + bits += zeros(7) # padding + + container = manualcode_format.parse(bits.tobytes()) + return SetupPayload.from_container(container, is_qrcode=False) + + @staticmethod + def parse(payload): + if payload.startswith('MT:'): + return SetupPayload.parse_qrcode(payload) + else: + return SetupPayload.parse_manualcode(payload) + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.argument('payload') +def parse(payload): + click.echo(f'Parsing payload: {payload}') + SetupPayload.parse(payload).p_print() + + +@cli.command() +@click.option('--discriminator', '-d', required=True, type=click.IntRange(0, 0xFFF), help='Discriminator') +@click.option('--passcode', '-p', required=True, type=click.IntRange(1, 0x5F5E0FE), help='setup pincode') +@click.option('--vendor-id', '-vid', type=click.IntRange(0, 0xFFFF), default=0, help='Vendor ID') +@click.option('--product-id', '-pid', type=click.IntRange(0, 0xFFFF), default=0, help='Product ID') +@click.option('--discovery-cap-bitmask', '-dm', type=click.IntRange(0, 7), default=4, help='Commissionable device discovery capability bitmask. 0:SoftAP, 1:BLE, 2:OnNetwork. Default: OnNetwork') +@click.option('--commissioning-flow', '-cf', type=click.IntRange(0, 2), default=0, help='Commissioning flow, 0:Standard, 1:User-Intent, 2:Custom') +def generate(passcode, discriminator, vendor_id, product_id, discovery_cap_bitmask, commissioning_flow): + payload = SetupPayload(discriminator, passcode, discovery_cap_bitmask, commissioning_flow, vendor_id, product_id) + print("Manualcode : {}".format(payload.generate_manualcode())) + print("QRCode : {}".format(payload.generate_qrcode())) + + +if __name__ == '__main__': + cli() diff --git a/src/setup_payload/python/generate_setup_payload.py b/src/setup_payload/python/generate_setup_payload.py deleted file mode 100755 index 28a834651214b1..00000000000000 --- a/src/setup_payload/python/generate_setup_payload.py +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2022 Project CHIP Authors -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import argparse -import enum -import sys - -import Base38 -from bitarray import bitarray -from stdnum.verhoeff import calc_check_digit - -# See section 5.1.4.1 Manual Pairing Code in the Matter specification v1.0 -MANUAL_DISCRIMINATOR_LEN = 4 -PINCODE_LEN = 27 - -MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN = 2 -MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_POS = 0 -MANUAL_CHUNK1_VID_PID_PRESENT_BIT_POS = MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_POS + MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN -MANUAL_CHUNK1_LEN = 1 - -MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_LEN = 2 -MANUAL_CHUNK2_PINCODE_LSBITS_LEN = 14 -MANUAL_CHUNK2_PINCODE_LSBITS_POS = 0 -MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_POS = MANUAL_CHUNK2_PINCODE_LSBITS_POS + MANUAL_CHUNK2_PINCODE_LSBITS_LEN -MANUAL_CHUNK2_LEN = 5 - -MANUAL_CHUNK3_PINCODE_MSBITS_LEN = 13 -MANUAL_CHUNK3_PINCODE_MSBITS_POS = 0 -MANUAL_CHUNK3_LEN = 4 - -MANUAL_VID_LEN = 5 -MANUAL_PID_LEN = 5 - -# See section 5.1.3. QR Code in the Matter specification v1.0 -QRCODE_VERSION_LEN = 3 -QRCODE_DISCRIMINATOR_LEN = 12 -QRCODE_VID_LEN = 16 -QRCODE_PID_LEN = 16 -QRCODE_COMMISSIONING_FLOW_LEN = 2 -QRCODE_DISCOVERY_CAP_BITMASK_LEN = 8 -QRCODE_PADDING_LEN = 4 -QRCODE_VERSION = 0 -QRCODE_PADDING = 0 - -INVALID_PASSCODES = [00000000, 11111111, 22222222, 33333333, 44444444, 55555555, - 66666666, 77777777, 88888888, 99999999, 12345678, 87654321] - - -class CommissioningFlow(enum.IntEnum): - Standard = 0, - UserIntent = 1, - Custom = 2 - - -class SetupPayload: - def __init__(self, discriminator, pincode, rendezvous=4, flow=CommissioningFlow.Standard, vid=0, pid=0): - self.long_discriminator = discriminator - self.short_discriminator = discriminator >> 8 - self.pincode = pincode - self.rendezvous = rendezvous - self.flow = flow - self.vid = vid - self.pid = pid - - def manual_chunk1(self): - discriminator_shift = (MANUAL_DISCRIMINATOR_LEN - MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN) - discriminator_mask = (1 << MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN) - 1 - discriminator_chunk = (self.short_discriminator >> discriminator_shift) & discriminator_mask - vid_pid_present_flag = 0 if self.flow == CommissioningFlow.Standard else 1 - return (discriminator_chunk << MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_POS) | (vid_pid_present_flag << MANUAL_CHUNK1_VID_PID_PRESENT_BIT_POS) - - def manual_chunk2(self): - discriminator_mask = (1 << MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_LEN) - 1 - pincode_mask = (1 << MANUAL_CHUNK2_PINCODE_LSBITS_LEN) - 1 - discriminator_chunk = self.short_discriminator & discriminator_mask - return ((self.pincode & pincode_mask) << MANUAL_CHUNK2_PINCODE_LSBITS_POS) | (discriminator_chunk << MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_POS) - - def manual_chunk3(self): - pincode_shift = PINCODE_LEN - MANUAL_CHUNK3_PINCODE_MSBITS_LEN - pincode_mask = (1 << MANUAL_CHUNK3_PINCODE_MSBITS_LEN) - 1 - return ((self.pincode >> pincode_shift) & pincode_mask) << MANUAL_CHUNK3_PINCODE_MSBITS_POS - - def generate_manualcode(self): - payload = str(self.manual_chunk1()).zfill(MANUAL_CHUNK1_LEN) - payload += str(self.manual_chunk2()).zfill(MANUAL_CHUNK2_LEN) - payload += str(self.manual_chunk3()).zfill(MANUAL_CHUNK3_LEN) - - if self.flow != CommissioningFlow.Standard: - payload += str(self.vid).zfill(MANUAL_VID_LEN) - payload += str(self.pid).zfill(MANUAL_PID_LEN) - - payload += calc_check_digit(payload) - return payload - - def generate_qrcode(self): - qrcode_bit_string = '{0:b}'.format(QRCODE_PADDING).zfill(QRCODE_PADDING_LEN) - qrcode_bit_string += '{0:b}'.format(self.pincode).zfill(PINCODE_LEN) - qrcode_bit_string += '{0:b}'.format(self.long_discriminator).zfill(QRCODE_DISCRIMINATOR_LEN) - qrcode_bit_string += '{0:b}'.format(self.rendezvous).zfill(QRCODE_DISCOVERY_CAP_BITMASK_LEN) - qrcode_bit_string += '{0:b}'.format(int(self.flow)).zfill(QRCODE_COMMISSIONING_FLOW_LEN) - qrcode_bit_string += '{0:b}'.format(self.pid).zfill(QRCODE_PID_LEN) - qrcode_bit_string += '{0:b}'.format(self.vid).zfill(QRCODE_VID_LEN) - qrcode_bit_string += '{0:b}'.format(QRCODE_VERSION).zfill(QRCODE_VERSION_LEN) - - qrcode_bits = bitarray(qrcode_bit_string) - bytes = list(qrcode_bits.tobytes()) - bytes.reverse() - return 'MT:{}'.format(Base38.encode(bytes)) - - -def validate_args(args): - def check_int_range(value, min_value, max_value, name): - if value and ((value < min_value) or (value > max_value)): - print('{} is out of range, should be in range from {} to {}'.format(name, min_value, max_value)) - sys.exit(1) - - if args.passcode is not None: - if ((args.passcode < 0x0000001 and args.passcode > 0x5F5E0FE) or (args.passcode in INVALID_PASSCODES)): - print('Invalid passcode:' + str(args.passcode)) - sys.exit(1) - - check_int_range(args.discriminator, 0x0000, 0x0FFF, 'Discriminator') - check_int_range(args.product_id, 0x0000, 0xFFFF, 'Product id') - check_int_range(args.vendor_id, 0x0000, 0xFFFF, 'Vendor id') - check_int_range(args.discovery_cap_bitmask, 0x0001, 0x0007, 'Discovery Capability Mask') - - -def main(): - def any_base_int(s): return int(s, 0) - parser = argparse.ArgumentParser(description='Matter Manual and QRCode Setup Payload Generator Tool') - parser.add_argument('-d', '--discriminator', type=any_base_int, required=True, - help='The discriminator for pairing, range: 0x00-0x0FFF') - parser.add_argument('-p', '--passcode', type=any_base_int, required=True, - help='The setup passcode for pairing, range: 0x01-0x5F5E0FE') - parser.add_argument('-vid', '--vendor-id', type=any_base_int, default=0, help='Vendor id') - parser.add_argument('-pid', '--product-id', type=any_base_int, default=0, help='Product id') - parser.add_argument('-cf', '--commissioning-flow', type=any_base_int, default=0, - help='Device commissioning flow, 0:Standard, 1:User-Intent, 2:Custom. \ - Default is 0.', choices=[0, 1, 2]) - parser.add_argument('-dm', '--discovery-cap-bitmask', type=any_base_int, default=4, - help='Commissionable device discovery capability bitmask. \ - 0:SoftAP, 1:BLE, 2:OnNetwork. Default: OnNetwork') - args = parser.parse_args() - validate_args(args) - - payloads = SetupPayload(args.discriminator, args.passcode, args.discovery_cap_bitmask, - CommissioningFlow(args.commissioning_flow), args.vendor_id, args.product_id) - manualcode = payloads.generate_manualcode() - qrcode = payloads.generate_qrcode() - - print("Manualcode : {}".format(manualcode)) - print("QRCode : {}".format(qrcode)) - - -if __name__ == '__main__': - main() diff --git a/src/setup_payload/python/requirements.txt b/src/setup_payload/python/requirements.txt index 43800d601c7736..1026fa98d061c5 100644 --- a/src/setup_payload/python/requirements.txt +++ b/src/setup_payload/python/requirements.txt @@ -1,2 +1,4 @@ -bitarray==2.6.0 +bitarray>=2.8.1 +click>=8.1.3 +construct>=2.10.68 python_stdnum==1.18 diff --git a/src/setup_payload/tests/run_python_setup_payload_gen_test.py b/src/setup_payload/tests/run_python_setup_payload_gen_test.py deleted file mode 100644 index b52000c1a6fd98..00000000000000 --- a/src/setup_payload/tests/run_python_setup_payload_gen_test.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2023 Project CHIP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import re -import subprocess -import sys - -CHIP_TOPDIR = os.path.dirname(os.path.realpath(__file__))[:-len(os.path.join('src', 'setup_payload', 'tests'))] -sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'src', 'setup_payload', 'python')) -from generate_setup_payload import CommissioningFlow, SetupPayload # noqa: E402 - - -def payload_param_dict(): - return { - 'Version': None, - 'VendorID': None, - 'ProductID': None, - 'Custom flow': None, - 'Discovery Bitmask': None, - 'Short discriminator': None, - 'Long discriminator': None, - 'Passcode': None - } - - -def remove_escape_sequence(data): - ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') - result = ansi_escape.sub('', data) - return result - - -def parse_setup_payload(chip_tool, payload): - cmd_args = [chip_tool, 'payload', 'parse-setup-payload', payload] - data = subprocess.check_output(cmd_args).decode('utf-8') - data = remove_escape_sequence(data) - parsed_params = payload_param_dict() - for key in parsed_params: - k_st = data.find(key) - if k_st == -1: - continue - - # 1 is for ":" - k_end = k_st + len(key) + 1 - - k_nl = data.find('\n', k_end) - parsed_params[key] = data[k_end:k_nl].split()[0] - - return parsed_params - - -def generate_payloads(in_params): - payloads = SetupPayload(in_params['Long discriminator'], in_params['Passcode'], - in_params['Discovery Bitmask'], CommissioningFlow(in_params['Custom flow']), - in_params['VendorID'], in_params['ProductID']) - manualcode = payloads.generate_manualcode() - qrcode = payloads.generate_qrcode() - return manualcode, qrcode - - -def verify_payloads(in_params, manualcode_params, qrcode_params): - assert in_params['Version'] == int(manualcode_params['Version'], 0) - assert in_params['Passcode'] == int(manualcode_params['Passcode'], 0) - assert in_params['Short discriminator'] == int(manualcode_params['Short discriminator'], 0) - if in_params['Custom flow'] != 0: - assert in_params['VendorID'] == int(manualcode_params['VendorID'], 0) - assert in_params['ProductID'] == int(manualcode_params['ProductID'], 0) - - assert in_params['Version'] == int(qrcode_params['Version'], 0) - assert in_params['VendorID'] == int(qrcode_params['VendorID'], 0) - assert in_params['ProductID'] == int(qrcode_params['ProductID'], 0) - assert in_params['Custom flow'] == int(qrcode_params['Custom flow'], 0) - assert in_params['Discovery Bitmask'] == int(qrcode_params['Discovery Bitmask'], 0) - assert in_params['Passcode'] == int(qrcode_params['Passcode'], 0) - assert in_params['Long discriminator'] == int(qrcode_params['Long discriminator'], 0) - - -def get_payload_params(discriminator, passcode, discovery=4, flow=0, vid=0, pid=0, version=0): - p = payload_param_dict() - p['Version'] = version - p['VendorID'] = vid - p['ProductID'] = pid - p['Custom flow'] = flow - p['Discovery Bitmask'] = discovery - p['Long discriminator'] = discriminator - p['Short discriminator'] = discriminator >> 8 - p['Passcode'] = passcode - return p - - -def run_tests(chip_tool): - test_data_set = [ - get_payload_params(3840, 20202021), - get_payload_params(3781, 12349876, flow=1, vid=1, pid=1), - get_payload_params(2310, 23005908, flow=2, vid=0xFFF3, pid=0x8098), - get_payload_params(3091, 43338551, discovery=2, flow=2, vid=0x1123, pid=0x0012), - get_payload_params(80, 54757432, discovery=6, flow=2, vid=0x2345, pid=0x1023), - get_payload_params(174, 81235604, discovery=7, flow=1, vid=0x45, pid=0x10), - ] - - for test_params in test_data_set: - manualcode, qrcode = generate_payloads(test_params) - manualcode_params = parse_setup_payload(chip_tool, manualcode) - qrcode_params = parse_setup_payload(chip_tool, qrcode) - - print("Input parameters:", test_params) - print("Manualcode:", manualcode) - print("QRCode:", qrcode) - print("Manualcode parsed by chip-tool:", manualcode_params) - print("QRCode parsed by chip-tool:", qrcode_params) - print("") - - verify_payloads(test_params, manualcode_params, qrcode_params) - - -def main(): - if len(sys.argv) == 2: - chip_tool = sys.argv[1] - run_tests(chip_tool) - - -if __name__ == '__main__': - main() diff --git a/src/setup_payload/tests/run_python_setup_payload_test.py b/src/setup_payload/tests/run_python_setup_payload_test.py new file mode 100644 index 00000000000000..da62a45c05fe97 --- /dev/null +++ b/src/setup_payload/tests/run_python_setup_payload_test.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import subprocess +import sys + +CHIP_TOPDIR = os.path.dirname(os.path.realpath(__file__))[:-len(os.path.join('src', 'setup_payload', 'tests'))] +sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'src', 'setup_payload', 'python')) +from SetupPayload import CommissioningFlow, SetupPayload # noqa: E402 + + +def payload_param_dict(): + return { + 'Version': None, + 'VendorID': None, + 'ProductID': None, + 'Custom flow': None, + 'Discovery Bitmask': None, + 'Short discriminator': None, + 'Long discriminator': None, + 'Passcode': None + } + + +def remove_escape_sequence(data): + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + result = ansi_escape.sub('', data) + return result + + +def chip_tool_parse_setup_payload(chip_tool, payload): + cmd_args = [chip_tool, 'payload', 'parse-setup-payload', payload] + data = subprocess.check_output(cmd_args).decode('utf-8') + data = remove_escape_sequence(data) + parsed_params = payload_param_dict() + for key in parsed_params: + k_st = data.find(key) + if k_st == -1: + continue + + # 1 is for ":" + k_end = k_st + len(key) + 1 + + k_nl = data.find('\n', k_end) + parsed_params[key] = data[k_end:k_nl].split()[0] + + return parsed_params + + +def generate_payloads(in_params): + payloads = SetupPayload(in_params['Long discriminator'], in_params['Passcode'], + in_params['Discovery Bitmask'], CommissioningFlow(in_params['Custom flow']), + in_params['VendorID'], in_params['ProductID']) + manualcode = payloads.generate_manualcode() + qrcode = payloads.generate_qrcode() + return manualcode, qrcode + + +def verify_generated_payloads(in_params, manualcode_params, qrcode_params): + assert in_params['Version'] == int(manualcode_params['Version'], 0) + assert in_params['Passcode'] == int(manualcode_params['Passcode'], 0) + assert in_params['Short discriminator'] == int(manualcode_params['Short discriminator'], 0) + if in_params['Custom flow'] != 0: + assert in_params['VendorID'] == int(manualcode_params['VendorID'], 0) + assert in_params['ProductID'] == int(manualcode_params['ProductID'], 0) + + assert in_params['Version'] == int(qrcode_params['Version'], 0) + assert in_params['VendorID'] == int(qrcode_params['VendorID'], 0) + assert in_params['ProductID'] == int(qrcode_params['ProductID'], 0) + assert in_params['Custom flow'] == int(qrcode_params['Custom flow'], 0) + assert in_params['Discovery Bitmask'] == int(qrcode_params['Discovery Bitmask'], 0) + assert in_params['Passcode'] == int(qrcode_params['Passcode'], 0) + assert in_params['Long discriminator'] == int(qrcode_params['Long discriminator'], 0) + + +def get_payload_params(discriminator, passcode, discovery=4, flow=0, vid=0, pid=0, version=0, short_discriminator=None): + p = payload_param_dict() + p['Version'] = version + p['VendorID'] = vid + p['ProductID'] = pid + p['Custom flow'] = flow + p['Discovery Bitmask'] = discovery + p['Long discriminator'] = discriminator + p['Short discriminator'] = short_discriminator if short_discriminator is not None else (discriminator >> 8) + p['Passcode'] = passcode + return p + + +def test_code_generation(chip_tool): + test_data_set = [ + get_payload_params(3840, 20202021), + get_payload_params(3781, 12349876, flow=1, vid=1, pid=1), + get_payload_params(2310, 23005908, flow=2, vid=0xFFF3, pid=0x8098), + get_payload_params(3091, 43338551, discovery=2, flow=2, vid=0x1123, pid=0x0012), + get_payload_params(80, 54757432, discovery=6, flow=2, vid=0x2345, pid=0x1023), + get_payload_params(174, 81235604, discovery=7, flow=1, vid=0x45, pid=0x10), + ] + + for test_params in test_data_set: + manualcode, qrcode = generate_payloads(test_params) + manualcode_params = chip_tool_parse_setup_payload(chip_tool, manualcode) + qrcode_params = chip_tool_parse_setup_payload(chip_tool, qrcode) + + verify_generated_payloads(test_params, manualcode_params, qrcode_params) + + +def test_onboardingcode_parsing(): + # This test dataset is generated using `chip-tool payload parse-setup-payload ` + + test_data_set = [ + { + 'code': '34970112332', + 'res': get_payload_params(discriminator=None, passcode=20202021, discovery=None, + flow=0, vid=None, pid=None, version=0, short_discriminator=15), + }, + { + 'code': '745492075300001000013', + 'res': get_payload_params(discriminator=None, passcode=12349876, discovery=None, + flow=2, vid=1, pid=1, version=0, short_discriminator=14), + }, + { + 'code': '619156140465523329207', + 'res': get_payload_params(discriminator=None, passcode=23005908, discovery=None, + flow=2, vid=65523, pid=32920, version=0, short_discriminator=9), + }, + { + 'code': '702871264504387000187', + 'res': get_payload_params(discriminator=None, passcode=43338551, discovery=None, + flow=2, vid=4387, pid=18, version=0, short_discriminator=12), + }, + { + 'code': '402104334209029041311', + 'res': get_payload_params(discriminator=None, passcode=54757432, discovery=None, + flow=2, vid=9029, pid=4131, version=0, short_discriminator=0), + }, + { + 'code': '403732495800069000166', + 'res': get_payload_params(discriminator=None, passcode=81235604, discovery=None, + flow=2, vid=69, pid=16, version=0, short_discriminator=0), + }, + { + 'code': 'MT:U9VJ0OMV172PX813210', + 'res': get_payload_params(discriminator=3431, passcode=49910688, discovery=2, + flow=0, vid=4891, pid=2, version=0, short_discriminator=None), + }, + { + 'code': 'MT:00000CQM00KA0648G00', + 'res': get_payload_params(discriminator=3840, passcode=20202021, discovery=4, + flow=0, vid=0, pid=0, version=0, short_discriminator=None), + }, + { + 'code': 'MT:A3L90ARR15G6N57Y900', + 'res': get_payload_params(discriminator=3781, passcode=12349876, discovery=4, + flow=1, vid=1, pid=1, version=0, short_discriminator=None), + }, + { + 'code': 'MT:MZWA6G6026O2XP0II00', + 'res': get_payload_params(discriminator=2310, passcode=23005908, discovery=4, + flow=2, vid=65523, pid=32920, version=0, short_discriminator=None), + }, + { + 'code': 'MT:KSNK4M5113-JPR4UY00', + 'res': get_payload_params(discriminator=3091, passcode=43338551, discovery=2, + flow=2, vid=4387, pid=18, version=0, short_discriminator=12), + }, + { + 'code': 'MT:0A.T0P--00Y0OJ0.510', + 'res': get_payload_params(discriminator=80, passcode=54757432, discovery=6, + flow=2, vid=9029, pid=4131, version=0, short_discriminator=None), + }, + { + 'code': 'MT:EPX0482F26DAVY09R10', + 'res': get_payload_params(discriminator=174, passcode=81235604, discovery=7, + flow=1, vid=69, pid=16, version=0, short_discriminator=None), + }, + ] + + for test_payload in test_data_set: + payload = SetupPayload.parse(test_payload['code']) + + assert payload.long_discriminator == test_payload['res']['Long discriminator'] + assert payload.short_discriminator == test_payload['res']['Short discriminator'] + assert payload.pincode == test_payload['res']['Passcode'] + assert payload.discovery == test_payload['res']['Discovery Bitmask'] + assert payload.flow == test_payload['res']['Custom flow'] + assert payload.vid == test_payload['res']['VendorID'] + assert payload.pid == test_payload['res']['ProductID'] + + +def main(): + if len(sys.argv) == 2: + chip_tool = sys.argv[1] + test_code_generation(chip_tool) + test_onboardingcode_parsing() + + +if __name__ == '__main__': + main() diff --git a/src/system/SystemPacketBuffer.cpp b/src/system/SystemPacketBuffer.cpp index 59e1e822901db0..f8dda8b01ab84e 100644 --- a/src/system/SystemPacketBuffer.cpp +++ b/src/system/SystemPacketBuffer.cpp @@ -508,37 +508,64 @@ void PacketBuffer::AddRef() PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aReservedSize) { - // Adding three 16-bit-int sized numbers together will never overflow - // assuming int is at least 32 bits. - static_assert(INT_MAX >= INT32_MAX, "int is not big enough"); + // Sanity check for kStructureSize to ensure that it matches the PacketBuffer size. static_assert(PacketBuffer::kStructureSize == sizeof(PacketBuffer), "PacketBuffer size mismatch"); - static_assert(PacketBuffer::kStructureSize < UINT16_MAX, "Check for overflow more carefully"); - static_assert(SIZE_MAX >= INT_MAX, "Our additions might not fit in size_t"); - static_assert(PacketBuffer::kMaxSizeWithoutReserve <= UINT32_MAX, "PacketBuffer may have size not fitting uint32_t"); + // Setting a static upper bound on kStructureSize to ensure the summation of all the sizes does not overflow. + static_assert(PacketBuffer::kStructureSize <= UINT16_MAX, "kStructureSize should not exceed UINT16_MAX."); + // Setting a static upper bound on the maximum buffer size allocation for regular sized messages (not large). + static_assert(PacketBuffer::kMaxSizeWithoutReserve <= UINT16_MAX, "kMaxSizeWithoutReserve should not exceed UINT16_MAX."); + + // Ensure that aAvailableSize is bound within a max and is not big enough to cause overflow during + // subsequent addition of all the sizes. + if (aAvailableSize > UINT32_MAX) + { + ChipLogError(chipSystemLayer, + "PacketBuffer: AvailableSize of a buffer cannot exceed UINT32_MAX. aAvailableSize = 0x" ChipLogFormatX64, + ChipLogValueX64(static_cast(aAvailableSize))); + return PacketBufferHandle(); + } + + // Cast all to uint64_t and add. This cannot overflow because we have + // ensured that the maximal value of the summation is + // UINT32_MAX + UINT16_MAX + UINT16_MAX, which should always fit in + // a uint64_t variable. + uint64_t sumOfSizes = static_cast(aAvailableSize) + static_cast(aReservedSize) + + static_cast(PacketBuffer::kStructureSize); + uint64_t sumOfAvailAndReserved = static_cast(aAvailableSize) + static_cast(aReservedSize); + + // Ensure that the sum fits in a size_t so that casting into size_t variables, + // viz., lBlockSize and lAllocSize, is safe. + if (!CanCastTo(sumOfSizes)) + { + ChipLogError(chipSystemLayer, + "PacketBuffer: Sizes of allocation request are invalid. (aAvailableSize = " ChipLogFormatX64 + ", aReservedSize = " ChipLogFormatX64 ")", + ChipLogValueX64(static_cast(aAvailableSize)), ChipLogValueX64(static_cast(aReservedSize))); + return PacketBufferHandle(); + } + #if CHIP_SYSTEM_CONFIG_USE_LWIP // LwIP based APIs have a maximum buffer size of UINT16_MAX. Ensure that // limit is met during allocation. - VerifyOrDieWithMsg(aAvailableSize + aReservedSize < UINT16_MAX, chipSystemLayer, - "LwIP based systems can handle only up to UINT16_MAX!"); + VerifyOrDieWithMsg(sumOfAvailAndReserved < UINT16_MAX, chipSystemLayer, "LwIP based systems can handle only up to UINT16_MAX!"); #endif // CHIP_SYSTEM_CONFIG_USE_LWIP - // When `aAvailableSize` fits in uint16_t (as tested below) and size_t is at least 32 bits (as asserted above), - // these additions will not overflow. - const size_t lAllocSize = aReservedSize + aAvailableSize; - const size_t lBlockSize = PacketBuffer::kStructureSize + lAllocSize; + // sumOfAvailAndReserved is no larger than sumOfSizes, which we checked can be cast to + // size_t. + const size_t lAllocSize = static_cast(sumOfAvailAndReserved); PacketBuffer * lPacket; CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return PacketBufferHandle()); - // TODO: Change the max to a lower value - if (aAvailableSize > UINT32_MAX || lAllocSize > PacketBuffer::kMaxSizeWithoutReserve || lBlockSize > UINT32_MAX) + if (lAllocSize > PacketBuffer::kMaxSizeWithoutReserve) { - ChipLogError(chipSystemLayer, "PacketBuffer: allocation too large."); + ChipLogError(chipSystemLayer, "PacketBuffer: allocation exceeding buffer capacity limits."); return PacketBufferHandle(); } #if CHIP_SYSTEM_CONFIG_USE_LWIP - + // This cast is safe because lAllocSize is no larger than + // kMaxSizeWithoutReserve, which fits in uint16_t. lPacket = static_cast( pbuf_alloc(PBUF_RAW, static_cast(lAllocSize), CHIP_SYSTEM_PACKETBUFFER_LWIP_PBUF_TYPE)); @@ -546,7 +573,6 @@ PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aRese #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL - static_cast(lBlockSize); #if !CHIP_SYSTEM_CONFIG_NO_LOCKING && CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING if (!sBufferPoolMutex.isInitialized()) { @@ -565,8 +591,10 @@ PacketBufferHandle PacketBufferHandle::New(size_t aAvailableSize, uint16_t aRese UNLOCK_BUF_POOL(); #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP - - lPacket = reinterpret_cast(chip::Platform::MemoryAlloc(lBlockSize)); + // sumOfSizes is essentially (kStructureSize + lAllocSize) which we already + // checked to fit in a size_t. + const size_t lBlockSize = static_cast(sumOfSizes); + lPacket = reinterpret_cast(chip::Platform::MemoryAlloc(lBlockSize)); SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs); #else diff --git a/src/transport/GroupSession.h b/src/transport/GroupSession.h index f20ff069ab029f..1c5ffecd2be3c9 100644 --- a/src/transport/GroupSession.h +++ b/src/transport/GroupSession.h @@ -75,6 +75,13 @@ class IncomingGroupSession : public Session, public ReferenceCounted; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::WiFiNetworkManagement::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::WiFiNetworkManagement::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE, + markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::WiFiNetworkManagement::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); +} + +} // namespace FeatureMap + +namespace ClusterRevision { + +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + Protocols::InteractionModel::Status status = + emberAfReadAttribute(endpoint, Clusters::WiFiNetworkManagement::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + *value = Traits::StorageToWorking(temp); + return status; +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::WiFiNetworkManagement::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE, markDirty); +} + +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return Protocols::InteractionModel::Status::ConstraintError; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::WiFiNetworkManagement::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); +} + +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace WiFiNetworkManagement + namespace WakeOnLan { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index e51fb1999e9ce8..d7c5c77d861bd0 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -5316,6 +5316,24 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu } // namespace Attributes } // namespace RadonConcentrationMeasurement +namespace WiFiNetworkManagement { +namespace Attributes { + +namespace FeatureMap { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value, MarkAttributeDirty markDirty); +} // namespace FeatureMap + +namespace ClusterRevision { +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint16_t * value); // int16u +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty); +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace WiFiNetworkManagement + namespace WakeOnLan { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 350190a22e5762..a3a86e3b222917 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -533,6 +533,11 @@ void emberAfTotalVolatileOrganicCompoundsConcentrationMeasurementClusterInitCall */ void emberAfRadonConcentrationMeasurementClusterInitCallback(chip::EndpointId endpoint); +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfWiFiNetworkManagementClusterInitCallback(chip::EndpointId endpoint); + /** * @param endpoint Endpoint that is being initialized */ @@ -4488,6 +4493,44 @@ chip::Protocols::InteractionModel::Status MatterRadonConcentrationMeasurementClu */ void emberAfRadonConcentrationMeasurementClusterServerTickCallback(chip::EndpointId endpoint); +// +// Wi-Fi Network Management Cluster +// + +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfWiFiNetworkManagementClusterServerInitCallback(chip::EndpointId endpoint); + +/** + * @param endpoint Endpoint that is being shutdown + */ +void MatterWiFiNetworkManagementClusterServerShutdownCallback(chip::EndpointId endpoint); + +/** + * @param endpoint Endpoint that is being initialized + */ +void emberAfWiFiNetworkManagementClusterClientInitCallback(chip::EndpointId endpoint); + +/** + * @param attributePath Concrete attribute path that changed + */ +void MatterWiFiNetworkManagementClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath); + +/** + * @param attributePath Concrete attribute path to be changed + * @param attributeType Attribute type + * @param size Attribute size + * @param value Attribute value + */ +chip::Protocols::InteractionModel::Status MatterWiFiNetworkManagementClusterServerPreAttributeChangedCallback( + const chip::app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value); + +/** + * @param endpoint Endpoint that is being served + */ +void emberAfWiFiNetworkManagementClusterServerTickCallback(chip::EndpointId endpoint); + // // Wake on LAN Cluster // diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index 42a54b95ee944f..bad7df9b4b8fa8 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -4309,6 +4309,8 @@ enum class Feature : uint32_t }; } // namespace RadonConcentrationMeasurement +namespace WiFiNetworkManagement {} // namespace WiFiNetworkManagement + namespace WakeOnLan {} // namespace WakeOnLan namespace Channel { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 32b62631ed30fd..3e72137d33179a 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -22865,6 +22865,93 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre namespace Events {} // namespace Events } // namespace RadonConcentrationMeasurement +namespace WiFiNetworkManagement { + +namespace Commands { +namespace NetworkPassphraseRequest { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + } +} +} // namespace NetworkPassphraseRequest. +namespace NetworkPassphraseResponse { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kPassphrase), passphrase); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kPassphrase)) + { + err = DataModel::Decode(reader, passphrase); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace NetworkPassphraseResponse. +} // namespace Commands + +namespace Attributes { +CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path) +{ + switch (path.mAttributeId) + { + case Attributes::Ssid::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, ssid); + case Attributes::GeneratedCommandList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, generatedCommandList); + case Attributes::AcceptedCommandList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, acceptedCommandList); + case Attributes::EventList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, eventList); + case Attributes::AttributeList::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, attributeList); + case Attributes::FeatureMap::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, featureMap); + case Attributes::ClusterRevision::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, clusterRevision); + default: + return CHIP_NO_ERROR; + } +} +} // namespace Attributes + +namespace Events {} // namespace Events + +} // namespace WiFiNetworkManagement namespace WakeOnLan { namespace Commands {} // namespace Commands @@ -30345,6 +30432,13 @@ bool CommandIsFabricScoped(ClusterId aCluster, CommandId aCommand) return false; } } + case Clusters::WiFiNetworkManagement::Id: { + switch (aCommand) + { + default: + return false; + } + } case Clusters::Channel::Id: { switch (aCommand) { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 89c36f3c6f147d..9dbcdfe8dcad68 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -34846,6 +34846,157 @@ struct TypeInfo }; } // namespace Attributes } // namespace RadonConcentrationMeasurement +namespace WiFiNetworkManagement { + +namespace Commands { +// Forward-declarations so we can reference these later. + +namespace NetworkPassphraseRequest { +struct Type; +struct DecodableType; +} // namespace NetworkPassphraseRequest + +namespace NetworkPassphraseResponse { +struct Type; +struct DecodableType; +} // namespace NetworkPassphraseResponse + +} // namespace Commands + +namespace Commands { +namespace NetworkPassphraseRequest { +enum class Fields : uint8_t +{ +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::NetworkPassphraseRequest::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::NetworkPassphraseRequest::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } + + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace NetworkPassphraseRequest +namespace NetworkPassphraseResponse { +enum class Fields : uint8_t +{ + kPassphrase = 0, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::NetworkPassphraseResponse::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } + + chip::ByteSpan passphrase; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = DataModel::NullObjectType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::NetworkPassphraseResponse::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } + + chip::ByteSpan passphrase; + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace NetworkPassphraseResponse +} // namespace Commands + +namespace Attributes { + +namespace Ssid { +struct TypeInfo +{ + using Type = chip::app::DataModel::Nullable; + using DecodableType = chip::app::DataModel::Nullable; + using DecodableArgType = const chip::app::DataModel::Nullable &; + + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::Ssid::Id; } + static constexpr bool MustUseTimedWrite() { return false; } + static constexpr size_t MaxLength() { return 32; } +}; +} // namespace Ssid +namespace GeneratedCommandList { +struct TypeInfo : public Clusters::Globals::Attributes::GeneratedCommandList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } +}; +} // namespace GeneratedCommandList +namespace AcceptedCommandList { +struct TypeInfo : public Clusters::Globals::Attributes::AcceptedCommandList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } +}; +} // namespace AcceptedCommandList +namespace EventList { +struct TypeInfo : public Clusters::Globals::Attributes::EventList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } +}; +} // namespace EventList +namespace AttributeList { +struct TypeInfo : public Clusters::Globals::Attributes::AttributeList::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } +}; +} // namespace AttributeList +namespace FeatureMap { +struct TypeInfo : public Clusters::Globals::Attributes::FeatureMap::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } +}; +} // namespace FeatureMap +namespace ClusterRevision { +struct TypeInfo : public Clusters::Globals::Attributes::ClusterRevision::TypeInfo +{ + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } +}; +} // namespace ClusterRevision + +struct TypeInfo +{ + struct DecodableType + { + static constexpr ClusterId GetClusterId() { return Clusters::WiFiNetworkManagement::Id; } + + CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path); + + Attributes::Ssid::TypeInfo::DecodableType ssid; + Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; + Attributes::AcceptedCommandList::TypeInfo::DecodableType acceptedCommandList; + Attributes::EventList::TypeInfo::DecodableType eventList; + Attributes::AttributeList::TypeInfo::DecodableType attributeList; + Attributes::FeatureMap::TypeInfo::DecodableType featureMap = static_cast(0); + Attributes::ClusterRevision::TypeInfo::DecodableType clusterRevision = static_cast(0); + }; +}; +} // namespace Attributes +} // namespace WiFiNetworkManagement namespace WakeOnLan { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index 8ff6313abe5940..b67160ef01706d 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -6583,6 +6583,40 @@ static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; } // namespace Attributes } // namespace RadonConcentrationMeasurement +namespace WiFiNetworkManagement { +namespace Attributes { + +namespace Ssid { +static constexpr AttributeId Id = 0x00000001; +} // namespace Ssid + +namespace GeneratedCommandList { +static constexpr AttributeId Id = Globals::Attributes::GeneratedCommandList::Id; +} // namespace GeneratedCommandList + +namespace AcceptedCommandList { +static constexpr AttributeId Id = Globals::Attributes::AcceptedCommandList::Id; +} // namespace AcceptedCommandList + +namespace EventList { +static constexpr AttributeId Id = Globals::Attributes::EventList::Id; +} // namespace EventList + +namespace AttributeList { +static constexpr AttributeId Id = Globals::Attributes::AttributeList::Id; +} // namespace AttributeList + +namespace FeatureMap { +static constexpr AttributeId Id = Globals::Attributes::FeatureMap::Id; +} // namespace FeatureMap + +namespace ClusterRevision { +static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; +} // namespace ClusterRevision + +} // namespace Attributes +} // namespace WiFiNetworkManagement + namespace WakeOnLan { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h index f457887220abad..1f790f889726f2 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h @@ -325,6 +325,9 @@ static constexpr ClusterId Id = 0x0000042E; namespace RadonConcentrationMeasurement { static constexpr ClusterId Id = 0x0000042F; } // namespace RadonConcentrationMeasurement +namespace WiFiNetworkManagement { +static constexpr ClusterId Id = 0x00000451; +} // namespace WiFiNetworkManagement namespace WakeOnLan { static constexpr ClusterId Id = 0x00000503; } // namespace WakeOnLan diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index da8b04c98c1963..d7ba0b240864fb 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -1381,6 +1381,20 @@ static constexpr CommandId Id = 0x0000004C; } // namespace Commands } // namespace ColorControl +namespace WiFiNetworkManagement { +namespace Commands { + +namespace NetworkPassphraseRequest { +static constexpr CommandId Id = 0x00000000; +} // namespace NetworkPassphraseRequest + +namespace NetworkPassphraseResponse { +static constexpr CommandId Id = 0x00000001; +} // namespace NetworkPassphraseResponse + +} // namespace Commands +} // namespace WiFiNetworkManagement + namespace Channel { namespace Commands { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 8a3081edc0dc1b..012407529d1369 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -135,6 +135,7 @@ | Pm10ConcentrationMeasurement | 0x042D | | TotalVolatileOrganicCompoundsConcentrationMeasurement | 0x042E | | RadonConcentrationMeasurement | 0x042F | +| WiFiNetworkManagement | 0x0451 | | WakeOnLan | 0x0503 | | Channel | 0x0504 | | TargetNavigator | 0x0505 | @@ -11017,6 +11018,61 @@ class ColorControlStepColorTemperature : public ClusterCommand | Events: | | \*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*\ +| Cluster WiFiNetworkManagement | 0x0451 | +|------------------------------------------------------------------------------| +| Commands: | | +| * NetworkPassphraseRequest | 0x00 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * Ssid | 0x0001 | +| * GeneratedCommandList | 0xFFF8 | +| * AcceptedCommandList | 0xFFF9 | +| * EventList | 0xFFFA | +| * AttributeList | 0xFFFB | +| * FeatureMap | 0xFFFC | +| * ClusterRevision | 0xFFFD | +|------------------------------------------------------------------------------| +| Events: | | +\*----------------------------------------------------------------------------*/ + +/* + * Command NetworkPassphraseRequest + */ +class WiFiNetworkManagementNetworkPassphraseRequest : public ClusterCommand +{ +public: + WiFiNetworkManagementNetworkPassphraseRequest(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("network-passphrase-request", credsIssuerConfig) + { + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, + commandId, endpointIds.at(0)); + return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); + } + + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, + groupId); + + return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); + } + +private: + chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Type mRequest; +}; + /*----------------------------------------------------------------------------*\ | Cluster WakeOnLan | 0x0503 | |------------------------------------------------------------------------------| @@ -24507,6 +24563,62 @@ void registerClusterRadonConcentrationMeasurement(Commands & commands, Credentia commands.RegisterCluster(clusterName, clusterCommands); } +void registerClusterWiFiNetworkManagement(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) +{ + using namespace chip::app::Clusters::WiFiNetworkManagement; + + const char * clusterName = "WiFiNetworkManagement"; + + commands_list clusterCommands = { + // + // Commands + // + make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // + // + // Attributes + // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "ssid", Attributes::Ssid::Id, credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + make_unique>(Id, credsIssuerConfig), // + make_unique>>( + Id, "ssid", Attributes::Ssid::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "generated-command-list", Attributes::GeneratedCommandList::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>>( + Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "event-list", Attributes::EventList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "attribute-list", Attributes::AttributeList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>(Id, "feature-map", 0, UINT32_MAX, Attributes::FeatureMap::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>(Id, "cluster-revision", 0, UINT16_MAX, Attributes::ClusterRevision::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "ssid", Attributes::Ssid::Id, credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + // + // Events + // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + }; + + commands.RegisterCluster(clusterName, clusterCommands); +} void registerClusterWakeOnLan(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) { using namespace chip::app::Clusters::WakeOnLan; @@ -26861,6 +26973,7 @@ void registerClusters(Commands & commands, CredentialIssuerCommands * credsIssue registerClusterPm10ConcentrationMeasurement(commands, credsIssuerConfig); registerClusterTotalVolatileOrganicCompoundsConcentrationMeasurement(commands, credsIssuerConfig); registerClusterRadonConcentrationMeasurement(commands, credsIssuerConfig); + registerClusterWiFiNetworkManagement(commands, credsIssuerConfig); registerClusterWakeOnLan(commands, credsIssuerConfig); registerClusterChannel(commands, credsIssuerConfig); registerClusterTargetNavigator(commands, credsIssuerConfig); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index fde5089bab8a7c..0d31e0f6074c81 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -7719,6 +7719,14 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; } +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + ReturnErrorOnFailure(DataModelLogger::LogValue("passphrase", indent + 1, value.passphrase)); + DataModelLogger::LogString(indent, "}"); + return CHIP_NO_ERROR; +} CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const Channel::Commands::ChangeChannelResponse::DecodableType & value) { @@ -16089,6 +16097,47 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP } break; } + case WiFiNetworkManagement::Id: { + switch (path.mAttributeId) + { + case WiFiNetworkManagement::Attributes::Ssid::Id: { + chip::app::DataModel::Nullable value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("SSID", 1, value); + } + case WiFiNetworkManagement::Attributes::GeneratedCommandList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("GeneratedCommandList", 1, value); + } + case WiFiNetworkManagement::Attributes::AcceptedCommandList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AcceptedCommandList", 1, value); + } + case WiFiNetworkManagement::Attributes::EventList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("EventList", 1, value); + } + case WiFiNetworkManagement::Attributes::AttributeList::Id: { + chip::app::DataModel::DecodableList value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AttributeList", 1, value); + } + case WiFiNetworkManagement::Attributes::FeatureMap::Id: { + uint32_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("FeatureMap", 1, value); + } + case WiFiNetworkManagement::Attributes::ClusterRevision::Id: { + uint16_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("ClusterRevision", 1, value); + } + } + break; + } case WakeOnLan::Id: { switch (path.mAttributeId) { @@ -18438,6 +18487,17 @@ CHIP_ERROR DataModelLogger::LogCommand(const chip::app::ConcreteCommandPath & pa } break; } + case WiFiNetworkManagement::Id: { + switch (path.mCommandId) + { + case WiFiNetworkManagement::Commands::NetworkPassphraseResponse::Id: { + WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("NetworkPassphraseResponse", 1, value); + } + } + break; + } case Channel::Id: { switch (path.mCommandId) { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index 1c790b5e002039..ca39e2ae069060 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -735,6 +735,9 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::DoorLock::Commands::GetCredentialStatusResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::Thermostat::Commands::GetWeeklyScheduleResponse::DecodableType & value); +static CHIP_ERROR +LogValue(const char * label, size_t indent, + const chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::Channel::Commands::ChangeChannelResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index c3034217db9c05..59bdd11dcb1cb3 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -137,6 +137,7 @@ | Pm10ConcentrationMeasurement | 0x042D | | TotalVolatileOrganicCompoundsConcentrationMeasurement | 0x042E | | RadonConcentrationMeasurement | 0x042F | +| WiFiNetworkManagement | 0x0451 | | WakeOnLan | 0x0503 | | Channel | 0x0504 | | TargetNavigator | 0x0505 | @@ -143040,6 +143041,674 @@ class SubscribeAttributeRadonConcentrationMeasurementClusterRevision : public Su } }; +#if MTR_ENABLE_PROVISIONAL +/*----------------------------------------------------------------------------*\ +| Cluster WiFiNetworkManagement | 0x0451 | +|------------------------------------------------------------------------------| +| Commands: | | +| * NetworkPassphraseRequest | 0x00 | +|------------------------------------------------------------------------------| +| Attributes: | | +| * Ssid | 0x0001 | +| * GeneratedCommandList | 0xFFF8 | +| * AcceptedCommandList | 0xFFF9 | +| * EventList | 0xFFFA | +| * AttributeList | 0xFFFB | +| * FeatureMap | 0xFFFC | +| * ClusterRevision | 0xFFFD | +|------------------------------------------------------------------------------| +| Events: | | +\*----------------------------------------------------------------------------*/ + +#if MTR_ENABLE_PROVISIONAL +/* + * Command NetworkPassphraseRequest + */ +class WiFiNetworkManagementNetworkPassphraseRequest : public ClusterCommand { +public: + WiFiNetworkManagementNetworkPassphraseRequest() + : ClusterCommand("network-passphrase-request") + { + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseRequest::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRWiFiNetworkManagementClusterNetworkPassphraseRequestParams alloc] init]; + params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; + uint16_t repeatCount = mRepeatCount.ValueOr(1); + uint16_t __block responsesNeeded = repeatCount; + while (repeatCount--) { + [cluster networkPassphraseRequestWithParams:params completion: + ^(MTRWiFiNetworkManagementClusterNetworkPassphraseResponseParams * _Nullable values, NSError * _Nullable error) { + NSLog(@"Values: %@", values); + if (error == nil) { + constexpr chip::CommandId responseId = chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::Id; + RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); + } + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + constexpr chip::CommandId responseId = chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::Id; + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; + } + return CHIP_NO_ERROR; + } + +private: +}; + +#endif // MTR_ENABLE_PROVISIONAL + +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute Ssid + */ +class ReadWiFiNetworkManagementSsid : public ReadAttribute { +public: + ReadWiFiNetworkManagementSsid() + : ReadAttribute("ssid") + { + } + + ~ReadWiFiNetworkManagementSsid() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::Ssid::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeSSIDWithCompletion:^(NSData * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.SSID response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement SSID read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementSsid : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementSsid() + : SubscribeAttribute("ssid") + { + } + + ~SubscribeAttributeWiFiNetworkManagementSsid() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::Ssid::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeSSIDWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSData * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.SSID response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute GeneratedCommandList + */ +class ReadWiFiNetworkManagementGeneratedCommandList : public ReadAttribute { +public: + ReadWiFiNetworkManagementGeneratedCommandList() + : ReadAttribute("generated-command-list") + { + } + + ~ReadWiFiNetworkManagementGeneratedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::GeneratedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeGeneratedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.GeneratedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement GeneratedCommandList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementGeneratedCommandList : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementGeneratedCommandList() + : SubscribeAttribute("generated-command-list") + { + } + + ~SubscribeAttributeWiFiNetworkManagementGeneratedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::GeneratedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeGeneratedCommandListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.GeneratedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AcceptedCommandList + */ +class ReadWiFiNetworkManagementAcceptedCommandList : public ReadAttribute { +public: + ReadWiFiNetworkManagementAcceptedCommandList() + : ReadAttribute("accepted-command-list") + { + } + + ~ReadWiFiNetworkManagementAcceptedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::AcceptedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAcceptedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.AcceptedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement AcceptedCommandList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementAcceptedCommandList : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementAcceptedCommandList() + : SubscribeAttribute("accepted-command-list") + { + } + + ~SubscribeAttributeWiFiNetworkManagementAcceptedCommandList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::AcceptedCommandList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAcceptedCommandListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.AcceptedCommandList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute EventList + */ +class ReadWiFiNetworkManagementEventList : public ReadAttribute { +public: + ReadWiFiNetworkManagementEventList() + : ReadAttribute("event-list") + { + } + + ~ReadWiFiNetworkManagementEventList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::EventList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeEventListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.EventList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement EventList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementEventList : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementEventList() + : SubscribeAttribute("event-list") + { + } + + ~SubscribeAttributeWiFiNetworkManagementEventList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::EventList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeEventListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.EventList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AttributeList + */ +class ReadWiFiNetworkManagementAttributeList : public ReadAttribute { +public: + ReadWiFiNetworkManagementAttributeList() + : ReadAttribute("attribute-list") + { + } + + ~ReadWiFiNetworkManagementAttributeList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::AttributeList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAttributeListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.AttributeList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement AttributeList read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementAttributeList : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementAttributeList() + : SubscribeAttribute("attribute-list") + { + } + + ~SubscribeAttributeWiFiNetworkManagementAttributeList() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::AttributeList::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAttributeListWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.AttributeList response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute FeatureMap + */ +class ReadWiFiNetworkManagementFeatureMap : public ReadAttribute { +public: + ReadWiFiNetworkManagementFeatureMap() + : ReadAttribute("feature-map") + { + } + + ~ReadWiFiNetworkManagementFeatureMap() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::FeatureMap::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeFeatureMapWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.FeatureMap response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement FeatureMap read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementFeatureMap : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementFeatureMap() + : SubscribeAttribute("feature-map") + { + } + + ~SubscribeAttributeWiFiNetworkManagementFeatureMap() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::FeatureMap::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeFeatureMapWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.FeatureMap response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute ClusterRevision + */ +class ReadWiFiNetworkManagementClusterRevision : public ReadAttribute { +public: + ReadWiFiNetworkManagementClusterRevision() + : ReadAttribute("cluster-revision") + { + } + + ~ReadWiFiNetworkManagementClusterRevision() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::ClusterRevision::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeClusterRevisionWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.ClusterRevision response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("WiFiNetworkManagement ClusterRevision read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeWiFiNetworkManagementClusterRevision : public SubscribeAttribute { +public: + SubscribeAttributeWiFiNetworkManagementClusterRevision() + : SubscribeAttribute("cluster-revision") + { + } + + ~SubscribeAttributeWiFiNetworkManagementClusterRevision() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::WiFiNetworkManagement::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::WiFiNetworkManagement::Attributes::ClusterRevision::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterWiFiNetworkManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeClusterRevisionWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"WiFiNetworkManagement.ClusterRevision response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#endif // MTR_ENABLE_PROVISIONAL /*----------------------------------------------------------------------------*\ | Cluster WakeOnLan | 0x0503 | |------------------------------------------------------------------------------| @@ -187891,6 +188560,54 @@ void registerClusterRadonConcentrationMeasurement(Commands & commands) commands.RegisterCluster(clusterName, clusterCommands); } +void registerClusterWiFiNetworkManagement(Commands & commands) +{ +#if MTR_ENABLE_PROVISIONAL + using namespace chip::app::Clusters::WiFiNetworkManagement; + + const char * clusterName = "WiFiNetworkManagement"; + + commands_list clusterCommands = { + make_unique(Id), // +#if MTR_ENABLE_PROVISIONAL + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL + make_unique(Id), // + make_unique(Id), // + make_unique(Id), // +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL + }; + + commands.RegisterCluster(clusterName, clusterCommands); +#endif // MTR_ENABLE_PROVISIONAL +} void registerClusterWakeOnLan(Commands & commands) { using namespace chip::app::Clusters::WakeOnLan; @@ -189301,6 +190018,7 @@ void registerClusters(Commands & commands) registerClusterPm10ConcentrationMeasurement(commands); registerClusterTotalVolatileOrganicCompoundsConcentrationMeasurement(commands); registerClusterRadonConcentrationMeasurement(commands); + registerClusterWiFiNetworkManagement(commands); registerClusterWakeOnLan(commands); registerClusterChannel(commands); registerClusterTargetNavigator(commands);