Browse Source

Refactored MQTT client

master
chodak166 4 years ago
parent
commit
113dc05239
  1. 9
      components/firmware/include/nx/firmware/MqttClient.h
  2. 1
      components/firmware/include/nx/firmware/Wifi.h
  3. 2
      components/firmware/src/HttpHelpers.h
  4. 1
      components/firmware/src/MqTriggerHttpServer.c
  5. 96
      components/firmware/src/MqttClient.c
  6. 8
      components/firmware/src/SntpClient.c
  7. 14
      components/firmware/src/Wifi.c
  8. 6
      components/software/include/nx/software/AppSettings.h
  9. 1
      components/software/include/nx/software/SystemSettings.h
  10. 69
      components/software/src/AppSettings.c
  11. 42
      components/software/src/AppSettingsApi.c
  12. 7
      components/software/src/KeyValueParser.c
  13. 42
      components/software/src/SystemSettings.c
  14. 31
      components/software/src/SystemSettingsApi.c
  15. 1
      main/CMakeLists.txt
  16. 55
      main/Main.c
  17. 22
      main/static/app.html
  18. 28
      main/static/index.js
  19. 6
      main/static/min/app.html
  20. 7
      main/static/min/index.js
  21. 3
      main/static/min/sys.html
  22. 6
      main/static/sys.html

9
components/firmware/include/nx/firmware/MqttClient.h

@ -2,10 +2,12 @@
#define COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_MQTTCLIENT_H_ #define COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_MQTTCLIENT_H_
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define MQTT_BROKER_URI_MAX_LEN 128 #define MQTT_BROKER_URI_MAX_LEN 128
#define MQTT_TOPIC_MAX_LEN 128 #define MQTT_TOPIC_MAX_LEN 128
#define MQTT_USER_MAX_LEN 16 #define MQTT_USER_MAX_LEN 32
typedef void (*MqttConnectedCallback)(); typedef void (*MqttConnectedCallback)();
typedef void (*MqttDisconnectedCallback)(); typedef void (*MqttDisconnectedCallback)();
@ -17,6 +19,7 @@ typedef struct MqttSettings
char brokerAddr[MQTT_BROKER_URI_MAX_LEN]; char brokerAddr[MQTT_BROKER_URI_MAX_LEN];
char apiTopic[MQTT_TOPIC_MAX_LEN]; char apiTopic[MQTT_TOPIC_MAX_LEN];
char hbTopic[MQTT_TOPIC_MAX_LEN]; char hbTopic[MQTT_TOPIC_MAX_LEN];
char clientId[MQTT_USER_MAX_LEN];
char user[MQTT_USER_MAX_LEN]; char user[MQTT_USER_MAX_LEN];
char password[MQTT_USER_MAX_LEN]; char password[MQTT_USER_MAX_LEN];
uint16_t hbIntervalSec; uint16_t hbIntervalSec;
@ -30,6 +33,8 @@ typedef struct MqttSettings
void nxStartMqttClient(const MqttSettings* settings); void nxStartMqttClient(const MqttSettings* settings);
void nxMqttHeartbeatTask(void*); bool nxMqttSubscribe(const char* topic, uint8_t qos);
uint32_t nxMqttPublish(const char* topic, uint8_t qos, const char* data, size_t size, uint8_t retain);
#endif /* COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_MQTTCLIENT_H_ */ #endif /* COMPONENTS_FIRMWARE_INCLUDE_NX_FIRMWARE_MQTTCLIENT_H_ */

1
components/firmware/include/nx/firmware/Wifi.h

@ -31,6 +31,7 @@ bool nxInitWifi(WifiSettings* wifiSettings);
void nxSetWifiConnectedCallback(WifiCallback callback); void nxSetWifiConnectedCallback(WifiCallback callback);
void nxSetWifiErrorCallback(WifiCallback callback); void nxSetWifiErrorCallback(WifiCallback callback);
const char* nxGetWifiDeviceName(void);
#endif // COMPONENTS_FIRMWARE_WIFI_H #endif // COMPONENTS_FIRMWARE_WIFI_H

2
components/firmware/src/HttpHelpers.h

@ -6,7 +6,7 @@
typedef void(*RequestCallback)(const uint8_t* content, size_t ctLen, typedef void(*RequestCallback)(const uint8_t* content, size_t ctLen,
const char** response, size_t* respLen); const char** response, size_t* respLen);
#define REQ_CONTENT_MAX_SIZE 1024 #define REQ_CONTENT_MAX_SIZE 2048
// Request handler helper macro // Request handler helper macro
#define ADD_HTTP_HANDLER(_URI, _NAME, _METHOD)\ #define ADD_HTTP_HANDLER(_URI, _NAME, _METHOD)\

1
components/firmware/src/MqTriggerHttpServer.c

