mirror of https://github.com/sfeakes/AqualinkD.git
parent
ab5c8f591c
commit
1333597ce1
|
|
@ -153,6 +153,13 @@ AqualinkD will be moving over to github hosted runners for compiling, currently
|
|||
<br>
|
||||
<br>
|
||||
|
||||
# Updates in 3.0.1
|
||||
* UI Update for web config.
|
||||
* UI Now support for themes. (auto, dark, light -or- custom)
|
||||
* Fixed UI not updating for sensors.
|
||||
* Updates to UOM's for HA. gal/min, W, rpm
|
||||
* Fix issue with multiple bad sensors in config.
|
||||
|
||||
# Updates in 3.0.0
|
||||
* <B>NOTE:- When upgradeing to v3.0.0</b> if you see bank AqualinkD screen (ie no buttons), please clear browser cache. This also goes for the mobile/webapp (you may need to delete and re-add to mobile home screen)
|
||||
* Serial optimization for AqualinkD HAT.
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -10,7 +10,7 @@
|
|||
#include "sensors.h"
|
||||
//#include "aq_panel.h" // Moved to later in file to overcome circular dependancy. (crappy I know)
|
||||
|
||||
//#define DPRINTF(format, ...) printf("%s:%d: " format, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#define DPRINTF(format, ...) printf("%s:%d: " format, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
//#define DPRINTF(format, ...)
|
||||
|
||||
#define isMASK_SET(bitmask, mask) ((bitmask & mask) == mask)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
|
|||
"Mardi Gras", // 0x50 (home panel) // 0x4b (simulator)
|
||||
"Cool Cabaret" // 0x51 (home panel) // 0x4c
|
||||
},
|
||||
{// 7 = Jandy Infinate Water Colors (RS485)
|
||||
{// 7 = Jandy Infinite Water Colors (RS485)
|
||||
"Off",
|
||||
"Alpine White",
|
||||
"Sky Blue",
|
||||
|
|
|
|||
|
|
@ -243,6 +243,15 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.web_config;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
_cfgParams[_numCfgParams].name = CFG_N_web_cfg_file;
|
||||
//_cfgParams[_numCfgParams].advanced = true;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
|
||||
_cfgParams[_numCfgParams].default_value = NULL;
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.paneltype_mask;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_SPECIAL;
|
||||
|
|
@ -1628,17 +1637,21 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
}
|
||||
|
||||
// Make sure all sensors are fully populated
|
||||
int sec = 0; // sensor error count
|
||||
for (i=0; i < aqdata->num_sensors; i++ ) {
|
||||
//if (aqdata->sensors[i].uom == NULL) {
|
||||
// aqdata->sensors[i].uom = cleanalloc("°C");
|
||||
//}
|
||||
if ( aqdata->sensors[i].label == NULL || aqdata->sensors[i].path == NULL ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Invalid sensor %d, removing!\n",i+1);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Invalid sensor %d, removing!\n",i+1+sec);
|
||||
sec++;
|
||||
setMASK(errors, ERR_INVALID_SENSORS);
|
||||
if (i == (aqdata->num_sensors-1) ) { // last sensor
|
||||
// don't need to do anything, just reduce total number sensors
|
||||
} else if (aqdata->num_sensors > 1) { // there are more sensors adter this bad one
|
||||
//printf("Remove last sensor\n");
|
||||
} else if (aqdata->num_sensors > 1) { // there are more sensors after this bad one
|
||||
for (int j=i; j < aqdata->num_sensors; j++) {
|
||||
//printf("Moved sensor %d to %d\n",(j+1),j);
|
||||
aqdata->sensors[j].label = aqdata->sensors[j+1].label;
|
||||
aqdata->sensors[j].path = aqdata->sensors[j+1].path;
|
||||
aqdata->sensors[j].factor = aqdata->sensors[j+1].factor;
|
||||
|
|
@ -1648,6 +1661,7 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
sprintf(aqdata->sensors[j].ID, "Aux_S%d", j+1);
|
||||
//printf("Sensor %d = %s, %s\n",j,aqdata->sensors[j].ID,aqdata->sensors[j].label);
|
||||
}
|
||||
i--; // Need re-test i incase we have multiple blank sensors
|
||||
}
|
||||
if (aqdata->num_sensors > 1) {
|
||||
aqdata->num_sensors --;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct aqconfig
|
|||
unsigned int log_level;
|
||||
unsigned int mg_log_level;
|
||||
char *web_directory;
|
||||
char *web_config;
|
||||
unsigned char device_id;
|
||||
unsigned char rssa_device_id;
|
||||
uint16_t paneltype_mask;
|
||||
|
|
@ -257,6 +258,7 @@ int _numCfgParams;
|
|||
#define CFG_N_cert_dir "https_cert_dir"
|
||||
|
||||
#define CFG_N_web_directory "web_directory"
|
||||
#define CFG_N_web_cfg_file "web_config_json"
|
||||
#define CFG_N_device_id "device_id"
|
||||
|
||||
#define CFG_V_device_id "[\"0x0a\", \"0x0b\", \"0x09\", \"0x08\", \"0x60\", \"0x33\", \"0xFF\"]"
|
||||
|
|
|
|||
|
|
@ -636,7 +636,7 @@ void publish_mqtt_discovery(struct aqualinkdata *aqdata, struct mg_connection *n
|
|||
"Pump",pn,"GPM",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","GPM",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_GPM_TOPIC,
|
||||
"GPM");
|
||||
"gal/min");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_discovery_topic, "Pump",pn,"GPM");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
|
|
@ -688,7 +688,7 @@ void publish_mqtt_discovery(struct aqualinkdata *aqdata, struct mg_connection *n
|
|||
"Pump",pn,"RPM",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","RPM",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_RPM_TOPIC,
|
||||
"RPM");
|
||||
"rpm");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_discovery_topic, "Pump",pn,"RPM");
|
||||
send_mqtt(nc, topic, msg);
|
||||
|
||||
|
|
@ -698,7 +698,7 @@ void publish_mqtt_discovery(struct aqualinkdata *aqdata, struct mg_connection *n
|
|||
"Pump",pn,"Watts",
|
||||
aqdata->pumps[i].button->label,(rsm_strncasestr(aqdata->pumps[i].button->label,"pump",strlen(aqdata->pumps[i].button->label))!=NULL)?"":"Pump","Watts",
|
||||
_aqconfig_.mqtt_aq_topic,aqdata->pumps[i].button->name ,PUMP_WATTS_TOPIC,
|
||||
"Watts");
|
||||
"W");
|
||||
sprintf(topic, "%s/sensor/aqualinkd/aqualinkd_%s%d_%s/config", _aqconfig_.mqtt_discovery_topic, "Pump",pn,"Watts");
|
||||
send_mqtt(nc, topic, msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1588,12 +1588,40 @@ void log_http_request(int level, char *message, struct mg_http_message *http_msg
|
|||
strncpy(uri, http_msg->uri.buf, http_msg->uri.len + http_msg->query.len + 1);
|
||||
uri[http_msg->uri.len + http_msg->query.len + 1] = '\0';
|
||||
|
||||
LOG(NET_LOG,level, "%s: '%s'\n", message, uri);
|
||||
LOG(NET_LOG,level, "%s: '%s', length %d\n", message, uri, http_msg->uri.len);
|
||||
|
||||
free(uri);
|
||||
}
|
||||
|
||||
void action_web_request(struct mg_connection *nc, struct mg_http_message *http_msg) {
|
||||
void serve_file(struct mg_connection *nc, struct mg_http_message *http_msg)
|
||||
{
|
||||
// Anything with .json should not be cached.
|
||||
if (FAST_SUFFIX_4_CI(http_msg->uri.buf, http_msg->uri.len, "json"))
|
||||
{
|
||||
if (_aqconfig_.web_config != NULL && strncmp(http_msg->uri.buf, "/config.json", 12) == 0)
|
||||
{
|
||||
mg_http_serve_file(nc, http_msg, _aqconfig_.web_config, &_http_server_opts_nocache);
|
||||
LOG(NET_LOG, LOG_NOTICE, "Using %s for web config\n", _aqconfig_.web_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_http_serve_dir(nc, http_msg, &_http_server_opts_nocache);
|
||||
}
|
||||
}
|
||||
else // can cache anything here.
|
||||
{
|
||||
if (http_msg->uri.len <= 12 && strncmp(http_msg->uri.buf, "/aqmanager", 10) == 0) {
|
||||
char buf[256];
|
||||
snprintf(buf, 256, "%s/aqmanager.html", _aqconfig_.web_directory);
|
||||
mg_http_serve_file(nc, http_msg, buf, &_http_server_opts);
|
||||
} else {
|
||||
mg_http_serve_dir(nc, http_msg, &_http_server_opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void action_web_request(struct mg_connection *nc, struct mg_http_message *http_msg)
|
||||
{
|
||||
char *msg = NULL;
|
||||
// struct http_message *http_msg = (struct http_message *)ev_data;
|
||||
#ifdef AQ_TM_DEBUG
|
||||
|
|
@ -1601,165 +1629,168 @@ void action_web_request(struct mg_connection *nc, struct mg_http_message *http_m
|
|||
int tid2;
|
||||
#endif
|
||||
|
||||
//DEBUG_TIMER_START(&tid);
|
||||
if (getLogLevel(NET_LOG) >= LOG_INFO) { // Simply for log message, check we are at
|
||||
// this log level before running all this junk
|
||||
/*
|
||||
char *uri = (char *)malloc(http_msg->uri.len + http_msg->query_string.len + 2);
|
||||
strncpy(uri, http_msg->uri.p, http_msg->uri.len + http_msg->query_string.len + 1);
|
||||
uri[http_msg->uri.len + http_msg->query_string.len + 1] = '\0';
|
||||
LOG(NET_LOG,LOG_INFO, "URI request: '%s'\n", uri);
|
||||
free(uri);*/
|
||||
log_http_request(LOG_INFO, "URI request: ", http_msg);
|
||||
// DEBUG_TIMER_START(&tid);
|
||||
if (getLogLevel(NET_LOG) >= LOG_INFO)
|
||||
{ // Simply for log message, check we are at
|
||||
log_http_request(LOG_INFO, "URI request", http_msg);
|
||||
}
|
||||
//DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request debug print crap took");
|
||||
// DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request debug print crap took");
|
||||
|
||||
//LOG(NET_LOG,LOG_INFO, "Message request:\n'%.*s'\n", http_msg->message.len, http_msg->message.p);
|
||||
// LOG(NET_LOG,LOG_INFO, "Message request:\n'%.*s'\n", http_msg->message.len, http_msg->message.p);
|
||||
|
||||
// If we have a get request, pass it
|
||||
if (strncmp(http_msg->uri.buf, "/api", 4 ) != 0) {
|
||||
DEBUG_TIMER_START(&tid);
|
||||
//if ( FAST_SUFFIX_3_CI(http_msg->uri.buf, http_msg->uri.len, ".js") ) {
|
||||
if ( FAST_SUFFIX_4_CI(http_msg->uri.buf, http_msg->uri.len, "json") ) {
|
||||
mg_http_serve_dir(nc, http_msg, &_http_server_opts_nocache);
|
||||
} else {
|
||||
mg_http_serve_dir(nc, http_msg, &_http_server_opts);
|
||||
}
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took");
|
||||
} else {
|
||||
char buf[JSON_BUFFER_SIZE];
|
||||
float value = 0;
|
||||
// If we have a get request (ie file), pass it
|
||||
if (strncmp(http_msg->uri.buf, "/api", 4) != 0)
|
||||
{
|
||||
DEBUG_TIMER_START(&tid);
|
||||
|
||||
// If query string.
|
||||
if (http_msg->query.len > 1) {
|
||||
//mg_get_http_var(&http_msg->query, "value", buf, sizeof(buf)); // Old mosquitto
|
||||
mg_http_get_var(&http_msg->query, "value", buf, sizeof(buf));
|
||||
value = atof(buf);
|
||||
} else if (http_msg->body.len > 1) {
|
||||
value = pass_mg_body(&http_msg->body);
|
||||
}
|
||||
|
||||
int len = mg_url_decode(http_msg->uri.buf, http_msg->uri.len, buf, 50, 0);
|
||||
|
||||
if (strncmp(http_msg->uri.buf, "/api/",4) == 0) {
|
||||
switch (action_URI(NET_API, &buf[5], len-5, value, false, &msg)) {
|
||||
case uActioned:
|
||||
mg_http_reply(nc, 200, CONTENT_TEXT, GET_RTN_OK);
|
||||
break;
|
||||
case uDevices:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, false);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_device_JSON took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uHomebridge:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, true);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uStatus:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_aqualink_status_JSON(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_aqualink_status_JSON took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uDynamicconf:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
/*
|
||||
build_dynamic_webconfig_js(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_webconfig_js took");
|
||||
mg_http_reply(nc, 200, CONTENT_JS, message);
|
||||
*/
|
||||
build_dynamic_webconfig_json(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_webconfig_json took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uSchedules:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_schedules_js(message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_schedules_js took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uSetSchedules:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
save_schedules_js(http_msg->body.buf, http_msg->body.len, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() save_schedules_js took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uConfig:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_aqualink_config_JSON(message, JSON_BUFFER_SIZE, _aqualink_data);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_aqualink_config_JSON took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
#ifndef AQ_MANAGER
|
||||
case uDebugStatus:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
snprintf(message,80,"{\"sLevel\":\"%s\", \"iLevel\":%d, \"logReady\":\"%s\"}\n",elevel2text(getLogLevel(NET_LOG)),getLogLevel(NET_LOG),islogFileReady()?"true":"false" );
|
||||
mg_http_reply(nc, 200, CONTENT_JS, message);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case uLogDownload:
|
||||
//int lines = 1000;
|
||||
#define DEFAULT_LOG_DOWNLOAD_LINES 100
|
||||
// If lines was passed in post use it, if not see if it's next path in URI is a number
|
||||
if (value == 0.0) {
|
||||
// /api/<downloadmsg>/<lines>
|
||||
char *pt = rsm_lastindexof(buf, "/", strlen(buf));
|
||||
value = atoi(pt+1);
|
||||
}
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading log of max %d lines\n",value>0?(int)value:DEFAULT_LOG_DOWNLOAD_LINES);
|
||||
if (write_systemd_logmessages_2file("/dev/shm/aqualinkd.log", value>0?(int)value:DEFAULT_LOG_DOWNLOAD_LINES) ) {
|
||||
mg_http_serve_file(nc, http_msg, "/dev/shm/aqualinkd.log", &_http_server_opts_nocache);
|
||||
remove("/dev/shm/aqualinkd.log");
|
||||
}
|
||||
break;
|
||||
|
||||
case uConfigDownload:
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading config\n");
|
||||
mg_http_serve_file(nc, http_msg, _aqconfig_.config_file, &_http_server_opts_nocache);
|
||||
break;
|
||||
#endif
|
||||
case uBad:
|
||||
default:
|
||||
if (msg == NULL) {
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, GET_RTN_UNKNOWN);
|
||||
} else {
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, GET_RTN_UNKNOWN);
|
||||
}
|
||||
|
||||
sprintf(buf, "action_web_request() request '%.*s' took",(int)http_msg->uri.len, http_msg->uri.buf);
|
||||
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, buf);
|
||||
serve_file(nc, http_msg);
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took");
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[JSON_BUFFER_SIZE];
|
||||
float value = 0;
|
||||
DEBUG_TIMER_START(&tid);
|
||||
|
||||
// If query string.
|
||||
if (http_msg->query.len > 1)
|
||||
{
|
||||
// mg_get_http_var(&http_msg->query, "value", buf, sizeof(buf)); // Old mosquitto
|
||||
mg_http_get_var(&http_msg->query, "value", buf, sizeof(buf));
|
||||
value = atof(buf);
|
||||
}
|
||||
else if (http_msg->body.len > 1)
|
||||
{
|
||||
value = pass_mg_body(&http_msg->body);
|
||||
}
|
||||
|
||||
int len = mg_url_decode(http_msg->uri.buf, http_msg->uri.len, buf, 50, 0);
|
||||
|
||||
if (strncmp(http_msg->uri.buf, "/api/", 4) == 0)
|
||||
{
|
||||
switch (action_URI(NET_API, &buf[5], len - 5, value, false, &msg))
|
||||
{
|
||||
case uActioned:
|
||||
mg_http_reply(nc, 200, CONTENT_TEXT, GET_RTN_OK);
|
||||
break;
|
||||
case uDevices:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, false);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_device_JSON took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uHomebridge:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, true);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uStatus:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_aqualink_status_JSON(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_aqualink_status_JSON took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uDynamicconf:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
/*
|
||||
build_dynamic_webconfig_js(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_webconfig_js took");
|
||||
mg_http_reply(nc, 200, CONTENT_JS, message);
|
||||
*/
|
||||
build_dynamic_webconfig_json(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_webconfig_json took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uSchedules:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_schedules_js(message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_schedules_js took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uSetSchedules:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
save_schedules_js(http_msg->body.buf, http_msg->body.len, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() save_schedules_js took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uConfig:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
build_aqualink_config_JSON(message, JSON_BUFFER_SIZE, _aqualink_data);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_aqualink_config_JSON took");
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
#ifndef AQ_MANAGER
|
||||
case uDebugStatus:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
snprintf(message, 80, "{\"sLevel\":\"%s\", \"iLevel\":%d, \"logReady\":\"%s\"}\n", elevel2text(getLogLevel(NET_LOG)), getLogLevel(NET_LOG), islogFileReady() ? "true" : "false");
|
||||
mg_http_reply(nc, 200, CONTENT_JS, message);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case uLogDownload:
|
||||
// int lines = 1000;
|
||||
#define DEFAULT_LOG_DOWNLOAD_LINES 100
|
||||
// If lines was passed in post use it, if not see if it's next path in URI is a number
|
||||
if (value == 0.0)
|
||||
{
|
||||
// /api/<downloadmsg>/<lines>
|
||||
char *pt = rsm_lastindexof(buf, "/", strlen(buf));
|
||||
value = atoi(pt + 1);
|
||||
}
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading log of max %d lines\n", value > 0 ? (int)value : DEFAULT_LOG_DOWNLOAD_LINES);
|
||||
if (write_systemd_logmessages_2file("/dev/shm/aqualinkd.log", value > 0 ? (int)value : DEFAULT_LOG_DOWNLOAD_LINES))
|
||||
{
|
||||
mg_http_serve_file(nc, http_msg, "/dev/shm/aqualinkd.log", &_http_server_opts_nocache);
|
||||
remove("/dev/shm/aqualinkd.log");
|
||||
}
|
||||
break;
|
||||
|
||||
case uConfigDownload:
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading config\n");
|
||||
mg_http_serve_file(nc, http_msg, _aqconfig_.config_file, &_http_server_opts_nocache);
|
||||
break;
|
||||
#endif
|
||||
case uBad:
|
||||
default:
|
||||
if (msg == NULL)
|
||||
{
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, GET_RTN_UNKNOWN);
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, GET_RTN_UNKNOWN);
|
||||
}
|
||||
|
||||
sprintf(buf, "action_web_request() request '%.*s' took", (int)http_msg->uri.len, http_msg->uri.buf);
|
||||
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, buf);
|
||||
}
|
||||
|
||||
void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm) {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ bool read_sensor(external_sensor *sensor) {
|
|||
status = regcomp(&preg, sensor->regex, REG_EXTENDED);
|
||||
if (status != 0) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Compiling sensor regex %s\n",sensor->regex);
|
||||
return 1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Run regex
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
#define AQUALINKD_SHORT_NAME "AqualinkD"
|
||||
|
||||
// Use Magor . Minor . Patch
|
||||
#define AQUALINKD_VERSION "3.0.0"
|
||||
#define AQUALINKD_VERSION "3.0.1"
|
||||
|
||||
|
|
@ -84,8 +84,11 @@ int save_web_config_json(const char* inBuf, int inSize, char* outBuf, int outSiz
|
|||
bool created_file;
|
||||
char *contents;
|
||||
|
||||
snprintf(configfile, 256, "%s%s", _aqconfig_.web_directory,WEBCONFIGFILE);
|
||||
|
||||
if ( _aqconfig_.web_config !=NULL) {
|
||||
snprintf(configfile, 256, "%s", _aqconfig_.web_config);
|
||||
} else {
|
||||
snprintf(configfile, 256, "%s%s", _aqconfig_.web_directory,WEBCONFIGFILE);
|
||||
}
|
||||
|
||||
fp = aq_open_file(configfile, &ro_root, &created_file);
|
||||
|
||||
|
|
|
|||
|
|
@ -450,6 +450,7 @@
|
|||
|
||||
.invalid_json {
|
||||
background-color: rgb(255, 100, 0);
|
||||
border-radius: 9px !important;
|
||||
}
|
||||
|
||||
.textarea-container {
|
||||
|
|
@ -1585,7 +1586,7 @@
|
|||
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
|
||||
//console.log("Height="+h);
|
||||
document.documentElement.style.setProperty('--max-config-height', (h - 50) + 'px');
|
||||
document.documentElement.style.setProperty('--web-config-textarea-height', (h - 180) + 'px');
|
||||
document.documentElement.style.setProperty('--web-config-textarea-height', (h - 190) + 'px');
|
||||
document.getElementById("web_config_options").classList.remove("hide");
|
||||
document.getElementById("web_config_options_pane").classList.remove("hide");
|
||||
// Link the scroll for the two text areas.
|
||||
|
|
@ -2492,6 +2493,11 @@
|
|||
<!-- <input type="button" onclick="updateWebConfigFromMaster()" value="get new"></input> -->
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" align="right" style="width:100%;padding:0px;">
|
||||
<input type="button" onclick="updateWebConfigFromMaster()" value="Get latest config from Github" style="scale:0.75;"></input>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div id="validation-result" style="padding-left: 10px;padding-right: 10px;"></div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
{
|
||||
"theme": "",
|
||||
"background_image": {
|
||||
"url": "hk/background.jpg",
|
||||
"url-light": "hk/background-light.jpg",
|
||||
"url-dark": "hk/background-dark.jpg",
|
||||
"url_reload": 0
|
||||
},
|
||||
"colors": {
|
||||
"colors-light": {
|
||||
"body_background": "#EBEBEB",
|
||||
"body_text": "#000000",
|
||||
"options_pane_background": "#F5F5F5",
|
||||
|
|
@ -26,7 +29,34 @@
|
|||
"tile_icon_background_color_heat": "rgb(255, 123, 0)",
|
||||
"tile_icon_background_color_cool": "rgb(4, 159, 248)",
|
||||
"tile_icon_background_color_enabled": "rgb(78, 196, 0)",
|
||||
"tile_icon_background_color_disabled": "rgb(110, 110, 110)"
|
||||
"tile_icon_background_color_disabled": "rgb(110, 110, 110)",
|
||||
"tile_off_opacity": "0.90"
|
||||
},
|
||||
"colors-dark": {
|
||||
"body_background": "#121212",
|
||||
"body_text": "#FFFFFF",
|
||||
"options_pane_background": "#1E1E1E",
|
||||
"options_pane_bordercolor": "#555555",
|
||||
"options_slider_highlight": "#64B5F6",
|
||||
"options_slider_lowlight": "#555555",
|
||||
"head_background": "#004d7a",
|
||||
"head_text": "#FFFFFF",
|
||||
"error_background": "#b00020",
|
||||
"tile_background": "#333333",
|
||||
"tile_text": "#AAAAAA",
|
||||
"tile_on_background": "#BBBBBB",
|
||||
"tile_on_text": "#000000",
|
||||
"tile_status_text": "#7b7b7b",
|
||||
"value_tile_normal_color": "#049FF8",
|
||||
"value_tile_attention_color": "#b04300",
|
||||
"value_tile_outofrange_color": "#b02300",
|
||||
"options_radio_highlight": "#64B5F6",
|
||||
"options_radio_lowlight": "#555555",
|
||||
"tile_icon_background_color_heat": "rgb(255, 123, 0)",
|
||||
"tile_icon_background_color_cool": "rgb(4, 159, 248)",
|
||||
"tile_icon_background_color_enabled": "rgb(78, 196, 0)",
|
||||
"tile_icon_background_color_disabled": "rgb(110, 110, 110)",
|
||||
"tile_off_opacity": "0.90"
|
||||
},
|
||||
"devices": {
|
||||
"Filter_Pump": {
|
||||
|
|
@ -272,31 +302,5 @@
|
|||
"show_vsp_gpm": "true",
|
||||
"disable_off_icon_background": "true",
|
||||
"light_program_use_dropdown": "false"
|
||||
},
|
||||
"colors-dark-example": {
|
||||
"body_background": "#121212",
|
||||
"body_text": "#FFFFFF",
|
||||
"options_pane_background": "#1E1E1E",
|
||||
"options_pane_bordercolor": "#555555",
|
||||
"options_slider_highlight": "#64B5F6",
|
||||
"options_slider_lowlight": "#555555",
|
||||
"head_background": "#004d7a",
|
||||
"head_text": "#FFFFFF",
|
||||
"error_background": "#b00020",
|
||||
"tile_background": "#333333",
|
||||
"tile_text": "#AAAAAA",
|
||||
"tile_on_background": "#BBBBBB",
|
||||
"tile_on_text": "#000000",
|
||||
"tile_status_text": "#888888",
|
||||
"value_tile_normal_color": "#049FF8",
|
||||
"value_tile_normal_color_": "#69F0AE",
|
||||
"value_tile_attention_color": "#FFB74D",
|
||||
"value_tile_outofrange_color": "#FF8A65",
|
||||
"options_radio_highlight": "#64B5F6",
|
||||
"options_radio_lowlight": "#555555",
|
||||
"tile_icon_background_color_heat": "rgb(255, 123, 0)",
|
||||
"tile_icon_background_color_cool": "rgb(4, 159, 248)",
|
||||
"tile_icon_background_color_enabled": "rgb(78, 196, 0)",
|
||||
"tile_icon_background_color_disabled": "rgb(110, 110, 110)"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 624 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 856 KiB |
|
|
@ -9,6 +9,7 @@
|
|||
<meta name='mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<meta name="apple-mobile-web-app-title" content="AqualinkD">
|
||||
|
||||
|
||||
<link href='aqualinkd.png' rel='apple-touch-icon'>
|
||||
|
|
@ -71,6 +72,8 @@
|
|||
--tile_icon_background_color_cool: rgb(4, 159, 248);
|
||||
--tile_icon_background_color_enabled: rgb(78, 196, 0);
|
||||
--tile_icon_background_color_disabled: rgb(110, 110, 110);
|
||||
|
||||
--tile_off_opacity: 0.95;
|
||||
}
|
||||
|
||||
div {
|
||||
|
|
@ -256,8 +259,8 @@
|
|||
padding: 5px;
|
||||
height: var(--tile-width);
|
||||
width: var(--tile-width);
|
||||
filter: opacity(95%);
|
||||
opacity: 0.95;
|
||||
/*filter: opacity(90%);*/
|
||||
opacity: var(--tile_off_opacity);
|
||||
}
|
||||
|
||||
.on {
|
||||
|
|
@ -763,6 +766,7 @@
|
|||
var _tile_line_char_limit = 0;
|
||||
var _devices = [];
|
||||
var _enable_schedules = false;
|
||||
var _theme = "";
|
||||
|
||||
var _switchOnUri;
|
||||
var _switchOffUri;
|
||||
|
|
@ -770,8 +774,8 @@
|
|||
|
||||
var _DisableOffIconCircle = true;
|
||||
|
||||
//_switchOnUri = createSwitchIcon("rgb(255, 255, 255)", false);
|
||||
//_switchOffUri = createSwitchIcon(_DisableOffIconCircle?"rgb(110, 110, 110)":"rgb(220, 220, 220)", _DisableOffIconCircle);
|
||||
const _isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
//console.log(_isDarkMode ? "Dark mode is on" : "Light mode is on");
|
||||
|
||||
async function loadConfig() {
|
||||
try {
|
||||
|
|
@ -790,6 +794,31 @@
|
|||
//_targetClearErrorMsg = new Date(Date.now() + 5000); // Set 5 sec from now.
|
||||
}
|
||||
|
||||
// Set current theme
|
||||
if ( _config?.theme === "auto" ) {
|
||||
_theme = window.matchMedia("(prefers-color-scheme: dark)").matches?"-dark":"-light";
|
||||
} else if ( _config?.theme ) {
|
||||
_theme = "-"+_config?.theme;
|
||||
} else {
|
||||
_theme = "";
|
||||
}
|
||||
|
||||
// Check we have correct objects for theme.
|
||||
if (_config?.background_image?.["url"+_theme]) {
|
||||
// console.log("Found background image - "+_config?.background_image?.["url"+_theme]);
|
||||
} else {
|
||||
console.log("ERROR: No image background found for theme, json path \"background_image\": {\"url"+_theme+"\":.....}`");
|
||||
}
|
||||
|
||||
if (_config?.["colors"+_theme]) {
|
||||
//console.log("Found colors - colors"+_theme+"{..}");
|
||||
} else {
|
||||
if ( _theme !== "" ) {
|
||||
// Don't error on blank theme, as we use default colors.
|
||||
console.log("ERROR: No colors found for theme '"+_theme+"', json path \"colors"+_theme+"\":{...}`");
|
||||
}
|
||||
}
|
||||
|
||||
// Set defaults.
|
||||
|
||||
if (typeof _config.background_image?.url === 'undefined') {
|
||||
|
|
@ -798,8 +827,9 @@
|
|||
_config.background_image.url_reload = 0;
|
||||
}
|
||||
|
||||
if (_config?.colors?.tile_on_background) {
|
||||
_switchOnUri = createSwitchIcon(_config.colors.tile_on_background, false);
|
||||
//if (_config?.colors?.tile_on_background) {
|
||||
if (_config?.["colors"+_theme]?.tile_on_background) {
|
||||
_switchOnUri = createSwitchIcon(_config["colors"+_theme].tile_on_background, false);
|
||||
} else {
|
||||
_switchOnUri = createSwitchIcon("rgb(255, 255, 255)", false);
|
||||
}
|
||||
|
|
@ -811,14 +841,16 @@
|
|||
}
|
||||
|
||||
if (_DisableOffIconCircle) {
|
||||
if (_config?.colors?.tile_icon_background_color_disabled) {
|
||||
_switchOffUri = createSwitchIcon(_config.colors.tile_icon_background_color_disabled, _DisableOffIconCircle);
|
||||
//if (_config?.colors?.tile_icon_background_color_disabled) {
|
||||
if (_config?.["colors"+_theme]?.tile_icon_background_color_disabled) {
|
||||
_switchOffUri = createSwitchIcon(_config["colors"+_theme].tile_icon_background_color_disabled, _DisableOffIconCircle);
|
||||
} else {
|
||||
_switchOffUri = createSwitchIcon("rgb(110, 110, 110)", _DisableOffIconCircle);
|
||||
}
|
||||
} else {
|
||||
if (_config?.colors?.tile_background) {
|
||||
_switchOffUri = createSwitchIcon(_config.colors.tile_background, _DisableOffIconCircle);
|
||||
//if (_config?.colors?.tile_background) {
|
||||
if (_config?.["colors"+_theme]?.tile_background) {
|
||||
_switchOffUri = createSwitchIcon(_config["colors"+_theme].tile_background, _DisableOffIconCircle);
|
||||
} else {
|
||||
_switchOffUri = createSwitchIcon("rgb(220, 220, 220)", _DisableOffIconCircle);
|
||||
}
|
||||
|
|
@ -1103,13 +1135,13 @@
|
|||
|
||||
// Simply loop over each key/value in color jason array and set that property adding -- to the beginning of key
|
||||
function setColors() {
|
||||
if ( _config?.colors ) {
|
||||
if ( _config?.["colors"+_theme] ) {
|
||||
const rootElement = document.documentElement;
|
||||
|
||||
Object.entries(_config.colors).forEach(([key, value]) => {
|
||||
Object.entries(_config["colors"+_theme]).forEach(([key, value]) => {
|
||||
//console.log(`Key (Color Variable): ${key}, Value (Color Code): ${value}`);
|
||||
//console.log(key+ " " +document.documentElement.style.getPropertyValue('--' + key)+" | "+window.getComputedStyle(document.documentElement).getPropertyValue('--' + key));
|
||||
if (window.getComputedStyle(rootElement).getPropertyValue('--'+key) && _config?.colors[key]) {
|
||||
if (window.getComputedStyle(rootElement).getPropertyValue('--'+key) && _config?.["colors"+_theme][key]) {
|
||||
document.documentElement.style.setProperty('--'+key, value);
|
||||
} else {
|
||||
console.log(`Invalid config (Color Variable): ${key}, Value : ${value}`);
|
||||
|
|
@ -1215,9 +1247,9 @@
|
|||
}
|
||||
|
||||
function load_background() {
|
||||
// check for undevined AND defined but empty
|
||||
// check for undefined AND defined but empty
|
||||
//if (typeof background_url === 'undefined' || background_url === undefined)
|
||||
if (!_config.background_image?.url) {
|
||||
if (!_config.background_image?.["url"+_theme]) {
|
||||
return;
|
||||
}
|
||||
//alert("load");
|
||||
|
|
@ -1233,13 +1265,13 @@
|
|||
//if (typeof background_reload !== 'undefined' && background_reload > 0) {
|
||||
if ( _config.background_image?.url_reload > 0) {
|
||||
if (_config.background_image.url.indexOf('?') > 0 )
|
||||
image.src = _config.background_image.url + '&aqrnd=' + new Date().getTime();
|
||||
image.src = _config.background_image["url"+_theme] + '&aqrnd=' + new Date().getTime();
|
||||
else
|
||||
image.src = _config.background_image.url + '?' + new Date().getTime();
|
||||
image.src = _config.background_image["url"+_theme] + '?' + new Date().getTime();
|
||||
|
||||
setTimeout(load_background, (_config.background_image.url_reload * 1000));
|
||||
} else {
|
||||
image.src = _config.background_image.url;
|
||||
image.src = _config.background_image["url"+_theme];
|
||||
}
|
||||
}
|
||||
// If the grid continer is larger than the page container, increase page so background looks nice
|
||||
|
|
@ -1566,7 +1598,7 @@
|
|||
}
|
||||
} catch (e) {
|
||||
// Devices that are hidden are not found
|
||||
//console.log('ERROR id=' + id + ' Line '+new Error().lineNumber+' | element = '+document.getElementById(id)+"\n"+e);
|
||||
console.log('ERROR id=' + id + ' Line '+new Error().lineNumber+' | element = '+document.getElementById(id)+"\n"+e);
|
||||
}
|
||||
//document.getElementById(id + '_tile_icon_value').textContent = value;
|
||||
var tile;
|
||||
|
|
@ -3154,8 +3186,8 @@
|
|||
|
||||
for (var obj in data.sensors) {
|
||||
//console.log("Set Value `Sensor/"+obj.toString()+"' to "+data.sensors[obj]);
|
||||
//setTileValue("Sensor/"+obj.toString(), data.sensors[obj]);
|
||||
setTileValue(obj.toString(), data.sensors[obj]);
|
||||
setTileValue("Sensor/"+obj.toString(), data.sensors[obj]);
|
||||
//setTileValue(obj.toString(), data.sensors[obj]);
|
||||
}
|
||||
|
||||
for (var obj in data.alternate_modes) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue