Compare commits

...

4 Commits

11 changed files with 135 additions and 39 deletions

View File

@ -1,7 +1,3 @@
# SCRIPT TO GZIP CRITICAL FILES FOR ACCELERATED WEBSERVING
# see also https://community.platformio.org/t/question-esp32-compress-files-in-data-to-gzip-before-upload-possible-to-spiffs/6274/10
import glob
import shutil
import gzip
@ -167,10 +163,15 @@ def gzip_webfiles(source, target, env):
shutil.rmtree(data_temp_dir_path)
return
def gzip_binffiles(source, target, env):
git_revision = popen('git rev-parse --short HEAD').read().strip()
custom_flash_version = env.GetProjectOption("custom_flash_version", "0.99")
# Format the target file name
target_filename = f"filesystem_{custom_flash_version}_{git_revision}.fs"
littlefsbin = target[0].get_abspath()
targetbin = os.path.join(os.path.dirname(littlefsbin), 'filesystem.fs')
targetbin = os.path.join(os.path.dirname(littlefsbin), target_filename)
shutil.copyfile(littlefsbin, targetbin)
gzip_file(targetbin, os.path.join(str(targetbin) + '.gz'))
os.remove(targetbin)

View File

@ -7,8 +7,27 @@ from os import popen
git_revision = popen('git rev-parse --short HEAD').read().strip()
env.Replace(PROGNAME="firmware_%s.fw" % git_revision)
env.Append(CPPDEFINES=[('GIT_REV', '\\"{}\\"'.format(git_revision))])
# Versionsnummern aus platformio.ini holen
custom_firmware_version = env.GetProjectOption("custom_firmware_version", "0.99")
custom_flash_version = env.GetProjectOption("custom_flash_version", "0.99")
# Versionsnummern aufteilen in Major und Minor
fw_major, fw_minor = custom_firmware_version.split('.')
fl_major, fl_minor = custom_flash_version.split('.')
# Version in Datei "version" im Ordner "data_src" überschreiben
with open('data_src/version', 'w') as version_file:
version_file.write(custom_flash_version)
# Build-Flags setzen
env.Replace(PROGNAME="firmware_%s_%s.fw" % (custom_firmware_version, git_revision))
env.Append(CPPDEFINES=[
('GIT_REV', '\\"{}\\"'.format(git_revision)),
('FW_MAJOR', fw_major),
('FW_MINOR', fw_minor),
('FL_MAJOR', fl_major),
('FL_MINOR', fl_minor)
])
struct2json.struct2json()
dtcs.build_dtcs()

View File

@ -35,7 +35,7 @@
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
DE Airsoft Timer
<span class="data-devicename">DE Airsoft Timer</span>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar"
aria-controls="collapsingNavbar" aria-expanded="false" aria-label="Toggle navigation">
@ -63,7 +63,7 @@
<div class="col text-center">
<div class="jumbotron">
<img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<h3 class="pt-3">Dark Emergency Timer</h3>
<h3 class="pt-3"><span class="data-devicename">DE Airsoft Timer</span></h3>
</div>
</div>
<!-- Div Group Battery remain -->
@ -96,14 +96,14 @@
<div id="header_faction3" class="col text-center data-name_faction3 text-white p-3">%NAME_FAC_3%</div>
</div>
<div class="row">
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac1.png"
class="rounded mx-auto img-fluid d-block" alt="...">
<div class="col bg-dark text-white p-3 data-activefaction faction-logo faction1">
<img src="static/img/logo_fac1.png" class="rounded mx-auto img-fluid d-block" alt="...">
</div>
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac2.png"
class="rounded mx-auto img-fluid d-block" alt="...">
<div class="col bg-dark text-white p-3 data-activefaction faction-logo faction2">
<img src="static/img/logo_fac2.png" class="rounded mx-auto img-fluid d-block" alt="...">
</div>
<div class="col bg-dark text-white p-3"><img src="static/img/logo_fac3.png"
class="rounded mx-auto img-fluid d-block" alt="...">
<div class="col bg-dark text-white p-3 data-activefaction faction-logo faction3">
<img src="static/img/logo_fac3.png" class="rounded mx-auto img-fluid d-block" alt="...">
</div>
</div>
<div class="row">

View File

@ -8438,4 +8438,23 @@ a.text-dark:hover {
.navbar-dark.bg-primary {
background-color: #111 !important
}
}
.glow-active-faction {
border: 3px solid #FFD700; /* Goldene Umrandung */
box-shadow: 0 0 20px #FFD700; /* Leuchtender Glüheffekt */
animation: glow 1.5s infinite alternate;
border-radius: 10px; /* Abgerundete Ecken */
margin-bottom: 10px; /* Abstand nach unten */
}
@keyframes glow {
from {
box-shadow: 0 0 10px #FFD700;
}
to {
box-shadow: 0 0 20px #FFD700;
}
}

