mirror of
https://github.com/esphome/esphome-flasher.git
synced 2024-11-15 10:45:29 +01:00
157 lines
5.3 KiB
Python
157 lines
5.3 KiB
Python
from __future__ import print_function
|
|
|
|
import argparse
|
|
from datetime import datetime
|
|
import re
|
|
import sys
|
|
|
|
import esptool
|
|
import serial
|
|
|
|
from esphomeflasher import const
|
|
from esphomeflasher.common import ESP32ChipInfo, EsphomeflasherError, chip_run_stub, \
|
|
configure_write_flash_args, detect_chip, detect_flash_size, read_chip_info
|
|
from esphomeflasher.const import ESP32_DEFAULT_BOOTLOADER_FORMAT, ESP32_DEFAULT_OTA_DATA, \
|
|
ESP32_DEFAULT_PARTITIONS
|
|
from esphomeflasher.helpers import list_serial_ports
|
|
|
|
|
|
def parse_args(argv):
|
|
parser = argparse.ArgumentParser(prog='esphomeflasher {}'.format(const.__version__))
|
|
parser.add_argument('-p', '--port',
|
|
help="Select the USB/COM port for uploading.")
|
|
group = parser.add_mutually_exclusive_group(required=False)
|
|
group.add_argument('--esp8266', action='store_true')
|
|
group.add_argument('--esp32', action='store_true')
|
|
parser.add_argument('--bootloader',
|
|
help="(ESP32-only) The bootloader to flash.",
|
|
default=ESP32_DEFAULT_BOOTLOADER_FORMAT)
|
|
parser.add_argument('--partitions',
|
|
help="(ESP32-only) The partitions to flash.",
|
|
default=ESP32_DEFAULT_PARTITIONS)
|
|
parser.add_argument('--otadata',
|
|
help="(ESP32-only) The otadata file to flash.",
|
|
default=ESP32_DEFAULT_OTA_DATA)
|
|
parser.add_argument('--no-erase',
|
|
help="Do not erase flash before flashing",
|
|
action='store_true')
|
|
parser.add_argument('binary', help="The binary image to flash.")
|
|
|
|
return parser.parse_args(argv[1:])
|
|
|
|
|
|
def select_port(args):
|
|
if args.port is not None:
|
|
print(u"Using '{}' as serial port.".format(args.port))
|
|
return args.port
|
|
ports = list_serial_ports()
|
|
if not ports:
|
|
raise EsphomeflasherError("No serial port found!")
|
|
if len(ports) != 1:
|
|
print("Found more than one serial port:")
|
|
for port, desc in ports:
|
|
print(u" * {} ({})".format(port, desc))
|
|
print("Please choose one with the --port argument.")
|
|
raise EsphomeflasherError
|
|
print(u"Auto-detected serial port: {}".format(ports[0][0]))
|
|
return ports[0][0]
|
|
|
|
|
|
ANSI_REGEX = re.compile(r"\033\[[0-9;]*m")
|
|
|
|
|
|
def run_esphomeflasher(argv):
|
|
args = parse_args(argv)
|
|
try:
|
|
firmware = open(args.binary, 'rb')
|
|
except IOError as err:
|
|
raise EsphomeflasherError("Error opening binary: {}".format(err))
|
|
port = select_port(args)
|
|
chip = detect_chip(port, args.esp8266, args.esp32)
|
|
info = read_chip_info(chip)
|
|
|
|
print()
|
|
print("Chip Info:")
|
|
print(" - Chip Family: {}".format(info.family))
|
|
print(" - Chip Model: {}".format(info.model))
|
|
if isinstance(info, ESP32ChipInfo):
|
|
print(" - Number of Cores: {}".format(info.num_cores))
|
|
print(" - Max CPU Frequency: {}".format(info.cpu_frequency))
|
|
print(" - Has Bluetooth: {}".format('YES' if info.has_bluetooth else 'NO'))
|
|
print(" - Has Embedded Flash: {}".format('YES' if info.has_embedded_flash else 'NO'))
|
|
print(" - Has Factory-Calibrated ADC: {}".format(
|
|
'YES' if info.has_factory_calibrated_adc else 'NO'))
|
|
else:
|
|
print(" - Chip ID: {:08X}".format(info.chip_id))
|
|
|
|
print(" - MAC Address: {}".format(info.mac))
|
|
|
|
stub_chip = chip_run_stub(chip)
|
|
|
|
flash_size = detect_flash_size(stub_chip)
|
|
print(" - Flash Size: {}".format(flash_size))
|
|
|
|
try:
|
|
stub_chip.flash_set_parameters(esptool.flash_size_bytes(flash_size))
|
|
except esptool.FatalError as err:
|
|
raise EsphomeflasherError("Error setting flash parameters: {}".format(err))
|
|
|
|
mock_args = configure_write_flash_args(info, firmware, flash_size,
|
|
args.bootloader, args.partitions,
|
|
args.otadata)
|
|
|
|
if not args.no_erase:
|
|
try:
|
|
esptool.erase_flash(stub_chip, mock_args)
|
|
except esptool.FatalError as err:
|
|
raise EsphomeflasherError("Error while erasing flash: {}".format(err))
|
|
|
|
try:
|
|
esptool.write_flash(stub_chip, mock_args)
|
|
except esptool.FatalError as err:
|
|
raise EsphomeflasherError("Error while writing flash: {}".format(err))
|
|
|
|
print("Hard Resetting...")
|
|
stub_chip.hard_reset()
|
|
|
|
print("Done! Flashing is complete!")
|
|
print()
|
|
|
|
print("Showing logs:")
|
|
with stub_chip._port as ser:
|
|
while True:
|
|
try:
|
|
raw = ser.readline()
|
|
except serial.SerialException:
|
|
print("Serial port closed!")
|
|
return
|
|
text = raw.decode(errors='ignore')
|
|
text = ANSI_REGEX.sub('', text)
|
|
line = text.replace('\r', '').replace('\n', '')
|
|
time = datetime.now().time().strftime('[%H:%M:%S]')
|
|
message = time + line
|
|
try:
|
|
print(message)
|
|
except UnicodeEncodeError:
|
|
print(message.encode('ascii', 'backslashreplace'))
|
|
|
|
|
|
def main():
|
|
try:
|
|
if len(sys.argv) <= 1:
|
|
from esphomeflasher import gui
|
|
|
|
return gui.main() or 0
|
|
return run_esphomeflasher(sys.argv) or 0
|
|
except EsphomeflasherError as err:
|
|
msg = str(err)
|
|
if msg:
|
|
print(msg)
|
|
return 1
|
|
except KeyboardInterrupt:
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|