Merge pull request #2049 from proddy/dev

package updates, python formatting
This commit is contained in:
Proddy
2024-09-25 17:33:36 +02:00
committed by GitHub
16 changed files with 208 additions and 108 deletions

View File

@@ -31,7 +31,7 @@
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"preact": "^10.24.0", "preact": "^10.24.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-icons": "^5.3.0", "react-icons": "^5.3.0",
@@ -47,8 +47,8 @@
"@preact/preset-vite": "^2.9.1", "@preact/preset-vite": "^2.9.1",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/formidable": "^3", "@types/formidable": "^3",
"@types/node": "^22.6.1", "@types/node": "^22.7.0",
"@types/react": "^18.3.8", "@types/react": "^18.3.9",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"concurrently": "^9.0.1", "concurrently": "^9.0.1",
@@ -59,7 +59,7 @@
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.33.0", "terser": "^5.33.0",
"typescript-eslint": "8.7.0", "typescript-eslint": "8.7.0",
"vite": "^5.4.7", "vite": "^5.4.8",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^5.0.1" "vite-tsconfig-paths": "^5.0.1"
}, },

View File

@@ -1437,7 +1437,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:*, @types/node@npm:^22.6.1": "@types/node@npm:*":
version: 22.6.1 version: 22.6.1
resolution: "@types/node@npm:22.6.1" resolution: "@types/node@npm:22.6.1"
dependencies: dependencies:
@@ -1446,6 +1446,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^22.7.0":
version: 22.7.0
resolution: "@types/node@npm:22.7.0"
dependencies:
undici-types: "npm:~6.19.2"
checksum: 10c0/127b1ac3eebe8c2b09e3d2de277ee906710c4908b4573cde23b9c7cec1cb1aaf1af8bdabbccdac08d005f820b770e7447b22c8eb56ca63344f4d2e26bcdc29fb
languageName: node
linkType: hard
"@types/parse-json@npm:^4.0.0": "@types/parse-json@npm:^4.0.0":
version: 4.0.2 version: 4.0.2
resolution: "@types/parse-json@npm:4.0.2" resolution: "@types/parse-json@npm:4.0.2"
@@ -1499,7 +1508,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react@npm:*, @types/react@npm:^18.3.8": "@types/react@npm:*":
version: 18.3.8 version: 18.3.8
resolution: "@types/react@npm:18.3.8" resolution: "@types/react@npm:18.3.8"
dependencies: dependencies:
@@ -1509,6 +1518,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react@npm:^18.3.9":
version: 18.3.9
resolution: "@types/react@npm:18.3.9"
dependencies:
"@types/prop-types": "npm:*"
csstype: "npm:^3.0.2"
checksum: 10c0/a92b8e061d0c833e096254782c56a802316593f4a907fb834b557cabe848a0829b9eb6056404ea239eb4d5ec5ac7b7724309761516c0a7a277916fa04dd4f805
languageName: node
linkType: hard
"@types/responselike@npm:^1.0.0": "@types/responselike@npm:^1.0.0":
version: 1.0.3 version: 1.0.3
resolution: "@types/responselike@npm:1.0.3" resolution: "@types/responselike@npm:1.0.3"
@@ -1659,8 +1678,8 @@ __metadata:
"@table-library/react-table-library": "npm:4.1.7" "@table-library/react-table-library": "npm:4.1.7"
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
"@types/formidable": "npm:^3" "@types/formidable": "npm:^3"
"@types/node": "npm:^22.6.1" "@types/node": "npm:^22.7.0"
"@types/react": "npm:^18.3.8" "@types/react": "npm:^18.3.9"
"@types/react-dom": "npm:^18.3.0" "@types/react-dom": "npm:^18.3.0"
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"
alova: "npm:3.0.16" alova: "npm:3.0.16"
@@ -1671,7 +1690,7 @@ __metadata:
formidable: "npm:^3.5.1" formidable: "npm:^3.5.1"
jwt-decode: "npm:^4.0.0" jwt-decode: "npm:^4.0.0"
mime-types: "npm:^2.1.35" mime-types: "npm:^2.1.35"
preact: "npm:^10.24.0" preact: "npm:^10.24.1"
prettier: "npm:^3.3.3" prettier: "npm:^3.3.3"
react: "npm:^18.3.1" react: "npm:^18.3.1"
react-dom: "npm:^18.3.1" react-dom: "npm:^18.3.1"
@@ -1683,7 +1702,7 @@ __metadata:
typesafe-i18n: "npm:^5.26.2" typesafe-i18n: "npm:^5.26.2"
typescript: "npm:^5.6.2" typescript: "npm:^5.6.2"
typescript-eslint: "npm:8.7.0" typescript-eslint: "npm:8.7.0"
vite: "npm:^5.4.7" vite: "npm:^5.4.8"
vite-plugin-imagemin: "npm:^0.6.1" vite-plugin-imagemin: "npm:^0.6.1"
vite-tsconfig-paths: "npm:^5.0.1" vite-tsconfig-paths: "npm:^5.0.1"
languageName: unknown languageName: unknown
@@ -5591,10 +5610,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"preact@npm:^10.24.0": "preact@npm:^10.24.1":
version: 10.24.0 version: 10.24.1
resolution: "preact@npm:10.24.0" resolution: "preact@npm:10.24.1"
checksum: 10c0/09d490d2326c511e205a96f81db0adf05f1b42dbe2a39be6fc494662c7476575494e96140252f351a0e3b3d15aee5b079bf963865bb01287f69c45c6755ed22e checksum: 10c0/f9bc8b2f88d340f1b8f854208889244059c46916449b8f8f2174fcacbc0904c445c5870896fb0cfeaf442eeade975857e8e03f0785135c41d63cd32d9414c9c6
languageName: node languageName: node
linkType: hard linkType: hard
@@ -6983,9 +7002,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"vite@npm:^5.4.7": "vite@npm:^5.4.8":
version: 5.4.7 version: 5.4.8
resolution: "vite@npm:5.4.7" resolution: "vite@npm:5.4.8"
dependencies: dependencies:
esbuild: "npm:^0.21.3" esbuild: "npm:^0.21.3"
fsevents: "npm:~2.3.3" fsevents: "npm:~2.3.3"
@@ -7022,7 +7041,7 @@ __metadata:
optional: true optional: true
bin: bin:
vite: bin/vite.js vite: bin/vite.js
checksum: 10c0/0ca7ca60f71c61f3855bbabf7e33909bec32933b35914d4d281813c728183e78e7ce5be05735a7671df3a994613d3881f520a32a80715faa92effb28deee9320 checksum: 10c0/af70af6d6316a3af71f44ebe3ab343bd66450d4157af73af3b32239e1b6ec43ff6f651d7cc4193b21ed3bff2e9356a3de9e96aee53857f39922e4a2d9fad75a1
languageName: node languageName: node
linkType: hard linkType: hard

