|
18 | 18 |
|
19 | 19 | import argparse
|
20 | 20 | import base64
|
| 21 | +import csv |
21 | 22 | import enum
|
| 23 | +import hashlib |
| 24 | +import json |
22 | 25 | import logging
|
23 | 26 | import os
|
| 27 | +import pyqrcode |
24 | 28 | import sys
|
25 |
| -from types import SimpleNamespace |
26 | 29 |
|
| 30 | +from types import SimpleNamespace |
27 | 31 | import cryptography.x509
|
28 | 32 | from bitarray import bitarray
|
29 | 33 | from bitarray.util import ba2int
|
|
32 | 36 | CHIP_TOPDIR = os.path.dirname(os.path.realpath(__file__))[:-len(os.path.join('scripts', 'tools'))]
|
33 | 37 | sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'scripts', 'tools', 'spake2p'))
|
34 | 38 | from spake2p import generate_verifier # noqa: E402 isort:skip
|
| 39 | +sys.path.insert(0,os.path.join(CHIP_TOPDIR, 'src', 'setup_payload','python')) |
| 40 | +from generate_setup_payload import SetupPayload, CommissioningFlow |
35 | 41 |
|
36 | 42 | if os.getenv('IDF_PATH'):
|
37 | 43 | sys.path.insert(0, os.path.join(os.getenv('IDF_PATH'),
|
|
48 | 54 |
|
49 | 55 | TOOLS = {}
|
50 | 56 |
|
51 |
| - |
52 | 57 | FACTORY_PARTITION_CSV = 'nvs_partition.csv'
|
53 | 58 | FACTORY_PARTITION_BIN = 'factory_partition.bin'
|
54 | 59 | NVS_KEY_PARTITION_BIN = 'nvs_key_partition.bin'
|
55 | 60 | ESP_SECURE_CERT_PARTITION_BIN = 'esp_secure_cert_partititon.bin'
|
| 61 | +CONFIG_FILE = 'config.json' |
| 62 | +ONBOARDING_DATA_FILE = 'onboarding_codes.csv' |
| 63 | +QROCDE_FILE = 'qrcode.png' |
56 | 64 |
|
57 | 65 | FACTORY_DATA = {
|
58 | 66 | # CommissionableDataProvider
|
|
167 | 175 | }
|
168 | 176 |
|
169 | 177 |
|
| 178 | +def save_config(args): |
| 179 | + with open(CONFIG_FILE, 'w') as config_file: |
| 180 | + json.dump(vars(args), config_file) |
| 181 | + |
| 182 | +def load_config(): |
| 183 | + try: |
| 184 | + with open(CONFIG_FILE, 'r') as config_file: |
| 185 | + return json.load(config_file) |
| 186 | + except FileNotFoundError: |
| 187 | + return None |
| 188 | + |
| 189 | +def calculate_hash(data): |
| 190 | + return hashlib.sha256(data.encode('utf-8')).hexdigest() |
| 191 | + |
| 192 | + |
| 193 | +def args_changed(current_args, saved_args): |
| 194 | + return calculate_hash(json.dumps(vars(current_args))) != calculate_hash(json.dumps(saved_args)) |
| 195 | + |
| 196 | + |
170 | 197 | class CalendarTypes(enum.Enum):
|
171 | 198 | Buddhist = 0
|
172 | 199 | Chinese = 1
|
@@ -602,6 +629,12 @@ def any_base_int(s): return int(s, 0)
|
602 | 629 | help='Do not generate the factory partition binary')
|
603 | 630 | parser.add_argument('--output_dir', type=str, default='bin', help='Created image output file path')
|
604 | 631 |
|
| 632 | + parser.add_argument('-cf', '--commissioning-flow', type=any_base_int, default=0, |
| 633 | + help='Device commissioning flow, 0:Standard, 1:User-Intent, 2:Custom. \ |
| 634 | + Default is 0.', choices=[0, 1, 2]) |
| 635 | + parser.add_argument('-dm', '--discovery-mode', type=any_base_int, default=1, |
| 636 | + help='Commissionable device discovery networking technology. \ |
| 637 | + 0:WiFi-SoftAP, 1:BLE, 2:On-network. Default is BLE.', choices=[0, 1, 2]) |
605 | 638 | parser.set_defaults(generate_bin=True)
|
606 | 639 |
|
607 | 640 | return parser.parse_args()
|
@@ -632,13 +665,42 @@ def generate_factory_partiton_binary(args):
|
632 | 665 | def set_up_out_dirs(args):
|
633 | 666 | os.makedirs(args.output_dir, exist_ok=True)
|
634 | 667 |
|
| 668 | +def generate_onboarding_data(args): |
| 669 | + payloads = SetupPayload(args.discriminator, args.passcode, args.discovery_mode, CommissioningFlow(args.commissioning_flow), |
| 670 | + args.vendor_id, args.product_id) |
| 671 | + logging.info('Discovery mode' + str(args.discovery_mode)) |
| 672 | + chip_qrcode = payloads.generate_qrcode() |
| 673 | + chip_manualcode = payloads.generate_manualcode() |
| 674 | + # ToDo: remove this if qrcode tool can handle the standard manual code format |
| 675 | + if args.commissioning_flow == CommissioningFlow.Standard: |
| 676 | + chip_manualcode = chip_manualcode[:4] + '-' + chip_manualcode[4:7] + '-' + chip_manualcode[7:] |
| 677 | + else: |
| 678 | + chip_manualcode = '"' + chip_manualcode[:4] + '-' + chip_manualcode[4:7] + '-' + chip_manualcode[7:11] + '\n' + chip_manualcode[11:15] + '-' + chip_manualcode[15:18] + '-' + chip_manualcode[18:20] + '-' + chip_manualcode[20:21] + '"' |
| 679 | + |
| 680 | + logging.info('Generated QR code: ' + chip_qrcode) |
| 681 | + logging.info('Generated manual code: ' + chip_manualcode) |
| 682 | + |
| 683 | + csv_data = 'qrcode,manualcode,discriminator,passcode\n' |
| 684 | + csv_data += chip_qrcode + ',' + chip_manualcode + ',' + str(args.discriminator) + ',' + str(args.passcode) + '\n' |
| 685 | + |
| 686 | + with open(os.path.join(args.output_dir,ONBOARDING_DATA_FILE), 'w') as f: |
| 687 | + f.write(csv_data) |
| 688 | + |
| 689 | + chip_qr = pyqrcode.create(chip_qrcode, version=2, error='M') |
| 690 | + chip_qr.png(os.path.join(args.output_dir,QROCDE_FILE), scale=6) |
| 691 | + |
635 | 692 |
|
636 | 693 | def main():
|
| 694 | + saved_args = load_config() |
637 | 695 | args = get_args()
|
638 |
| - set_up_out_dirs(args) |
639 |
| - set_up_factory_data(args) |
640 |
| - generate_factory_partiton_binary(args) |
641 |
| - |
| 696 | + if saved_args is None or args_changed(args, saved_args): |
| 697 | + set_up_out_dirs(args) |
| 698 | + set_up_factory_data(args) |
| 699 | + generate_factory_partiton_binary(args) |
| 700 | + generate_onboarding_data(args) |
| 701 | + save_config(args) |
| 702 | + else: |
| 703 | + logging.info("No changes in arguments. Skipping partition generation.") |
642 | 704 |
|
643 | 705 | if __name__ == "__main__":
|
644 | 706 | logging.basicConfig(format='[%(asctime)s] [%(levelname)7s] - %(message)s', level=logging.INFO)
|
|
0 commit comments