@ -82,6 +82,7 @@ bool nxStartMqTriggerHttpServer(void)
config.server_port = 80; config.server_port = 80;
config.max_uri_handlers = 16; config.max_uri_handlers = 16;
config.uri_match_fn = httpd_uri_match_wildcard; config.uri_match_fn = httpd_uri_match_wildcard;
config.stack_size = 8192;
// ... // ...
if (server != NULL) { if (server != NULL) {

96
components/firmware/src/MqttClient.c

@ -17,12 +17,6 @@
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
static const char* TAG = "MQTT"; static const char* TAG = "MQTT";
static const int CMD_QOS = 2;
//static const int HB_QOS = 1;
//static const long int MINIMAL_HB_INTERVAL_MS = 1000 * 60;
static const char* CLIENT_ID = "p10-dev";
static const MqttSettings* settings = NULL; static const MqttSettings* settings = NULL;
@ -32,8 +26,6 @@ esp_mqtt_client_handle_t clientHandle = NULL;
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{ {
esp_mqtt_client_handle_t client = event->client; esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) { switch (event->event_id) {
case MQTT_EVENT_CONNECTED: case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
@ -42,15 +34,6 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
if (settings->connectedCb) { if (settings->connectedCb) {
settings->connectedCb(); settings->connectedCb();
} }
msg_id = esp_mqtt_client_subscribe(client, settings->apiTopic, CMD_QOS);
if (msg_id == -1) {
ESP_LOGE(TAG, "Subscribtion failed");
if (settings->errorCb) {
settings->errorCb();
}
}
break; break;
case MQTT_EVENT_DISCONNECTED: case MQTT_EVENT_DISCONNECTED:
@ -78,8 +61,6 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
settings->messageCb(event->data); settings->messageCb(event->data);
} }
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break; break;
case MQTT_EVENT_ERROR: case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
@ -116,59 +97,42 @@ void nxStartMqttClient(const MqttSettings* mqttSettings)
esp_mqtt_client_config_t mqtt_cfg = {}; esp_mqtt_client_config_t mqtt_cfg = {};
mqtt_cfg.uri = settings->brokerAddr; mqtt_cfg.uri = settings->brokerAddr;
mqtt_cfg.client_id = settings->clientId;
mqtt_cfg.cert_pem = settings->caCrt;
mqtt_cfg.username = settings->user;
mqtt_cfg.password = settings->password;
mqtt_cfg.client_id = CLIENT_ID; esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
mqtt_cfg.cert_pem = settings->caCrt; esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
mqtt_cfg.username = settings->user; esp_mqtt_client_start(client);
mqtt_cfg.password = settings->password; }
if (mqtt_cfg.host) { bool nxMqttSubscribe(const char* topic, uint8_t qos)
ESP_LOGI(TAG, "host: %s", mqtt_cfg.host); {
if (!clientHandle) {
ESP_LOGE(TAG, "MQTT client not initialized, aborting subscription of topic %s", topic);
return false;
} }
if (mqtt_cfg.uri) {
ESP_LOGI(TAG, "uri: %s", mqtt_cfg.uri); int msg_id = esp_mqtt_client_subscribe(clientHandle, settings->apiTopic, qos);
if (msg_id == -1) {
ESP_LOGE(TAG, "Subscribtion of topic %s failed", topic);
if (settings->errorCb) {
settings->errorCb();
}
return false;
} }
ESP_LOGI(TAG, "client: %s", mqtt_cfg.client_id);
ESP_LOGI(TAG, "user: %s", mqtt_cfg.username);
ESP_LOGI(TAG, "pass: %s", mqtt_cfg.password);
ESP_LOGI(TAG, "cert: %s", mqtt_cfg.cert_pem);
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); return true;
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
esp_mqtt_client_start(client);
} }
void nxMqttHeartbeatTask(void* param) uint32_t nxMqttPublish(const char* topic, uint8_t qos, const char* data, size_t size, uint8_t retain)
{ {
UNUSED(param); if (!clientHandle) {
// ESP_LOGI(TAG, "Starting MQTT heartbeat task"); ESP_LOGE(TAG, "MQTT client not initialized, aborting data publishing in topic %s", topic);
// return -1;
// ESP_LOGI(TAG, "hbIntervalMin: %d", settings->hbIntervalMin); }
// return esp_mqtt_client_publish(clientHandle, topic, data, size, qos, retain);
// long int hbIntervalMs = 1000 * 60 * settings->hbIntervalMin;
//
// ESP_LOGI(TAG, "hbIntervalMs: %li", hbIntervalMs);
//
//
// if (hbIntervalMs < MINIMAL_HB_INTERVAL_MS) {
// hbIntervalMs = MINIMAL_HB_INTERVAL_MS;
// }
//
// while (1) {
// if (clientHandle) {
// ESP_LOGI(TAG, "Sending MQTT heartbeat");
//
// char timeStr[DT_FORMAT_LEN];
// getTimeStr(timeStr);
// char hbMessage[DT_FORMAT_LEN + strlen(DEVICE_ID) + 2];
// strcpy(hbMessage, DEVICE_ID);
// strcat(hbMessage, " ");
// strcat(hbMessage, timeStr);
//
// esp_mqtt_client_publish(clientHandle, HEARTBEAT_TOPIC,
// hbMessage, strlen(hbMessage), HB_QOS, 1);
// }
// vTaskDelay(hbIntervalMs / portTICK_PERIOD_MS);
// }
} }

8
components/firmware/src/SntpClient.c

@ -8,7 +8,7 @@
static const char* TAG = "SNTP_CLIENT"; static const char* TAG = "SNTP_CLIENT";
static const char* tzString = "CET-1CEST,M3.5.0,M10.5.0/3"; static const char* tzString = NULL;
bool nxInitSntpClient(int retries, const char* serverAddr, const char* timezoneString) bool nxInitSntpClient(int retries, const char* serverAddr, const char* timezoneString)
{ {
@ -35,8 +35,10 @@ void nxGetTimeStr(char buf[DT_FORMAT_LEN])
struct tm timeinfo; struct tm timeinfo;
time(&now); time(&now);
setenv("TZ", tzString, 1); if (tzString) {
tzset(); setenv("TZ", tzString, 1);
tzset();
}
localtime_r(&now, &timeinfo); localtime_r(&now, &timeinfo);
strftime(buf, DT_FORMAT_LEN, "%Y-%m-%d %H:%M:%S", &timeinfo); strftime(buf, DT_FORMAT_LEN, "%Y-%m-%d %H:%M:%S", &timeinfo);
} }

14
components/firmware/src/Wifi.c

@ -43,7 +43,7 @@ static WifiSettings* settings = NULL;
static WifiCallback errorCallback = NULL; static WifiCallback errorCallback = NULL;
static WifiCallback connectedCallback = NULL; static WifiCallback connectedCallback = NULL;
static char deviceName[DEVICE_NAME_MAX_LEN]; static char deviceName[DEVICE_NAME_MAX_LEN] = {0};
static bool initWifiStation(void); static bool initWifiStation(void);
@ -342,3 +342,15 @@ static bool initWifiStation(void)
return waitForStaConnection(); return waitForStaConnection();
} }
const char* nxGetWifiDeviceName(void)
{
if (settings && settings->devicePrefix && strlen(deviceName) == 0) {
generateDeviceName();
return deviceName;
}
else if (strlen(deviceName)) {
return deviceName;
}
return "unknown";
}

6
components/software/include/nx/software/AppSettings.h

