diff --git a/Makefile b/Makefile index 50daeba..1cec028 100755 --- a/Makefile +++ b/Makefile @@ -56,8 +56,8 @@ DBGFLAGS = -g -O0 -Wall -D AQ_DEBUG -D AQ_TM_DEBUG #MGFLAGS = -D MG_ENABLE_HTTP_SSI=0 -D MG_ENABLE_DIRECTORY_LISTING=0 -D MG_ENABLE_HTTP_CGI=0 # Mongoose 7.19 flags -#MGFLAGS = -D MG_TLS = 2 #(2=MG_TLS_OPENSSL. 3=MG_TLS_BUILTIN) -MGFLAGS = +#MGFLAGS = -D MG_TLS=2 #(2=MG_TLS_OPENSSL. 3=MG_TLS_BUILTIN) --or-- -DMG_TLS=MG_TLS_BUILTIN +MGFLAGS = -D MG_TLS=3 # Detect OS and set some specifics ifeq ($(OS),Windows_NT) diff --git a/README.md b/README.md index ac18f98..ff72587 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ NEED TO FIX FOR THIS RELEASE. # Updates in 3.0.0 (dev) * Serial optimization for AqualinkD HAT. * upgraded network library ( HTTP(S), MQTT(S), WS ) +* Added support for HTTPS and MQTTS * Added options to force upgrades in aqmanager. (add ?upgrade or ?devupgrade to url to enable upgrade button) * MQTT Discovery for all supporting hubs (HomeAssistant Domoticz Hubitat OpenHAB etc) * Moved Domoticz support over to MQTT autodiscovery. @@ -157,7 +158,6 @@ NEED TO FIX FOR THIS RELEASE. * With aqmanager is packet_logger still valid? (maybe for raw, but it's not been used in years) * Get panel size and clean up the ap_panel code around config size/type and reported size/type * WebUI Config in aqmanager. - * button pre-state was for domotics, delete # Updates in 2.6.11 (Sept 14 2025) diff --git a/release/aqualinkd-arm64 b/release/aqualinkd-arm64 index 3556fd9..d22fbbe 100755 Binary files a/release/aqualinkd-arm64 and b/release/aqualinkd-arm64 differ diff --git a/release/aqualinkd-armhf b/release/aqualinkd-armhf index e2b1e48..baec71d 100755 Binary files a/release/aqualinkd-armhf and b/release/aqualinkd-armhf differ diff --git a/release/serial_logger-arm64 b/release/serial_logger-arm64 index 9669b10..3ab1a5d 100755 Binary files a/release/serial_logger-arm64 and b/release/serial_logger-arm64 differ diff --git a/release/serial_logger-armhf b/release/serial_logger-armhf index 122b0a8..606d329 100755 Binary files a/release/serial_logger-armhf and b/release/serial_logger-armhf differ diff --git a/source/aq_scheduler.c b/source/aq_scheduler.c index e2805e1..5ec7fd2 100644 --- a/source/aq_scheduler.c +++ b/source/aq_scheduler.c @@ -162,8 +162,8 @@ int save_schedules_js(const char* inBuf, int inSize, char* outBuf, int outSize) LOG(SCHD_LOG,LOG_DEBUG, "Write to cron Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value); //LOG(SCHD_LOG,LOG_INFO, "%s%s %s %s %s %s curl -s -S --show-error -o /dev/null localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value); //fprintf(fp, "%s%s %s %s %s %s root curl -s -S --show-error -o /dev/null localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value); - LOG(SCHD_LOG,LOG_INFO, "%s%s %s %s %s %s curl -s -S --show-error -o /dev/null %s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, (iface->localurl==NULL?_aqconfig_.listen_address:iface->localurl), cline.url, cline.value); - fprintf(fp, "%s%s %s %s %s %s root curl -s -S --show-error -o /dev/null %s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, (iface->localurl==NULL?_aqconfig_.listen_address:iface->localurl), cline.url, cline.value); + LOG(SCHD_LOG,LOG_INFO, "%s%s %s %s %s %s curl -s -S --show-error %s -o /dev/null %s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, (iface->isLocalurlTLS?"--insecure":""),(iface->localurl==NULL?_aqconfig_.listen_address:iface->localurl), cline.url, cline.value); + fprintf(fp, "%s%s %s %s %s %s root curl -s -S --show-error %s -o /dev/null %s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, (iface->isLocalurlTLS?"--insecure":""),(iface->localurl==NULL?_aqconfig_.listen_address:iface->localurl), cline.url, cline.value); } } diff --git a/source/aq_systemutils.c b/source/aq_systemutils.c index f1a6428..2276920 100644 --- a/source/aq_systemutils.c +++ b/source/aq_systemutils.c @@ -22,9 +22,11 @@ #include #include #include +#include #include "aqualink.h" #include "aq_scheduler.h" +#include "aq_systemutils.h" bool remount_root_ro(bool readonly) { @@ -247,4 +249,68 @@ bool run_aqualinkd_upgrade(uint8_t type) //printf("Command execution complete.\n"); LOG(AQUA_LOG, LOG_NOTICE, "AqualinkD is upgrading!"); return true; -} \ No newline at end of file +} + + + +#if MG_TLS > 0 + +char* read_pem_file(const char* fmt, ...) { + char filepath[1024]; + + // Build file path from format + arguments + va_list args; + va_start(args, fmt); + vsnprintf(filepath, sizeof(filepath), fmt, args); + va_end(args); + + FILE* file = fopen(filepath, "rb"); + if (!file) { + LOG(AQUA_LOG, LOG_ERR, "Failed to open file %s\n",filepath); + return NULL; + } + + // Move to end to check file size + if (fseek(file, 0, SEEK_END) != 0) { + LOG(AQUA_LOG, LOG_ERR, "fseek failed on %s\n",filepath); + fclose(file); + return NULL; + } + + long filesize = ftell(file); + if (filesize < 0) { + LOG(AQUA_LOG, LOG_ERR, "ftell failed on %s\n",filepath); + fclose(file); + return NULL; + } + + // Enforce size sanity check + if (filesize > MAX_PEM_SIZE) { + LOG(AQUA_LOG, LOG_ERR, "Error: PEM file %s too large (%ld bytes, limit is %d)\n", filepath, filesize, MAX_PEM_SIZE); + fclose(file); + return NULL; + } + + // Allocate buffer (+1 for null terminator) + char* buffer = malloc(filesize + 1); + if (!buffer) { + LOG(AQUA_LOG, LOG_ERR, "malloc failed on %s\n",filepath); + fclose(file); + return NULL; + } + + rewind(file); + size_t bytesRead = fread(buffer, 1, filesize, file); + if (bytesRead != (size_t)filesize) { + LOG(AQUA_LOG, LOG_ERR, "fread failed on %s\n",filepath); + free(buffer); + fclose(file); + return NULL; + } + + buffer[filesize] = '\0'; // Null-terminate + + fclose(file); + return buffer; +} +#endif \ No newline at end of file diff --git a/source/aq_systemutils.h b/source/aq_systemutils.h index 531bb43..5863851 100644 --- a/source/aq_systemutils.h +++ b/source/aq_systemutils.h @@ -1,6 +1,10 @@ #ifndef AQ_FILESYSTEM_H_ #define AQ_FILESYSTEM_H_ +#if MG_TLS > 0 + #define MAX_PEM_SIZE (64 * 1024) // 64KB limit + char* read_pem_file(const char* fmt, ...); +#endif FILE *aq_open_file( char *filename, bool *ro_root, bool* created_file); bool aq_close_file(FILE *file, bool ro_root); diff --git a/source/aqualinkd.c b/source/aqualinkd.c index 77727cc..416b6e6 100644 --- a/source/aqualinkd.c +++ b/source/aqualinkd.c @@ -71,7 +71,10 @@ //#define DEFAULT_CONFIG_FILE "./aqualinkd.conf" static volatile bool _keepRunning = true; + +#ifdef SELF_RESTART static volatile bool _restart = false; +#endif //char** _argv; //static struct aqconfig _aqconfig_; static struct aqualinkdata _aqualink_data; @@ -125,8 +128,10 @@ void intHandler(int sig_num) execve(newargv[0], newargv, newenviron); exit (EXIT_SUCCESS); } +#ifdef SELF_RESTART } else { _restart = true; +#endif } } //LOG(AQUA_LOG,LOG_NOTICE, "Stopping!\n"); @@ -405,7 +410,9 @@ void printHelp() int main(int argc, char *argv[]) { +#ifdef SELF_RESTART _restart = false; +#endif char defaultCfg[] = "./aqualinkd.conf"; char *cfgFile; @@ -538,6 +545,13 @@ int startup(char *self, char *cfgFile) _aqualink_data.updated = true; //_aqualink_data.chiller_button == NULL; // HATE having this here, but needs to be null before config. + //sd_journal_print(LOG_NOTICE, "Starting %s v%s !\n", AQUALINKD_NAME, AQUALINKD_VERSION); + + + // Setup a log level just to get this message out, will be re-set once config is read + setSystemLogLevel(LOG_NOTICE); + LOG(AQUA_LOG,LOG_NOTICE, "Starting %s v%s !\n", AQUALINKD_NAME, AQUALINKD_VERSION); + sprintf(_aqualink_data.self, basename(self)); clearDebugLogMask(); read_config(&_aqualink_data, cfgFile); @@ -561,7 +575,7 @@ int startup(char *self, char *cfgFile) setLoggingPrms(_aqconfig_.log_level, _aqconfig_.deamonize, _aqconfig_.log_file, NULL); #endif - LOG(AQUA_LOG,LOG_NOTICE, "Starting %s v%s !\n", AQUALINKD_NAME, AQUALINKD_VERSION); + //LOG(AQUA_LOG,LOG_NOTICE, "Starting %s v%s !\n", AQUALINKD_NAME, AQUALINKD_VERSION); check_upgrade_log(); @@ -1479,7 +1493,11 @@ void main_loop() //if (_aqconfig_.debug_RSProtocol_packets) stopPacketLogger(); stopPacketLogger(); - if (! _restart) { // Stop network if we are not restarting +#ifdef SELF_RESTART + if (! _restart) +#endif + { + // Stop network if we are not restarting stop_net_services(); stop_sensors_thread(); } @@ -1488,7 +1506,7 @@ void main_loop() close_serial_port(rs_fd); // Clear webbrowser //mg_mgr_free(&mgr); - +/* if (! _restart) { // NSF need to run through config memory and clean up. LOG(AQUA_LOG,LOG_NOTICE, "Exit!\n"); @@ -1502,6 +1520,24 @@ void main_loop() _restart = false; startup(_self, _cfgFile); } +*/ + #ifdef SELF_RESTART + if (! _restart) { + LOG(AQUA_LOG,LOG_WARNING, "Waiting for process to fininish!\n"); + delay(5 * 1000); + LOG(AQUA_LOG,LOG_WARNING, "Restarting!\n"); + _keepRunning = true; + _restart = false; + startup(_self, _cfgFile); + } else + #else + { + // NSF need to run through config memory and clean up. + LOG(AQUA_LOG,LOG_NOTICE, "Exit!\n"); + //exit(EXIT_FAILURE); + exit(exit_code); + } + #endif } diff --git a/source/config.c b/source/config.c index 5d5f3a0..e83ce15 100644 --- a/source/config.c +++ b/source/config.c @@ -191,6 +191,20 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART; _cfgParams[_numCfgParams].default_value = (void *)_dcfg_web_port; + +#if MG_TLS > 0 + _numCfgParams++; + _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.cert_dir; + _cfgParams[_numCfgParams].value_type = CFG_STRING; + _cfgParams[_numCfgParams].name = CFG_N_cert_dir; + _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_null; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; + //_cfgParams[_numCfgParams].config_mask |= CFG_READONLY; + _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART; +#endif + + _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.serial_port; _cfgParams[_numCfgParams].value_type = CFG_STRING; @@ -319,11 +333,24 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_discovery; _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; - _numCfgParams++; + _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_discovery_use_mac; _cfgParams[_numCfgParams].value_type = CFG_BOOL; _cfgParams[_numCfgParams].name = CFG_N_mqtt_discovery_use_mac; _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_true; + + +#if MG_TLS > 0 + _numCfgParams++; + _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_cert_dir; + _cfgParams[_numCfgParams].value_type = CFG_STRING; + _cfgParams[_numCfgParams].name = CFG_N_mqtt_cert_dir; + _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_null; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; + //_cfgParams[_numCfgParams].config_mask |= CFG_READONLY; + _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART; +#endif _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_timed_update; diff --git a/source/config.h b/source/config.h index 83a380e..ac6c51b 100644 --- a/source/config.h +++ b/source/config.h @@ -42,6 +42,10 @@ struct aqconfig { +#if MG_TLS > 0 + char *cert_dir; // for future + char *mqtt_cert_dir; +#endif char *config_file; char *listen_address; char *serial_port; @@ -233,6 +237,8 @@ int _numCfgParams; #define CFG_N_MG_log_level "mg_log_level" #define CFG_V_log_level "[\"DEBUG_SERIAL\", \"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]" #define CFG_N_listen_address "listen_address" +#define CFG_N_cert_dir "https_cert_dir" + #define CFG_N_web_directory "web_directory" #define CFG_N_device_id "device_id" @@ -262,6 +268,7 @@ int _numCfgParams; #define CFG_N_mqtt_discovery_topic "mqtt_discovery_topic" #define CFG_N_mqtt_discovery_use_mac "mqtt_discovery_use_mac" #define CFG_N_mqtt_timed_update "mqtt_timed_update" +#define CFG_N_mqtt_cert_dir "mqtt_cert_dir" #define CFG_N_light_programming_mode "light_programming_mode" #define CFG_N_light_programming_initial_on "light_programming_initial_on" diff --git a/source/net_interface.c b/source/net_interface.c index e558e81..b5f1889 100644 --- a/source/net_interface.c +++ b/source/net_interface.c @@ -145,6 +145,13 @@ const net_iface *get_first_valid_interface() } else { LOG(NET_LOG, LOG_ERR,"Could not understand URL '%s' (unable to get protocol & port) \n",_aqconfig_.listen_address); } + + if (_aqconfig_.listen_address[(int)(protocol - _aqconfig_.listen_address)-1] == 's' || + _aqconfig_.listen_address[(int)(protocol - _aqconfig_.listen_address)-1] == 'S') + info.isLocalurlTLS = true; + else + info.isLocalurlTLS = false; + LOG(NET_LOG, LOG_DEBUG, "Interface %s = %s, %s\n", info.name, info.ip, info.mac); } else { LOG(NET_LOG, LOG_ERR,"Could not find a valid network interface"); diff --git a/source/net_interface.h b/source/net_interface.h index 5274f24..2b3c287 100644 --- a/source/net_interface.h +++ b/source/net_interface.h @@ -11,6 +11,7 @@ typedef struct { char url[INET_ADDRSTRLEN + 14]; // allow for "https://" and ":80801" char localurl[10 + 14]; // allow for "https://" "localhost" ":80801" char rawmac[18]; + bool isLocalurlTLS; } net_iface; /* diff --git a/source/net_services.c b/source/net_services.c index d7761a3..8773485 100644 --- a/source/net_services.c +++ b/source/net_services.c @@ -47,6 +47,7 @@ #include "version.h" #include "color_lights.h" #include "net_interface.h" +#include "aq_systemutils.h" #ifdef AQ_PDA #include "pda.h" @@ -57,6 +58,14 @@ struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) { } +#define FAST_SUFFIX_3_CI(str, len, SUFFIX) ( \ + (len) >= 3 && \ + tolower((unsigned char)(str)[(len)-3]) == tolower((unsigned char)(SUFFIX)[0]) && \ + tolower((unsigned char)(str)[(len)-2]) == tolower((unsigned char)(SUFFIX)[1]) && \ + tolower((unsigned char)(str)[(len)-1]) == tolower((unsigned char)(SUFFIX)[2]) \ +) + + /* #if defined AQ_DEBUG || defined AQ_TM_DEBUG #include "timespec_subtract.h" @@ -111,7 +120,8 @@ static int is_websocket_aqmanager(const struct mg_connection *nc) { return nc->aq_flags & AQ_MG_CON_WS_AQM; } static int is_mqtt(const struct mg_connection *nc) { - return nc->aq_flags & AQ_MG_CON_MQTT; + //return nc->aq_flags & AQ_MG_CON_MQTT; + return nc->aq_flags & (AQ_MG_CON_MQTT | AQ_MG_CON_MQTT_CONNECTING); } /* static void set_mqtt(struct mg_connection *nc) { @@ -575,21 +585,6 @@ void send_mqtt_swg_state_msg(struct mg_connection *nc, char *dev_name, aqledstat void send_mqtt_heater_state_msg(struct mg_connection *nc, char *dev_name, aqledstate state) { send_mqtt_led_state_msg(nc, dev_name, state, MQTT_ON, MQTT_OFF); -/* - static char mqtt_pub_topic[250]; - - sprintf(mqtt_pub_topic, "%s/%s",_aqconfig_.mqtt_aq_topic, dev_name); - - if (state == ENABLE) { - send_mqtt(nc, mqtt_pub_topic, MQTT_OFF); - sprintf(mqtt_pub_topic, "%s/%s%s",_aqconfig_.mqtt_aq_topic, dev_name, ENABELED_SUBT); - send_mqtt(nc, mqtt_pub_topic, MQTT_ON); - } else { - send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON)); - sprintf(mqtt_pub_topic, "%s/%s%s",_aqconfig_.mqtt_aq_topic, dev_name, ENABELED_SUBT); - send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON)); - } -*/ } @@ -604,18 +599,7 @@ void send_mqtt_temp_msg(struct mg_connection *nc, char *dev_name, long value) sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name); send_mqtt(nc, mqtt_pub_topic, degC); } -/* -void send_mqtt_temp_msg_new(struct mg_connection *nc, char *dev_name, long value) -{ - static char mqtt_pub_topic[250]; - static char degC[5]; - // NSF remove false below once we have finished. - sprintf(degC, "%.2f", (false && _aqualink_data->temp_units==FAHRENHEIT && _aqconfig_.convert_mqtt_temp)?degFtoC(value):value ); - //sprintf(degC, "%d", value ); - sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name); - send_mqtt(nc, mqtt_pub_topic, degC); -} -*/ + void send_mqtt_setpoint_msg(struct mg_connection *nc, char *dev_name, long value) { static char mqtt_pub_topic[250]; @@ -646,14 +630,6 @@ void send_mqtt_float_msg(struct mg_connection *nc, char *dev_name, float value) void send_mqtt_int_msg(struct mg_connection *nc, char *dev_name, int value) { send_mqtt_numeric_msg(nc, dev_name, value); - /* - static char mqtt_pub_topic[250]; - static char msg[10]; - - sprintf(msg, "%d", value); - sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name); - send_mqtt(nc, mqtt_pub_topic, msg); - */ } void send_mqtt_string_msg(struct mg_connection *nc, const char *dev_name, const char *msg) { @@ -1628,19 +1604,9 @@ void action_web_request(struct mg_connection *nc, struct mg_http_message *http_m // If we have a get request, pass it if (strncmp(http_msg->uri.buf, "/api", 4 ) != 0) { - //if (strstr(http_msg->method.p, "GET") && http_msg->query_string.len > 0) { - // log_http_request(LOG_ERR, "Old API stanza requested, ignoring request :", http_msg); - //} else { DEBUG_TIMER_START(&tid); - - //mg_serve_http(nc, http_msg, _http_server_opts); - //mg_http_serve_file(nc, http_msg, _http_server_opts.root_dir, &_http_server_opts); mg_http_serve_dir(nc, http_msg, &_http_server_opts); - // _aqconfig_.web_directory - DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took"); - //} - //} else if (strstr(http_msg->method.p, "PUT")) { } else { char buf[JSON_BUFFER_SIZE]; float value = 0; @@ -1772,7 +1738,6 @@ void action_web_request(struct mg_connection *nc, struct mg_http_message *http_m } } - void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm) { char buffer[100]; struct JSONkvptr jsonkv; @@ -1907,17 +1872,6 @@ void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm } } -/* -static void mqtt_subscribe(struct mg_connection *c, const char *topic) { - static uint8_t qos=1;// PUT IN FUNCTION HEADDER can't be bothered with ack, so set to 0 - struct mg_mqtt_opts opts = {}; - memset(&opts, 0, sizeof(opts)); - opts.topic = mg_str(topic); - opts.qos = qos; - mg_mqtt_sub(c, &opts); - LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing to '%s'\n", topic); -} -*/ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct mg_mqtt_message *mqtt_msg; @@ -1978,11 +1932,65 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { break; + case MG_EV_ACCEPT: + if (is_mqtt(nc)) { + return; + } + // Only want HTTPS & WS connections +#if MG_TLS > 0 + if (nc->is_tls) { + static char *crt; + static char *key; + + struct mg_tls_opts opts; + memset(&opts, 0, sizeof(opts)); + + if (crt == NULL || key == NULL) { + LOG(NET_LOG,LOG_NOTICE, "HTTPS: loading certs from : %s\n", _aqconfig_.cert_dir); + crt = read_pem_file("%s/crt.pem",_aqconfig_.cert_dir); + key = read_pem_file("%s/key.pem",_aqconfig_.cert_dir); + } + opts.cert = mg_str(crt); + opts.key = mg_str(key); + +#ifdef TLS_TWOWAY + static char *ca; + if (ca == NULL) + ca = read_pem_file("%s/ca.pem",_aqconfig_.cert_dir); + opts.ca = mg_str(ca); +#endif + + mg_tls_init(nc, &opts); + } +#endif + break; + case MG_EV_CONNECT: { set_mqttconnected(nc); //set_mqtt(nc); _mqtt_exit_flag = false; LOG(NET_LOG,LOG_DEBUG, "MQTT: Connected to : %s\n", _aqconfig_.mqtt_server); +#if MG_TLS > 0 + if (nc->is_tls) { + static char *crt; + static char *key; + static char *ca; + + struct mg_tls_opts opts; + memset(&opts, 0, sizeof(opts)); + + if (crt == NULL || key == NULL) { + LOG(NET_LOG,LOG_NOTICE, "MQTTS: loading certs from : %s\n", _aqconfig_.mqtt_cert_dir); + crt = read_pem_file("%s/crt.pem",_aqconfig_.cert_dir); + key = read_pem_file("%s/key.pem",_aqconfig_.cert_dir); + ca = read_pem_file("%s/ca.pem",_aqconfig_.cert_dir); + } + opts.cert = mg_str(crt); + opts.key = mg_str(key); + opts.ca = mg_str(ca); + mg_tls_init(nc, &opts); + } +#endif } break; case MG_EV_MQTT_OPEN: @@ -2016,17 +2024,9 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { case MG_EV_MQTT_MSG: mqtt_msg = (struct mg_mqtt_message *)ev_data; - //if ( mqtt_msg->topic.buf[mqtt_msg->topic.len-3] == 's' || mqtt_msg->topic.buf[mqtt_msg->topic.len-3] == 'S') - /* - if (mqtt_msg->id != 0) { // NSF Not good check mongoose.h # 2842 - LOG(NET_LOG,LOG_DEBUG, "MQTT: received (msg_id: %d), looks like my own message, ignoring\n", mqtt_msg->id); - break; - }*/ -// NSF Need to change strlen to a global so it's not executed every time we check a topic - if ( ( mqtt_msg->topic.buf[mqtt_msg->topic.len-3] == 's' || mqtt_msg->topic.buf[mqtt_msg->topic.len-3] == 'S') && - ( mqtt_msg->topic.buf[mqtt_msg->topic.len-2] == 'e' || mqtt_msg->topic.buf[mqtt_msg->topic.len-2] == 'E') && - ( mqtt_msg->topic.buf[mqtt_msg->topic.len-1] == 't' || mqtt_msg->topic.buf[mqtt_msg->topic.len-1] == 'T') && - (_aqconfig_.mqtt_aq_topic != NULL && strncmp(mqtt_msg->topic.buf, _aqconfig_.mqtt_aq_topic, strlen(_aqconfig_.mqtt_aq_topic)) == 0) ) + // We are only subscribed to aqualink topic, (so not checking that). + // Just check we have "set" as string end + if ( FAST_SUFFIX_3_CI(mqtt_msg->topic.buf, mqtt_msg->topic.len, "set")) { DEBUG_TIMER_START(&tid); action_mqtt_message(nc, mqtt_msg); diff --git a/source/version.h b/source/version.h index 900702a..1aabe04 100644 --- a/source/version.h +++ b/source/version.h @@ -4,5 +4,5 @@ #define AQUALINKD_SHORT_NAME "AqualinkD" // Use Magor . Minor . Patch -#define AQUALINKD_VERSION "3.0.0 (dev 3)" +#define AQUALINKD_VERSION "3.0.0 (dev 4)" \ No newline at end of file diff --git a/web/config.js b/web/config.js index 609d1bf..7f9085c 100644 --- a/web/config.js +++ b/web/config.js @@ -104,14 +104,13 @@ // this will show RPM for all pumps (ie Jandy VF pumps) //var show_vsp_gpm=false; - // By default all Temperatures & Value tiles are on when they have a value other than 0. - // this will turn them off permanently - //var turn_off_sensortiles = true; + // Keeps sensor tiles in on state showing last reading. (default true= turn off tiles when device is off. ie SWG=off turn off PPM tile) + //var turn_off_sensortiles = false; // This will turn on/off the Spa Heater when you turn on/off Spa Mode. //var link_spa_and_spa_heater = true; - /* + /* Example of setting custom range and appropriate messages var tile_thresholds = { "SWG/PPM": { outofrange: {min: 2600, max: 3500, mintext:"Add Salt"}, diff --git a/web/controller.html b/web/controller.html index dcd22aa..4aaefe8 100644 --- a/web/controller.html +++ b/web/controller.html @@ -663,7 +663,7 @@ } } - const _turn_off_sensortiles = (typeof turn_off_sensortiles !== 'undefined') ? turn_off_sensortiles : false; + const _turn_off_sensortiles = (typeof turn_off_sensortiles !== 'undefined') ? turn_off_sensortiles : true; const _show_vsp_gpm = (typeof show_vsp_gpm !== 'undefined') ? show_vsp_gpm : true; const _link_spa_and_heater = (typeof link_spa_and_spa_heater !== 'undefined') ? link_spa_and_spa_heater : false; @@ -1129,14 +1129,17 @@ } } - if ((type == 'temperature' || type == 'value') && _turn_off_sensortiles == false) { + if ((type == 'temperature' || type == 'value') /*&& _turn_off_sensortiles == false*/) { // Anything specific (SWG PPM should be off if SWG is off) // This needs a try catch, or is above try block good enough? - if (id == 'SWG/PPM' && document.getElementById('SWG').getAttribute('status') != 'on' ) { + if (id == 'SWG/PPM' && document.getElementById('SWG').getAttribute('status') != 'on' && _turn_off_sensortiles) { + setTileOn(id, 'off'); + setTileOnText(id, ""); + } else if ( (id == 'CHEM/ORP' || id == 'CHEM/pH' ) && document.getElementById('Filter_Pump').getAttribute('status') == 'off' && _turn_off_sensortiles) { setTileOn(id, 'off'); setTileOnText(id, ""); // Generic for all. - } else if (value == 0 || value == '--') { + } else if ((value == 0 || value == '--') && _turn_off_sensortiles) { setTileOn(id, 'off'); setTileOnText(id, ""); } else {