mirror of
https://github.com/esphome/esphome.git
synced 2024-11-23 15:38:11 +01:00
Allow downloading all bin files from backend in dashboard (#2514)
Co-authored-by: Otto Winter <otto@otto-winter.com>
This commit is contained in:
parent
f83950fd75
commit
db3fa1ade7
2 changed files with 99 additions and 12 deletions
|
@ -180,7 +180,11 @@ def compile_program(args, config):
|
||||||
from esphome import platformio_api
|
from esphome import platformio_api
|
||||||
|
|
||||||
_LOGGER.info("Compiling app...")
|
_LOGGER.info("Compiling app...")
|
||||||
return platformio_api.run_compile(config, CORE.verbose)
|
rc = platformio_api.run_compile(config, CORE.verbose)
|
||||||
|
if rc != 0:
|
||||||
|
return rc
|
||||||
|
idedata = platformio_api.get_idedata(config)
|
||||||
|
return 0 if idedata is not None else 1
|
||||||
|
|
||||||
|
|
||||||
def upload_using_esptool(config, port):
|
def upload_using_esptool(config, port):
|
||||||
|
@ -458,6 +462,21 @@ def command_update_all(args):
|
||||||
return failed
|
return failed
|
||||||
|
|
||||||
|
|
||||||
|
def command_idedata(args, config):
|
||||||
|
from esphome import platformio_api
|
||||||
|
import json
|
||||||
|
|
||||||
|
logging.disable(logging.INFO)
|
||||||
|
logging.disable(logging.WARNING)
|
||||||
|
|
||||||
|
idedata = platformio_api.get_idedata(config)
|
||||||
|
if idedata is None:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print(json.dumps(idedata.raw, indent=2) + "\n")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
PRE_CONFIG_ACTIONS = {
|
PRE_CONFIG_ACTIONS = {
|
||||||
"wizard": command_wizard,
|
"wizard": command_wizard,
|
||||||
"version": command_version,
|
"version": command_version,
|
||||||
|
@ -475,6 +494,7 @@ POST_CONFIG_ACTIONS = {
|
||||||
"clean-mqtt": command_clean_mqtt,
|
"clean-mqtt": command_clean_mqtt,
|
||||||
"mqtt-fingerprint": command_mqtt_fingerprint,
|
"mqtt-fingerprint": command_mqtt_fingerprint,
|
||||||
"clean": command_clean,
|
"clean": command_clean,
|
||||||
|
"idedata": command_idedata,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -650,6 +670,11 @@ def parse_args(argv):
|
||||||
"configuration", help="Your YAML configuration file directories.", nargs="+"
|
"configuration", help="Your YAML configuration file directories.", nargs="+"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser_idedata = subparsers.add_parser("idedata")
|
||||||
|
parser_idedata.add_argument(
|
||||||
|
"configuration", help="Your YAML configuration file(s).", nargs=1
|
||||||
|
)
|
||||||
|
|
||||||
# Keep backward compatibility with the old command line format of
|
# Keep backward compatibility with the old command line format of
|
||||||
# esphome <config> <command>.
|
# esphome <config> <command>.
|
||||||
#
|
#
|
||||||
|
@ -762,7 +787,7 @@ def run_esphome(argv):
|
||||||
|
|
||||||
config = read_config(dict(args.substitution) if args.substitution else {})
|
config = read_config(dict(args.substitution) if args.substitution else {})
|
||||||
if config is None:
|
if config is None:
|
||||||
return 1
|
return 2
|
||||||
CORE.config = config
|
CORE.config = config
|
||||||
|
|
||||||
if args.command not in POST_CONFIG_ACTIONS:
|
if args.command not in POST_CONFIG_ACTIONS:
|
||||||
|
|
|
@ -9,6 +9,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
import secrets
|
import secrets
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -26,7 +27,7 @@ import tornado.process
|
||||||
import tornado.web
|
import tornado.web
|
||||||
import tornado.websocket
|
import tornado.websocket
|
||||||
|
|
||||||
from esphome import const, util
|
from esphome import const, platformio_api, util
|
||||||
from esphome.helpers import mkdir_p, get_bool_env, run_system_command
|
from esphome.helpers import mkdir_p, get_bool_env, run_system_command
|
||||||
from esphome.storage_json import (
|
from esphome.storage_json import (
|
||||||
EsphomeStorageJSON,
|
EsphomeStorageJSON,
|
||||||
|
@ -398,17 +399,45 @@ class DownloadBinaryRequestHandler(BaseHandler):
|
||||||
@authenticated
|
@authenticated
|
||||||
@bind_config
|
@bind_config
|
||||||
def get(self, configuration=None):
|
def get(self, configuration=None):
|
||||||
# pylint: disable=no-value-for-parameter
|
type = self.get_argument("type", "firmware.bin")
|
||||||
storage_path = ext_storage_path(settings.config_dir, configuration)
|
|
||||||
storage_json = StorageJSON.load(storage_path)
|
if type == "firmware.bin":
|
||||||
if storage_json is None:
|
storage_path = ext_storage_path(settings.config_dir, configuration)
|
||||||
self.send_error()
|
storage_json = StorageJSON.load(storage_path)
|
||||||
|
if storage_json is None:
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
filename = f"{storage_json.name}.bin"
|
||||||
|
path = storage_json.firmware_bin_path
|
||||||
|
|
||||||
|
else:
|
||||||
|
args = ["esphome", "idedata", settings.rel_path(configuration)]
|
||||||
|
rc, stdout, _ = run_system_command(*args)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
self.send_error(404 if rc == 2 else 500)
|
||||||
|
return
|
||||||
|
|
||||||
|
idedata = platformio_api.IDEData(json.loads(stdout))
|
||||||
|
|
||||||
|
found = False
|
||||||
|
for image in idedata.extra_flash_images:
|
||||||
|
if image.path.endswith(type):
|
||||||
|
path = image.path
|
||||||
|
filename = type
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.set_header("Content-Type", "application/octet-stream")
|
||||||
|
self.set_header("Content-Disposition", f'attachment; filename="{filename}"')
|
||||||
|
if not Path(path).is_file():
|
||||||
|
self.send_error(404)
|
||||||
return
|
return
|
||||||
|
|
||||||
path = storage_json.firmware_bin_path
|
|
||||||
self.set_header("Content-Type", "application/octet-stream")
|
|
||||||
filename = f"{storage_json.name}.bin"
|
|
||||||
self.set_header("Content-Disposition", f'attachment; filename="{filename}"')
|
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
while True:
|
while True:
|
||||||
data = f.read(16384)
|
data = f.read(16384)
|
||||||
|
@ -418,6 +447,38 @@ class DownloadBinaryRequestHandler(BaseHandler):
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
|
|
||||||
|
class ManifestRequestHandler(BaseHandler):
|
||||||
|
@authenticated
|
||||||
|
@bind_config
|
||||||
|
def get(self, configuration=None):
|
||||||
|
args = ["esphome", "idedata", settings.rel_path(configuration)]
|
||||||
|
rc, stdout, _ = run_system_command(*args)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
self.send_error(404 if rc == 2 else 500)
|
||||||
|
return
|
||||||
|
|
||||||
|
idedata = platformio_api.IDEData(json.loads(stdout))
|
||||||
|
|
||||||
|
firmware_offset = "0x10000" if idedata.extra_flash_images else "0x0"
|
||||||
|
flash_images = [
|
||||||
|
{
|
||||||
|
"path": f"./download.bin?configuration={configuration}&type=firmware.bin",
|
||||||
|
"offset": firmware_offset,
|
||||||
|
}
|
||||||
|
] + [
|
||||||
|
{
|
||||||
|
"path": f"./download.bin?configuration={configuration}&type={os.path.basename(image.path)}",
|
||||||
|
"offset": image.offset,
|
||||||
|
}
|
||||||
|
for image in idedata.extra_flash_images
|
||||||
|
]
|
||||||
|
|
||||||
|
self.set_header("Content-Type", "application/json")
|
||||||
|
self.write(json.dumps(flash_images))
|
||||||
|
self.finish()
|
||||||
|
|
||||||
|
|
||||||
def _list_dashboard_entries():
|
def _list_dashboard_entries():
|
||||||
files = settings.list_yaml_files()
|
files = settings.list_yaml_files()
|
||||||
return [DashboardEntry(file) for file in files]
|
return [DashboardEntry(file) for file in files]
|
||||||
|
@ -862,6 +923,7 @@ def make_app(debug=get_bool_env(ENV_DEV)):
|
||||||
(f"{rel}info", InfoRequestHandler),
|
(f"{rel}info", InfoRequestHandler),
|
||||||
(f"{rel}edit", EditRequestHandler),
|
(f"{rel}edit", EditRequestHandler),
|
||||||
(f"{rel}download.bin", DownloadBinaryRequestHandler),
|
(f"{rel}download.bin", DownloadBinaryRequestHandler),
|
||||||
|
(f"{rel}manifest.json", ManifestRequestHandler),
|
||||||
(f"{rel}serial-ports", SerialPortRequestHandler),
|
(f"{rel}serial-ports", SerialPortRequestHandler),
|
||||||
(f"{rel}ping", PingRequestHandler),
|
(f"{rel}ping", PingRequestHandler),
|
||||||
(f"{rel}delete", DeleteRequestHandler),
|
(f"{rel}delete", DeleteRequestHandler),
|
||||||
|
|
Loading…
Reference in a new issue