diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 18f9f61..6818f2d 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -65,7 +65,6 @@ jobs: - name: Create release uses: ncipollo/release-action@v1 with: - name: release-${{ steps.dateAndTime.outputs.dateAndTime }} artifacts: "output/full-firmware.bin,output/full-firmware.sha256,.pio/build/lolin_s3_mini_qr/*.bin" allowUpdates: true removeArtifacts: true diff --git a/data/src/js/script.ts b/data/src/js/script.ts index 5a27700..e995f4f 100644 --- a/data/src/js/script.ts +++ b/data/src/js/script.ts @@ -149,6 +149,8 @@ fetch('/api/settings', { document.getElementById('fullRefreshMin').value = jsonData.fullRefreshMin; document.getElementById('tzOffset').value = jsonData.tzOffset; document.getElementById('mempoolInstance').value = jsonData.mempoolInstance; + document.getElementById('hostnamePrefix').value = jsonData.hostnamePrefix; + document.getElementById('minSecPriceUpd').value = jsonData.minSecPriceUpd; if (jsonData.gitRev) diff --git a/scripts/find_btclocks.py b/scripts/find_btclocks.py new file mode 100644 index 0000000..79aa3de --- /dev/null +++ b/scripts/find_btclocks.py @@ -0,0 +1,86 @@ +import sys +import os +import logging + +from os.path import expanduser + +sys.path.append(expanduser("~") + '/.platformio/packages/framework-arduinoespressif32/tools') + +from zeroconf import ServiceBrowser, ServiceListener, Zeroconf +from requests import request +import espota +import argparse +import random +import subprocess + +FLASH = 0 +SPIFFS = 100 + +PROGRESS = True +TIMEOUT = 10 + +revision = ( + subprocess.check_output(["git", "rev-parse", "HEAD"]) + .strip() + .decode("utf-8") +) + +class Listener(ServiceListener): + + def update_service(self, zc: Zeroconf, type_: str, name: str) -> None: + print(f"Service {name} updated") + + def remove_service(self, zc: Zeroconf, type_: str, name: str) -> None: + print(f"Service {name} removed") + + def add_service(self, zc: Zeroconf, type_: str, name: str) -> None: + global PROGRESS + PROGRESS = True + espota.PROGRESS = True + global TIMEOUT + TIMEOUT = 10 + espota.TIMEOUT = 10 + info = zc.get_service_info(type_, name) + if (name.startswith('btclock-')): + print(f"Service {name} added") + print("Address: " + str(info.parsed_addresses())) + # python ~/.platformio/packages/framework-arduinoespressif32/tools/espota.py -i 192.168.20.231 -f .pio/build/lolin_s3_mini_qr/firmware.bin -r + #arguments = [f"-i {str()} -f -r"] + namespace = argparse.Namespace( + esp_ip=info.parsed_addresses()[0], + image=f"{os.getcwd()}/.pio/build/lolin_s3_mini_qr/firmware.bin", + littlefs=f"{os.getcwd()}/.pio/build/lolin_s3_mini_qr/littlefs.bin", + progress=True + ) + if (str(info.properties.get(b"version").decode())) != "3.0": + print("Too old version") + return + + if (str(info.properties.get(b"rev").decode())) == revision: + print("Newest version, skipping but updating LittleFS") + espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.littlefs, SPIFFS) + + else: + print("Different version, going to update") + #espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.littlefs, SPIFFS) + + #espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.image, FLASH) + #print(arguments) + + #logging.basicConfig(level = logging.DEBUG, format = '%(asctime)-8s [%(levelname)s]: %(message)s', datefmt = '%H:%M:%S') + + #espota.serve(namespace.esp_ip, "0.0.0.0", 3232, random.randint(10000,60000), "", namespace.image, FLASH) + #address = "http://" + info.parsed_addresses()[0]+"/api/restart" + #response = request("GET", address) + #espota.main(namespace) + +zconf = Zeroconf() + +serviceListener = Listener() + +browser = ServiceBrowser(zconf, "_http._tcp.local.", serviceListener) + +try: + input("Press enter to exit...\n\n") +finally: + zconf.close() \ No newline at end of file diff --git a/scripts/hash.sh b/scripts/hash.sh new file mode 100755 index 0000000..cd04d31 --- /dev/null +++ b/scripts/hash.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +data_directory="data/build" + +# Use find to list all files in the directory (including hidden files), sort them, and then calculate the hash +#hash=$(find "$data_directory" -type f \( ! -iname ".*" \) | LC_ALL=C sort | xargs cat | shasum -a 256 | cut -d ' ' -f 1) +hash=$(find "$data_directory" -type f \( ! -iname ".*" \) | LC_ALL=C sort | xargs -I {} cat {} | shasum -a 256 | cut -d ' ' -f 1) + +echo "Hash of files in $data_directory: $hash" \ No newline at end of file diff --git a/scripts/hash_fsdata.py b/scripts/hash_fsdata.py new file mode 100644 index 0000000..9e97055 --- /dev/null +++ b/scripts/hash_fsdata.py @@ -0,0 +1,75 @@ +import os +from pathlib import Path +import hashlib + +def calculate_file_hash(file_path): + hasher = hashlib.sha256() + with open(file_path, 'rb') as file: + for chunk in iter(lambda: file.read(4096), b''): + hasher.update(chunk) + return hasher.hexdigest() + +# def calculate_directory_hash(directory_path): +# file_hashes = [] +# for root, dirs, files in os.walk(directory_path): +# for file_name in sorted(files): # Sorting based on filenames +# if not file_name.startswith('.'): # Skip dotfiles +# file_path = os.path.join(root, file_name) +# file_hash = calculate_file_hash(file_path) +# file_hashes.append((file_path, file_hash)) + +# combined_hash = hashlib.sha256() +# for file_path, _ in sorted(file_hashes): # Sorting based on filenames +# print(f"{file_path}: {file_hash}") +# file_hash = calculate_file_hash(file_path) +# combined_hash.update(file_hash.encode('utf-8')) + +# return combined_hash.hexdigest() + + +# def calculate_directory_hash(directory_path): +# combined_hash = hashlib.sha256() +# for root, dirs, files in os.walk(directory_path): +# for file_name in sorted(files): # Sorting based on filenames +# if not file_name.startswith('.'): # Skip dotfiles +# file_path = os.path.join(root, file_name) +# with open(file_path, 'rb') as file: +# print(f"{file_path}") +# for chunk in iter(lambda: file.read(4096), b''): +# combined_hash.update(chunk) + +# return combined_hash.hexdigest() + +# def calculate_directory_hash(directory_path): +# combined_content = b'' +# for root, dirs, files in os.walk(directory_path): +# for file_name in sorted(files): # Sorting based on filenames +# if not file_name.startswith('.'): # Skip dotfiles +# file_path = os.path.join(root, file_name) +# with open(file_path, 'rb') as file: +# print(f"{file_path}") +# combined_content += file.read() + +# combined_hash = hashlib.sha256(combined_content).hexdigest() +# return combined_hash + +def calculate_directory_hash(directory_path): + file_paths = [] + for root, dirs, files in os.walk(directory_path): + for file_name in files: + if not file_name.startswith('.'): # Skip dotfiles + file_paths.append(os.path.join(root, file_name)) + + combined_content = b'' + for file_path in sorted(file_paths): # Sorting based on filenames + with open(file_path, 'rb') as file: + print(f"{file_path}") + combined_content += file.read() + + combined_hash = hashlib.sha256(combined_content).hexdigest() + return combined_hash + +data_directory = 'data/build' +directory_hash = calculate_directory_hash(data_directory) + +print(f"Hash of files in {data_directory}: {directory_hash}") \ No newline at end of file diff --git a/src/lib/utils.cpp b/src/lib/utils.cpp index abf5d51..445b1b0 100644 --- a/src/lib/utils.cpp +++ b/src/lib/utils.cpp @@ -10,8 +10,9 @@ String getMyHostname() { //WiFi.macAddress(mac); esp_efuse_mac_get_default(mac); char hostname[15]; - snprintf(hostname, sizeof(hostname), "btclock-%02x%02x%02x", - mac[3], mac[4], mac[5]); + String hostnamePrefix = preferences.getString("hostnamePrefix", "btclock"); + snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x", + hostnamePrefix, mac[3], mac[4], mac[5]); return hostname; } diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index cb4f378..19af52c 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -272,6 +272,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", true); root["otaEnabled"] = preferences.getBool("otaEnabled", true); root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", false); + root["hostnamePrefix"] = preferences.getString("hostnamePrefix", "btclock"); root["hostname"] = getMyHostname(); root["ip"] = WiFi.localIP(); @@ -431,6 +432,14 @@ void onApiSettingsPost(AsyncWebServerRequest *request) settingsChanged = true; } + if (request->hasParam("hostnamePrefix", true)) + { + AsyncWebParameter *hostnamePrefix = request->getParam("hostnamePrefix", true); + + preferences.putString("hostnamePrefix", hostnamePrefix->value().c_str()); + settingsChanged = true; + } + if (request->hasParam("ledBrightness", true)) { AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);