@ -8,6 +8,8 @@
#define WIFI_STRINGS_MAX_LEN 32 #define WIFI_STRINGS_MAX_LEN 32
#define URI_MAX_SIZE 64 #define URI_MAX_SIZE 64
#define USER_DATA_MAX_SIZE 16 #define USER_DATA_MAX_SIZE 16
#define CA_CERT_MAX_SIZE 1500
#define DEVICE_NAME_MAX_LEN 64
typedef bool (*StorageReadFn)(const char* key, void* data, size_t size); typedef bool (*StorageReadFn)(const char* key, void* data, size_t size);
@ -23,7 +25,9 @@ typedef struct AppSettings {
char mqttPassword[USER_DATA_MAX_SIZE]; char mqttPassword[USER_DATA_MAX_SIZE];
uint16_t mqttHbIntervalSec; uint16_t mqttHbIntervalSec;
uint8_t mqttUseTls; uint8_t mqttUseTls;
char caCert[CA_CERT_MAX_SIZE];
bool overrideDevName;
char customDevName[DEVICE_NAME_MAX_LEN];
} AppSettings; } AppSettings;

1
components/software/include/nx/software/SystemSettings.h

@ -26,6 +26,7 @@ typedef struct SystemSettings {
char sntpAddr[URI_MAX_LEN]; char sntpAddr[URI_MAX_LEN];
char tzEnv[TZ_ENV_LEN]; char tzEnv[TZ_ENV_LEN];
char rsSchedule[RESTART_SCHEDULE_SIZE]; char rsSchedule[RESTART_SCHEDULE_SIZE];
const char* deviceName; // set in the main component
} SystemSettings; } SystemSettings;

69
components/software/src/AppSettings.c

@ -10,6 +10,9 @@
#define KEY_MQTT_TLS "mqtls" #define KEY_MQTT_TLS "mqtls"
#define KEY_MQTT_USER "mquser" #define KEY_MQTT_USER "mquser"
#define KEY_MQTT_PASS "mqpass" #define KEY_MQTT_PASS "mqpass"
#define KEY_OVR_DEVNAME "ovdn"
#define KEY_CUSTOM_DEVNAME "cdn"
#define KEY_CA_CERT "cacert"
#define STORAGE_READ(_KEY, _NAME)\ #define STORAGE_READ(_KEY, _NAME)\
storageRead(_KEY, &settings._NAME, sizeof(settings._NAME)); storageRead(_KEY, &settings._NAME, sizeof(settings._NAME));
@ -19,13 +22,16 @@
static const uint8_t INIT_FLAG_VALUE = 1; static const uint8_t INIT_FLAG_VALUE = 1;
static const char* DEFAULT_MQTT_HOST = ""; static const char* DEFAULT_MQTT_HOST = "";
static const char* DEFAULT_MQTT_API_URI = "dev/api"; static const char* DEFAULT_MQTT_API_URI = "dev/api";
static const char* DEFAULT_MQTT_HB_URI = "dev/hb"; static const char* DEFAULT_MQTT_HB_URI = "dev/hb";
static const uint16_t DEFAULT_MQTT_HB_SEC = 60 * 15; static const uint16_t DEFAULT_MQTT_HB_SEC = 60 * 15;
static const uint8_t DEFAULT_MQTT_TLS = 0; static const uint8_t DEFAULT_MQTT_TLS = 0;
static const char* DEFAULT_MQTT_USER = ""; static const char* DEFAULT_MQTT_USER = "";
static const char* DEFAULT_MQTT_PASS = ""; static const char* DEFAULT_MQTT_PASS = "";
static const bool DEFAULT_OV_DEVNAME = false;
static const char* DEFAULT_CUSTOM_DEVNAME = "esp-dev";
static const char* DEFAULT_CA_CERT = "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n";
static StorageWriteFn storageWrite = NULL; static StorageWriteFn storageWrite = NULL;
@ -46,13 +52,16 @@ static bool firstRun(void)
static void loadSettings(void) static void loadSettings(void)
{ {
printf("Loading application settings\n"); printf("Loading application settings\n");
STORAGE_READ(KEY_MQTT_HOST , mqttHost ); STORAGE_READ(KEY_MQTT_HOST , mqttHost );
STORAGE_READ(KEY_MQTT_API_URI, mqttApiUri ); STORAGE_READ(KEY_MQTT_API_URI , mqttApiUri );
STORAGE_READ(KEY_MQTT_HB_URI , mqttHbUri ); STORAGE_READ(KEY_MQTT_HB_URI , mqttHbUri );
STORAGE_READ(KEY_MQTT_HB_SEC , mqttHbIntervalSec); STORAGE_READ(KEY_MQTT_HB_SEC , mqttHbIntervalSec);
STORAGE_READ(KEY_MQTT_TLS , mqttUseTls ); STORAGE_READ(KEY_MQTT_TLS , mqttUseTls );
STORAGE_READ(KEY_MQTT_USER , mqttUser ); STORAGE_READ(KEY_MQTT_USER , mqttUser );
STORAGE_READ(KEY_MQTT_PASS , mqttPassword ); STORAGE_READ(KEY_MQTT_PASS , mqttPassword );
STORAGE_READ(KEY_OVR_DEVNAME , overrideDevName );
STORAGE_READ(KEY_CUSTOM_DEVNAME , customDevName );
STORAGE_READ(KEY_CA_CERT , caCert );
} }
@ -87,11 +96,15 @@ void nxRestoreAppDefaultSettings(void)
settings.mqttHbIntervalSec = DEFAULT_MQTT_HB_SEC; settings.mqttHbIntervalSec = DEFAULT_MQTT_HB_SEC;
settings.mqttUseTls = DEFAULT_MQTT_TLS; settings.mqttUseTls = DEFAULT_MQTT_TLS;
strcpy(settings.mqttHbUri , DEFAULT_MQTT_HB_URI ); strcpy(settings.mqttHbUri , DEFAULT_MQTT_HB_URI );
strcpy(settings.mqttApiUri , DEFAULT_MQTT_API_URI); strcpy(settings.mqttApiUri , DEFAULT_MQTT_API_URI );
strcpy(settings.mqttHost , DEFAULT_MQTT_HOST ); strcpy(settings.mqttHost , DEFAULT_MQTT_HOST );
strcpy(settings.mqttUser , DEFAULT_MQTT_USER ); strcpy(settings.mqttUser , DEFAULT_MQTT_USER );
strcpy(settings.mqttPassword, DEFAULT_MQTT_PASS ); strcpy(settings.mqttPassword , DEFAULT_MQTT_PASS );
strcpy(settings.caCert , DEFAULT_CA_CERT );
strcpy(settings.customDevName , DEFAULT_CUSTOM_DEVNAME);
settings.overrideDevName = DEFAULT_OV_DEVNAME;
nxWriteAppSettings(); nxWriteAppSettings();
} }
@ -102,14 +115,16 @@ void nxWriteAppSettings(void)
printf("WRITING APPLICATION SETTINGS\n"); printf("WRITING APPLICATION SETTINGS\n");
storageWrite(KEY_INIT_FLAG , &INIT_FLAG_VALUE , 1); storageWrite(KEY_INIT_FLAG , &INIT_FLAG_VALUE , 1);
STORAGE_WRITE(KEY_MQTT_HOST , mqttHost ); STORAGE_WRITE(KEY_MQTT_HOST , mqttHost );
STORAGE_WRITE(KEY_MQTT_API_URI, mqttApiUri ); STORAGE_WRITE(KEY_MQTT_API_URI , mqttApiUri );
STORAGE_WRITE(KEY_MQTT_HB_URI , mqttHbUri ); STORAGE_WRITE(KEY_MQTT_HB_URI , mqttHbUri );
STORAGE_WRITE(KEY_MQTT_HB_SEC , mqttHbIntervalSec); STORAGE_WRITE(KEY_MQTT_HB_SEC , mqttHbIntervalSec);
STORAGE_WRITE(KEY_MQTT_TLS , mqttUseTls ); STORAGE_WRITE(KEY_MQTT_TLS , mqttUseTls );
STORAGE_WRITE(KEY_MQTT_USER , mqttUser ); STORAGE_WRITE(KEY_MQTT_USER , mqttUser );
STORAGE_WRITE(KEY_MQTT_PASS , mqttPassword ); STORAGE_WRITE(KEY_MQTT_PASS , mqttPassword );
STORAGE_WRITE(KEY_CA_CERT , caCert );
STORAGE_WRITE(KEY_CUSTOM_DEVNAME , customDevName );
STORAGE_WRITE(KEY_OVR_DEVNAME , overrideDevName );
settingsUpdatedCb(); settingsUpdatedCb();
} }

