mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 19:13:13 +00:00
[mfg_tool] Replaces spake2p, mfg_gen, chip-tool binary executable usages in 'tools/mfg_tool/mfg_tool.py' with respective python implementations - spake2p.py, mfg_gen.py, generate_setup_payload.py
Removes functions get_chip_qrcode, get_chip_manualcode, get_qrcode_args & get_manualcode_args from 'tools/mfg_tool/utlis.py' Adds python_stdnum dependency for using 'tools/mfg_tool/mfg_tool.py' in `tools/mfg_tool/requirements.txt' Signed-off-by: dhairyashah1 <dhairya.shah@espressif.com> [mfg_tool] Adds python_stdnum dependency for using mfg_tool.py in 'requirements.txt' Signed-off-by: dhairyashah1 <dhairya.shah@espressif.com> mfg_tool: Adds mfg_tool dependencies reinstallation note in 'RELEASE_NOTES.md' Signed-off-by: dhairyashah1 <dhairya.shah@espressif.com> [mfg_tool] Adds details on reinstalling tools/mfg_tool dependencies Signed-off-by: dhairyashah1 <dhairya.shah@espressif.com>
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
# 7-April-2023
|
||||
|
||||
- `tools/mfg_tool/mfg_tool.py` now uses `connectedhomeip/connectedhomeip/src/setup_payload/python/generate_setup_payload.py` instead of previously used compiled `chip-tool` binary executable which additionally depends on `python-stdnum` module.
|
||||
- Reinstall dependencies to use `mfg_tool` by running the following commands -
|
||||
```
|
||||
source $IDF_PATH/export.sh
|
||||
python3 -m pip install -r tools/mfg_tool/requirements.txt
|
||||
```
|
||||
|
||||
# 15-March-2023
|
||||
|
||||
API Change
|
||||
|
||||
+48
-51
@@ -23,6 +23,7 @@ import sys
|
||||
import csv
|
||||
import uuid
|
||||
import shutil
|
||||
import base64
|
||||
import random
|
||||
import logging
|
||||
import binascii
|
||||
@@ -32,16 +33,27 @@ import pyqrcode
|
||||
from chip_nvs import *
|
||||
from utils import *
|
||||
from datetime import datetime
|
||||
from types import SimpleNamespace
|
||||
|
||||
if not os.getenv('IDF_PATH'):
|
||||
logging.error("IDF_PATH environment variable is not set")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.getenv('ESP_MATTER_PATH'):
|
||||
logging.error("ESP_MATTER_PATH environment variable is not set")
|
||||
sys.exit(1)
|
||||
|
||||
sys.path.insert(0, os.path.join(os.getenv('ESP_MATTER_PATH'), 'connectedhomeip', 'connectedhomeip', 'scripts', 'tools', 'spake2p'))
|
||||
from spake2p import generate_verifier
|
||||
|
||||
sys.path.insert(0, os.path.join(os.getenv('IDF_PATH'), 'tools', 'mass_mfg'))
|
||||
from mfg_gen import generate
|
||||
|
||||
sys.path.insert(0, os.path.join(os.getenv('ESP_MATTER_PATH'), 'connectedhomeip', 'connectedhomeip', 'src', 'setup_payload', 'python'))
|
||||
from generate_setup_payload import SetupPayload, CommissioningFlow
|
||||
|
||||
TOOLS = {
|
||||
'spake2p': None,
|
||||
'chip-cert': None,
|
||||
'chip-tool': None,
|
||||
'mfg_gen': None,
|
||||
}
|
||||
|
||||
PAI = {
|
||||
@@ -67,10 +79,6 @@ UUIDs = list()
|
||||
|
||||
|
||||
def check_tools_exists(args):
|
||||
TOOLS['spake2p'] = shutil.which('spake2p')
|
||||
if TOOLS['spake2p'] is None:
|
||||
logging.error('spake2p not found, please add spake2p path to PATH environment variable')
|
||||
sys.exit(1)
|
||||
# if the certs and keys are not in the generated partitions or the specific dac cert and key are used,
|
||||
# the chip-cert is not needed.
|
||||
if args.paa or (args.pai and (args.dac_cert is None and args.dac_key is None)):
|
||||
@@ -79,40 +87,26 @@ def check_tools_exists(args):
|
||||
logging.error('chip-cert not found, please add chip-cert path to PATH environment variable')
|
||||
sys.exit(1)
|
||||
|
||||
TOOLS['chip-tool'] = shutil.which('chip-tool')
|
||||
if TOOLS['chip-tool'] is None:
|
||||
logging.error('chip-tool not found, please add chip-tool path to PATH environment variable')
|
||||
sys.exit(1)
|
||||
|
||||
TOOLS['mfg_gen'] = os.sep.join([os.getenv('IDF_PATH'), 'tools', 'mass_mfg', 'mfg_gen.py'])
|
||||
if not os.path.exists(TOOLS['mfg_gen']):
|
||||
logging.error('mfg_gen.py not found, please make sure IDF_PATH environment variable is set correctly')
|
||||
sys.exit(1)
|
||||
|
||||
logging.debug('Using following tools:')
|
||||
logging.debug('spake2p: {}'.format(TOOLS['spake2p']))
|
||||
logging.debug('chip-cert: {}'.format(TOOLS['chip-cert']))
|
||||
logging.debug('chip-tool: {}'.format(TOOLS['chip-tool']))
|
||||
logging.debug('mfg_gen: {}'.format(TOOLS['mfg_gen']))
|
||||
|
||||
|
||||
def generate_passcodes(args):
|
||||
iter_count_max = 10000
|
||||
salt_len_max = 32
|
||||
|
||||
cmd = [
|
||||
TOOLS['spake2p'], 'gen-verifier',
|
||||
'--count', str(args.count),
|
||||
'--iteration-count', str(iter_count_max),
|
||||
'--salt-len', str(salt_len_max),
|
||||
'--out', OUT_FILE['pin_csv'],
|
||||
]
|
||||
|
||||
# If passcode is provided, use it
|
||||
if (args.passcode):
|
||||
cmd.extend(['--pin-code', str(args.passcode)])
|
||||
|
||||
execute_cmd(cmd)
|
||||
with open(OUT_FILE['pin_csv'], 'w', newline='') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(["Index", "PIN Code", "Iteration Count", "Salt", "Verifier"])
|
||||
for i in range(0, args.count):
|
||||
if args.passcode:
|
||||
passcode = args.passcode
|
||||
else:
|
||||
passcode = random.randint(1, 99999998)
|
||||
if passcode in INVALID_PASSCODES:
|
||||
passcode -= 1
|
||||
salt = os.urandom(salt_len_max)
|
||||
verifier = generate_verifier(passcode, salt, iter_count_max)
|
||||
writer.writerow([i, passcode, iter_count_max, base64.b64encode(salt).decode('utf-8'), base64.b64encode(verifier).decode('utf-8')])
|
||||
|
||||
|
||||
def generate_discriminators(args):
|
||||
@@ -402,33 +396,36 @@ def generate_summary(args):
|
||||
for row in pin_disc_dict:
|
||||
pincode = row['PIN Code']
|
||||
discriminator = row['Discriminator']
|
||||
qrcode = get_chip_qrcode(TOOLS['chip-tool'], args.vendor_id, args.product_id,
|
||||
args.commissioning_flow, discriminator, pincode, args.discovery_mode)
|
||||
manualcode = get_chip_manualcode(TOOLS['chip-tool'], args.vendor_id, args.product_id,
|
||||
args.commissioning_flow, discriminator, pincode)
|
||||
payloads = SetupPayload(int(discriminator), int(pincode), 1 << args.discovery_mode, CommissioningFlow(args.commissioning_flow),
|
||||
args.vendor_id, args.product_id)
|
||||
qrcode = payloads.generate_qrcode()
|
||||
manualcode = payloads.generate_manualcode()
|
||||
summary_csv_data += summary_lines[1 + int(row['Index'])] + ',' + pincode + ',' + qrcode + ',' + manualcode + '\n'
|
||||
|
||||
with open(summary_csv, 'w') as scsvf:
|
||||
scsvf.write(summary_csv_data)
|
||||
|
||||
def generate_partitions(suffix, size, encrypt):
|
||||
cmd = [
|
||||
'python3', TOOLS['mfg_gen'], 'generate',
|
||||
OUT_FILE['config_csv'], OUT_FILE['mcsv'],
|
||||
suffix, hex(size), '--outdir', OUT_DIR['top']
|
||||
]
|
||||
|
||||
partition_args = SimpleNamespace(fileid = None,
|
||||
version = 2,
|
||||
inputkey = None,
|
||||
outdir = OUT_DIR['top'],
|
||||
conf = OUT_FILE['config_csv'],
|
||||
values = OUT_FILE['mcsv'],
|
||||
size = hex(size),
|
||||
prefix = suffix)
|
||||
if encrypt:
|
||||
cmd.append('--keygen')
|
||||
|
||||
execute_cmd(cmd)
|
||||
partition_args.keygen = True
|
||||
else:
|
||||
partition_args.keygen = False
|
||||
generate(partition_args)
|
||||
|
||||
|
||||
def generate_onboarding_data(args, index, discriminator, passcode):
|
||||
chip_manualcode = get_chip_manualcode(TOOLS['chip-tool'], args.vendor_id, args.product_id,
|
||||
args.commissioning_flow, discriminator, passcode)
|
||||
chip_qrcode = get_chip_qrcode(TOOLS['chip-tool'], args.vendor_id, args.product_id,
|
||||
args.commissioning_flow, discriminator, passcode, args.discovery_mode)
|
||||
payloads = SetupPayload(discriminator, passcode, 1 << args.discovery_mode, CommissioningFlow(args.commissioning_flow),
|
||||
args.vendor_id, args.product_id)
|
||||
chip_qrcode = payloads.generate_qrcode()
|
||||
chip_manualcode = payloads.generate_manualcode()
|
||||
|
||||
logging.info('Generated QR code: ' + chip_qrcode)
|
||||
logging.info('Generated manual code: ' + chip_manualcode)
|
||||
|
||||
@@ -5,3 +5,4 @@ future==0.18.2
|
||||
pycparser==2.21
|
||||
pypng==0.0.21
|
||||
PyQRCode==1.2.1
|
||||
python_stdnum==1.18
|
||||
@@ -277,60 +277,3 @@ def execute_cmd(cmd):
|
||||
logging.error('[stderr]: {}'.format(status.stderr.decode('utf-8').strip()))
|
||||
logging.error('Command failed with error: {}'.format(e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_manualcode_args(vid, pid, flow, discriminator, passcode):
|
||||
payload_args = list()
|
||||
payload_args.append('--discriminator')
|
||||
payload_args.append(str(discriminator))
|
||||
payload_args.append('--setup-pin-code')
|
||||
payload_args.append(str(passcode))
|
||||
payload_args.append('--version')
|
||||
payload_args.append('0')
|
||||
payload_args.append('--vendor-id')
|
||||
payload_args.append(str(vid))
|
||||
payload_args.append('--product-id')
|
||||
payload_args.append(str(pid))
|
||||
payload_args.append('--commissioning-mode')
|
||||
payload_args.append(str(flow))
|
||||
return payload_args
|
||||
|
||||
|
||||
def get_qrcode_args(vid, pid, flow, discriminator, passcode, disc_mode):
|
||||
payload_args = get_manualcode_args(vid, pid, flow, discriminator, passcode)
|
||||
payload_args.append('--rendezvous')
|
||||
payload_args.append(str(1 << disc_mode))
|
||||
return payload_args
|
||||
|
||||
|
||||
def get_chip_qrcode(chip_tool, vid, pid, flow, discriminator, passcode, disc_mode):
|
||||
payload_args = get_qrcode_args(vid, pid, flow, discriminator, passcode, disc_mode)
|
||||
cmd_args = [chip_tool, 'payload', 'generate-qrcode']
|
||||
cmd_args.extend(payload_args)
|
||||
data = subprocess.check_output(cmd_args)
|
||||
|
||||
# Command output is as below:
|
||||
# \x1b[0;32m[1655386003372] [23483:7823617] CHIP: [TOO] QR Code: MT:Y.K90-WB010E7648G00\x1b[0m
|
||||
return data.decode('utf-8').split('QR Code: ')[1][:QRCODE_LEN]
|
||||
|
||||
|
||||
def get_chip_manualcode(chip_tool, vid, pid, flow, discriminator, passcode):
|
||||
payload_args = get_manualcode_args(vid, pid, flow, discriminator, passcode)
|
||||
cmd_args = [chip_tool, 'payload', 'generate-manualcode']
|
||||
cmd_args.extend(payload_args)
|
||||
data = subprocess.check_output(cmd_args)
|
||||
|
||||
# Command output is as below:
|
||||
# \x1b[0;32m[1655386909774] [24424:7837894] CHIP: [TOO] Manual Code: 749721123365521327689\x1b[0m\n
|
||||
# OR
|
||||
# \x1b[0;32m[1655386926028] [24458:7838229] CHIP: [TOO] Manual Code: 34972112338\x1b[0m\n
|
||||
# Length of manual code depends on the commissioning flow:
|
||||
# For standard commissioning flow it is 11 digits
|
||||
# For User-intent and custom commissioning flow it is 21 digits
|
||||
manual_code_len = LONG_MANUALCODE_LEN if flow else SHORT_MANUALCODE_LEN
|
||||
ret = data.decode('utf-8').split('Manual Code: ')[1][:manual_code_len]
|
||||
# For 11-digits manual code, use the format 'XXXX-XXX-XXXX'
|
||||
# TODO: change the format of 21-digits maunal code
|
||||
if manual_code_len == SHORT_MANUALCODE_LEN:
|
||||
ret = ret[:4] + '-' + ret[4:7] + '-' + ret[7:]
|
||||
return ret
|
||||
|
||||
Reference in New Issue
Block a user