View File

@ -3,6 +3,13 @@ const jsonFilePath = "static/dtc_table.json";
var dtcState = {};
async function processDTCNotifications(dtcArray) {
// Entferne DTCs aus dtcState, die nicht im dtcArray enthalten sind
for (var key in dtcState) {
if (!dtcArray.some((dtc) => parseInt(dtc.split(",")[1]) == key)) {
delete dtcState[key];
}
}
if (dtcArray.length === 0 || dtcArray[0] == "0") {
dtcState = {};
return;
@ -31,14 +38,14 @@ async function processDTCNotifications(dtcArray) {
if (dtcState[errorCode]) {
// Überprüfen, ob sich der Zustand von "previous" auf "active" geändert hat
if (activity !== dtcState[errorCode]) {
dtcState[errorCode] = activity;
if (activity !== dtcState[errorCode].activity) {
dtcState[errorCode].activity = activity;
if (activity === 1) showNotification(description, severity);
}
} else {
// DTC ist neu, Zustand speichern und Benachrichtigung anzeigen
dtcState[errorCode] = activity;
showNotification(description, severity);
// DTC ist neu, Zustand speichern und wenn active, Benachrichtigung anzeigen
dtcState[errorCode] = { activity: activity };
if (activity === 1) showNotification(description, severity);
}
} catch (error) {
console.error("Error processing DTC:", error);
@ -89,14 +96,15 @@ async function showDTCModal(event) {
} catch (error) {
console.error("Fehler beim Abrufen der Beschreibung:", error);
modal.find(".modal-title").text("Fehler");
modal.find(".dtc-desc").text("DTC-Beschreibung konnte nicht geladen werden");
modal
.find(".dtc-desc")
.text("DTC-Beschreibung konnte nicht geladen werden");
}
// Modal anzeigen
modal.modal("show");
}
function fillDTCTable(dtcArray) {
// Referenz auf das Tabellen-Element
var table = document.getElementById("dtc_table");
@ -108,11 +116,28 @@ function fillDTCTable(dtcArray) {
tablediv.hidden = true;
table.innerHTML = "";
return;
} else {
// Zeige das Tabellen-Div, wenn DTC vorhanden sind
tablediv.hidden = false;
}
// Prüfen, ob sich der Inhalt der Tabelle geändert hat
var tableContentChanged = false;
for (var i = 0; i < dtcArray.length; i++) {
var dtcInfo = dtcArray[i].split(",");
var errorCode = parseInt(dtcInfo[1]);
var activity = parseInt(dtcInfo[3]);
if (!dtcState[errorCode] || dtcState[errorCode].activity !== activity) {
tableContentChanged = true;
break;
}
}
if (!tableContentChanged) {
return;
}
// Zeige das Tabellen-Div, wenn DTC vorhanden sind
tablediv.hidden = false;
// Tabelle leeren, bevor sie neu gefüllt wird
table.innerHTML = "";

View File

@ -178,9 +178,12 @@ function fillValuesToHTML(dataset) {
// Wenn das Element ein Settingsabschnitt-div ist
if (dataset[key] == 0) element.style.display = "none";
else element.style.display = "";
} else if (element.tagName === "DIV") {
} else if (element.tagName === "DIV" || element.tagName === "SPAN") {
if (element.classList.contains("format-time")) {
element.innerText = formatTime(dataset[key]);
} else if (element.classList.contains("faction-logo")) {
// Faction-Logo-Logik
updateFactionLogo(element, dataset[key]);
} else {
element.innerText = dataset[key];
}
@ -190,6 +193,10 @@ function fillValuesToHTML(dataset) {
}
}
}
// Aktualisiere den <title>-Tag, wenn der Schlüssel 'devicename' im dataset vorhanden ist
if (key === "devicename") {
document.title = dataset[key];
}
}
}
@ -207,6 +214,22 @@ function formatTime(seconds) {
);
}
function updateFactionLogo(element, faction) {
const glowClass = "glow-active-faction";
const factionClasses = ["faction1", "faction2", "faction3"];
factionClasses.forEach((factionClass) => {
if (
factionClass === "faction" + faction &&
element.classList.contains(factionClass)
) {
element.classList.add(glowClass);
} else {
element.classList.remove(glowClass);
}
});
}
// Funktion zum Setzen des ausgewählten Werts für Dropdowns
function setDropdownValue(selectElement, value) {
for (var i = 0; i < selectElement.options.length; i++) {

View File

@ -12,8 +12,10 @@
#define TRUE 1
#define FALSE 0
#ifndef HOST_NAME
#define HOST_NAME "AirsoftTimer_%08X"
#ifndef DEVICE_NAME
#define HOST_NAME "AirsoftTimer"
#else
#define HOST_NAME DEVICE_NAME
#endif
#define SHUTDOWN_DELAY_MS 5000

View File

@ -11,6 +11,7 @@ typedef struct Globals_s
char systemStatustxt[16] = ""; /**< Text representation of system status */
EERequest_t requestEEAction = EE_IDLE; /**< EEPROM-related request */
char DeviceName[33]; /**< Device name */
char DeviceNameId[sizeof(DeviceName) + 8]; /**< Device name plus 8 chars chipID */
char FlashVersion[10]; /**< Flash version */
uint16_t eePersistanceAdress; /**< EEPROM persistence address */
bool hasDTC;
@ -31,8 +32,8 @@ typedef struct Constants_s
} Constants_t;
const Constants_t constants PROGMEM = {
1, 5, // Firmware_Version
1, 5, // Required Flash Version
FW_MAJOR, FW_MINOR, // Firmware_Version
FL_MAJOR, FL_MINOR, // Required Flash Version
GIT_REV // Git-Hash-String
};

View File

@ -17,6 +17,9 @@ platform = espressif8266
framework = arduino
board = d1_mini
custom_firmware_version = 1.05
custom_flash_version = 1.05
upload_protocol = esptool
upload_speed = 921600
;upload_port = 10.0.1.48

View File

@ -84,7 +84,8 @@ void setup()
system_update_cpu_freq(SYS_CPU_80MHZ);
// Generate a unique device name based on ESP chip ID
snprintf(globals.DeviceName, 32, HOST_NAME, ESP.getChipId());
strncpy(globals.DeviceName, HOST_NAME, sizeof(globals.DeviceName));
snprintf(globals.DeviceNameId, sizeof(globals.DeviceNameId), "%s_%08X", globals.DeviceName, ESP.getChipId());
// Disable WiFi persistent storage
WiFi.persistent(false);
@ -95,7 +96,7 @@ void setup()
#ifdef FEATURE_ENABLE_WIFI_CLIENT
// Configure WiFi settings for client mode if enabled
WiFi.mode(WIFI_STA);
WiFi.setHostname(globals.DeviceName);
WiFi.setHostname(globals.DeviceNameId);
wifiMulti.addAP(QUOTE(WIFI_SSID_CLIENT), QUOTE(WIFI_PASSWORD_CLIENT));
tmrWiFiMaintainConnection.start();
#else
@ -108,7 +109,7 @@ void setup()
Serial.setDebugOutput(false);
Serial.print("\n\n-------------------START-------------------\n");
Serial.print(globals.DeviceName);
Serial.print(globals.DeviceNameId);
Serial.print("\nby Hiabuto Defense\n");
// Initialize EEPROM, load configuration, and persistence data from EEPROM
@ -150,7 +151,7 @@ void setup()
// Set up OTA updates
ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(globals.DeviceName);
ArduinoOTA.setHostname(globals.DeviceNameId);
ArduinoOTA.setPassword(QUOTE(ADMIN_PASSWORD));
ArduinoOTA.onStart([]()
@ -583,7 +584,7 @@ void toggleWiFiAP(bool shutdown)
// Start WiFi in Access Point (AP) mode
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(IPAddress(WIFI_AP_IP_GW), IPAddress(WIFI_AP_IP_GW), IPAddress(255, 255, 255, 0));
WiFi.softAP(globals.DeviceName, QUOTE(WIFI_AP_PASSWORD));
WiFi.softAP(globals.DeviceNameId, QUOTE(WIFI_AP_PASSWORD));
// Stop WiFi maintenance connection ticker if enabled and display debug messages
#ifdef FEATURE_ENABLE_WIFI_CLIENT

View File

@ -71,7 +71,7 @@ void initWebUI()
}
// Initialize mDNS and add service
MDNS.begin(globals.DeviceName);
MDNS.begin(globals.DeviceNameId);
MDNS.addService("http", "tcp", 80);
// Set up WebSocket event handler and attach to web server
@ -342,7 +342,7 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
char buffer[16];
info["DeviceName"] = globals.DeviceName;
info["DeviceNameId"] = globals.DeviceNameId;
sprintf(buffer, "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor);
info["FW-Version"] = buffer;
info["FS-Version"] = globals.FlashVersion;
@ -653,6 +653,7 @@ void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping)
if (send_mapping)
{
const char mapping[] = "MAPPING_STATIC:"
"devicename;"
"active_faction_on_reboot;"
"batteryType;"
"name_faction1;"
@ -669,6 +670,7 @@ void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping)
String temp = "STATIC:";
temp.concat(String(globals.DeviceName) + ";");
temp.concat(String(ConfigData.active_faction_on_reboot) + ";");
temp.concat(String(ConfigData.batteryType) + ";");
temp.concat(String(ConfigData.Faction_1_Name) + ";");