42
components/software/src/AppSettingsApi.c

@ -15,23 +15,26 @@
#define API_KEY_MQTT_TLS "mqtls" #define API_KEY_MQTT_TLS "mqtls"
#define API_KEY_MQTT_USER "mquser" #define API_KEY_MQTT_USER "mquser"
#define API_KEY_MQTT_PASS "mqpass" #define API_KEY_MQTT_PASS "mqpass"
#define API_KEY_CA_CERT "cacert"
#define API_KEY_OV_DEVNAME "ovdn"
#define API_KEY_CUSTOM_DEVNAME "cdn"
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
#define RESP_BUF_SIZE 1024 #define RESP_BUF_SIZE 2048
char responseBuffer[RESP_BUF_SIZE]; char responseBuffer[RESP_BUF_SIZE];
static void handleKvPair(const char* key, const char* value, const void* userData, bool* done) static void handleKvPair(const char* key, const char* value, const void* userData, bool* done)
{ {
printf("LED display settings update; Key: %s, Value: %s\n", key, value); printf("App settings update; Key: %s, Value: %s\n", key, value);
AppSettings* settings = nxGetAppSettings(); AppSettings* settings = nxGetAppSettings();
if (strcmp(key, API_KEY_RESTORE) == 0) { if (strcmp(key, API_KEY_RESTORE) == 0) {
nxRestoreAppDefaultSettings(); nxRestoreAppDefaultSettings();
} }
else if (strcmp(key, API_KEY_MQTT_HOST) == 0) { else if (strcmp(key, API_KEY_MQTT_HOST) == 0) {
strcpy(settings->mqttHost, value); strcpy(settings->mqttHost, value);
} }
else if (strcmp(key, API_KEY_MQTT_API_URI) == 0) { else if (strcmp(key, API_KEY_MQTT_API_URI) == 0) {
strcpy(settings->mqttApiUri, value); strcpy(settings->mqttApiUri, value);
@ -46,10 +49,19 @@ static void handleKvPair(const char* key, const char* value, const void* userDat
strcpy(settings->mqttPassword, value); strcpy(settings->mqttPassword, value);
} }
else if (strcmp(key, API_KEY_MQTT_HB_SEC) == 0) { else if (strcmp(key, API_KEY_MQTT_HB_SEC) == 0) {
settings->mqttHbIntervalSec = atoi(value); settings->mqttHbIntervalSec = atoi(value);
} }
else if (strcmp(key, API_KEY_MQTT_TLS) == 0) { else if (strcmp(key, API_KEY_MQTT_TLS) == 0) {
settings->mqttUseTls = atoi(value); settings->mqttUseTls = atoi(value);
}
else if (strcmp(key, API_KEY_CA_CERT) == 0) {
strcpy(settings->caCert, value);
}
else if (strcmp(key, API_KEY_CUSTOM_DEVNAME) == 0) {
strcpy(settings->customDevName, value);
}
else if (strcmp(key, API_KEY_OV_DEVNAME) == 0) {
settings->overrideDevName = atoi(value);
} }
else { else {
fprintf(stderr, "Unknown key: %s\n", key); fprintf(stderr, "Unknown key: %s\n", key);
@ -59,7 +71,7 @@ static void handleKvPair(const char* key, const char* value, const void* userDat
// --------- Public API --------- // // --------- Public API --------- //
void nxApiGetAppSettings(const uint8_t* msg, size_t msgLen, void nxApiGetAppSettings(const uint8_t* msg, size_t msgLen,
const char** response, size_t* respLen) const char** response, size_t* respLen)
{ {
UNUSED(msg); UNUSED(msgLen); UNUSED(msg); UNUSED(msgLen);
memset(responseBuffer, 0, RESP_BUF_SIZE); memset(responseBuffer, 0, RESP_BUF_SIZE);
@ -72,14 +84,18 @@ void nxApiGetAppSettings(const uint8_t* msg, size_t msgLen,
"\"%s\":\"%s\", " "\"%s\":\"%s\", "
"\"%s\":%i, " // hb interval "\"%s\":%i, " // hb interval
"\"%s\":%i, " "\"%s\":%i, "
"\"%s\":\"%s\" " // mqtt user "\"%s\":\"%s\", " // mqtt user
"\"%s\":%i," // ovdn
"\"%s\":\"%s\"" // cdn
"}", "}",
API_KEY_MQTT_HOST , settings->mqttHost , API_KEY_MQTT_HOST , settings->mqttHost ,
API_KEY_MQTT_API_URI, settings->mqttApiUri , API_KEY_MQTT_API_URI , settings->mqttApiUri ,
API_KEY_MQTT_HB_URI , settings->mqttHbUri , API_KEY_MQTT_HB_URI , settings->mqttHbUri ,
API_KEY_MQTT_HB_SEC , settings->mqttHbIntervalSec, API_KEY_MQTT_HB_SEC , settings->mqttHbIntervalSec,
API_KEY_MQTT_TLS , settings->mqttUseTls , API_KEY_MQTT_TLS , settings->mqttUseTls ,
API_KEY_MQTT_USER , settings->mqttUser API_KEY_MQTT_USER , settings->mqttUser ,
API_KEY_OV_DEVNAME , settings->overrideDevName ,
API_KEY_CUSTOM_DEVNAME, settings->customDevName
); );
*response = responseBuffer; *response = responseBuffer;
*respLen = strlen(responseBuffer); *respLen = strlen(responseBuffer);

7
components/software/src/KeyValueParser.c

@ -1,24 +1,25 @@
#include "KeyValueParser.h" #include "KeyValueParser.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#define MAX_KEY_SIZE 32 #define MAX_KEY_SIZE 32
#define MAX_VALUE_SIZE 32
#define MAX_PAIRS 16 #define MAX_PAIRS 16
void nxParseKeyValueString(const char* string, KeyValueHandler handler, const void* userData) void nxParseKeyValueString(const char* string, KeyValueHandler handler, const void* userData)
{ {
bool done = false; bool done = false;
char key[MAX_KEY_SIZE]; char key[MAX_KEY_SIZE];
char value[MAX_VALUE_SIZE]; char* value = calloc(1, strlen(string));
FILE *stream; FILE *stream;
stream = fmemopen((void*)string, strlen(string), "r"); stream = fmemopen((void*)string, strlen(string), "r");
int maxPairs = MAX_PAIRS; int maxPairs = MAX_PAIRS;
while (fscanf(stream, "%127[^=]=%127[^&]%*c", key, value) == 2 && maxPairs > 0 && !done) { while (fscanf(stream, "%32[^=]=%2048[^&]%*c", key, value) == 2 && maxPairs > 0 && !done) {
handler(key, value, userData, &done); handler(key, value, userData, &done);
maxPairs -= 1; maxPairs -= 1;
} }
fclose(stream); fclose(stream);
free(value);
} }

42
components/software/src/SystemSettings.c

@ -54,15 +54,15 @@ static bool firstRun(void)
static void loadSystemSettings(void) static void loadSystemSettings(void)
{ {
printf("Loading system settings\n"); printf("Loading system settings\n");
storageRead(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN); storageRead(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN);
storageRead(KEY_WIFI_PASS , settings.wifiPassword, WIFI_STRINGS_MAX_LEN); storageRead(KEY_WIFI_PASS , settings.wifiPassword , WIFI_STRINGS_MAX_LEN);
storageRead(KEY_WIFI_ADDR , settings.ip4addr , IPV4_ADDR_SIZE); storageRead(KEY_WIFI_ADDR , settings.ip4addr , IPV4_ADDR_SIZE);
storageRead(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE); storageRead(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE);
storageRead(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE); storageRead(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE);
storageRead(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE); storageRead(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE);
storageRead(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN); storageRead(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN);
storageRead(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN); storageRead(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN);
storageRead(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE); storageRead(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE);
STORAGE_READ(KEY_WIFI_POWER_SAVE, wifiPowerSave); STORAGE_READ(KEY_WIFI_POWER_SAVE, wifiPowerSave);
STORAGE_READ(KEY_WIFI_USE_STATIC, useStaticAddr); STORAGE_READ(KEY_WIFI_USE_STATIC, useStaticAddr);
@ -115,18 +115,18 @@ void nxWriteSystemSettings(void)
printf("WRITING SYSTEM SETTINGS\n"); printf("WRITING SYSTEM SETTINGS\n");
storageWrite(KEY_INIT_FLAG, &INIT_FLAG_VALUE, 1); storageWrite(KEY_INIT_FLAG, &INIT_FLAG_VALUE, 1);
storageWrite(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN ); storageWrite(KEY_WIFI_SSID , settings.wifiSsid , WIFI_STRINGS_MAX_LEN );
storageWrite(KEY_WIFI_PASS , settings.wifiPassword, 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_ADDR , settings.ip4addr , IPV4_ADDR_SIZE );
storageWrite(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE ); storageWrite(KEY_WIFI_GW , settings.ip4gw , IPV4_ADDR_SIZE );
storageWrite(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE ); storageWrite(KEY_WIFI_MASK , settings.ip4mask , IPV4_ADDR_SIZE );
storageWrite(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE ); storageWrite(KEY_DNS_ADDR , settings.dnsAddr , IPV4_ADDR_SIZE );
storageWrite(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN ); storageWrite(KEY_SNTP_ADDR , settings.sntpAddr , URI_MAX_LEN );
storageWrite(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN ); storageWrite(KEY_TZ_ENV , settings.tzEnv , TZ_ENV_LEN );
storageWrite(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE ); storageWrite(KEY_RS_SCHEDULE , settings.rsSchedule , RESTART_SCHEDULE_SIZE );
STORAGE_WRITE(KEY_WIFI_POWER_SAVE, wifiPowerSave); STORAGE_WRITE(KEY_WIFI_POWER_SAVE, wifiPowerSave );
STORAGE_WRITE(KEY_WIFI_USE_STATIC, useStaticAddr); STORAGE_WRITE(KEY_WIFI_USE_STATIC, useStaticAddr );
} }
SystemSettings* nxGetSystemSettings(void) SystemSettings* nxGetSystemSettings(void)

31
components/software/src/SystemSettingsApi.c

@ -14,18 +14,19 @@
ssid=myssid&wpass=mypassword&wpwsave=1&wstatic=1&ip=3232237657&gw=3232237569&mask=4294967040 ssid=myssid&wpass=mypassword&wpwsave=1&wstatic=1&ip=3232237657&gw=3232237569&mask=4294967040
*/ */
#define API_KEY_SSID "ssid" #define API_KEY_SSID "ssid"
#define API_KEY_WPASS "wpass" #define API_KEY_WPASS "wpass"
#define API_KEY_WPWSAVE "wpwsave" #define API_KEY_WPWSAVE "wpwsave"
#define API_KEY_USE_STATIC "wstatic" #define API_KEY_USE_STATIC "wstatic"
#define API_KEY_IPV4ADDR "ip" #define API_KEY_IPV4ADDR "ip"
#define API_KEY_IPV4GW "gw" #define API_KEY_IPV4GW "gw"
#define API_KEY_IPV4MASK "mask" #define API_KEY_IPV4MASK "mask"
#define API_KEY_DNS_ADDR "dns" #define API_KEY_DNS_ADDR "dns"
#define API_KEY_SNTP_ADDR "sntp" #define API_KEY_SNTP_ADDR "sntp"
#define API_KEY_TZ_ENV "tz" #define API_KEY_TZ_ENV "tz"
#define API_KEY_RS_SCHEDULE "rsch" #define API_KEY_RS_SCHEDULE "rsch"
#define API_KEY_RESTORE "restore_default" #define API_KEY_DEVNAME "dn"
#define API_KEY_RESTORE "restore_default"
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
@ -111,7 +112,8 @@ void nxApiGetSystemSettings(const uint8_t* msg, size_t msgLen,
"\"%s\":\"%i.%i.%i.%i\"," // dns "\"%s\":\"%i.%i.%i.%i\"," // dns
"\"%s\":\"%s\"," // sntp "\"%s\":\"%s\"," // sntp
"\"%s\":\"%s\"," // tz "\"%s\":\"%s\"," // tz
"\"%s\":\"%s\"" // rsch "\"%s\":\"%s\"," // rsch
"\"%s\":\"%s\"" // dn
"}", "}",
API_KEY_SSID, settings->wifiSsid, API_KEY_SSID, settings->wifiSsid,
API_KEY_WPWSAVE, settings->wifiPowerSave ? "true" : "false", API_KEY_WPWSAVE, settings->wifiPowerSave ? "true" : "false",
@ -122,7 +124,8 @@ void nxApiGetSystemSettings(const uint8_t* msg, size_t msgLen,
API_KEY_DNS_ADDR, settings->dnsAddr[0], settings->dnsAddr[1], settings->dnsAddr[2], settings->dnsAddr[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_SNTP_ADDR, settings->sntpAddr,
API_KEY_TZ_ENV, settings->tzEnv, API_KEY_TZ_ENV, settings->tzEnv,
API_KEY_RS_SCHEDULE, settings->rsSchedule API_KEY_RS_SCHEDULE, settings->rsSchedule,
API_KEY_DEVNAME, settings->deviceName
); );
*response = responseBuffer; *response = responseBuffer;
*respLen = strlen(responseBuffer); *respLen = strlen(responseBuffer);

1
main/CMakeLists.txt

@ -12,4 +12,3 @@ target_add_binary_data(${COMPONENT_TARGET} "static/min/index.css" TEXT)
target_add_binary_data(${COMPONENT_TARGET} "static/min/index.js" TEXT) target_add_binary_data(${COMPONENT_TARGET} "static/min/index.js" TEXT)
target_add_binary_data(${COMPONENT_TARGET} "static/min/sys.html" TEXT) target_add_binary_data(${COMPONENT_TARGET} "static/min/sys.html" TEXT)
target_add_binary_data(${COMPONENT_TARGET} "static/min/app.html" TEXT) target_add_binary_data(${COMPONENT_TARGET} "static/min/app.html" TEXT)
target_add_binary_data(${COMPONENT_TARGET} "static/ca.crt" TEXT)

55
main/Main.c

@ -24,10 +24,10 @@
#define TAG "MAIN" #define TAG "MAIN"
#define SNTP_RETRIES 8 #define SNTP_RETRIES 8
#define API_QOS 2
#define HB_QOS 1
static const char* DEVICE_NAME_PREFIX = "mqtrigger-"; static const char* DEVICE_NAME_PREFIX = "mqt-";
extern const char ca_crt_start[] asm("_binary_ca_crt_start");
static void startWifi(void); static void startWifi(void);
static void onWifiConnected(void); static void onWifiConnected(void);
@ -38,6 +38,8 @@ static void onMqttDisconnected();
static void onMqttError(); static void onMqttError();
static void onMqttMessage(const char* msg); static void onMqttMessage(const char* msg);
static void hbTask(void*);
static SystemSettings* systemSettings = NULL; static SystemSettings* systemSettings = NULL;
static AppSettings* appSettings = NULL; static AppSettings* appSettings = NULL;
static WifiSettings wifiSettings; static WifiSettings wifiSettings;
@ -53,7 +55,7 @@ static const MqTriggerHttpCallbacks httpCallbacks = {
.postSysSet = nxApiUpdateSystemSettings, .postSysSet = nxApiUpdateSystemSettings,
.getAppSet = nxApiGetAppSettings, .getAppSet = nxApiGetAppSettings,
.postAppSet = nxApiUpdateAppSettings .postAppSet = nxApiUpdateAppSettings
// .postCmd = nxApiHandleLedCmd // .postCmd = nxApiHandleCmd
}; };
void app_main(void) void app_main(void)
@ -81,8 +83,6 @@ void app_main(void)
static void startWifi(void) static void startWifi(void)
{ {
strcpy(systemSettings->wifiSsid, "cintra");
strcpy(systemSettings->wifiPassword, "fffefdfcfb");
systemSettings->useStaticAddr = true; systemSettings->useStaticAddr = true;
systemSettings->ip4addr[3] = 91; systemSettings->ip4addr[3] = 91;
@ -106,15 +106,22 @@ static void startWifi(void)
static void onWifiConnected(void) static void onWifiConnected(void)
{ {
systemSettings->deviceName = nxGetWifiDeviceName();
nxInitSntpClient(SNTP_RETRIES, systemSettings->sntpAddr, systemSettings->tzEnv); nxInitSntpClient(SNTP_RETRIES, systemSettings->sntpAddr, systemSettings->tzEnv);
strcpy(mqttSettings.brokerAddr, appSettings->mqttHost); strcpy(mqttSettings.brokerAddr, appSettings->mqttHost);
strcpy(mqttSettings.apiTopic, appSettings->mqttApiUri); strcpy(mqttSettings.apiTopic, appSettings->mqttApiUri);
strcpy(mqttSettings.hbTopic, appSettings->mqttHbUri); strcpy(mqttSettings.hbTopic, appSettings->mqttHbUri);
strcpy(mqttSettings.user, appSettings->mqttUser); strcpy(mqttSettings.user, appSettings->mqttUser);
strcpy(mqttSettings.password, appSettings->mqttPassword); strcpy(mqttSettings.password, appSettings->mqttPassword);
strcpy(mqttSettings.clientId, appSettings->overrideDevName
? appSettings->customDevName
: systemSettings->deviceName);
mqttSettings.hbIntervalSec = appSettings->mqttHbIntervalSec; mqttSettings.hbIntervalSec = appSettings->mqttHbIntervalSec;
mqttSettings.caCrt = appSettings->mqttUseTls ? ca_crt_start : NULL; mqttSettings.caCrt = appSettings->mqttUseTls ? appSettings->caCert : NULL;
mqttSettings.messageCb = onMqttMessage; mqttSettings.messageCb = onMqttMessage;
mqttSettings.connectedCb = onMqttConnected; mqttSettings.connectedCb = onMqttConnected;
mqttSettings.disconnectedCb = onMqttDisconnected; mqttSettings.disconnectedCb = onMqttDisconnected;
@ -147,7 +154,10 @@ static void onWifiError()
static void onMqttConnected() static void onMqttConnected()
{ {
ESP_LOGI(TAG, "MQTT CONNECTED"); ESP_LOGI(TAG, "MQTT CONNECTED");
nxUpdateStatus(STATUS_OK); if (nxMqttSubscribe(appSettings->mqttApiUri, API_QOS)) {
xTaskCreate(&hbTask, "hb_task", 2048, NULL, 1, NULL);
nxUpdateStatus(STATUS_OK);
}
} }
static void onMqttDisconnected() static void onMqttDisconnected()
@ -161,3 +171,32 @@ static void onMqttError()
ESP_LOGE(TAG, "MQTT ERROR"); ESP_LOGE(TAG, "MQTT ERROR");
nxUpdateStatus(STATUS_APP_ERROR); nxUpdateStatus(STATUS_APP_ERROR);
} }
static void hbTask(void* param)
{
// UNUSED(param);
ESP_LOGI(TAG, "Starting MQTT heartbeat task");
ESP_LOGI(TAG, "hbIntervalSec: %d", appSettings->mqttHbIntervalSec);
if (appSettings->mqttHbIntervalSec < 1) {
ESP_LOGI(TAG, "Heartbeat interval < 1 sec, skipping");
vTaskDelete(NULL);
return;
}
while (1) {
ESP_LOGI(TAG, "Sending MQTT heartbeat");
char timeStr[DT_FORMAT_LEN];
nxGetTimeStr(timeStr);
char hbMessage[DT_FORMAT_LEN + strlen(nxGetWifiDeviceName()) + 2];
strcpy(hbMessage, nxGetWifiDeviceName());
strcat(hbMessage, " ");
strcat(hbMessage, timeStr);
nxMqttPublish(appSettings->mqttHbUri, HB_QOS, hbMessage, strlen(hbMessage), 1);
vTaskDelay(appSettings->mqttHbIntervalSec*1000 / portTICK_PERIOD_MS);
}
}

22
main/static/app.html

@ -48,6 +48,27 @@
</label> </label>
</p> </p>
<p>
<label class="label">Override device name:
<select class="select" name="ovdn">
<option value="0">No</option>
<option value="1">Yes</option>
</select>
</label>
</p>
<p>
<label>Custom device name:
<input type="text" name="cdn">
</label>
</p>
<p>
<label>Certificate data (begin to end, tags included):
<p><textarea name="cacert"></textarea></p>
</label>
</p>
<p> <p>
<button type="button" class="send">SEND</button> <button type="button" class="send">SEND</button>
</p> </p>
@ -61,7 +82,6 @@
</div> </div>
<h3>Restore defaults</h3> <h3>Restore defaults</h3>
<form id="restore-form" action="/app"> <form id="restore-form" action="/app">
<input type="hidden" name="restore_default" value="1" /> <input type="hidden" name="restore_default" value="1" />

28
main/static/index.js

@ -1,3 +1,5 @@
var valuesCache = {};
function ip2int(ip) { function ip2int(ip) {
return ip.split('.').reduce(function(ipInt, octet) { return (ipInt<<8) + parseInt(octet, 10)}, 0) >>> 0; return ip.split('.').reduce(function(ipInt, octet) { return (ipInt<<8) + parseInt(octet, 10)}, 0) >>> 0;
} }
@ -70,16 +72,37 @@ function loadContent(url) {
} }
function loadValues(element) { function loadValues(element) {
const forms = element.querySelectorAll('form'); const forms = element.querySelectorAll('form');
for (i = 0; i < forms.length; ++i) { for (i = 0; i < forms.length; ++i) {
const srcUrl = forms[i].getAttribute('data-values-src'); const srcUrl = forms[i].getAttribute('data-values-src');
if (!srcUrl) { if (!srcUrl) {
continue; continue;
} }
if (valuesCache[srcUrl]) {
console.log("Source values already cached: " + valuesCache[srcUrl]);
//TODO: dry
let obj = JSON.parse(valuesCache[srcUrl]);
if (obj) {
for (var key of Object.keys(obj)) {
console.log(key + " -> " + obj[key])
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"));
}
}
}
}
continue;
}
console.log("Getting values from " + srcUrl); console.log("Getting values from " + srcUrl);
let http = new XMLHttpRequest(); let http = new XMLHttpRequest();
http.open('GET', srcUrl, true); http.open('GET', srcUrl, false);
//Send the proper header information along with the request //Send the proper header information along with the request
//http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); //http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
@ -87,6 +110,9 @@ function loadValues(element) {
http.onreadystatechange = function () {//Call a function when the state changes. http.onreadystatechange = function () {//Call a function when the state changes.
if (http.readyState == 4 && http.status == 200) { if (http.readyState == 4 && http.status == 200) {
console.log("Values received: " + http.responseText); console.log("Values received: " + http.responseText);
valuesCache[srcUrl] = http.responseText;
//TODO: dry
let obj = JSON.parse(http.responseText); let obj = JSON.parse(http.responseText);
if (obj) { if (obj) {
for (var key of Object.keys(obj)) { for (var key of Object.keys(obj)) {

6
main/static/min/app.html

@ -7,4 +7,8 @@
<input type=password name=mqpass></label><p><label class=label>Use TLS: <input type=password name=mqpass></label><p><label class=label>Use TLS:
<select class=select name=mqtls> <select class=select name=mqtls>
<option value=0>No <option value=0>No
<option value=1>Yes</select></label><p><button type=button class=send>SEND</button></p>NOTE: device reboot is required</form><div class=col-md-offset-1><hr></div><h3>Restore defaults</h3><form id=restore-form action=/app><input type=hidden name=restore_default value=1><p><button type=button class=send>RESTORE DEFAULT SETTINGS</button></form><div class=col-md-offset-1><hr></div><h3>Reboot</h3><form id=reboot-form action=/sys/reboot><input type=hidden name=reboot value=1><p><button type=button class=send>REBOOT</button></form> <option value=1>Yes</select></label><p><label class=label>Override device name:
<select class=select name=ovdn>
<option value=0>No
<option value=1>Yes</select></label><p><label>Custom device name:
<input name=cdn></label><p><label>Certificate data (begin to end, tags included):<p><textarea name=cacert></textarea></label><p><button type=button class=send>SEND</button></p>NOTE: device reboot is required</form><div class=col-md-offset-1><hr></div><h3>Restore defaults</h3><form id=restore-form action=/app><input type=hidden name=restore_default value=1><p><button type=button class=send>RESTORE DEFAULT SETTINGS</button></form><div class=col-md-offset-1><hr></div><h3>Reboot</h3><form id=reboot-form action=/sys/reboot><input type=hidden name=reboot value=1><p><button type=button class=send>REBOOT</button></form>

7
main/static/min/index.js

@ -1,4 +1,4 @@
function ip2int(ip){return ip.split('.').reduce(function(ipInt,octet){return(ipInt<<8)+parseInt(octet,10)},0)>>>0;} var valuesCache={};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){if(!element.hasAttribute('data-ignore')){params+=params?'&':'';if(element.hasAttribute('data-ip32')){console.log("IPv4 32");params+=element.name+'='+ip2int(element.value);} 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{params+=element.name+'='+element.value;}}
else{console.log("Ignoring "+element.name);}}});console.log("params: "+params);postParams(form.getAttribute('action'),params);console.log("Form sent");} else{console.log("Ignoring "+element.name);}}});console.log("params: "+params);postParams(form.getAttribute('action'),params);console.log("Form sent");}
@ -6,7 +6,10 @@ function initFormSendButtons(form){const btns=form.querySelectorAll('.send');for
function loadContent(url){let http=new XMLHttpRequest();http.open('GET',url,true);let element=document.getElementById('content');element.innerHTML="LOADING...";http.onreadystatechange=function(){if(http.readyState==4&&http.status==200){console.log("Content received");element.innerHTML=http.responseText;loadValues(element);initFormSendButtons(element);}} function loadContent(url){let http=new XMLHttpRequest();http.open('GET',url,true);let element=document.getElementById('content');element.innerHTML="LOADING...";http.onreadystatechange=function(){if(http.readyState==4&&http.status==200){console.log("Content received");element.innerHTML=http.responseText;loadValues(element);initFormSendButtons(element);}}
http.send();} http.send();}
function loadValues(element){const forms=element.querySelectorAll('form');for(i=0;i<forms.length;++i){const srcUrl=forms[i].getAttribute('data-values-src');if(!srcUrl){continue;} function loadValues(element){const forms=element.querySelectorAll('form');for(i=0;i<forms.length;++i){const srcUrl=forms[i].getAttribute('data-values-src');if(!srcUrl){continue;}
console.log("Getting values from "+srcUrl);let http=new XMLHttpRequest();http.open('GET',srcUrl,true);http.onreadystatechange=function(){if(http.readyState==4&&http.status==200){console.log("Values received: "+http.responseText);let obj=JSON.parse(http.responseText);if(obj){for(var key of Object.keys(obj)){console.log(key+" -> "+obj[key]) if(valuesCache[srcUrl]){console.log("Source values already cached: "+valuesCache[srcUrl]);let obj=JSON.parse(valuesCache[srcUrl]);if(obj){for(var key of Object.keys(obj)){console.log(key+" -> "+obj[key])
let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];if(input.hasAttribute('data-onset')){eval(input.getAttribute("data-onset"));}}}}
continue;}
console.log("Getting values from "+srcUrl);let http=new XMLHttpRequest();http.open('GET',srcUrl,false);http.onreadystatechange=function(){if(http.readyState==4&&http.status==200){console.log("Values received: "+http.responseText);valuesCache[srcUrl]=http.responseText;let obj=JSON.parse(http.responseText);if(obj){for(var key of Object.keys(obj)){console.log(key+" -> "+obj[key])
let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];if(input.hasAttribute('data-onset')){eval(input.getAttribute("data-onset"));}}}}}} let input=element.querySelector("[name='"+key+"'");if(input){input.value=obj[key];if(input.hasAttribute('data-onset')){eval(input.getAttribute("data-onset"));}}}}}}
http.send();}} 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);}} 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);}}

3
main/static/min/sys.html

@ -1,4 +1,5 @@
<h1>Device system management</h1><form id=net-form action=/sys data-values-src=/sys><h3>Network</h3><p><label>WiFi SSID: <h1>Device system management</h1><form id=net-form action=/sys data-values-src=/sys><p><label>Device name:
<input name=dn readonly data-ignore></label><h3>Network</h3><p><label>WiFi SSID:
<input name=ssid></label><p><label>WiFi password: <input name=ssid></label><p><label>WiFi password:
<input type=password name=wpass></label><p><label class=label>WiFi power saving: <input type=password name=wpass></label><p><label class=label>WiFi power saving:
<select class=select name=wpwsave> <select class=select name=wpwsave>

6
main/static/sys.html

@ -1,6 +1,12 @@
<h1>Device system management</h1> <h1>Device system management</h1>
<form id="net-form" action="/sys" data-values-src="/sys"> <form id="net-form" action="/sys" data-values-src="/sys">
<p>
<label>Device name:
<input type="text" name="dn" readonly="readonly" data-ignore>
</label>
</p>
<h3>Network</h3> <h3>Network</h3>
<p> <p>
<label>WiFi SSID: <label>WiFi SSID:

Loading…
Cancel
Save