View File

@@ -3,6 +3,7 @@ import os
Import("env") Import("env")
def buildWeb(): def buildWeb():
os.chdir("interface") os.chdir("interface")
print("Building web interface...") print("Building web interface...")

View File

@@ -3,6 +3,7 @@
# copied from esphome # copied from esphome
# run from Linux using ./scripts/clang-forrmat.py # run from Linux using ./scripts/clang-forrmat.py
from helpers import get_output, src_files, filter_changed
import argparse import argparse
import multiprocessing import multiprocessing
import os import os
@@ -14,7 +15,7 @@ import threading
import click import click
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from helpers import get_output, src_files, filter_changed
def run_format(args, queue, lock, failed_files): def run_format(args, queue, lock, failed_files):
"""Takes filenames out of queue and runs clang-format on them.""" """Takes filenames out of queue and runs clang-format on them."""
@@ -27,11 +28,13 @@ def run_format(args, queue, lock, failed_files):
invocation.extend(['--dry-run', '-Werror']) invocation.extend(['--dry-run', '-Werror'])
invocation.append(path) invocation.append(path)
proc = subprocess.run(invocation, capture_output=True, encoding='utf-8') proc = subprocess.run(
invocation, capture_output=True, encoding='utf-8')
if proc.returncode != 0: if proc.returncode != 0:
with lock: with lock:
print() print()
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(path)) print(
"\033[0;32m************* File \033[1;32m{}\033[0m".format(path))
print(proc.stdout) print(proc.stdout)
print(proc.stderr) print(proc.stderr)
print() print()
@@ -42,6 +45,7 @@ def run_format(args, queue, lock, failed_files):
def progress_bar_show(value): def progress_bar_show(value):
return value if value is not None else '' return value if value is not None else ''
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-j', '--jobs', type=int, parser.add_argument('-j', '--jobs', type=int,

View File

