diff --git a/docs/cluster_ids.md b/docs/cluster_ids.md new file mode 100644 index 00000000000000..5becc78f9f0e8d --- /dev/null +++ b/docs/cluster_ids.md @@ -0,0 +1,118 @@ +# Matter Cluster IDs +This file was **AUTOMATICALLY** generated by `python scripts/generate_spec_xml.py`. DO NOT EDIT BY HAND! + +| ID (Decimal) | ID (hex) | Name | +|--------------|----------|----------------------------------------------------------| +|3 |0x0003 |Identify | +|4 |0x0004 |Groups | +|6 |0x0006 |On/Off | +|8 |0x0008 |Level Control | +|28 |0x001C |Pulse Width Modulation | +|29 |0x001D |Descriptor | +|30 |0x001E |Binding | +|31 |0x001F |AccessControl | +|37 |0x0025 |Actions | +|40 |0x0028 |Basic Information | +|41 |0x0029 |OTA Software Update Provider | +|42 |0x002A |OTA Software Update Requestor | +|43 |0x002B |Localization Configuration | +|44 |0x002C |Time Format Localization | +|45 |0x002D |Unit Localization | +|46 |0x002E |Power Source Configuration | +|47 |0x002F |Power Source | +|48 |0x0030 |General Commissioning | +|49 |0x0031 |Network Commissioning | +|50 |0x0032 |Diagnostic Logs | +|51 |0x0033 |General Diagnostics | +|52 |0x0034 |Software Diagnostics | +|53 |0x0035 |Thread Network Diagnostics | +|54 |0x0036 |Wi | +|55 |0x0037 |Ethernet Network Diagnostics | +|56 |0x0038 |Time Synchronization | +|57 |0x0039 |Bridged Device Basic Information | +|59 |0x003B |Switch | +|60 |0x003C |Administrator Commissioning | +|62 |0x003E |Operational Credentials | +|63 |0x003F |GroupKeyManagement | +|64 |0x0040 |Fixed Label | +|65 |0x0041 |User Label | +|69 |0x0045 |Boolean State | +|70 |0x0046 |ICDManagement | +|72 |0x0048 |Oven Cavity Operational State | +|73 |0x0049 |Oven Mode | +|74 |0x004A |Laundry Dryer Controls | +|80 |0x0050 |Mode Select | +|81 |0x0051 |Laundry Washer Mode | +|82 |0x0052 |Refrigerator And Temperature Controlled Cabinet Mode | +|83 |0x0053 |Laundry Washer Controls | +|84 |0x0054 |RVC Run Mode | +|85 |0x0055 |RVC Clean Mode | +|86 |0x0056 |Temperature Control | +|87 |0x0057 |Refrigerator Alarm | +|89 |0x0059 |Dishwasher Mode | +|91 |0x005B |Air Quality | +|92 |0x005C |Smoke CO Alarm | +|93 |0x005D |Dishwasher Alarm | +|94 |0x005E |Microwave Oven Mode | +|95 |0x005F |Microwave Oven Control | +|96 |0x0060 |Operational State | +|97 |0x0061 |RVC Operational State | +|98 |0x0062 |Scenes Management | +|113 |0x0071 |HEPA Filter Monitoring | +|114 |0x0072 |Activated Carbon Filter Monitoring | +|128 |0x0080 |Boolean State Configuration | +|129 |0x0081 |Valve Configuration and Control | +|144 |0x0090 |Electrical Power Measurement | +|145 |0x0091 |Electrical Energy Measurement | +|148 |0x0094 |Water Heater Management | +|149 |0x0095 |Energy Price | +|150 |0x0096 |Demand Response and Load Control | +|151 |0x0097 |Messages | +|152 |0x0098 |Device Energy Management | +|153 |0x0099 |Energy EVSE | +|154 |0x009A |Energy Calendar | +|155 |0x009B |Energy Preference | +|156 |0x009C |Power Topology | +|157 |0x009D |Energy EVSE Mode | +|158 |0x009E |Water Heater Mode | +|159 |0x009F |Device Energy Management Mode | +|257 |0x0101 |Door Lock | +|258 |0x0102 |Window Covering | +|512 |0x0200 |Pump Configuration and Control | +|513 |0x0201 |Thermostat | +|514 |0x0202 |Fan Control | +|516 |0x0204 |Thermostat User Interface Configuration | +|768 |0x0300 |Color Control | +|769 |0x0301 |Ballast Configuration | +|1024 |0x0400 |Illuminance Measurement | +|1026 |0x0402 |Temperature Measurement | +|1027 |0x0403 |Pressure Measurement | +|1028 |0x0404 |Flow Measurement | +|1029 |0x0405 |Relative Humidity Measurement | +|1030 |0x0406 |Occupancy Sensing | +|1036 |0x040C |Carbon Monoxide Concentration Measurement | +|1037 |0x040D |Carbon Dioxide Concentration Measurement | +|1043 |0x0413 |Nitrogen Dioxide Concentration Measurement | +|1045 |0x0415 |Ozone Concentration Measurement | +|1066 |0x042A |PM2 | +|1067 |0x042B |Formaldehyde Concentration Measurement | +|1068 |0x042C |PM1 Concentration Measurement | +|1069 |0x042D |PM10 Concentration Measurement | +|1070 |0x042E |Total Volatile Organic Compounds Concentration Measurement| +|1071 |0x042F |Radon Concentration Measurement | +|1104 |0x0450 |Network Identity Management | +|1105 |0x0451 |Wi | +|1283 |0x0503 |Wake on LAN | +|1284 |0x0504 |Channel | +|1285 |0x0505 |Target Navigator | +|1286 |0x0506 |Media Playback | +|1287 |0x0507 |Media Input | +|1288 |0x0508 |Low Power | +|1289 |0x0509 |Keypad Input | +|1290 |0x050A |Content Launcher | +|1291 |0x050B |Audio Output | +|1292 |0x050C |Application Launcher | +|1293 |0x050D |Application Basic | +|1294 |0x050E |Account Login | +|1295 |0x050F |Content Control | +|1296 |0x0510 |Content App Observer | diff --git a/scripts/spec_xml/generate_spec_xml.py b/scripts/spec_xml/generate_spec_xml.py index 016f92d4b5759a..70684b228aef17 100755 --- a/scripts/spec_xml/generate_spec_xml.py +++ b/scripts/spec_xml/generate_spec_xml.py @@ -18,11 +18,16 @@ import os import re import subprocess +import sys import click -DEFAULT_CHIP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) -DEFAULT_OUTPUT_DIR = os.path.abspath(os.path.join(DEFAULT_CHIP_ROOT, 'data_model')) +DEFAULT_CHIP_ROOT = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', '..')) +DEFAULT_OUTPUT_DIR = os.path.abspath( + os.path.join(DEFAULT_CHIP_ROOT, 'data_model')) +DEFAULT_DOCUMENTATION_DIR = os.path.abspath( + os.path.join(DEFAULT_CHIP_ROOT, 'docs', 'cluster_ids.md')) def get_xml_path(filename, output_dir): @@ -56,14 +61,17 @@ def main(scraper, spec_root, output_dir, dry_run): scrape_device_types(scraper, spec_root, output_dir, dry_run) if not dry_run: dump_versions(scraper, spec_root, output_dir) + dump_cluster_ids(output_dir) def scrape_clusters(scraper, spec_root, output_dir, dry_run): src_dir = os.path.abspath(os.path.join(spec_root, 'src')) - sdm_clusters_dir = os.path.abspath(os.path.join(src_dir, 'service_device_management')) + sdm_clusters_dir = os.path.abspath( + os.path.join(src_dir, 'service_device_management')) app_clusters_dir = os.path.abspath(os.path.join(src_dir, 'app_clusters')) dm_clusters_dir = os.path.abspath(os.path.join(src_dir, 'data_model')) - media_clusters_dir = os.path.abspath(os.path.join(app_clusters_dir, 'media')) + media_clusters_dir = os.path.abspath( + os.path.join(app_clusters_dir, 'media')) clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters')) dm_clusters_list = ['ACL-Cluster.adoc', 'Binding-Cluster.adoc', 'bridge-clusters.adoc', 'Descriptor-Cluster.adoc', 'Group-Key-Management-Cluster.adoc', 'ICDManagement.adoc', @@ -79,7 +87,8 @@ def scrape_clusters(scraper, spec_root, output_dir, dry_run): def scrape_cluster(filename: str) -> None: xml_path = get_xml_path(filename, clusters_output_dir) - cmd = [scraper, 'cluster', '-i', filename, '-o', xml_path, '-nd', '--define', 'in-progress'] + cmd = [scraper, 'cluster', '-i', filename, '-o', + xml_path, '-nd', '--define', 'in-progress'] if dry_run: print(cmd) else: @@ -100,8 +109,10 @@ def scrape_all_clusters(dir: str, exclude_list: list[str] = []) -> None: def scrape_device_types(scraper, spec_root, output_dir, dry_run): - device_type_dir = os.path.abspath(os.path.join(spec_root, 'src', 'device_types')) - device_types_output_dir = os.path.abspath(os.path.join(output_dir, 'device_types')) + device_type_dir = os.path.abspath( + os.path.join(spec_root, 'src', 'device_types')) + device_types_output_dir = os.path.abspath( + os.path.join(output_dir, 'device_types')) clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters')) if not os.path.exists(device_types_output_dir): @@ -109,7 +120,8 @@ def scrape_device_types(scraper, spec_root, output_dir, dry_run): def scrape_device_type(filename: str) -> None: xml_path = get_xml_path(filename, device_types_output_dir) - cmd = [scraper, 'devicetype', '-c', clusters_output_dir, '-nd', '-i', filename, '-o', xml_path] + cmd = [scraper, 'devicetype', '-c', clusters_output_dir, + '-nd', '-i', filename, '-o', xml_path] if dry_run: print(cmd) else: @@ -125,17 +137,52 @@ def scrape_device_type(filename: str) -> None: def dump_versions(scraper, spec_root, output_dir): sha_file = os.path.abspath(os.path.join(output_dir, 'spec_sha')) - out = subprocess.run(['git', 'rev-parse', 'HEAD'], capture_output=True, encoding="utf8", cwd=spec_root) + out = subprocess.run(['git', 'rev-parse', 'HEAD'], + capture_output=True, encoding="utf8", cwd=spec_root) sha = out.stdout with open(sha_file, 'wt', encoding='utf8') as output: output.write(sha) scraper_file = os.path.abspath(os.path.join(output_dir, 'scraper_version')) - out = subprocess.run([scraper, '--version'], capture_output=True, encoding="utf8") + out = subprocess.run([scraper, '--version'], + capture_output=True, encoding="utf8") version = out.stdout with open(scraper_file, "wt", encoding='utf8') as output: output.write(version) +def dump_cluster_ids(output_dir): + python_testing_path = os.path.abspath( + os.path.join(DEFAULT_CHIP_ROOT, 'src', 'python_testing')) + sys.path.insert(0, python_testing_path) + clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters')) + device_types_output_dir = os.path.abspath( + os.path.join(output_dir, 'device_types')) + + from spec_parsing_support import build_xml_clusters + + header = '# Matter Cluster IDs\n' + header += 'This file was **AUTOMATICALLY** generated by `python scripts/generate_spec_xml.py`. DO NOT EDIT BY HAND!\n\n' + + clusters, problems = build_xml_clusters() + all_name_lens = [len(c.name) for c in clusters.values()] + name_len = max(all_name_lens) + title_id_decimal = ' ID (Decimal) ' + title_id_hex = ' ID (hex) ' + title_name_raw = ' Name ' + title_name = f'{title_name_raw:<{name_len}}' + dec_len = len(title_id_decimal) + hex_len = len(title_id_hex) + title = f'|{title_id_decimal}|{title_id_hex}|{title_name}|\n' + hashes = f'|{"-" * dec_len}|{"-" * hex_len}|{"-" * name_len}|\n' + s = title + hashes + for id, cluster in sorted(clusters.items()): + hex_id = f'0x{id:04X}' + s += f'|{id:<{dec_len}}|{hex_id:<{hex_len}}|{cluster.name:<{name_len}}|\n' + with open(DEFAULT_DOCUMENTATION_DIR, 'w') as fout: + fout.write(header) + fout.write(s) + + if __name__ == '__main__': main()