diff --git a/components/firmware/CMakeLists.txt b/components/firmware/CMakeLists.txt index 51a5418..267aca0 100644 --- a/components/firmware/CMakeLists.txt +++ b/components/firmware/CMakeLists.txt @@ -7,6 +7,8 @@ idf_component_register( src/MqttClient.c src/Buttons.c src/SntpClient.c + src/StatusIndicator.c + src/Restarter.c INCLUDE_DIRS ./include PRIV_INCLUDE_DIRS ./src diff --git a/components/firmware/include/nx/firmware/HwConfig.h b/components/firmware/include/nx/firmware/HwConfig.h new file mode 100644 index 0000000..1b84fb5 --- /dev/null +++ b/components/firmware/include/nx/firmware/HwConfig.h @@ -0,0 +1,22 @@ +#ifndef COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_HWCONFIG_H_ +#define COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_HWCONFIG_H_ + +#define DEVICE_ID "dev01" + +#define GPIO_SERVICE_BTN 15 + +#define GPIO_TRIGGER_OUT_1 27 +#define GPIO_TRIGGER_OUT_2 26 +#define GPIO_TRIGGER_OUT_3 25 +#define GPIO_TRIGGER_OUT_4 33 + +#define USED_OUTPUTS_COUNT 4 + +#define GPIO_LED_RED 14 +#define GPIO_LED_GREEN 12 +#define GPIO_LED_BLUE 13 + +#define LED_LEVEL_ON 1 +#define LED_LEVEL_OFF 0 + +#endif /* COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_HWCONFIG_H_ */ diff --git a/components/firmware/include/nx/firmware/Restarter.h b/components/firmware/include/nx/firmware/Restarter.h new file mode 100644 index 0000000..1bbded4 --- /dev/null +++ b/components/firmware/include/nx/firmware/Restarter.h @@ -0,0 +1,6 @@ +#ifndef COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_RESTARTER_H_ +#define COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_RESTARTER_H_ + +void nxStartRestarter(const char* schedule, const char* timezone); + +#endif /* COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_RESTARTER_H_ */ diff --git a/components/firmware/include/nx/firmware/StatusIndicator.h b/components/firmware/include/nx/firmware/StatusIndicator.h new file mode 100644 index 0000000..96719d3 --- /dev/null +++ b/components/firmware/include/nx/firmware/StatusIndicator.h @@ -0,0 +1,20 @@ +#ifndef COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_STATUSINDICATOR_H_ +#define COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_STATUSINDICATOR_H_ + +#include + +typedef enum { + STATUS_BOOT = 0, // cont. red + STATUS_OK, // cont. green + STATUS_OK_WORKING, // 10Hz green + STATUS_OK_ALT, // 1Hz blue (e.g. service mode) + STATUS_SYSTEM_ERROR, // 1Hz red (e.g. wifi not connected) + STATUS_APP_ERROR // 2 x 2Hz + 1s off (e.g. mqtt not connected) +} HwStatus; + +void nxInitStatusIndicator(); +void nxUpdateStatus(HwStatus status); +void nxStatusIndicatorTask(void*); +void nxEnablePowerSavingStatus(bool enable); + +#endif /* COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_STATUSINDICATOR_H_ */ diff --git a/components/firmware/src/MqTriggerHttpServer.c b/components/firmware/src/MqTriggerHttpServer.c index 8856e10..08934be 100644 --- a/components/firmware/src/MqTriggerHttpServer.c +++ b/components/firmware/src/MqTriggerHttpServer.c @@ -54,6 +54,7 @@ static httpd_uri_t uriReboot = { .handler = uriRebootHandler }; + void registerMqTriggerHttpHandlers(void) { httpd_register_uri_handler(server, &uriOptions); @@ -79,7 +80,7 @@ bool nxStartMqTriggerHttpServer(void) // configure server here: config.server_port = 80; - config.max_uri_handlers = 8; + config.max_uri_handlers = 16; config.uri_match_fn = httpd_uri_match_wildcard; // ... diff --git a/components/firmware/src/Restarter.c b/components/firmware/src/Restarter.c new file mode 100644 index 0000000..410f049 --- /dev/null +++ b/components/firmware/src/Restarter.c @@ -0,0 +1,95 @@ +#include "nx/firmware/Restarter.h" + +#include "esp_log.h" +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include + +#define TAG "RESTARTER" + +#define RESTARTER_CHECK_INTERVAL_SEC 10 +#define RESTART_SCHEDULE_SIZE 12 +#define RESTART_SCHEDULE_MIN_LEN 7 // 'x x x x' + +const char* schedule = ""; +const char* tz = ""; + +// day - days from sunday (0 is sunday), schedule - binary schedule from sunday (1 is sunday, 64 is saturday) +int isDayInSchedule(int day, int schedule) +{ + int dayMatch = 1 << day; + int match = (dayMatch & schedule); + return match != 0; +} + +void restarterTask(void* param) +{ + //UNUSED(param); + ESP_LOGI(TAG, "Starting restarter task"); + + if (strlen(schedule) < RESTART_SCHEDULE_MIN_LEN) { + ESP_LOGW(TAG, "Closing restarter task due to the incomplete schedule: [%s]", schedule); + vTaskDelete( NULL ); + return; + } + + long int intervalMs = 1000 * RESTARTER_CHECK_INTERVAL_SEC; + + char scheduleLine[RESTART_SCHEDULE_SIZE]; + strcpy(scheduleLine, schedule); + + int daySchedule = atoi( strtok(scheduleLine, " ") ); + int hour = atoi( strtok(NULL, " ") ); + int minute = atoi( strtok(NULL, " ") ); + int maxUptime = atoi( strtok(NULL, " ") ); + + ESP_LOGI(TAG, "Restart schedule: %i %i %i %i", daySchedule, hour, minute, maxUptime); + + if (daySchedule == 0) { + ESP_LOGI(TAG, "Closing restarter task due to zero days in schedule"); + vTaskDelete( NULL ); + return; + } + + while (1) { + vTaskDelay(intervalMs / portTICK_PERIOD_MS); + + int uptimeMin = portTICK_PERIOD_MS * xTaskGetTickCount() / 1000 / 60; + + time_t now; + struct tm timeinfo; + time(&now); + + // Set timezone to Eastern Standard Time and print local time + setenv("TZ", tz, 1); + tzset(); + localtime_r(&now, &timeinfo); + + if (uptimeMin < maxUptime) { + continue; + } + if (!isDayInSchedule(timeinfo.tm_wday, daySchedule)) { + continue; + } + if (hour != timeinfo.tm_hour || hour == -1) { + continue; + } + if (minute != timeinfo.tm_min) { + continue; + } + + ESP_LOGI(TAG, "all conditions met, restarting..."); + esp_restart(); + } +} + +void nxStartRestarter(const char* scheduleString, const char* timezone) +{ + schedule = scheduleString; + tz = timezone; + + xTaskCreate(restarterTask, "restarter_task", 2048, + (void*)1, tskIDLE_PRIORITY, NULL); +} diff --git a/components/firmware/src/StatusIndicator.c b/components/firmware/src/StatusIndicator.c new file mode 100644 index 0000000..b2a11cc --- /dev/null +++ b/components/firmware/src/StatusIndicator.c @@ -0,0 +1,212 @@ +#include "nx/firmware/StatusIndicator.h" +#include "nx/firmware/HwConfig.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include + + +#define UNUSED(x) (void)(x) + +#define BLINK_GPIO GPIO_LED_GREEN + +#define RED_ON gpio_set_level(GPIO_LED_RED, LED_LEVEL_ON) +#define RED_OFF gpio_set_level(GPIO_LED_RED, LED_LEVEL_OFF) + +#define GREEN_ON gpio_set_level(GPIO_LED_GREEN, LED_LEVEL_ON) +#define GREEN_OFF gpio_set_level(GPIO_LED_GREEN, LED_LEVEL_OFF) + +#define BLUE_ON gpio_set_level(GPIO_LED_BLUE, LED_LEVEL_ON) +#define BLUE_OFF gpio_set_level(GPIO_LED_BLUE, LED_LEVEL_OFF) + +#define BLINK_INTERVAL 500/portTICK_PERIOD_MS + +static const char* TAG = "STATUS"; + +static HwStatus prevStatus = STATUS_BOOT; +static HwStatus currentStatus = STATUS_BOOT; + +static bool powerSaving = false; + +static void statusCycleBoot() +{ + GREEN_OFF; + BLUE_OFF; + RED_ON; + vTaskDelay(BLINK_INTERVAL); +} + +static void statusCycleOk() +{ + GREEN_ON; + BLUE_OFF; + RED_OFF; + vTaskDelay(BLINK_INTERVAL); +} + +static void statusCycleOkPowerSave() +{ + GREEN_OFF; + BLUE_OFF; + RED_OFF; + + const int factor = 5; + int cycles = 20 * factor; + while (--cycles >= 0 && currentStatus == STATUS_OK) { + vTaskDelay(BLINK_INTERVAL / factor); + } + + if (currentStatus == STATUS_OK) { + GREEN_ON; + vTaskDelay(BLINK_INTERVAL / 5); + } +} + +static void statusCycleOkWorking() +{ + int cycles = 3; + while (--cycles >= 0) { + GREEN_ON; + BLUE_OFF; + RED_OFF; + vTaskDelay(BLINK_INTERVAL/10); + + GREEN_OFF; + vTaskDelay(BLINK_INTERVAL/10); + } + currentStatus = prevStatus; +} + +static void statusCycleBtEnabled() +{ + GREEN_OFF; + BLUE_ON; + RED_OFF; + vTaskDelay(BLINK_INTERVAL); + + BLUE_OFF; + vTaskDelay(BLINK_INTERVAL); +} + +static void statusCycleWifiError() +{ + GREEN_OFF; + BLUE_OFF; + RED_ON; + vTaskDelay(BLINK_INTERVAL); + + RED_OFF; + vTaskDelay(BLINK_INTERVAL); +} + +static void statusCycleMqttError() +{ + GREEN_OFF; + BLUE_OFF; + + RED_ON; + vTaskDelay(BLINK_INTERVAL/2); + RED_OFF; + vTaskDelay(BLINK_INTERVAL/2); + + RED_ON; + vTaskDelay(BLINK_INTERVAL/2); + RED_OFF; + vTaskDelay(BLINK_INTERVAL*2); +} + +static void printStatus() +{ + ets_printf("TRIGGER STATUS: "); + switch (currentStatus) { + case STATUS_BOOT: + ets_printf("BOOT"); + break; + case STATUS_OK: + ets_printf("OK"); + break; + case STATUS_OK_WORKING: + ets_printf("OK WORKING"); + break; + case STATUS_OK_ALT: + ets_printf("BT ENABLED"); + break; + case STATUS_SYSTEM_ERROR: + ets_printf("WIFI ERROR"); + break; + case STATUS_APP_ERROR: + ets_printf("MQTT ERROR"); + break; + } + ets_printf("\n"); +} + +void nxEnablePowerSavingStatus(bool enable) +{ + powerSaving = enable; +} + +void nxStatusIndicatorTask(void* params) +{ + UNUSED(params); + + ESP_LOGI(TAG, "STATUS INIT"); + + while(1) { + switch (currentStatus) { + case STATUS_BOOT: + statusCycleBoot(); + break; + case STATUS_OK: + if (powerSaving == true) { + statusCycleOkPowerSave(); + } + else { + statusCycleOk(); + } + break; + case STATUS_OK_WORKING: + statusCycleOkWorking(); + break; + case STATUS_OK_ALT: + statusCycleBtEnabled(); + break; + case STATUS_SYSTEM_ERROR: + statusCycleWifiError(); + break; + case STATUS_APP_ERROR: + statusCycleMqttError(); + break; + } + + } +} + +void nxInitStatusIndicator() +{ + gpio_reset_pin(GPIO_LED_RED); + gpio_reset_pin(GPIO_LED_GREEN); + gpio_reset_pin(GPIO_LED_BLUE); + + gpio_set_direction(GPIO_LED_RED, GPIO_MODE_OUTPUT); + gpio_set_direction(GPIO_LED_GREEN, GPIO_MODE_OUTPUT); + gpio_set_direction(GPIO_LED_BLUE, GPIO_MODE_OUTPUT); + + GREEN_OFF; + BLUE_OFF; + RED_ON; +} + +void nxUpdateStatus(HwStatus newStatus) +{ + // priority filters: + if (currentStatus == STATUS_SYSTEM_ERROR + && newStatus == STATUS_APP_ERROR) { + return; + } + prevStatus = currentStatus; + currentStatus = newStatus; + printStatus(); +} diff --git a/components/software/include/nx/software/SystemSettings.h b/components/software/include/nx/software/SystemSettings.h index 93fef29..6cdeb92 100644 --- a/components/software/include/nx/software/SystemSettings.h +++ b/components/software/include/nx/software/SystemSettings.h @@ -8,6 +8,7 @@ #define WIFI_STRINGS_MAX_LEN 32 #define URI_MAX_LEN 64 #define TZ_ENV_LEN 32 +#define RESTART_SCHEDULE_SIZE 12 typedef bool (*StorageReadFn)(const char* key, void* data, size_t size); @@ -24,6 +25,7 @@ typedef struct SystemSettings { uint8_t dnsAddr[4]; char sntpAddr[URI_MAX_LEN]; char tzEnv[TZ_ENV_LEN]; + char rsSchedule[RESTART_SCHEDULE_SIZE]; } SystemSettings; diff --git a/components/software/src/AppSettings.c b/components/software/src/AppSettings.c index c3281ed..c74194b 100644 --- a/components/software/src/AppSettings.c +++ b/components/software/src/AppSettings.c @@ -22,7 +22,7 @@ static const uint8_t INIT_FLAG_VALUE = 1; static const char* DEFAULT_MQTT_HOST = ""; static const char* DEFAULT_MQTT_API_URI = "dev/api"; static const char* DEFAULT_MQTT_HB_URI = "dev/hb"; -static const uint16_t DEFAULT_MQTT_HB_SEC = 0; +static const uint16_t DEFAULT_MQTT_HB_SEC = 60 * 15; static const uint8_t DEFAULT_MQTT_TLS = 0; static const char* DEFAULT_MQTT_USER = ""; static const char* DEFAULT_MQTT_PASS = ""; diff --git a/components/software/src/SystemSettings.c b/components/software/src/SystemSettings.c index ff075b6..7387bf6 100644 --- a/components/software/src/SystemSettings.c +++ b/components/software/src/SystemSettings.c @@ -14,6 +14,7 @@ #define KEY_DNS_ADDR "dns" #define KEY_SNTP_ADDR "sntp" #define KEY_TZ_ENV "tz" +#define KEY_RS_SCHEDULE "rsch" #define IPV4_ADDR_SIZE 4 @@ -34,6 +35,7 @@ static const char DEFAULT_WIFI_MASK[IPV4_ADDR_SIZE] = {255,255,255,0}; static const char DEFAULT_DNS_ADDR[IPV4_ADDR_SIZE] = {8,8,8,8}; static const char* DEFAULT_SNTP_ADDR = "pool.ntp.org"; static const char* DEFAULT_TZ_ENV = "CET-1CEST,M3.5.0,M10.5.0/3"; +static const char* DEFAULT_RS_SCHEDULE = "72 23 59 60"; // days (bin), hour, minute, required uptime (min) static StorageWriteFn storageWrite = NULL; static StorageReadFn storageRead = NULL; @@ -60,6 +62,7 @@ static void loadSystemSettings(void) storageRead(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE); storageRead(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN); storageRead(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN); + storageRead(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE); STORAGE_READ(KEY_WIFI_POWER_SAVE, wifiPowerSave); STORAGE_READ(KEY_WIFI_USE_STATIC, useStaticAddr); @@ -96,6 +99,7 @@ void nxRestoreSystemDefaultSettings(void) memcpy(settings.dnsAddr, DEFAULT_DNS_ADDR, IPV4_ADDR_SIZE); strcpy(settings.sntpAddr, DEFAULT_SNTP_ADDR); strcpy(settings.tzEnv, DEFAULT_TZ_ENV); + strcpy(settings.rsSchedule, DEFAULT_RS_SCHEDULE); nxWriteSystemSettings(); } @@ -111,14 +115,15 @@ void nxWriteSystemSettings(void) printf("WRITING SYSTEM SETTINGS\n"); storageWrite(KEY_INIT_FLAG, &INIT_FLAG_VALUE, 1); - storageWrite(KEY_WIFI_SSID, settings.wifiSsid , WIFI_STRINGS_MAX_LEN); - storageWrite(KEY_WIFI_PASS, settings.wifiPassword, WIFI_STRINGS_MAX_LEN); - storageWrite(KEY_WIFI_ADDR, settings.ip4addr , IPV4_ADDR_SIZE ); - storageWrite(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE ); - storageWrite(KEY_WIFI_MASK, settings.ip4mask , IPV4_ADDR_SIZE ); - storageWrite(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE ); - storageWrite(KEY_SNTP_ADDR, settings.sntpAddr , URI_MAX_LEN ); - storageWrite(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN ); + storageWrite(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN ); + storageWrite(KEY_WIFI_PASS , settings.wifiPassword, WIFI_STRINGS_MAX_LEN ); + storageWrite(KEY_WIFI_ADDR , settings.ip4addr , IPV4_ADDR_SIZE ); + storageWrite(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE ); + storageWrite(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE ); + storageWrite(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE ); + storageWrite(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN ); + storageWrite(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN ); + storageWrite(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE ); STORAGE_WRITE(KEY_WIFI_POWER_SAVE, wifiPowerSave); STORAGE_WRITE(KEY_WIFI_USE_STATIC, useStaticAddr); diff --git a/components/software/src/SystemSettingsApi.c b/components/software/src/SystemSettingsApi.c index 50a5195..1915cd8 100644 --- a/components/software/src/SystemSettingsApi.c +++ b/components/software/src/SystemSettingsApi.c @@ -24,6 +24,7 @@ #define API_KEY_DNS_ADDR "dns" #define API_KEY_SNTP_ADDR "sntp" #define API_KEY_TZ_ENV "tz" +#define API_KEY_RS_SCHEDULE "rsch" #define API_KEY_RESTORE "restore_default" #define UNUSED(x) (void)(x) @@ -82,6 +83,9 @@ void handleKvPair(const char* key, const char* value, const void* userData, bool else if (strcmp(key, API_KEY_TZ_ENV) == 0) { strcpy(settings->tzEnv, value); } + else if (strcmp(key, API_KEY_RS_SCHEDULE) == 0) { + strcpy(settings->rsSchedule, value); + } else { fprintf(stderr, "Unknown key: %s\n", key); } @@ -106,7 +110,8 @@ void nxApiGetSystemSettings(const uint8_t* msg, size_t msgLen, "\"%s\":\"%i.%i.%i.%i\"," // mask "\"%s\":\"%i.%i.%i.%i\"," // dns "\"%s\":\"%s\"," // sntp - "\"%s\":\"%s\"" // tz + "\"%s\":\"%s\"," // tz + "\"%s\":\"%s\"" // rsch "}", API_KEY_SSID, settings->wifiSsid, API_KEY_WPWSAVE, settings->wifiPowerSave ? "true" : "false", @@ -116,7 +121,8 @@ void nxApiGetSystemSettings(const uint8_t* msg, size_t msgLen, API_KEY_IPV4MASK, settings->ip4mask[0], settings->ip4mask[1], settings->ip4mask[2], settings->ip4mask[3], API_KEY_DNS_ADDR, settings->dnsAddr[0], settings->dnsAddr[1], settings->dnsAddr[2], settings->dnsAddr[3], API_KEY_SNTP_ADDR, settings->sntpAddr, - API_KEY_TZ_ENV, settings->tzEnv + API_KEY_TZ_ENV, settings->tzEnv, + API_KEY_RS_SCHEDULE, settings->rsSchedule ); *response = responseBuffer; *respLen = strlen(responseBuffer); diff --git a/main/Main.c b/main/Main.c index 95cbce6..839b6bf 100644 --- a/main/Main.c +++ b/main/Main.c @@ -4,6 +4,7 @@ #include "nx/software/AppSettingsApi.h" #include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "esp_system.h" #include "nx/firmware/Storage.h" @@ -11,6 +12,8 @@ #include "nx/firmware/MqTriggerHttpServer.h" #include "nx/firmware/MqttClient.h" #include "nx/firmware/SntpClient.h" +#include "nx/firmware/StatusIndicator.h" +#include "nx/firmware/Restarter.h" #include "HttpHandlers.h" @@ -20,7 +23,7 @@ #define TAG "MAIN" -#define SNTP_RETRIES 5 +#define SNTP_RETRIES 8 static const char* DEVICE_NAME_PREFIX = "mqtrigger-"; @@ -28,7 +31,11 @@ extern const char ca_crt_start[] asm("_binary_ca_crt_start"); static void startWifi(void); static void onWifiConnected(void); +static void onWifiError(void); static void onAppSettingsUpdate(void); +static void onMqttConnected(); +static void onMqttDisconnected(); +static void onMqttError(); static void onMqttMessage(const char* msg); static SystemSettings* systemSettings = NULL; @@ -51,6 +58,10 @@ static const MqTriggerHttpCallbacks httpCallbacks = { void app_main(void) { + nxInitStatusIndicator(); + nxUpdateStatus(STATUS_BOOT); + xTaskCreate(&nxStatusIndicatorTask, "status_task", 2048, NULL, 1, NULL); + nxInitStorage(); nxInitSystemSettings(nxStorageWrite, nxStorageRead); @@ -59,7 +70,10 @@ void app_main(void) systemSettings = nxGetSystemSettings(); appSettings = nxGetAppSettings(); + nxStartRestarter(systemSettings->rsSchedule, systemSettings->tzEnv); + nxSetWifiConnectedCallback(onWifiConnected); + nxSetWifiErrorCallback(onWifiError); startWifi(); } @@ -85,7 +99,9 @@ static void startWifi(void) }; ESP_LOGI(TAG, "Initializing WiFi"); - nxInitWifi(&wifiSettings); + if (!nxInitWifi(&wifiSettings)) { + nxUpdateStatus(STATUS_SYSTEM_ERROR); + } } static void onWifiConnected(void) @@ -100,6 +116,9 @@ static void onWifiConnected(void) mqttSettings.hbIntervalSec = appSettings->mqttHbIntervalSec; mqttSettings.caCrt = appSettings->mqttUseTls ? ca_crt_start : NULL; mqttSettings.messageCb = onMqttMessage; + mqttSettings.connectedCb = onMqttConnected; + mqttSettings.disconnectedCb = onMqttDisconnected; + mqttSettings.errorCb = onMqttError; nxStartMqttClient(&mqttSettings); @@ -110,9 +129,35 @@ static void onWifiConnected(void) static void onAppSettingsUpdate(void) { ESP_LOGI(TAG, "App settings updated"); + nxUpdateStatus(STATUS_OK_WORKING); } static void onMqttMessage(const char* msg) { ESP_LOGI(TAG, "MQTT MESSAGE RECEIVED: %s", msg); + nxUpdateStatus(STATUS_OK_WORKING); +} + +static void onWifiError() +{ + ESP_LOGE(TAG, "WiFi ERROR"); + nxUpdateStatus(STATUS_SYSTEM_ERROR); +} + +static void onMqttConnected() +{ + ESP_LOGI(TAG, "MQTT CONNECTED"); + nxUpdateStatus(STATUS_OK); +} + +static void onMqttDisconnected() +{ + ESP_LOGW(TAG, "MQTT DISCONNECTED"); + nxUpdateStatus(STATUS_APP_ERROR); +} + +static void onMqttError() +{ + ESP_LOGE(TAG, "MQTT ERROR"); + nxUpdateStatus(STATUS_APP_ERROR); } diff --git a/main/static/index.js b/main/static/index.js index 768feb5..ad716af 100644 --- a/main/static/index.js +++ b/main/static/index.js @@ -15,15 +15,21 @@ function sendClickHandler(event) { console.log(element.value); if (element.value) { //TODO: checkbox/radio - params += params ? '&' : ''; - if (element.hasAttribute('data-ip32')) { - console.log("IPv4 32"); - params += element.name + '=' + ip2int(element.value); + if (!element.hasAttribute('data-ignore')) { + params += params ? '&' : ''; + if (element.hasAttribute('data-ip32')) { + console.log("IPv4 32"); + params += element.name + '=' + ip2int(element.value); + } + else { + params += element.name + '=' + element.value; + } } else { - params += element.name + '=' + element.value; + console.log("Ignoring " + element.name); } + } @@ -88,6 +94,9 @@ function loadValues(element) { let input = element.querySelector("[name='" + key + "'"); if (input) { //TODO: checkbox/radio input.value = obj[key]; + if (input.hasAttribute('data-onset')) { + eval(input.getAttribute("data-onset")); + } } } } @@ -123,4 +132,36 @@ function initNavButtons() { for (i = 0; i < btns.length; ++i) { btns[i].addEventListener('click', navClickHandler); } +} + +function getRschDays() { + let daysBin = 0; + for (let i = 0; i < 7; ++i) { + let day = document.getElementById("rsd_" + i.toString()); + if (day && day.checked === true) { + daysBin |= (1 << i); + } + } + return daysBin; +} + +function rschUpdate() { + let rschElem = document.getElementById("rsch"); + rschElem.value = getRschDays() + + " " + + document.getElementById("rsch_time").value.replace(":", " ") + + " " + + document.getElementById("rsch_rup").value; +} + +function rschSet() { + let data = document.getElementById("rsch").value.split(" "); + document.getElementById("rsch_time").value = data[1] + ":" + data[2]; + document.getElementById("rsch_rup").value = data[3]; + for (let i = 0; i < 7; ++i) { + if (data[0] & (1 << i)) { + document.getElementById("rsd_" + i.toString()).checked = true; + } + } + } \ No newline at end of file diff --git a/main/static/min/index.js b/main/static/min/index.js index 7536e1a..b3d75cd 100644 --- a/main/static/min/index.js +++ b/main/static/min/index.js @@ -1,14 +1,23 @@ function ip2int(ip){return ip.split('.').reduce(function(ipInt,octet){return(ipInt<<8)+parseInt(octet,10)},0)>>>0;} -function sendClickHandler(event){console.log("Sending form...");let form=event.srcElement.form;console.debug(form);let params='';Array.from(form.elements).forEach(element=>{console.log(element);console.log(element.name);console.log(element.value);if(element.value){params+=params?'&':'';if(element.hasAttribute('data-ip32')){console.log("IPv4 32");params+=element.name+'='+ip2int(element.value);} -else{params+=element.name+'='+element.value;}}});console.log("params: "+params);postParams(form.getAttribute('action'),params);console.log("Form sent");} +function sendClickHandler(event){console.log("Sending form...");let form=event.srcElement.form;console.debug(form);let params='';Array.from(form.elements).forEach(element=>{console.log(element);console.log(element.name);console.log(element.value);if(element.value){if(!element.hasAttribute('data-ignore')){params+=params?'&':'';if(element.hasAttribute('data-ip32')){console.log("IPv4 32");params+=element.name+'='+ip2int(element.value);} +else{params+=element.name+'='+element.value;}} +else{console.log("Ignoring "+element.name);}}});console.log("params: "+params);postParams(form.getAttribute('action'),params);console.log("Form sent");} function initFormSendButtons(form){const btns=form.querySelectorAll('.send');for(i=0;i "+obj[key]) -let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];}}}}} +let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];if(input.hasAttribute('data-onset')){eval(input.getAttribute("data-onset"));}}}}}} http.send();}} function postParams(url,params){var http=new XMLHttpRequest();http.open('POST',url,true);http.setRequestHeader('Content-type','application/x-www-form-urlencoded');http.onreadystatechange=function(){if(http.readyState==4&&http.status==200){alert(http.responseText);}} http.send(params);} function navClickHandler(event){console.log('Button Clicked');console.log('Destination: '+this.getAttribute('data-dst'));loadContent(this.getAttribute('data-dst'));} -function initNavButtons(){const btns=document.querySelectorAll('.nav-btn');for(i=0;iDevice system management

Device system management

Network


Time


Restore defaults


Reboot

\ No newline at end of file +


Restarter schedule

+ + + + + +


Restore defaults


Reboot

\ No newline at end of file diff --git a/main/static/sys.html b/main/static/sys.html index 01e1bde..1037ed9 100644 --- a/main/static/sys.html +++ b/main/static/sys.html @@ -1,14 +1,15 @@

Device system management

-
+ +

Network

@@ -32,37 +33,96 @@

- + + +
+ +
+
+
+ +
+

Time

+

+

+ + +
+ +
+
+
+ +
+

Restarter schedule

+ + + +

+ + + + + + +

+

+ +

+ +

+ +

+ +
@@ -70,6 +130,7 @@
+

Restore defaults