@@ -3,6 +3,8 @@
# copied from esphome # copied from esphome
# run from Linux using ./scripts/clang-forrmat.py # run from Linux using ./scripts/clang-forrmat.py
from helpers import shlex_quote, get_output, \
build_all_include, temp_header_file, filter_changed, load_idedata, src_files
import argparse import argparse
import multiprocessing import multiprocessing
import os import os
@@ -16,8 +18,7 @@ import click
import pexpect import pexpect
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from helpers import shlex_quote, get_output, \
build_all_include, temp_header_file, filter_changed, load_idedata, src_files
def clang_options(idedata): def clang_options(idedata):
cmd = [ cmd = [
@@ -46,6 +47,7 @@ def clang_options(idedata):
return cmd return cmd
def run_tidy(args, options, tmpdir, queue, lock, failed_files): def run_tidy(args, options, tmpdir, queue, lock, failed_files):
while True: while True:
path = queue.get() path = queue.get()
@@ -73,20 +75,24 @@ def run_tidy(args, options, tmpdir, queue, lock, failed_files):
if rc != 0: if rc != 0:
with lock: with lock:
print() print()
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(path)) print(
"\033[0;32m************* File \033[1;32m{}\033[0m".format(path))
print(output) print(output)
print() print()
failed_files.append(path) failed_files.append(path)
queue.task_done() queue.task_done()
def progress_bar_show(value): def progress_bar_show(value):
if value is None: if value is None:
return '' return ''
def split_list(a, n): def split_list(a, n):
k, m = divmod(len(a), n) k, m = divmod(len(a), n)
return [a[i * k + min(i, m):(i + 1) * k + min(i + 1, m)] for i in range(n)] return [a[i * k + min(i, m):(i + 1) * k + min(i + 1, m)] for i in range(n)]
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-j', '--jobs', type=int, parser.add_argument('-j', '--jobs', type=int,

View File

@@ -59,6 +59,7 @@ with fileinput.input() as f_input:
entity[headers[i]] = val entity[headers[i]] = val
entities.append(entity) entities.append(entity)
def device_name_key(e): return e["device name"] def device_name_key(e): return e["device name"]

View File

@@ -4,7 +4,8 @@ import subprocess
import json import json
from pathlib import Path from pathlib import Path
root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, "..", ".."))) root_path = os.path.abspath(os.path.normpath(
os.path.join(__file__, "..", "..")))
basepath = os.path.join(root_path, "src") basepath = os.path.join(root_path, "src")
temp_folder = os.path.join(root_path, ".temp") temp_folder = os.path.join(root_path, ".temp")
temp_header_file = os.path.join(temp_folder, "all-include.cpp") temp_header_file = os.path.join(temp_folder, "all-include.cpp")
@@ -18,6 +19,7 @@ def shlex_quote(s):
return "'" + s.replace("'", "'\"'\"'") + "'" return "'" + s.replace("'", "'\"'\"'") + "'"
def build_all_include(): def build_all_include():
# Build a cpp file that includes all header files in this repo. # Build a cpp file that includes all header files in this repo.
# Otherwise header-only integrations would not be tested by clang-tidy # Otherwise header-only integrations would not be tested by clang-tidy
@@ -36,6 +38,7 @@ def build_all_include():
p.parent.mkdir(exist_ok=True) p.parent.mkdir(exist_ok=True)
p.write_text(content) p.write_text(content)
def src_files(filetypes=None): def src_files(filetypes=None):
file_list = [] file_list = []
for path in walk_files(basepath): for path in walk_files(basepath):
@@ -45,24 +48,31 @@ def src_files(filetypes=None):
file_list.append(path) file_list.append(path)
return file_list return file_list
def walk_files(path): def walk_files(path):
for root, _, files in os.walk(path): for root, _, files in os.walk(path):
for name in files: for name in files:
yield os.path.join(root, name) yield os.path.join(root, name)
def get_output(*args): def get_output(*args):
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = proc.communicate() output, err = proc.communicate()
return output.decode("utf-8") return output.decode("utf-8")
def get_err(*args): def get_err(*args):
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = proc.communicate() output, err = proc.communicate()
return err.decode("utf-8") return err.decode("utf-8")
def splitlines_no_ends(string): def splitlines_no_ends(string):
return [s.strip() for s in string.splitlines()] return [s.strip() for s in string.splitlines()]
def changed_files(): def changed_files():
check_remotes = ["upstream", "origin"] check_remotes = ["upstream", "origin"]
check_remotes.extend(splitlines_no_ends(get_output("git", "remote"))) check_remotes.extend(splitlines_no_ends(get_output("git", "remote")))
@@ -81,6 +91,7 @@ def changed_files():
changed.sort() changed.sort()
return changed return changed
def filter_changed(files): def filter_changed(files):
changed = changed_files() changed = changed_files()
files = [f for f in files if f in changed] files = [f for f in files if f in changed]
@@ -91,6 +102,7 @@ def filter_changed(files):
print(f" {c}") print(f" {c}")
return files return files
def git_ls_files(patterns=None): def git_ls_files(patterns=None):
command = ["git", "ls-files", "-s"] command = ["git", "ls-files", "-s"]
if patterns is not None: if patterns is not None:
@@ -100,6 +112,7 @@ def git_ls_files(patterns=None):
lines = [x.split() for x in output.decode("utf-8").splitlines()] lines = [x.split() for x in output.decode("utf-8").splitlines()]
return {s[3].strip(): int(s[0]) for s in lines} return {s[3].strip(): int(s[0]) for s in lines}
def load_idedata(environment): def load_idedata(environment):
platformio_ini = Path(root_path) / "platformio.ini" platformio_ini = Path(root_path) / "platformio.ini"
temp_idedata = Path(temp_folder) / f"idedata-{environment}.json" temp_idedata = Path(temp_folder) / f"idedata-{environment}.json"
@@ -113,7 +126,8 @@ def load_idedata(environment):
if not changed: if not changed:
return json.loads(temp_idedata.read_text()) return json.loads(temp_idedata.read_text())
stdout = subprocess.check_output(["pio", "run", "-t", "idedata", "-e", environment]) stdout = subprocess.check_output(
["pio", "run", "-t", "idedata", "-e", environment])
match = re.search(r'{\s*".*}', stdout.decode("utf-8")) match = re.search(r'{\s*".*}', stdout.decode("utf-8"))
data = json.loads(match.group()) data = json.loads(match.group())

