Skip to content

Commit c36485a

Browse files
committed
Add function to dump cluster IDs for documentation
1 parent f7db85e commit c36485a

File tree

2 files changed

+175
-10
lines changed

2 files changed

+175
-10
lines changed

docs/cluster_ids.md

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Matter Cluster IDs
2+
This file was **AUTOMATICALLY** generated by `python scripts/generate_spec_xml.py`. DO NOT EDIT BY HAND!
3+
4+
| ID (Decimal) | ID (hex) | Name |
5+
|--------------|----------|----------------------------------------------------------|
6+
|3 |0x0003 |Identify |
7+
|4 |0x0004 |Groups |
8+
|6 |0x0006 |On/Off |
9+
|8 |0x0008 |Level Control |
10+
|28 |0x001C |Pulse Width Modulation |
11+
|29 |0x001D |Descriptor |
12+
|30 |0x001E |Binding |
13+
|31 |0x001F |AccessControl |
14+
|37 |0x0025 |Actions |
15+
|40 |0x0028 |Basic Information |
16+
|41 |0x0029 |OTA Software Update Provider |
17+
|42 |0x002A |OTA Software Update Requestor |
18+
|43 |0x002B |Localization Configuration |
19+
|44 |0x002C |Time Format Localization |
20+
|45 |0x002D |Unit Localization |
21+
|46 |0x002E |Power Source Configuration |
22+
|47 |0x002F |Power Source |
23+
|48 |0x0030 |General Commissioning |
24+
|49 |0x0031 |Network Commissioning |
25+
|50 |0x0032 |Diagnostic Logs |
26+
|51 |0x0033 |General Diagnostics |
27+
|52 |0x0034 |Software Diagnostics |
28+
|53 |0x0035 |Thread Network Diagnostics |
29+
|54 |0x0036 |Wi |
30+
|55 |0x0037 |Ethernet Network Diagnostics |
31+
|56 |0x0038 |Time Synchronization |
32+
|57 |0x0039 |Bridged Device Basic Information |
33+
|59 |0x003B |Switch |
34+
|60 |0x003C |Administrator Commissioning |
35+
|62 |0x003E |Operational Credentials |
36+
|63 |0x003F |GroupKeyManagement |
37+
|64 |0x0040 |Fixed Label |
38+
|65 |0x0041 |User Label |
39+
|69 |0x0045 |Boolean State |
40+
|70 |0x0046 |ICDManagement |
41+
|72 |0x0048 |Oven Cavity Operational State |
42+
|73 |0x0049 |Oven Mode |
43+
|74 |0x004A |Laundry Dryer Controls |
44+
|80 |0x0050 |Mode Select |
45+
|81 |0x0051 |Laundry Washer Mode |
46+
|82 |0x0052 |Refrigerator And Temperature Controlled Cabinet Mode |
47+
|83 |0x0053 |Laundry Washer Controls |
48+
|84 |0x0054 |RVC Run Mode |
49+
|85 |0x0055 |RVC Clean Mode |
50+
|86 |0x0056 |Temperature Control |
51+
|87 |0x0057 |Refrigerator Alarm |
52+
|89 |0x0059 |Dishwasher Mode |
53+
|91 |0x005B |Air Quality |
54+
|92 |0x005C |Smoke CO Alarm |
55+
|93 |0x005D |Dishwasher Alarm |
56+
|94 |0x005E |Microwave Oven Mode |
57+
|95 |0x005F |Microwave Oven Control |
58+
|96 |0x0060 |Operational State |
59+
|97 |0x0061 |RVC Operational State |
60+
|98 |0x0062 |Scenes Management |
61+
|113 |0x0071 |HEPA Filter Monitoring |
62+
|114 |0x0072 |Activated Carbon Filter Monitoring |
63+
|128 |0x0080 |Boolean State Configuration |
64+
|129 |0x0081 |Valve Configuration and Control |
65+
|144 |0x0090 |Electrical Power Measurement |
66+
|145 |0x0091 |Electrical Energy Measurement |
67+
|148 |0x0094 |Water Heater Management |
68+
|149 |0x0095 |Energy Price |
69+
|150 |0x0096 |Demand Response and Load Control |
70+
|151 |0x0097 |Messages |
71+
|152 |0x0098 |Device Energy Management |
72+
|153 |0x0099 |Energy EVSE |
73+
|154 |0x009A |Energy Calendar |
74+
|155 |0x009B |Energy Preference |
75+
|156 |0x009C |Power Topology |
76+
|157 |0x009D |Energy EVSE Mode |
77+
|158 |0x009E |Water Heater Mode |
78+
|159 |0x009F |Device Energy Management Mode |
79+
|257 |0x0101 |Door Lock |
80+
|258 |0x0102 |Window Covering |
81+
|512 |0x0200 |Pump Configuration and Control |
82+
|513 |0x0201 |Thermostat |
83+
|514 |0x0202 |Fan Control |
84+
|516 |0x0204 |Thermostat User Interface Configuration |
85+
|768 |0x0300 |Color Control |
86+
|769 |0x0301 |Ballast Configuration |
87+
|1024 |0x0400 |Illuminance Measurement |
88+
|1026 |0x0402 |Temperature Measurement |
89+
|1027 |0x0403 |Pressure Measurement |
90+
|1028 |0x0404 |Flow Measurement |
91+
|1029 |0x0405 |Relative Humidity Measurement |
92+
|1030 |0x0406 |Occupancy Sensing |
93+
|1036 |0x040C |Carbon Monoxide Concentration Measurement |
94+
|1037 |0x040D |Carbon Dioxide Concentration Measurement |
95+
|1043 |0x0413 |Nitrogen Dioxide Concentration Measurement |
96+
|1045 |0x0415 |Ozone Concentration Measurement |
97+
|1066 |0x042A |PM2 |
98+
|1067 |0x042B |Formaldehyde Concentration Measurement |
99+
|1068 |0x042C |PM1 Concentration Measurement |
100+
|1069 |0x042D |PM10 Concentration Measurement |
101+
|1070 |0x042E |Total Volatile Organic Compounds Concentration Measurement|
102+
|1071 |0x042F |Radon Concentration Measurement |
103+
|1104 |0x0450 |Network Identity Management |
104+
|1105 |0x0451 |Wi |
105+
|1283 |0x0503 |Wake on LAN |
106+
|1284 |0x0504 |Channel |
107+
|1285 |0x0505 |Target Navigator |
108+
|1286 |0x0506 |Media Playback |
109+
|1287 |0x0507 |Media Input |
110+
|1288 |0x0508 |Low Power |
111+
|1289 |0x0509 |Keypad Input |
112+
|1290 |0x050A |Content Launcher |
113+
|1291 |0x050B |Audio Output |
114+
|1292 |0x050C |Application Launcher |
115+
|1293 |0x050D |Application Basic |
116+
|1294 |0x050E |Account Login |
117+
|1295 |0x050F |Content Control |
118+
|1296 |0x0510 |Content App Observer |

