-#include "Somfy.h"
-#ifndef webserver_h
-#define webserver_h
-class Web {
- public:
- bool uploadSuccess = false;
- void sendCORSHeaders(WebServer &server);
- void sendCacheHeaders(uint32_t seconds=604800);
- void startup();
- void handleLogin(WebServer &server);
- void handleLogout(WebServer &server);
- void handleStreamFile(WebServer &server, const char *filename, const char *encoding);
- void handleController(WebServer &server);
- void handleLoginContext(WebServer &server);
- void handleGetRepeaters(WebServer &server);
- void handleGetRooms(WebServer &server);
- void handleGetShades(WebServer &server);
- void handleGetGroups(WebServer &server);
- void handleShadeCommand(WebServer &server);
- void handleRepeatCommand(WebServer &server);
- void handleGroupCommand(WebServer &server);
- void handleTiltCommand(WebServer &server);
- void handleDiscovery(WebServer &server);
- void handleNotFound(WebServer &server);
- void handleRoom(WebServer &server);
- void handleShade(WebServer &server);
- void handleGroup(WebServer &server);
- void handleSetPositions(WebServer &server);
- void handleSetSensor(WebServer &server);
- void handleDownloadFirmware(WebServer &server);
- void handleBackup(WebServer &server, bool attach = false);
- void handleReboot(WebServer &server);
- void handleDeserializationError(WebServer &server, DeserializationError &err);
- void begin();
- void loop();
- void end();
- // Web Handlers
- bool createAPIToken(const IPAddress ipAddress, char *token);
- bool createAPIToken(const char *payload, char *token);
- bool createAPIPinToken(const IPAddress ipAddress, const char *pin, char *token);
- bool createAPIPasswordToken(const IPAddress ipAddress, const char *username, const char *password, char *token);
- bool isAuthenticated(WebServer &server, bool cfg = false);
-
- //void chunkRoomsResponse(WebServer &server, const char *elem = nullptr);
- //void chunkShadesResponse(WebServer &server, const char *elem = nullptr);
- //void chunkGroupsResponse(WebServer &server, const char *elem = nullptr);
- //void chunkGroupResponse(WebServer &server, SomfyGroup *, const char *prefix = nullptr);
-};
-#endif
diff --git a/app_version.py b/app_version.py
new file mode 100644
index 00000000..533442ac
--- /dev/null
+++ b/app_version.py
@@ -0,0 +1,32 @@
+import os
+Import("env")
+
+# Define the folder and filename
+DATA_FOLDER = "data-src"
+FILENAME = "appversion"
+
+# Construct the full path: /your/project/path/data-src/appversion
+project_dir = env.get("PROJECT_DIR")
+version_file_path = os.path.join(project_dir, DATA_FOLDER, FILENAME)
+
+# Default fallback if something goes wrong
+version = "0.0.0"
+
+if os.path.exists(version_file_path):
+ try:
+ with open(version_file_path, "r") as f:
+ version = f.read().strip()
+ # Clean output for the PlatformIO console
+ print(f"--- SUCCESS: Found version {version} in {version_file_path} ---")
+ except Exception as e:
+ print(f"--- ERROR: could not read version file: {e} ---")
+else:
+ print(f"--- ERROR: File NOT FOUND at {version_file_path} ---")
+
+# Apply to the build environment
+# We use escaped quotes so C++ treats it as a string literal "vX.X.X"
+full_version_str = f'\\"v{version}\\"'
+
+env.Append(CPPDEFINES=[
+ ("FW_VERSION", full_version_str)
+])
\ No newline at end of file
diff --git a/archive_elf.py b/archive_elf.py
new file mode 100644
index 00000000..0e5416ee
--- /dev/null
+++ b/archive_elf.py
@@ -0,0 +1,45 @@
+"""
+PlatformIO post-build script: archive firmware.elf files.
+
+Copies firmware.elf to elf_archive/ with a timestamp after each build.
+Keeps only the last 10 files to avoid filling up disk space.
+
+Usage in platformio.ini
+-----------------------
+ extra_scripts = post:archive_elf.py
+"""
+
+Import("env")
+
+import os
+import shutil
+from datetime import datetime
+
+MAX_ARCHIVES = 10
+ARCHIVE_DIR = os.path.join(env.subst("$PROJECT_DIR"), "elf_archive")
+
+
+def archive_elf(source, target, env):
+ elf_path = os.path.join(env.subst("$BUILD_DIR"), "firmware.elf")
+ if not os.path.isfile(elf_path):
+ print("[archive_elf] firmware.elf not found, skipping.")
+ return
+
+ os.makedirs(ARCHIVE_DIR, exist_ok=True)
+
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ dest = os.path.join(ARCHIVE_DIR, f"firmware_{timestamp}.elf")
+ shutil.copy2(elf_path, dest)
+ print(f"[archive_elf] Saved {dest}")
+
+ # Keep only the last MAX_ARCHIVES files
+ files = sorted(
+ [f for f in os.listdir(ARCHIVE_DIR) if f.endswith(".elf")],
+ )
+ while len(files) > MAX_ARCHIVES:
+ old = os.path.join(ARCHIVE_DIR, files.pop(0))
+ os.remove(old)
+ print(f"[archive_elf] Removed old archive {old}")
+
+
+env.AddPostAction("$BUILD_DIR/firmware.elf", archive_elf)
diff --git a/data/apple-icon.png b/data-src/apple-icon.png
similarity index 100%
rename from data/apple-icon.png
rename to data-src/apple-icon.png
diff --git a/data-src/appversion b/data-src/appversion
new file mode 100644
index 00000000..9c25f93c
--- /dev/null
+++ b/data-src/appversion
@@ -0,0 +1 @@
+3.0.13
\ No newline at end of file
diff --git a/data/favicon.png b/data-src/favicon.png
similarity index 100%
rename from data/favicon.png
rename to data-src/favicon.png
diff --git a/data/icon.png b/data-src/icon.png
similarity index 100%
rename from data/icon.png
rename to data-src/icon.png
diff --git a/data/icon.svg b/data-src/icon.svg
similarity index 100%
rename from data/icon.svg
rename to data-src/icon.svg
diff --git a/data/icons.css b/data-src/icons.css
similarity index 100%
rename from data/icons.css
rename to data-src/icons.css
diff --git a/data/index.html b/data-src/index.html
similarity index 97%
rename from data/index.html
rename to data-src/index.html
index fda06701..4cc3eef0 100644
--- a/data/index.html
+++ b/data-src/index.html
@@ -8,9 +8,9 @@
-
-
-
+
+
+
@@ -114,7 +114,7 @@
rel="apple-touch-startup-image">
-
+
@@ -246,6 +246,8 @@
Min:
+ Uptime:
+
+
+
+
+
@@ -986,7 +992,7 @@
-
+
-