View File

@@ -2,10 +2,12 @@ import os
Import("env") Import("env")
def refresh_module(): def refresh_module():
print("Fetching latest module for Native target...") print("Fetching latest module for Native target...")
os.system("pio pkg install -f -s -e native -l file://../../modules/EMS-ESP-Modules") os.system(
"pio pkg install -f -s -e native -l file://../../modules/EMS-ESP-Modules")
if not (env.IsCleanTarget()): if not (env.IsCleanTarget()):
refresh_module() refresh_module()

View File

@@ -1,11 +1,12 @@
import hashlib
import shutil import shutil
import re import re
import os import os
Import("env") Import("env")
import hashlib
OUTPUT_DIR = "build{}".format(os.path.sep) OUTPUT_DIR = "build{}".format(os.path.sep)
def bin_copy(source, target, env): def bin_copy(source, target, env):
# get the application version from version.h # get the application version from version.h
@@ -60,7 +61,9 @@ def bin_copy(source, target, env):
# convert . to _ so Windows doesn't complain # convert . to _ so Windows doesn't complain
# Format is EMS-ESP-<version>-<mcu>-<flash> with + at the end if it has PSRAM # Format is EMS-ESP-<version>-<mcu>-<flash> with + at the end if it has PSRAM
variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + mcu + "-" + flash_mem + ("+" if psram else "") variant = "EMS-ESP-" + \
app_version.replace(".", "_") + "-" + mcu + "-" + \
flash_mem + ("+" if psram else "")
# check if output directories exist and create if necessary # check if output directories exist and create if necessary
if not os.path.isdir(OUTPUT_DIR): if not os.path.isdir(OUTPUT_DIR):
@@ -89,7 +92,7 @@ def bin_copy(source, target, env):
# copy firmware.bin to firmware/<variant>.bin # copy firmware.bin to firmware/<variant>.bin
shutil.copy(str(target[0]), bin_file) shutil.copy(str(target[0]), bin_file)
with open(bin_file,"rb") as f: with open(bin_file, "rb") as f:
result = hashlib.md5(f.read()) result = hashlib.md5(f.read())
print("MD5: "+result.hexdigest()) print("MD5: "+result.hexdigest())
file1 = open(md5_file, 'w') file1 = open(md5_file, 'w')
@@ -105,16 +108,19 @@ def bin_copy(source, target, env):
# #
extra_variant = "" extra_variant = ""
if env.get('PIOENV') == "ci_s3_16M_P": if env.get('PIOENV') == "ci_s3_16M_P":
extra_variant = "EMS-ESP-" + app_version.replace(".", "_") + "-ESP32_S3" extra_variant = "EMS-ESP-" + \
app_version.replace(".", "_") + "-ESP32_S3"
elif env.get('PIOENV') == "ci_s_4M": elif env.get('PIOENV') == "ci_s_4M":
extra_variant = "EMS-ESP-" + app_version.replace(".", "_") + "-ESP32" extra_variant = "EMS-ESP-" + app_version.replace(".", "_") + "-ESP32"
if extra_variant: if extra_variant:
extra_bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, extra_variant) extra_bin_file = "{}firmware{}{}.bin".format(
OUTPUT_DIR, os.path.sep, extra_variant)
if os.path.isfile(extra_bin_file): if os.path.isfile(extra_bin_file):
os.remove(extra_bin_file) os.remove(extra_bin_file)
extra_md5_file = "{}firmware{}{}.md5".format(OUTPUT_DIR, os.path.sep, extra_variant) extra_md5_file = "{}firmware{}{}.md5".format(
OUTPUT_DIR, os.path.sep, extra_variant)
if os.path.isfile(extra_md5_file): if os.path.isfile(extra_md5_file):
os.remove(extra_md5_file) os.remove(extra_md5_file)
@@ -124,5 +130,6 @@ def bin_copy(source, target, env):
print("*********************************************") print("*********************************************")
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_copy]) env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_copy])
env.AddPostAction("$BUILD_DIR/${PROGNAME}.md5", [bin_copy]) env.AddPostAction("$BUILD_DIR/${PROGNAME}.md5", [bin_copy])