scripts/spec_xml/generate_spec_xml.py

+57-10
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,16 @@
1818
import os
1919
import re
2020
import subprocess
21+
import sys
2122

2223
import click
2324

24-
DEFAULT_CHIP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
25-
DEFAULT_OUTPUT_DIR = os.path.abspath(os.path.join(DEFAULT_CHIP_ROOT, 'data_model'))
25+
DEFAULT_CHIP_ROOT = os.path.abspath(
26+
os.path.join(os.path.dirname(__file__), '..', '..'))
27+
DEFAULT_OUTPUT_DIR = os.path.abspath(
28+
os.path.join(DEFAULT_CHIP_ROOT, 'data_model'))
29+
DEFAULT_DOCUMENTATION_DIR = os.path.abspath(
30+
os.path.join(DEFAULT_CHIP_ROOT, 'docs', 'cluster_ids.md'))
2631

2732

2833
def get_xml_path(filename, output_dir):
@@ -56,14 +61,17 @@ def main(scraper, spec_root, output_dir, dry_run):
5661
scrape_device_types(scraper, spec_root, output_dir, dry_run)
5762
if not dry_run:
5863
dump_versions(scraper, spec_root, output_dir)
64+
dump_cluster_ids(output_dir)
5965

6066

6167
def scrape_clusters(scraper, spec_root, output_dir, dry_run):
6268
src_dir = os.path.abspath(os.path.join(spec_root, 'src'))
63-
sdm_clusters_dir = os.path.abspath(os.path.join(src_dir, 'service_device_management'))
69+
sdm_clusters_dir = os.path.abspath(
70+
os.path.join(src_dir, 'service_device_management'))
6471
app_clusters_dir = os.path.abspath(os.path.join(src_dir, 'app_clusters'))
6572
dm_clusters_dir = os.path.abspath(os.path.join(src_dir, 'data_model'))
66-
media_clusters_dir = os.path.abspath(os.path.join(app_clusters_dir, 'media'))
73+
media_clusters_dir = os.path.abspath(
74+
os.path.join(app_clusters_dir, 'media'))
6775
clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters'))
6876
dm_clusters_list = ['ACL-Cluster.adoc', 'Binding-Cluster.adoc', 'bridge-clusters.adoc',
6977
'Descriptor-Cluster.adoc', 'Group-Key-Management-Cluster.adoc', 'ICDManagement.adoc',
@@ -79,7 +87,8 @@ def scrape_clusters(scraper, spec_root, output_dir, dry_run):
7987

8088
def scrape_cluster(filename: str) -> None:
8189
xml_path = get_xml_path(filename, clusters_output_dir)
82-
cmd = [scraper, 'cluster', '-i', filename, '-o', xml_path, '-nd', '--define', 'in-progress']
90+
cmd = [scraper, 'cluster', '-i', filename, '-o',
91+
xml_path, '-nd', '--define', 'in-progress']
8392
if dry_run:
8493
print(cmd)
8594
else:
@@ -100,16 +109,19 @@ def scrape_all_clusters(dir: str, exclude_list: list[str] = []) -> None:
100109

101110

102111
def scrape_device_types(scraper, spec_root, output_dir, dry_run):
103-
device_type_dir = os.path.abspath(os.path.join(spec_root, 'src', 'device_types'))
104-
device_types_output_dir = os.path.abspath(os.path.join(output_dir, 'device_types'))
112+
device_type_dir = os.path.abspath(
113+
os.path.join(spec_root, 'src', 'device_types'))
114+
device_types_output_dir = os.path.abspath(
115+
os.path.join(output_dir, 'device_types'))
105116
clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters'))
106117

107118
if not os.path.exists(device_types_output_dir):
108119
os.makedirs(device_types_output_dir)
109120

110121
def scrape_device_type(filename: str) -> None:
111122
xml_path = get_xml_path(filename, device_types_output_dir)
112-
cmd = [scraper, 'devicetype', '-c', clusters_output_dir, '-nd', '-i', filename, '-o', xml_path]
123+
cmd = [scraper, 'devicetype', '-c', clusters_output_dir,
124+
'-nd', '-i', filename, '-o', xml_path]
113125
if dry_run:
114126
print(cmd)
115127
else:
@@ -125,17 +137,52 @@ def scrape_device_type(filename: str) -> None:
125137

126138
def dump_versions(scraper, spec_root, output_dir):
127139
sha_file = os.path.abspath(os.path.join(output_dir, 'spec_sha'))
128-
out = subprocess.run(['git', 'rev-parse', 'HEAD'], capture_output=True, encoding="utf8", cwd=spec_root)
140+
out = subprocess.run(['git', 'rev-parse', 'HEAD'],
141+
capture_output=True, encoding="utf8", cwd=spec_root)
129142
sha = out.stdout
130143
with open(sha_file, 'wt', encoding='utf8') as output:
131144
output.write(sha)
132145

133146
scraper_file = os.path.abspath(os.path.join(output_dir, 'scraper_version'))
134-
out = subprocess.run([scraper, '--version'], capture_output=True, encoding="utf8")
147+
out = subprocess.run([scraper, '--version'],
148+
capture_output=True, encoding="utf8")
135149
version = out.stdout
136150
with open(scraper_file, "wt", encoding='utf8') as output:
137151
output.write(version)
138152

139153

154+
def dump_cluster_ids(output_dir):
155+
python_testing_path = os.path.abspath(
156+
os.path.join(DEFAULT_CHIP_ROOT, 'src', 'python_testing'))
157+
sys.path.insert(0, python_testing_path)
158+
clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters'))
159+
device_types_output_dir = os.path.abspath(
160+
os.path.join(output_dir, 'device_types'))
161+
162+
from spec_parsing_support import build_xml_clusters
163+
164+
header = '# Matter Cluster IDs\n'
165+
header += 'This file was **AUTOMATICALLY** generated by `python scripts/generate_spec_xml.py`. DO NOT EDIT BY HAND!\n\n'
166+
167+
clusters, problems = build_xml_clusters()
168+
all_name_lens = [len(c.name) for c in clusters.values()]
169+
name_len = max(all_name_lens)
170+
title_id_decimal = ' ID (Decimal) '
171+
title_id_hex = ' ID (hex) '
172+
title_name_raw = ' Name '
173+
title_name = f'{title_name_raw:<{name_len}}'
174+
dec_len = len(title_id_decimal)
175+
hex_len = len(title_id_hex)
176+
title = f'|{title_id_decimal}|{title_id_hex}|{title_name}|\n'
177+
hashes = f'|{"-" * dec_len}|{"-" * hex_len}|{"-" * name_len}|\n'
178+
s = title + hashes
179+
for id, cluster in sorted(clusters.items()):
180+
hex_id = f'0x{id:04X}'
181+
s += f'|{id:<{dec_len}}|{hex_id:<{hex_len}}|{cluster.name:<{name_len}}|\n'
182+
with open(DEFAULT_DOCUMENTATION_DIR, 'w') as fout:
183+
fout.write(header)
184+
fout.write(s)
185+
186+
140187
if __name__ == '__main__':
141188
main()

0 commit comments

Comments
 (0)