esp-matter-mfg-tool 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ include requirements.txt
@@ -0,0 +1,50 @@
1
+ Metadata-Version: 2.1
2
+ Name: esp-matter-mfg-tool
3
+ Version: 1.0.0
4
+ Summary: A python utility which helps to generate matter manufacturing partitions
5
+ Home-page: https://github.com/espressif/esp-matter-tools/tree/main/mfg_tool
6
+ Author: Espressif Systems
7
+ Author-email:
8
+ License: Apache-2.0
9
+ Project-URL: Documentation, https://github.com/espressif/esp-matter-tools/tree/main/mfg_tool/README.md
10
+ Project-URL: Source, https://github.com/espressif/esp-matter-tools/tree/main/mfg_tool
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Operating System :: MacOS :: MacOS X
16
+ Classifier: Topic :: Software Development :: Embedded Systems
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/x-rst
22
+ Requires-Dist: bitarray>=2.6.0
23
+ Requires-Dist: cryptography==36.0.0
24
+ Requires-Dist: cffi==1.15.0
25
+ Requires-Dist: future==0.18.2
26
+ Requires-Dist: pycparser==2.21
27
+ Requires-Dist: pypng==0.0.21
28
+ Requires-Dist: PyQRCode==1.2.1
29
+ Requires-Dist: python_stdnum==1.18
30
+ Requires-Dist: esp-secure-cert-tool==1.0.1
31
+ Requires-Dist: ecdsa==0.18.0
32
+
33
+
34
+ ====================
35
+ esp-matter-mfg-tool
36
+ ====================
37
+ The python utility helps to generate the matter manufacturing partitions.
38
+
39
+ Source code for `esp-matter-mfg-tool` is
40
+ `hosted on github <https://github.com/espressif/esp-matter-tools/tree/main/mfg_tool>`_.
41
+
42
+ Documentation
43
+ -------------
44
+ Visit online `esp-matter-mfg-tool documentation <https://github.com/espressif/esp-matter-tools/tree/main/mfg_tool>`_
45
+ or run ``esp-matter-mfg-tool -h``.
46
+
47
+ License
48
+ -------
49
+ The License for the project can be found
50
+ `here <https://github.com/espressif/esp-matter-tools/tree/main/LICENSE>`_
@@ -0,0 +1,251 @@
1
+ # Matter Manufacturing Partitions Generator Utility
2
+
3
+ esp-matter-mfg-tool helps generate the Matter compatible manufacturing and
4
+ secure certificate partitions.
5
+
6
+ Manufacturing partition can contain the Matter specific data as well as it
7
+ supports adding custom manufacturer specific data using csv files.
8
+
9
+ ## How to install
10
+
11
+ ### Install using pip
12
+
13
+ esp-matter-mfg-tool can be installed using package installer for Python
14
+
15
+ ```
16
+ python3 -m pip install esp-matter-mfg-tool
17
+ ```
18
+
19
+ ### Optional dependency
20
+
21
+ If you want to use the esp-matter-mfg-tool for signing DAC by providing PAI or PAA certificate and key, then chip-cert is required.
22
+
23
+ [CHIP Certificate Tool](https://github.com/project-chip/connectedhomeip/tree/master/src/tools/chip-cert), *chip-cert*,
24
+ provides command line interface (CLI) utility used for generating and manipulating CHIP certificates and CHIP private keys.
25
+
26
+ If you have already setup the esp-matter and ran `install.sh` and sourced `export.sh` then you can skip building and adding tools to path steps.
27
+
28
+ #### Build chip-cert
29
+ ```
30
+ cd $ESP_MATTER_PATH/connectedhomeip/connectedhomeip
31
+ source scripts/activate.sh
32
+ gn gen out/host
33
+ ninja -C out/host chip-cert
34
+ ```
35
+ Above commands will generate chip-cert at `esp-matter/connectedhomeip/connectedhomeip/out/host`.
36
+
37
+ #### Add the tools path to $PATH
38
+ ```
39
+ export PATH="$PATH:$ESP_MATTER_PATH/connectedhomeip/connectedhomeip/out/host"
40
+ ```
41
+
42
+ ## Configure your app
43
+ Open the project configuration menu using -
44
+
45
+ ```
46
+ cd <your_app>
47
+ idf.py menuconfig
48
+ ```
49
+ In the configuration menu, set the following additional configuration to use custom factory partition and different values for Data and Device Info Providers.
50
+
51
+ 1. Enable `ESP32 Factory Data Provider` [Component config → CHIP Device Layer → Commissioning options → Use ESP32 Factory Data Provider]
52
+
53
+ Enable config option [`CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER`](https://github.com/project-chip/connectedhomeip/blob/master/config/esp32/components/chip/Kconfig#L645)
54
+ to use ESP32 specific implementation of CommissionableDataProvider and DeviceAttestationCredentialsProvider.
55
+
56
+ 2. Enable `ESP32 Device Instance Info Provider` [Component config → CHIP Device Layer → Commissioning options → Use ESP32 Device Instance Info Provider]
57
+
58
+ Enable config option [`ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER`](https://github.com/project-chip/connectedhomeip/blob/master/config/esp32/components/chip/Kconfig#L655)
59
+ to get device instance info from factory partition.
60
+
61
+ 3. Enable `Attestation - Factory` [ Component config → ESP Matter → DAC Provider options → Attestation - Factory]
62
+
63
+ Enable config option `CONFIG_FACTORY_PARTITION_DAC_PROVIDER` to use DAC certificates from the factory partition during Attestation.
64
+
65
+ 4. Set `chip-factory namespace partition label` [Component config → CHIP Device Layer → Matter Manufacturing Options → chip-factory namespace partition label]
66
+
67
+ Set config option [`CHIP_FACTORY_NAMESPACE_PARTITION_LABEL`](https://github.com/project-chip/connectedhomeip/blob/master/config/esp32/components/chip/Kconfig#L856)
68
+ to choose the label of the partition to store key-values in the "chip-factory" namespace. The default chosen partition label is `nvs`.
69
+
70
+ ## Output files and directory structure
71
+ ```
72
+ out
73
+ └── fff1_8000
74
+ ├── 11fe2c53-9a38-445c-b58f-2ff0554cd981
75
+ │   ├── 11fe2c53-9a38-445c-b58f-2ff0554cd981-onb_codes.csv
76
+ │   ├── 11fe2c53-9a38-445c-b58f-2ff0554cd981-partition.bin
77
+ │   ├── 11fe2c53-9a38-445c-b58f-2ff0554cd981-qrcode.png
78
+ │   └── internal
79
+ │   ├── DAC_cert.der
80
+ │   ├── DAC_cert.pem
81
+ │   ├── DAC_key.pem
82
+ │   ├── DAC_private_key.bin
83
+ │   ├── DAC_public_key.bin
84
+ │   ├── PAI_cert.der
85
+ │   └── partition.csv
86
+ ├── 14874525-30b5-4c66-a00e-30e4af5dfb20
87
+ │   ├── 14874525-30b5-4c66-a00e-30e4af5dfb20-onb_codes.csv
88
+ │   ├── 14874525-30b5-4c66-a00e-30e4af5dfb20-partition.bin
89
+ │   ├── 14874525-30b5-4c66-a00e-30e4af5dfb20-qrcode.png
90
+ │   └── internal
91
+ │   ├── DAC_cert.der
92
+ │   ├── DAC_cert.pem
93
+ │   ├── DAC_key.pem
94
+ │   ├── DAC_private_key.bin
95
+ │   ├── DAC_public_key.bin
96
+ │   ├── PAI_cert.der
97
+ │   └── partition.csv
98
+ └── staging
99
+ ├── config.csv
100
+ ├── master.csv
101
+ ├── pai_cert.der
102
+ └── pin_disc.csv
103
+ ```
104
+
105
+ Tool generates following output files:
106
+ - Partition Binary : `<uuid>-partition.bin`
107
+ - Onboarding codes : `<uuid>-onb_codes.csv`
108
+ - QR Code image : `<uuid>-qrcode.png`
109
+
110
+ Other intermediate files are stored in `internal/` directory:
111
+ - Partition CSV : `partition.csv`
112
+ - PAI Certificate : `PAI_cert.der`
113
+ - DAC Certificates : `DAC_cert.der`, `DAC_cert.pem`
114
+ - DAC Private Key : `DAC_private_key.bin`
115
+ - DAC Public Key : `DAC_public_key.bin`
116
+
117
+ Above files are stored at `out/<vid_pid>/<UUID>`. Each device is identified with an unique UUID.
118
+
119
+ Common intermediate files are stored at `out/<vid_pid>/staging`.
120
+
121
+ ## Usage examples
122
+ `esp-matter-mfg-tool -h` lists the options.
123
+
124
+ Below commands uses the test PAI signing certificate and key, test certificate declaration present in Matter SDK, Vendor ID: 0xFFF2, and Product ID: 0x8001.
125
+
126
+ Export the Matter SDK path to simplify the certificate and key paths.
127
+ ```
128
+ export MATTER_SDK_PATH=$ESP_MATTER_PATH/connectedhomeip/connectedhomeip
129
+ ```
130
+
131
+ ### Generate a factory partition
132
+ ```
133
+ esp-matter-mfg-tool -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
134
+ -k $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
135
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
136
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der
137
+ ```
138
+
139
+ #### Generate a factory partition and store DAC certificate and private key in secure cert partition [Optional argument : `--dac-in-secure-cert` and `--target`]
140
+ ```
141
+ esp-matter-mfg-tool -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
142
+ -k $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
143
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
144
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der \
145
+ --dac-in-secure-cert --target esp32
146
+ ```
147
+ *NOTE*: By default, DAC certificates and private key is stored in the NVS factory partition.
148
+
149
+ #### Generate a factory partition and store DAC certificate and private key in secure cert partition using DS Peripheral
150
+ ```
151
+ esp-matter-mfg-tool -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
152
+ -k $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
153
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
154
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der
155
+ --dac-in-secure-cert --ds-peripheral --target esp32h2 --efuse-key-id 1
156
+ ```
157
+ *NOTE*: Currently, only esp32h2 supports DS peripheral.
158
+
159
+ #### Generate 5 factory partitions [Optional argument : `-n`]
160
+ ```
161
+ esp-matter-mfg-tool -n 5 -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
162
+ -k $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
163
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
164
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der
165
+ ```
166
+
167
+ #### Generate factory partition using existing DAC certificate and private key [Optional arguments : `--dac-cert` and `--dac-key`]
168
+ ```
169
+ esp-matter-mfg-tool -cn "My Bulb" -v 0xFFF2 -p 0x8001 --pai \
170
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
171
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der \
172
+ --dac-key DAC_key.pem --dac-cert DAC_cert.pem
173
+ ```
174
+
175
+ #### Generate factory partitions using existing Passcode, Discriminator, and rotating device ID [Optional arguments : `--passcode`, `--discriminator`, and `--rd-id-uid`]
176
+ ```
177
+ esp-matter-mfg-tool -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
178
+ -k $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
179
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
180
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der \
181
+ --passcode 20202021 --discriminator 3840 --enable-rotating-device-id --rd-id-uid d2f351f57bb9387445a5f92a601d1c14
182
+ ```
183
+
184
+ * NOTE: Script generates only one factory partition if **DAC or Discriminator or Passcode or Rotating-Device-ID** is specified.
185
+
186
+ #### Generate factory partitions with extra NVS key-values specified using csv and mcsv file [Optional arguments : `--csv` and `--mcsv`]
187
+ ```
188
+ esp-matter-mfg-tool -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
189
+ -k $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
190
+ -c $MATTER_SDK_PATH/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
191
+ -cd $MATTER_SDK_PATH/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der \
192
+ --csv extra_nvs_key_config.csv --mcsv extra_nvs_key_value.csv
193
+ ```
194
+
195
+ Above command will generate `n` number of partitions. Where `n` is the rows in the mcsv file.
196
+ Output binary contains all the chip specific key/value and key/values specified using `--csv` and `--mcsv` option.
197
+
198
+ #### Generate factory partitions without device attestation certificates and keys
199
+ ```
200
+ esp-matter-mfg-tool -v 0xFFF2 -p 0x8001 \
201
+ -cd $ESP_MATTER_PATH/connectedhomeip/connectedhomeip/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der
202
+ ```
203
+
204
+ * NOTE: These factory partitions are only for firmwares with other ways to get the certificates and sign message with the private key.
205
+
206
+ ## Flashing the manufacturing binary
207
+ Please note that `esp-matter-mfg-tool` only generates manufacturing binary images which need to be flashed onto device using `esptool.py`.
208
+
209
+ * Flashing a binary image to the device
210
+ ```
211
+ esptool.py -p <serial_port> write_flash <address> path/to/<uuid>-partition.bin
212
+ ```
213
+
214
+ * NOTE: First flash your app firmware and then followed by the custom partition binary on the device.
215
+ Please flash the manufacturing binary at the corresponding address of the configured factory partition set by
216
+ [`CHIP_FACTORY_NAMESPACE_PARTITION_LABEL`](https://github.com/project-chip/connectedhomeip/blob/master/config/esp32/components/chip/Kconfig#L856)
217
+ which by default is `nvs`.
218
+
219
+ ## Commissioning the device
220
+ You can commission the device by using either -
221
+ 1. The QR code for Matter commissioners is generated at `out/<vid_pid>/<uuid>/<uuid>-qrcode.png`.
222
+ If QR code is not visible, paste the below link into the browser replacing `<qr_code>` with the **QR code string**
223
+ (eg. `MT:Y.K9042C00KA0648G00` - this is also the default test QR code) and scan the QR code.
224
+
225
+ ```
226
+ https://project-chip.github.io/connectedhomeip/qrcode.html?data=<qr_code>
227
+ ```
228
+
229
+ 2. Refer the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#commissioning-and-control)
230
+ for other methods using onboarding payload found at `out/<vid_pid>/<uuid>/<uuid>-onb_codes.csv`. This contains the `QR
231
+ Code String, Manual Pairing Code, Passcode and Discriminator`.
232
+
233
+ ## Encrypting NVS partition
234
+
235
+ Below are the steps for encrypting the application and factory partition but before proceeding further please READ THE DOCS FIRST. Documentation References:
236
+
237
+ - [Flash and NVS encryption](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/esp32/flash_nvs_encryption.md#flash-and-nvs-encryption)
238
+
239
+ Provide `-e` option along with other options to generate the encrypted NVS partition binary.
240
+
241
+ It will generate additional partition binary (`<uuid>-keys-partition.bin`) containing the key for decrypting encrypted partition.
242
+
243
+ - Flash the partition binary containing factory data, as NVS encryption works differently, please flash is without `--encrypt` option
244
+ ```
245
+ esptool.py -p (PORT) write_flash (FACTORY_PARTITION_ADDR) path/to/factory_partition.bin
246
+ ```
247
+
248
+ - Flash the partition binary containing encryption keys, these SHALL be flashed with `--encrypt` option
249
+ ```
250
+ esptool.py -p (PORT) write_flash --encrypt (NVS_KEYS_PARTITION_ADDR) path/to/nvs_key_partition.bin
251
+ ```
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Copyright (c) 2022 Project CHIP Authors
4
+ # All rights reserved.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ # TODO: Implement the decode method
19
+
20
+ CODES = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
21
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
22
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
23
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.']
24
+ RADIX = len(CODES)
25
+ BASE38_CHARS_NEEDED_IN_CHUNK = [2, 4, 5]
26
+ MAX_BYTES_IN_CHUNK = 3
27
+
28
+
29
+ def encode(bytes):
30
+ total_bytes = len(bytes)
31
+ qrcode = ''
32
+
33
+ for i in range(0, total_bytes, MAX_BYTES_IN_CHUNK):
34
+ if (i + MAX_BYTES_IN_CHUNK) > total_bytes:
35
+ bytes_in_chunk = total_bytes - i
36
+ else:
37
+ bytes_in_chunk = MAX_BYTES_IN_CHUNK
38
+
39
+ value = 0
40
+ for j in range(i, i + bytes_in_chunk):
41
+ value = value + (bytes[j] << (8 * (j - i)))
42
+
43
+ base38_chars_needed = BASE38_CHARS_NEEDED_IN_CHUNK[bytes_in_chunk - 1]
44
+ while base38_chars_needed > 0:
45
+ qrcode += CODES[int(value % RADIX)]
46
+ value = int(value / RADIX)
47
+ base38_chars_needed -= 1
48
+
49
+ return qrcode
@@ -0,0 +1,7 @@
1
+ # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import os
5
+ import sys
6
+
7
+ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Copyright (c) 2022 Project CHIP Authors
4
+ # All rights reserved.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ import argparse
19
+ import enum
20
+ import sys
21
+
22
+ import Base38
23
+ from bitarray import bitarray
24
+ from stdnum.verhoeff import calc_check_digit
25
+
26
+ # See section 5.1.4.1 Manual Pairing Code in the Matter specification v1.0
27
+ MANUAL_DISCRIMINATOR_LEN = 4
28
+ PINCODE_LEN = 27
29
+
30
+ MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN = 2
31
+ MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_POS = 0
32
+ MANUAL_CHUNK1_VID_PID_PRESENT_BIT_POS = MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_POS + MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN
33
+ MANUAL_CHUNK1_LEN = 1
34
+
35
+ MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_LEN = 2
36
+ MANUAL_CHUNK2_PINCODE_LSBITS_LEN = 14
37
+ MANUAL_CHUNK2_PINCODE_LSBITS_POS = 0
38
+ MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_POS = MANUAL_CHUNK2_PINCODE_LSBITS_POS + MANUAL_CHUNK2_PINCODE_LSBITS_LEN
39
+ MANUAL_CHUNK2_LEN = 5
40
+
41
+ MANUAL_CHUNK3_PINCODE_MSBITS_LEN = 13
42
+ MANUAL_CHUNK3_PINCODE_MSBITS_POS = 0
43
+ MANUAL_CHUNK3_LEN = 4
44
+
45
+ MANUAL_VID_LEN = 5
46
+ MANUAL_PID_LEN = 5
47
+
48
+ # See section 5.1.3. QR Code in the Matter specification v1.0
49
+ QRCODE_VERSION_LEN = 3
50
+ QRCODE_DISCRIMINATOR_LEN = 12
51
+ QRCODE_VID_LEN = 16
52
+ QRCODE_PID_LEN = 16
53
+ QRCODE_COMMISSIONING_FLOW_LEN = 2
54
+ QRCODE_DISCOVERY_CAP_BITMASK_LEN = 8
55
+ QRCODE_PADDING_LEN = 4
56
+ QRCODE_VERSION = 0
57
+ QRCODE_PADDING = 0
58
+
59
+ INVALID_PASSCODES = [00000000, 11111111, 22222222, 33333333, 44444444, 55555555,
60
+ 66666666, 77777777, 88888888, 99999999, 12345678, 87654321]
61
+
62
+
63
+ class CommissioningFlow(enum.IntEnum):
64
+ Standard = 0,
65
+ UserIntent = 1,
66
+ Custom = 2
67
+
68
+
69
+ class SetupPayload:
70
+ def __init__(self, discriminator, pincode, rendezvous=4, flow=CommissioningFlow.Standard, vid=0, pid=0):
71
+ self.long_discriminator = discriminator
72
+ self.short_discriminator = discriminator >> 8
73
+ self.pincode = pincode
74
+ self.rendezvous = rendezvous
75
+ self.flow = flow
76
+ self.vid = vid
77
+ self.pid = pid
78
+
79
+ def manual_chunk1(self):
80
+ discriminator_shift = (MANUAL_DISCRIMINATOR_LEN - MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN)
81
+ discriminator_mask = (1 << MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_LEN) - 1
82
+ discriminator_chunk = (self.short_discriminator >> discriminator_shift) & discriminator_mask
83
+ vid_pid_present_flag = 0 if self.flow == CommissioningFlow.Standard else 1
84
+ return (discriminator_chunk << MANUAL_CHUNK1_DISCRIMINATOR_MSBITS_POS) | (vid_pid_present_flag << MANUAL_CHUNK1_VID_PID_PRESENT_BIT_POS)
85
+
86
+ def manual_chunk2(self):
87
+ discriminator_mask = (1 << MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_LEN) - 1
88
+ pincode_mask = (1 << MANUAL_CHUNK2_PINCODE_LSBITS_LEN) - 1
89
+ discriminator_chunk = self.short_discriminator & discriminator_mask
90
+ return ((self.pincode & pincode_mask) << MANUAL_CHUNK2_PINCODE_LSBITS_POS) | (discriminator_chunk << MANUAL_CHUNK2_DISCRIMINATOR_LSBITS_POS)
91
+
92
+ def manual_chunk3(self):
93
+ pincode_shift = PINCODE_LEN - MANUAL_CHUNK3_PINCODE_MSBITS_LEN
94
+ pincode_mask = (1 << MANUAL_CHUNK3_PINCODE_MSBITS_LEN) - 1
95
+ return ((self.pincode >> pincode_shift) & pincode_mask) << MANUAL_CHUNK3_PINCODE_MSBITS_POS
96
+
97
+ def generate_manualcode(self):
98
+ payload = str(self.manual_chunk1()).zfill(MANUAL_CHUNK1_LEN)
99
+ payload += str(self.manual_chunk2()).zfill(MANUAL_CHUNK2_LEN)
100
+ payload += str(self.manual_chunk3()).zfill(MANUAL_CHUNK3_LEN)
101
+
102
+ if self.flow != CommissioningFlow.Standard:
103
+ payload += str(self.vid).zfill(MANUAL_VID_LEN)
104
+ payload += str(self.pid).zfill(MANUAL_PID_LEN)
105
+
106
+ payload += calc_check_digit(payload)
107
+ return payload
108
+
109
+ def generate_qrcode(self):
110
+ qrcode_bit_string = '{0:b}'.format(QRCODE_PADDING).zfill(QRCODE_PADDING_LEN)
111
+ qrcode_bit_string += '{0:b}'.format(self.pincode).zfill(PINCODE_LEN)
112
+ qrcode_bit_string += '{0:b}'.format(self.long_discriminator).zfill(QRCODE_DISCRIMINATOR_LEN)
113
+ qrcode_bit_string += '{0:b}'.format(self.rendezvous).zfill(QRCODE_DISCOVERY_CAP_BITMASK_LEN)
114
+ qrcode_bit_string += '{0:b}'.format(int(self.flow)).zfill(QRCODE_COMMISSIONING_FLOW_LEN)
115
+ qrcode_bit_string += '{0:b}'.format(self.pid).zfill(QRCODE_PID_LEN)
116
+ qrcode_bit_string += '{0:b}'.format(self.vid).zfill(QRCODE_VID_LEN)
117
+ qrcode_bit_string += '{0:b}'.format(QRCODE_VERSION).zfill(QRCODE_VERSION_LEN)
118
+
119
+ qrcode_bits = bitarray(qrcode_bit_string)
120
+ bytes = list(qrcode_bits.tobytes())
121
+ bytes.reverse()
122
+ return 'MT:{}'.format(Base38.encode(bytes))
123
+
124
+
125
+ def validate_args(args):
126
+ def check_int_range(value, min_value, max_value, name):
127
+ if value and ((value < min_value) or (value > max_value)):
128
+ print('{} is out of range, should be in range from {} to {}'.format(name, min_value, max_value))
129
+ sys.exit(1)
130
+
131
+ if args.passcode is not None:
132
+ if ((args.passcode < 0x0000001 and args.passcode > 0x5F5E0FE) or (args.passcode in INVALID_PASSCODES)):
133
+ print('Invalid passcode:' + str(args.passcode))
134
+ sys.exit(1)
135
+
136
+ check_int_range(args.discriminator, 0x0000, 0x0FFF, 'Discriminator')
137
+ check_int_range(args.product_id, 0x0000, 0xFFFF, 'Product id')
138
+ check_int_range(args.vendor_id, 0x0000, 0xFFFF, 'Vendor id')
139
+ check_int_range(args.discovery_cap_bitmask, 0x0001, 0x0007, 'Discovery Capability Mask')
140
+
141
+
142
+ def main():
143
+ def any_base_int(s): return int(s, 0)
144
+ parser = argparse.ArgumentParser(description='Matter Manual and QRCode Setup Payload Generator Tool')
145
+ parser.add_argument('-d', '--discriminator', type=any_base_int, required=True,
146
+ help='The discriminator for pairing, range: 0x00-0x0FFF')
147
+ parser.add_argument('-p', '--passcode', type=any_base_int, required=True,
148
+ help='The setup passcode for pairing, range: 0x01-0x5F5E0FE')
149
+ parser.add_argument('-vid', '--vendor-id', type=any_base_int, default=0, help='Vendor id')
150
+ parser.add_argument('-pid', '--product-id', type=any_base_int, default=0, help='Product id')
151
+ parser.add_argument('-cf', '--commissioning-flow', type=any_base_int, default=0,
152
+ help='Device commissioning flow, 0:Standard, 1:User-Intent, 2:Custom. \
153
+ Default is 0.', choices=[0, 1, 2])
154
+ parser.add_argument('-dm', '--discovery-cap-bitmask', type=any_base_int, default=4,
155
+ help='Commissionable device discovery capability bitmask. \
156
+ 0:SoftAP, 1:BLE, 2:OnNetwork. Default: OnNetwork')
157
+ args = parser.parse_args()
158
+ validate_args(args)
159
+
160
+ payloads = SetupPayload(args.discriminator, args.passcode, args.discovery_cap_bitmask,
161
+ CommissioningFlow(args.commissioning_flow), args.vendor_id, args.product_id)
162
+ manualcode = payloads.generate_manualcode()
163
+ qrcode = payloads.generate_qrcode()
164
+
165
+ print("Manualcode : {}".format(manualcode))
166
+ print("QRCode : {}".format(qrcode))
167
+
168
+
169
+ if __name__ == '__main__':
170
+ main()