View File

@@ -14,13 +14,15 @@ import platform # For getting the operating system type
import subprocess # For executing a shell command import subprocess # For executing a shell command
from termcolor import cprint from termcolor import cprint
def print_success(x): return cprint(x, 'green') def print_success(x): return cprint(x, 'green')
def print_fail(x): return cprint(x, 'red') def print_fail(x): return cprint(x, 'red')
def ping_until_up(ip, text): def ping_until_up(ip, text):
print(text + "...", flush=True, end="") print(text + "...", flush=True, end="")
time.sleep(1) time.sleep(1)
param = '-n' if platform.system().lower()=='windows' else '-c' param = '-n' if platform.system().lower() == 'windows' else '-c'
command = ["ping", param, "2", ip] command = ["ping", param, "2", ip]
while True: while True:
if (subprocess.run(args=command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0): if (subprocess.run(args=command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0):
@@ -30,13 +32,15 @@ def ping_until_up(ip, text):
print(".", flush=True, end="") print(".", flush=True, end="")
time.sleep(1) time.sleep(1)
def run_test(ip, wait, name, token): def run_test(ip, wait, name, token):
BASE_URL = "http://" + str(ip) BASE_URL = "http://" + str(ip)
INFO_URL = BASE_URL + "/api/system/info" INFO_URL = BASE_URL + "/api/system/info"
RESTART_URL = BASE_URL + "/api/system/restart" RESTART_URL = BASE_URL + "/api/system/restart"
TEST_URL = BASE_URL + "/api?device=system&cmd=test&data=" + name TEST_URL = BASE_URL + "/api?device=system&cmd=test&data=" + name
GET_HEADERS = { 'Content-Type': 'application/json'} GET_HEADERS = {'Content-Type': 'application/json'}
GET_HEADERS_SECURE = { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + str(token) } GET_HEADERS_SECURE = {'Content-Type': 'application/json',
'Authorization': 'Bearer ' + str(token)}
# BODY = json.dumps({ "value": 22.5 }) # BODY = json.dumps({ "value": 22.5 })
start = timer() start = timer()
@@ -51,12 +55,15 @@ def run_test(ip, wait, name, token):
end = timer() end = timer()
# check if IP exists # check if IP exists
ping_until_up(ip, "(" + str(round(end - start, 1)) + ")\t1. Checking if EMS-ESP is reachable") ping_until_up(ip, "(" + str(round(end - start, 1)) +
")\t1. Checking if EMS-ESP is reachable")
end = timer() end = timer()
# Restart EMS-ESP # Restart EMS-ESP
print("(" + str(round(end - start, 1)) + ")\t2. Doing a cold restart...", end="") print("(" + str(round(end - start, 1)) +
response = requests.get(RESTART_URL, headers=GET_HEADERS_SECURE, verify=False) ")\t2. Doing a cold restart...", end="")
response = requests.get(
RESTART_URL, headers=GET_HEADERS_SECURE, verify=False)
if (response.status_code != 200): if (response.status_code != 200):
print_fail("Failed") print_fail("Failed")
return return
@@ -64,20 +71,24 @@ def run_test(ip, wait, name, token):
end = timer() end = timer()
# Wait for EMS-ESP to come back up and reconnect to WiFi # Wait for EMS-ESP to come back up and reconnect to WiFi
ping_until_up(ip, "(" + str(round(end - start, 1)) + ")\t3. Waiting for EMS-ESP to come back online") ping_until_up(ip, "(" + str(round(end - start, 1)) +
")\t3. Waiting for EMS-ESP to come back online")
end = timer() end = timer()
print("(" + str(round(end - start, 1)) + ")\t4. Getting initial memory stats...", flush=True, end="") print("(" + str(round(end - start, 1)) +
")\t4. Getting initial memory stats...", flush=True, end="")
time.sleep(1) time.sleep(1)
response = requests.get(INFO_URL, headers=GET_HEADERS, verify=False) response = requests.get(INFO_URL, headers=GET_HEADERS, verify=False)
uptime_a = response.json()['System Info']['uptime (seconds)'] uptime_a = response.json()['System Info']['uptime (seconds)']
freemem_a = response.json()['System Info']['free mem'] freemem_a = response.json()['System Info']['free mem']
maxalloc_a = response.json()['System Info']['max alloc'] maxalloc_a = response.json()['System Info']['max alloc']
print_success("Uptime is " + str(uptime_a) + " secs, Free mem/Max alloc before=" + str(freemem_a) + "/" + str(maxalloc_a) ) print_success("Uptime is " + str(uptime_a) +
" secs, Free mem/Max alloc before=" + str(freemem_a) + "/" + str(maxalloc_a))
end = timer() end = timer()
# run test # run test
print("(" + str(round(end - start, 1)) + ")\t5. Running test called '" + name + "'...", end="") print("(" + str(round(end - start, 1)) +
")\t5. Running test called '" + name + "'...", end="")
response = requests.get(TEST_URL, headers=GET_HEADERS, verify=False) response = requests.get(TEST_URL, headers=GET_HEADERS, verify=False)
test_output = response.json()['message'] test_output = response.json()['message']
if (test_output != 'OK'): if (test_output != 'OK'):
@@ -87,25 +98,29 @@ def run_test(ip, wait, name, token):
end = timer() end = timer()
# wait n seconds # wait n seconds
print("(" + str(round(end - start, 1)) + ")\t6. Waiting for " + str(wait) + " seconds...", flush=True, end="") print("(" + str(round(end - start, 1)) + ")\t6. Waiting for " +
str(wait) + " seconds...", flush=True, end="")
time.sleep(wait) time.sleep(wait)
print_success("Done") print_success("Done")
end = timer() end = timer()
# get latest stats # get latest stats
print("(" + str(round(end - start, 1)) + ")\t7. Getting latest memory stats...", end="") print("(" + str(round(end - start, 1)) +
")\t7. Getting latest memory stats...", end="")
response = requests.get(INFO_URL, headers=GET_HEADERS, verify=False) response = requests.get(INFO_URL, headers=GET_HEADERS, verify=False)
uptime_b = response.json()['System Info']['uptime (seconds)'] uptime_b = response.json()['System Info']['uptime (seconds)']
freemem_b = response.json()['System Info']['free mem'] freemem_b = response.json()['System Info']['free mem']
maxalloc_b = response.json()['System Info']['max alloc'] maxalloc_b = response.json()['System Info']['max alloc']
print_success("Uptime is " + str(uptime_b) + " secs, Free mem/Max alloc after=" + str(freemem_b) + "/" + str(maxalloc_b) ) print_success("Uptime is " + str(uptime_b) +
" secs, Free mem/Max alloc after=" + str(freemem_b) + "/" + str(maxalloc_b))
print() print()
# check if it worked and report back # check if it worked and report back
if (uptime_b <= uptime_a): if (uptime_b <= uptime_a):
print(" Error! EMS-ESP crashed and restarted :-(") print(" Error! EMS-ESP crashed and restarted :-(")
else: else:
print("In the " + str(uptime_b - uptime_a) + " seconds elapsed, we have Free mem/Max alloc: ", end="") print("In the " + str(uptime_b - uptime_a) +
" seconds elapsed, we have Free mem/Max alloc: ", end="")
cprint("before=" + str(freemem_a) + "/" + str(maxalloc_a) + cprint("before=" + str(freemem_a) + "/" + str(maxalloc_a) +
" after=" + str(freemem_b) + "/" + str(maxalloc_b) + " after=" + str(freemem_b) + "/" + str(maxalloc_b) +
" diff=" + str(freemem_a - freemem_b) + "/" + str(maxalloc_a - maxalloc_b), "cyan", attrs=["bold"]) " diff=" + str(freemem_a - freemem_b) + "/" + str(maxalloc_a - maxalloc_b), "cyan", attrs=["bold"])
@@ -113,11 +128,17 @@ def run_test(ip, wait, name, token):
# finish # finish
print() print()
# main # main
parser = argparse.ArgumentParser(description="Benchmark EMS-ESP, memory profiler") parser = argparse.ArgumentParser(
parser.add_argument("-i", "--ip", metavar="IP", type=str, default="ems-esp.local", help="IP address of EMS-ESP") description="Benchmark EMS-ESP, memory profiler")
parser.add_argument("-w", "--wait", metavar="WAIT", type=int, default="10", help="time to wait between test") parser.add_argument("-i", "--ip", metavar="IP", type=str,
parser.add_argument("-n", "--name", metavar="NAME", type=str, default="memory", help="Name of test to run") default="ems-esp.local", help="IP address of EMS-ESP")
parser.add_argument("-t", "--token", metavar="TOKEN", type=str, help="Bearer Token") parser.add_argument("-w", "--wait", metavar="WAIT", type=int,
default="10", help="time to wait between test")
parser.add_argument("-n", "--name", metavar="NAME", type=str,
default="memory", help="Name of test to run")
parser.add_argument("-t", "--token", metavar="TOKEN",
type=str, help="Bearer Token")
args = parser.parse_args() args = parser.parse_args()
run_test(**vars(args)) run_test(**vars(args))

View File

@@ -5,6 +5,7 @@ Import("env")
OUTPUT_DIR = "build{}".format(os.path.sep) OUTPUT_DIR = "build{}".format(os.path.sep)
def move_file(source, target, env): def move_file(source, target, env):
# get the build info # get the build info
@@ -57,4 +58,5 @@ def move_file(source, target, env):
print("Executing file") print("Executing file")
os.system(bin_file) os.system(bin_file)
env.AddPostAction("$BUILD_DIR/${PROGNAME}", [move_file]) env.AddPostAction("$BUILD_DIR/${PROGNAME}", [move_file])

View File

@@ -192,10 +192,12 @@ for entity in entities:
# set size for string entities # set size for string entities
if entity["modbus count"] == "0" and entity_dev_name in string_sizes: if entity["modbus count"] == "0" and entity_dev_name in string_sizes:
entity["modbus count"] = -(-string_sizes[entity_dev_name] // 2) # divide and round up entity["modbus count"] = - \
(-string_sizes[entity_dev_name] // 2) # divide and round up
if int(entity["modbus count"]) <= 0: if int(entity["modbus count"]) <= 0:
raise Exception('Entity "' + entity_shortname + '" does not have a size - string sizes need to be added manually to update_modbus_registers.py') raise Exception('Entity "' + entity_shortname +
'" does not have a size - string sizes need to be added manually to update_modbus_registers.py')
# if entity["modbus count"] == "0": # if entity["modbus count"] == "0":
# print("ignoring " + entity_dev_name + " - it has a register length of zero") # print("ignoring " + entity_dev_name + " - it has a register length of zero")
@@ -254,7 +256,8 @@ for device_type_name in device_type_names:
for entity_name, modbus_info in sorted(entities.items(), key=lambda x: int(x[1]["modbus offset"])): for entity_name, modbus_info in sorted(entities.items(), key=lambda x: int(x[1]["modbus offset"])):
params = { params = {
'devtype': "dt::" + device_type_name, 'devtype': "dt::" + device_type_name,
"tagtype": tag_to_tagtype[int(tag)], # re.sub(r"[0-9]+", "*", tag), # re.sub(r"[0-9]+", "*", tag),
"tagtype": tag_to_tagtype[int(tag)],
"shortname": 'FL_(' + listNames[entity_name] + ")", "shortname": 'FL_(' + listNames[entity_name] + ")",
"entity_name": entity_name, "entity_name": entity_name,
'registeroffset': modbus_info["modbus offset"], 'registeroffset': modbus_info["modbus offset"],

View File

@@ -33,14 +33,17 @@ except ImportError:
from tqdm import tqdm from tqdm import tqdm
from termcolor import cprint from termcolor import cprint
def print_success(x): return cprint(x, 'green') def print_success(x): return cprint(x, 'green')
def print_fail(x): return cprint('Error: '+x, 'red') def print_fail(x): return cprint('Error: '+x, 'red')
def on_upload(source, target, env): def on_upload(source, target, env):
# make sure we have set the upload_protocol to custom # make sure we have set the upload_protocol to custom
if env.get('UPLOAD_PROTOCOL') != 'custom': if env.get('UPLOAD_PROTOCOL') != 'custom':
print_fail("Please set upload_protocol = custom in your pio_local.ini file when using upload.py") print_fail(
"Please set upload_protocol = custom in your pio_local.ini file when using upload.py")
return return
# first check authentication # first check authentication
@@ -52,7 +55,6 @@ def on_upload(source, target, env):
print_fail('Missing settings. Add these to your pio_local.ini file: \n\ncustom_username=username\ncustom_password=password\ncustom_emsesp_ip=ems-esp.local\n') print_fail('Missing settings. Add these to your pio_local.ini file: \n\ncustom_username=username\ncustom_password=password\ncustom_emsesp_ip=ems-esp.local\n')
return return
emsesp_url = "http://" + env.GetProjectOption('custom_emsesp_ip') emsesp_url = "http://" + env.GetProjectOption('custom_emsesp_ip')
parsed_url = urlparse(emsesp_url) parsed_url = urlparse(emsesp_url)
host_ip = parsed_url.netloc host_ip = parsed_url.netloc
@@ -75,10 +77,12 @@ def on_upload(source, target, env):
"password": password "password": password
} }
response = requests.post(signon_url, json=username_password, headers=signon_headers) response = requests.post(
signon_url, json=username_password, headers=signon_headers)
if response.status_code != 200: if response.status_code != 200:
print_fail("Authentication with EMS-ESP failed (code " + str(response.status_code) + ")") print_fail("Authentication with EMS-ESP failed (code " +
str(response.status_code) + ")")
return return
print_success("Authentication with EMS-ESP successful") print_success("Authentication with EMS-ESP successful")
@@ -105,7 +109,8 @@ def on_upload(source, target, env):
unit_divisor=1024 unit_divisor=1024
) )
monitor = MultipartEncoderMonitor(encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n)) monitor = MultipartEncoderMonitor(
encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))
post_headers = { post_headers = {
'Host': host_ip, 'Host': host_ip,
@@ -123,7 +128,8 @@ def on_upload(source, target, env):
upload_url = f"{emsesp_url}/rest/uploadFile" upload_url = f"{emsesp_url}/rest/uploadFile"
response = requests.post(upload_url, data=monitor, headers=post_headers) response = requests.post(
upload_url, data=monitor, headers=post_headers)
bar.close() bar.close()
time.sleep(0.1) time.sleep(0.1)
@@ -148,8 +154,10 @@ def on_upload(source, target, env):
restart_url = f"{emsesp_url}/api/system/restart" restart_url = f"{emsesp_url}/api/system/restart"
response = requests.get(restart_url, headers=restart_headers) response = requests.get(restart_url, headers=restart_headers)
if response.status_code != 200: if response.status_code != 200:
print_fail("Restart failed (code " + str(response.status_code) + ")") print_fail("Restart failed (code " +
str(response.status_code) + ")")
print() print()
env.Replace(UPLOADCMD=on_upload) env.Replace(UPLOADCMD=on_upload)

View File

@@ -19,9 +19,11 @@ from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
from tqdm import tqdm from tqdm import tqdm
from termcolor import cprint from termcolor import cprint
def print_success(x): return cprint(x, 'green') def print_success(x): return cprint(x, 'green')
def print_fail(x): return cprint(x, 'red') def print_fail(x): return cprint(x, 'red')
def upload(file, ip, username, password): def upload(file, ip, username, password):
# Print welcome message # Print welcome message
@@ -51,10 +53,12 @@ def upload(file, ip, username, password):
"password": password "password": password
} }
response = requests.post(signon_url, json=username_password, headers=signon_headers, auth=None) response = requests.post(
signon_url, json=username_password, headers=signon_headers, auth=None)
if response.status_code != 200: if response.status_code != 200:
print_fail("Authentication failed (code " + str(response.status_code) + ")") print_fail("Authentication failed (code " +
str(response.status_code) + ")")
return return
print_success("Authentication successful") print_success("Authentication successful")
@@ -79,7 +83,8 @@ def upload(file, ip, username, password):
unit_divisor=1024 unit_divisor=1024
) )
monitor = MultipartEncoderMonitor(encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n)) monitor = MultipartEncoderMonitor(
encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))
post_headers = { post_headers = {
'Host': host_ip, 'Host': host_ip,
@@ -97,7 +102,8 @@ def upload(file, ip, username, password):
upload_url = f"{emsesp_url}/rest/uploadFile" upload_url = f"{emsesp_url}/rest/uploadFile"
response = requests.post(upload_url, data=monitor, headers=post_headers, auth=None) response = requests.post(
upload_url, data=monitor, headers=post_headers, auth=None)
bar.close() bar.close()
time.sleep(0.1) time.sleep(0.1)
@@ -120,16 +126,21 @@ def upload(file, ip, username, password):
restart_url = f"{emsesp_url}/api/system/restart" restart_url = f"{emsesp_url}/api/system/restart"
response = requests.get(restart_url, headers=restart_headers) response = requests.get(restart_url, headers=restart_headers)
if response.status_code != 200: if response.status_code != 200:
print_fail("Restart failed (code " + str(response.status_code) + ")") print_fail("Restart failed (code " +
str(response.status_code) + ")")
print() print()
# main # main
parser = argparse.ArgumentParser(description="EMS-ESP Firmware Upload") parser = argparse.ArgumentParser(description="EMS-ESP Firmware Upload")
parser.add_argument("-f", "--file", metavar="FILE", required=True, type=str, help="firmware file") parser.add_argument("-f", "--file", metavar="FILE",
parser.add_argument("-i", "--ip", metavar="IP", type=str, default="ems-esp.local", help="IP address of EMS-ESP") required=True, type=str, help="firmware file")
parser.add_argument("-u", "--username", metavar="USERNAME", type=str, default="admin", help="admin user") parser.add_argument("-i", "--ip", metavar="IP", type=str,
parser.add_argument("-p", "--password", metavar="PASSWORD", type=str, default="admin", help="admin password") default="ems-esp.local", help="IP address of EMS-ESP")
parser.add_argument("-u", "--username", metavar="USERNAME",
type=str, default="admin", help="admin user")
parser.add_argument("-p", "--password", metavar="PASSWORD",
type=str, default="admin", help="admin password")
args = parser.parse_args() args = parser.parse_args()
upload(**vars(args)) upload(**vars(args))

View File

@@ -1731,7 +1731,8 @@ void EMSESP::start_serial_console() {
void EMSESP::shell_prompt() { void EMSESP::shell_prompt() {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
serial_console_.println(); serial_console_.println();
serial_console_.println("Press CTRL-C to activate this serial console"); serial_console_.printf("EMS-ESP %s: press CTRL-C to activate this serial console", EMSESP_APP_VERSION);
serial_console_.println();
#endif #endif
} }