Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM XMLs: Add function to dump cluster IDs for documentation #32761

Merged
merged 10 commits into from
Apr 2, 2024
118 changes: 118 additions & 0 deletions docs/cluster_ids.md
Original file line number Diff line number Diff line change
@@ -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 |
67 changes: 57 additions & 10 deletions scripts/spec_xml/generate_spec_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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',
Expand All @@ -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:
Expand All @@ -100,16 +109,19 @@ 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):
os.makedirs(device_types_output_dir)

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:
Expand All @@ -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()
Loading