diff --git a/README.md b/README.md index 735efe6..21c6ab6 100644 --- a/README.md +++ b/README.md @@ -125,10 +125,20 @@ NEED TO FIX FOR THIS RELEASE. * Try an auto-update * Update Mongoose + +* PDA Crap. +* pda_aq_programmer line 702/703 color light. +* pda_aq_programmer line 782 back menu testing in pda_init + +* FIX Panel name in config to accept output from panel actual name + + --> -# Updates in 2.6.8 (Dev) +# Updates in 2.6.8 (June 29 2025) * Fixed some UI bugs, added download config option +* Changes to config options & config editor * Heatpump / chiller updates +* PDA updates (detect temperature units, other small changes) # Updates in 2.6.7 (May 23 2025) * Fixed bug with iaqualink protocol when no virtual buttons configured. diff --git a/release/aqualinkd-arm64 b/release/aqualinkd-arm64 index c87d217..239c1df 100755 Binary files a/release/aqualinkd-arm64 and b/release/aqualinkd-arm64 differ diff --git a/release/aqualinkd-armhf b/release/aqualinkd-armhf index c0a6a2b..c573dd1 100755 Binary files a/release/aqualinkd-armhf and b/release/aqualinkd-armhf differ diff --git a/release/aqualinkd.upstart.conf b/release/aqualinkd.upstart.conf deleted file mode 100644 index e37d482..0000000 --- a/release/aqualinkd.upstart.conf +++ /dev/null @@ -1,32 +0,0 @@ -# aqualinkd - aqualinkd job file -# -# check with `initctl check-config aqualinkd` -# -description "aqualink RS daemon service" -author "Me " - -# Stanzas -# -# Stanzas control when and how a process is started and stopped -# See a list of stanzas here: http://upstart.ubuntu.com/wiki/Stanzas#respawn - -# When to start the service -start on runlevel [2345] - -# When to stop the service -stop on runlevel [016] - -# Automatically restart process if crashed -respawn - -# Essentially lets upstart know the process will detach itself to the background -expect fork - -# Run before process -#pre-start script -# [ -d /var/run/myservice ] || mkdir -p /var/run/myservice -# echo "Put bash code here" -#end script - -# Start the process -exec /usr/local/bin/aqualinkd -c /etc/aqualinkd/aqualinkd.conf diff --git a/release/serial_logger-arm64 b/release/serial_logger-arm64 index 70d9597..1c95c48 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 4057c28..f1022be 100755 Binary files a/release/serial_logger-armhf and b/release/serial_logger-armhf differ diff --git a/source/allbutton_aq_programmer.c b/source/allbutton_aq_programmer.c index 1bed271..c654c78 100644 --- a/source/allbutton_aq_programmer.c +++ b/source/allbutton_aq_programmer.c @@ -612,10 +612,12 @@ void *set_allbutton_light_programmode( void *ptr ) } else { for (i = 1; i < val; i++) { const int dt = 0.5; // Time to wait after receiving conformation of light on/off + waitfor_queue2empty(); LOG(ALLB_LOG, LOG_INFO, "Light Programming button press number %d - %s of %d\n", i, "ON", val); send_cmd(code); waitForButtonState(aq_data, button, ON, 2); delay(dt * seconds); + waitfor_queue2empty(); LOG(ALLB_LOG, LOG_INFO, "Light Programming button press number %d - %s of %d\n", i, "OFF", val); send_cmd(code); waitForButtonState(aq_data, button, OFF, 2); @@ -623,7 +625,8 @@ void *set_allbutton_light_programmode( void *ptr ) } LOG(ALLB_LOG, LOG_INFO, "Finished - Light Programming button press number %d - %s of %d\n", i, "ON", val); send_cmd(code); - waitfor_queue2empty(); + //waitfor_queue2empty(); + longwaitfor_queue2empty(); } //waitForButtonState(aq_data, &aq_data->aqbuttons[btn], ON, 2); diff --git a/source/aq_panel.c b/source/aq_panel.c index da87121..3f917ec 100644 --- a/source/aq_panel.c +++ b/source/aq_panel.c @@ -625,6 +625,8 @@ void setPanelByName(struct aqualinkdata *aqdata, const char *str) rs = false; if (str[2] == '-' || str[2] == ' ') // Account for PD-8 size = atoi(&str[3]); + if (str[3] == '-' || str[4] == 'P') // PDA-PS6 Combo + size = atoi(&str[6]); else // Account for PDA-8 size = atoi(&str[4]); } else { @@ -1363,12 +1365,15 @@ void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int de //void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button) void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIndex) { + #ifdef AQ_PDA if (isPDA_PANEL && !isPDA_IAQT) { LOG(PANL_LOG,LOG_ERR, "Light mode control not supported in PDA mode\n"); return; } #endif + + /* int i; clight_detail *light = NULL; @@ -1400,7 +1405,12 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIn } else if (isRSSA_ENABLED) { // If we are using rs-serial then turn light on first. if (light->button->led->state != ON) { - set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON); + set_aqualink_rssadapter_aux_state(light->button, TRUE); + //set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON); + //set_aqualink_rssadapter_aux_extended_state(light->button, 100); + // Add a few delays to slow it down. 0 is get status + //set_aqualink_rssadapter_aux_extended_state(light->button, 0); + //set_aqualink_rssadapter_aux_extended_state(light->button, 0); } if (light->lightType == LC_DIMMER) { // Value 1 = 25, 2 = 50, 3 = 75, 4 = 100 (need to convert value into binary) @@ -1545,8 +1555,13 @@ void updateButtonLightProgram(struct aqualinkdata *aqdata, int value, int button } light->currentValue = value; - if (value > 0) + if (value > 0 && light->lastValue != value) { light->lastValue = value; + if (_aqconfig_.save_light_programming_value && light->lightType == LC_PROGRAMABLE ) { + LOG(PANL_LOG,LOG_NOTICE, "Writing light programming value to config\n",button); + writeCfg(aqdata); + } + } } clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button) diff --git a/source/aq_programmer.c b/source/aq_programmer.c index 3634f91..29b1edb 100644 --- a/source/aq_programmer.c +++ b/source/aq_programmer.c @@ -107,6 +107,7 @@ const func_ptr _prog_functions[AQP_RSSADAPTER_MAX] = { [AQ_PDA_SET_SPA_HEATER_TEMPS] = set_aqualink_PDA_spa_heater_temps, [AQ_PDA_SET_FREEZE_PROTECT_TEMP] = set_aqualink_PDA_freeze_protectsetpoint, [AQ_PDA_SET_TIME] = set_PDA_aqualink_time, + [AQ_PDA_SET_LIGHT_MODE] = set_aqualink_PDA_light_mode, //[AQ_PDA_GET_POOL_SPA_HEATER_TEMPS]= get_aqualink_PDA_pool_spa_heater_temps, [AQ_PDA_GET_FREEZE_PROTECT_TEMP] = get_PDA_aqualink_pool_spa_heater_temps /* @@ -599,6 +600,9 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat case AQ_SET_TIME: type = AQ_PDA_SET_TIME; break; + case AQ_SET_LIGHTCOLOR_MODE: + type = AQ_PDA_SET_LIGHT_MODE; + break; #ifdef BETA_PDA_AUTOLABEL case AQ_GET_AUX_LABELS: type = AQ_PDA_AUX_LABELS: @@ -963,6 +967,9 @@ const char *ptypeName(program_type type) case AQ_PDA_GET_FREEZE_PROTECT_TEMP: return "Get PDA freeze protect"; break; + case AQ_PDA_SET_LIGHT_MODE: + return "Set PDA light mode"; + break; #endif case AQP_NULL: default: @@ -1059,6 +1066,9 @@ const char *programtypeDisplayName(program_type type) case AQ_PDA_WAKE_INIT: return "Programming: PDA wakeup"; break; + case AQ_PDA_SET_LIGHT_MODE: + return "Programming: setting light color"; + break; #endif default: return "Programming: please wait!"; diff --git a/source/aq_programmer.h b/source/aq_programmer.h index 1145554..d827542 100644 --- a/source/aq_programmer.h +++ b/source/aq_programmer.h @@ -78,6 +78,7 @@ typedef enum { AQ_PDA_SET_TIME, AQ_PDA_GET_POOL_SPA_HEATER_TEMPS, AQ_PDA_GET_FREEZE_PROTECT_TEMP, + AQ_PDA_SET_LIGHT_MODE, // ******** OneTouch Delimiter make sure to change MAX/MIN below AQ_SET_ONETOUCH_PUMP_RPM, AQ_SET_ONETOUCH_MACRO, diff --git a/source/aqualinkd.c b/source/aqualinkd.c index 0d2a1b3..65ff23e 100644 --- a/source/aqualinkd.c +++ b/source/aqualinkd.c @@ -1039,7 +1039,7 @@ void main_loop() } */ if (is_valid_port(rs_fd)) { - LOG(AQUA_LOG,LOG_NOTICE, "Listening to Aqualink RS8 on serial port: %s\n", _aqconfig_.serial_port); + LOG(AQUA_LOG,LOG_NOTICE, "Listening to Aqualink %s on serial port: %s\n", getPanelString(), _aqconfig_.serial_port); } else { LOG(AQUA_LOG,LOG_ERR, "Error Aqualink bad serial port: %s\n", _aqconfig_.serial_port); AddAQDstatusMask(ERROR_SERIAL); diff --git a/source/config.c b/source/config.c index 73dc347..cdd8972 100644 --- a/source/config.c +++ b/source/config.c @@ -34,6 +34,8 @@ #include #include #include +#include + #define CONFIG_C #include "config.h" @@ -262,12 +264,15 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].value_type = CFG_STRING; _cfgParams[_numCfgParams].name = CFG_N_mqtt_server; _cfgParams[_numCfgParams].default_value = (void *)_dcfg_null; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; + _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART; _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_user; _cfgParams[_numCfgParams].value_type = CFG_STRING; _cfgParams[_numCfgParams].name = CFG_N_mqtt_user; _cfgParams[_numCfgParams].default_value = (void *)NULL; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_passwd; @@ -275,18 +280,21 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_mqtt_passwd; _cfgParams[_numCfgParams].config_mask |= CFG_PASSWD_MASK; _cfgParams[_numCfgParams].default_value = (void *)NULL; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_aq_topic; _cfgParams[_numCfgParams].value_type = CFG_STRING; _cfgParams[_numCfgParams].name = CFG_N_mqtt_aq_topic; _cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_aq_tp; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _numCfgParams++; _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_hass_discover_topic; _cfgParams[_numCfgParams].value_type = CFG_STRING; _cfgParams[_numCfgParams].name = CFG_N_mqtt_hass_discover_topic; _cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_ha_discover; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _numCfgParams++; @@ -313,6 +321,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_mqtt_dz_sub_topic; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = NULL; _numCfgParams++; @@ -321,6 +330,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_mqtt_dz_pub_topic; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = NULL; /* _numCfgParams++; @@ -336,6 +346,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_dzidx_air_temp; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -344,6 +355,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_dzidx_pool_water_temp; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -352,6 +364,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_dzidx_spa_water_temp; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -360,6 +373,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_dzidx_swg_percent; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -368,6 +382,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_dzidx_swg_ppm; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -376,6 +391,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_dzidx_swg_status; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -384,6 +400,7 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].name = CFG_N_convert_dz_temp; //_cfgParams[_numCfgParams].advanced = true; _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED; + _cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK; _cfgParams[_numCfgParams].default_value = (void *)&unknownInt; _numCfgParams++; @@ -610,6 +627,21 @@ void init_parameters (struct aqconfig * parms) _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_true; #endif + // Optional values to store in config + _numCfgParams++; + _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.save_debug_log_masks; + _cfgParams[_numCfgParams].value_type = CFG_BOOL; + _cfgParams[_numCfgParams].name = CFG_N_save_debug_log_masks; + _cfgParams[_numCfgParams].config_mask |= CFG_READONLY; + _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false; + + _numCfgParams++; + _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.save_light_programming_value; + _cfgParams[_numCfgParams].value_type = CFG_BOOL; + _cfgParams[_numCfgParams].name = CFG_N_save_light_programming_value; + _cfgParams[_numCfgParams].config_mask |= CFG_READONLY; + _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false; + //#endif // Default to daemonize @@ -947,7 +979,7 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) { } if (strlen(cleanwhitespace(value)) <= 0) { - LOG(AQUA_LOG,LOG_NOTICE,"Set configuration option `%s` to default since value is blank\n",_cfgParams[i].name ); + LOG(AQUA_LOG,LOG_INFO,"Set configuration option `%s` to default since value is blank\n",_cfgParams[i].name ); set_cfg_parm_to_default(&_cfgParams[i]); return true; } @@ -1125,9 +1157,8 @@ if (strlen(cleanwhitespace(value)) <= 0) { char *name = cleanalloc(value); int len = strlen(name); if (len > 0) { - if ( strncmp(name+len-7, " - Show", 7) == 0 ) { + if ( strncasecmp(name+len-7, " - show", 7) == 0 ) { name[len-7] = '\0'; - //printf("Value '%s' index %d is show\n",name,num); set_aqualinkd_light_mode_name(name,num,true); } else { set_aqualinkd_light_mode_name(name,num,false); @@ -1159,6 +1190,19 @@ if (strlen(cleanwhitespace(value)) <= 0) { aqdata->aqbuttons[num].label = cleanalloc(value); rtn=true; #endif + } else if (strncasecmp(param + 9, "_lightModeCacheValue", 20) == 0) { + if (isPLIGHT(aqdata->aqbuttons[num].special_mask)) { + if ( ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType == LC_PROGRAMABLE ) { + int val = strtoul(value, NULL, 10); + ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lastValue = val; + printf("**** Set lastValue=%d for %s\n",val,aqdata->aqbuttons[num].label); + } else { + LOG(AQUA_LOG,LOG_ERR, "Config error, '%s' is invalied for light type '%s'\n",value,((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType); + } + } else { + LOG(AQUA_LOG,LOG_ERR, "Config error, Couldn't find light for '%s'\n",value); + } + rtn=true; } else if (strncasecmp(param + 9, "_lightMode", 10) == 0) { int type = strtoul(value, NULL, 10); @@ -1186,6 +1230,18 @@ if (strlen(cleanwhitespace(value)) <= 0) { LOG(AQUA_LOG,LOG_ERR, "Config error, (colored|programmable) Lights limited to %d, ignoring %s'\n",MAX_LIGHTS,param); } rtn=true; + /* + } else if (strncasecmp(param + 9, "_lightModeCacheValue", 20) == 0) { + int val = strtoul(value, NULL, 20); + if (isPLIGHT(aqdata->aqbuttons[num].special_mask)) { + if ( ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType == LC_PROGRAMABLE ) { + ((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lastValue = val; + } else { + LOG(AQUA_LOG,LOG_ERR, "Config error, '%s' is invalied for light type '%s'\n",value,((clight_detail *)aqdata->aqbuttons[num].special_mask_ptr)->lightType); + } + } else { + LOG(AQUA_LOG,LOG_ERR, "Config error, Couldn't find light for '%s'\n",value); + }*/ } else if (strncasecmp(param + 9, "_pump", 5) == 0) { if ( ! populatePumpData(aqdata, param + 10, &aqdata->aqbuttons[num], value) ) @@ -1447,6 +1503,8 @@ void init_config() init_parameters(&_aqconfig_); } + + //void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *cfgFile) void read_config (struct aqualinkdata *aqdata, char *cfgFile) { @@ -1655,6 +1713,26 @@ void check_print_config (struct aqualinkdata *aqdata) } + /* + PDA Mode + + No light mode 11 + (chiller????? ) + + */ + + if (_aqconfig_.device_id == 0x60) { + // Check lights. + for (i = 0; i < aqdata->total_buttons; i++) + { + if (isPLIGHT(aqdata->aqbuttons[i].special_mask)) { + if ( ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType == LC_DIMMER2 ) { + LOG(AQUA_LOG,LOG_WARNING, "Config error, PDA does not support lightmode %d setting to %d\n",LC_DIMMER2,LC_DIMMER); + ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType = LC_DIMMER; + } + } + } + } /* PDA sleep and PDA ID. */ @@ -1918,6 +1996,8 @@ int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, str snprintf(value, 64, "%.*s", (groupArray[2].rm_eo - groupArray[2].rm_so), (cursor + groupArray[2].rm_so)); //printf("**** Pair = %s : %s \n",key,value); + LOG(AQUA_LOG,LOG_DEBUG, "Read json cfg Pair = %s : %s \n",key,value); + // If panel size changed, see if we should ignore the label if (strncasecmp(key, "button_", 7 ) == 0) { if ( strtoul(key + 7, NULL, 10) >= ignodeBtnLabelsGrater) { @@ -2015,6 +2095,18 @@ bool writeCfg (struct aqualinkdata *aqdata) //char fp[100]; + // Testing shit + if (_aqconfig_.save_debug_log_masks) { + for (int i = 0; i < (sizeof(logmask_t) * CHAR_BIT); i++) { + if(isDebugLogMaskSet((1 << i))) { + fprintf(fp, "debug_log_mask=%d\n", (1 << i)); + } + } + fprintf(fp,"\n"); + } + + // Loop over config parameters. + for ( i=0; i <= _numCfgParams; i++) { if (isMASK_SET(_cfgParams[i].config_mask, CFG_HIDE) ) { continue; @@ -2137,6 +2229,9 @@ bool writeCfg (struct aqualinkdata *aqdata) } else if (isPLIGHT(aqdata->aqbuttons[i].special_mask)) { //if (((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType > 0) { fprintf(fp,"%s_lightMode=%d\n", prefix, ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType); + if (_aqconfig_.save_light_programming_value && ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType == LC_PROGRAMABLE ) { + fprintf(fp,"%s_lightModeCacheValue=%d\n", prefix, ((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lastValue); + } //} } else if ( (isVBUTTON(aqdata->aqbuttons[i].special_mask) && aqdata->aqbuttons[i].rssd_code >= IAQ_ONETOUCH_1 && aqdata->aqbuttons[i].rssd_code <= IAQ_ONETOUCH_6 ) ) { fprintf(fp,"%s_onetouchID=%d\n", prefix, (aqdata->aqbuttons[i].rssd_code - 15)); diff --git a/source/config.h b/source/config.h index c751940..4732cea 100644 --- a/source/config.h +++ b/source/config.h @@ -107,6 +107,8 @@ struct aqconfig bool ftdi_low_latency; int frame_delay; bool device_pre_state; + bool save_debug_log_masks; + bool save_light_programming_value; #ifdef AQ_NO_THREAD_NETSERVICE int rs_poll_speed; // Need to remove bool thread_netservices; // Need to remove @@ -192,6 +194,7 @@ typedef enum cfg_value_type{ //#define CFG_READONLY (1 << 4) // Don't show in UI, but do write to CFG file. #define CFG_PASSWD_MASK (1 << 4) // Mask password with ***** #define CFG_FORCE_RESTART (1 << 5) // Force aqualinkd to restart +#define CFG_ALLOW_BLANK (1 << 6) // Allow blank entry //#define CFG_ (1 << 3) // Text to show when CFG_PASSWD_MASK is set @@ -222,152 +225,91 @@ int _numCfgParams; // Below are missed //RSSD_LOG_filter //debug_log_mask + #define CFG_V_BOOL "[\"Yes\", \"No\"]" #define CFG_N_serial_port "serial_port" -#define CFG_C_serial_port 11 #define CFG_N_log_level "log_level" #define CFG_V_log_level "[\"DEBUG_SERIAL\", \"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]" -#define CFG_C_log_level 9 -#define CFG_N_socket_port "socket_port" // Change to Web_socket -#define CFG_C_socket_port 11 +#define CFG_N_socket_port "socket_port" #define CFG_N_web_directory "web_directory" -#define CFG_C_web_directory 13 #define CFG_N_device_id "device_id" #define CFG_V_device_id "[\"0x0a\", \"0x0b\", \"0x09\", \"0x08\", \"0x60\", \"0xFF\"]" -#define CFG_C_device_id 9 #define CFG_N_rssa_device_id "rssa_device_id" #define CFG_V_rssa_device_id "[\"0x00\", \"0x48\"]" -#define CFG_C_rssa_device_id 14 #define CFG_N_RSSD_LOG_filter "RSSD_LOG_filter" #define CFG_C_RSSD_LOG_filter 15 #define CFG_N_panel_type "panel_type" -#define CFG_C_panel_type 10 #define CFG_N_extended_device_id "extended_device_id" #define CFG_V_extended_device_id "[\"0x00\", \"0x30\", \"0x31\", \"0x32\", \"0x33\", \"0x40\", \"0x41\", \"0x42\", \"0x43\"]" -#define CFG_C_extended_device_id 18 #define CFG_N_sync_panel_time "sync_panel_time" -#define CFG_C_sync_panel_time 15 -//#define CFG_N_extended_device_id2 "extended_device_id2" -//#define CFG_C_extended_device_id2 20 #define CFG_N_extended_device_id_programming "extended_device_id_programming" -#define CFG_C_extended_device_id_programming 30 #define CFG_N_enable_iaqualink "enable_iaqualink" -#define CFG_C_enable_iaqualink 16 #define CFG_N_log_file "log_file" -#define CFG_C_log_file 8 #define CFG_N_mqtt_aq_topic "mqtt_aq_topic" -#define CFG_C_mqtt_aq_topic 13 #define CFG_N_mqtt_server "mqtt_address" -#define CFG_C_mqtt_server 12 #define CFG_N_mqtt_user "mqtt_user" -#define CFG_C_mqtt_user 9 #define CFG_N_mqtt_passwd "mqtt_passwd" -#define CFG_C_mqtt_passwd 11 #define CFG_N_mqtt_hass_discover_topic "mqtt_ha_discover_topic" -#define CFG_C_mqtt_hass_discover_topic 24 #define CFG_N_mqtt_hass_discover_use_mac "mqtt_ha_discover_use_mac" -#define CFG_C_mqtt_hass_discover_use_mac 27 #define CFG_N_mqtt_timed_update "mqtt_timed_update" -#define CFG_C_mqtt_timed_update 17 -//#define CFG_N_mqtt_ID "mqtt_ID" -//#define CFG_C_mqtt_ID 7 #define CFG_N_mqtt_dz_sub_topic "mqtt_dz_sub_topic" -#define CFG_C_mqtt_dz_sub_topic 17 #define CFG_N_mqtt_dz_pub_topic "mqtt_dz_pub_topic" -#define CFG_C_mqtt_dz_pub_topic 17 #define CFG_N_dzidx_air_temp "dzidx_air_temp" -#define CFG_C_dzidx_air_temp 14 #define CFG_N_dzidx_pool_water_temp "dzidx_pool_water_temp" -#define CFG_C_dzidx_pool_water_temp 21 #define CFG_N_dzidx_spa_water_temp "dzidx_spa_water_temp" -#define CFG_C_dzidx_spa_water_temp 20 #define CFG_N_dzidx_swg_percent "dzidx_SWG_percent" -#define CFG_C_dzidx_swg_percent 17 #define CFG_N_dzidx_swg_ppm "dzidx_SWG_PPM" -#define CFG_C_dzidx_swg_ppm 13 #define CFG_N_dzidx_swg_status "dzidx_SWG_Status" -#define CFG_C_dzidx_swg_status 16 #define CFG_N_light_programming_mode "light_programming_mode" -#define CFG_C_light_programming_mode 22 #define CFG_N_light_programming_initial_on "light_programming_initial_on" -#define CFG_C_light_programming_initial_on 28 #define CFG_N_light_programming_initial_off "light_programming_initial_off" -#define CFG_C_light_programming_initial_off 29 #define CFG_N_override_freeze_protect "override_freeze_protect" -#define CFG_C_override_freeze_protect 23 #define CFG_N_pda_sleep_mode "pda_sleep_mode" -#define CFG_C_pda_sleep_mode 14 #define CFG_N_convert_mqtt_temp "mqtt_convert_temp_to_c" -#define CFG_C_convert_mqtt_temp 22 #define CFG_N_convert_dz_temp "dz_convert_temp_to_c" -#define CFG_C_convert_dz_temp 20 #define CFG_N_report_zero_spa_temp "report_zero_spa_temp" -#define CFG_C_report_zero_spa_temp 20 #define CFG_N_report_zero_pool_temp "report_zero_pool_temp" -#define CFG_C_report_zero_pool_temp 21 #define CFG_N_read_RS485_devmask "read_RS485_devmask" -#define CFG_C_read_RS485_devmask 18 #define CFG_N_use_panel_aux_labels "use_panel_aux_labels" -#define CFG_C_use_panel_aux_labels 20 #define CFG_N_force_swg "force_swg" -#define CFG_C_force_swg 9 #define CFG_N_force_ps_setpoints "force_ps_setpoints" -#define CFG_C_force_ps_setpoints 18 #define CFG_N_force_frzprotect_setpoints "force_frzprotect_setpoints" -#define CFG_C_force_frzprotect_setpoints 26 #define CFG_N_force_chem_feeder "force_chem_feeder" -#define CFG_C_force_chem_feeder 17 #define CFG_N_force_chiller "force_chiller" #define CFG_N_display_warnings_web "display_warnings_web" -#define CFG_C_display_warnings_web 20 #define CFG_N_log_protocol_packets "log_protocol_packets" -#define CFG_C_log_protocol_packets 20 #define CFG_N_device_pre_state "device_pre_state" -#define CFG_C_device_pre_state 16 #define CFG_N_read_RS485_swg "read_RS485_swg" -#define CFG_C_read_RS485_swg 14 #define CFG_N_read_RS485_ePump "read_RS485_ePump" -#define CFG_C_read_RS485_ePump 16 #define CFG_N_read_RS485_vsfPump "read_RS485_vsfPump" -#define CFG_C_read_RS485_vsfPump 18 #define CFG_N_read_RS485_JXi "read_RS485_JXi" -#define CFG_C_read_RS485_JXi 14 #define CFG_N_read_RS485_LX "read_RS485_LX" -#define CFG_C_read_RS485_LX 13 #define CFG_N_read_RS485_Chem "read_RS485_Chem" -#define CFG_C_read_RS485_Chem 15 #define CFG_N_read_RS485_iAqualink "read_RS485_iAqualink" -#define CFG_C_read_RS485_iAqualink 20 #define CFG_N_read_RS485_HeatPump "read_RS485_HeatPump" #define CFG_N_enable_scheduler "enable_scheduler" -#define CFG_C_enable_scheduler 16 #define CFG_N_event_check_poweron "event_poweron_check_pump" -#define CFG_C_event_check_poweron 24 #define CFG_N_event_check_freezeprotectoff "event_freezeprotectoff_check_pump" -#define CFG_C_event_check_freezeprotectoff 33 #define CFG_N_event_check_boostoff "event_boostoff_check_pump" -#define CFG_C_event_check_boostoff 25 #define CFG_N_event_check_pumpon_hour "event_check_pumpon_hour" -#define CFG_C_event_check_pumpon_hour 23 #define CFG_N_event_check_pumpoff_hour "event_check_pumpoff_hour" -#define CFG_C_event_check_pumpoff_hour 24 #define CFG_N_event_check_usecron "event_check_use_scheduler_times" -#define CFG_C_event_check_usecron 32 #define CFG_N_event_check_booston_device "event_booston_check_device" #define CFG_N_ftdi_low_latency "ftdi_low_latency" -#define CFG_C_ftdi_low_latency 16 #define CFG_N_rs485_frame_delay "rs485_frame_delay" -#define CFG_C_rs485_frame_delay 17 -#endif +#define CFG_N_save_debug_log_masks "save_debug_log_masks" +#define CFG_N_save_light_programming_value "save_light_programming_value" + +#endif \ No newline at end of file diff --git a/source/dummy_device.c b/source/dummy_device.c index 7153472..2c3bc7f 100644 --- a/source/dummy_device.c +++ b/source/dummy_device.c @@ -28,7 +28,14 @@ #include "config.h" +#define SWG +//#define HEATPUMP + +#ifdef SWG +unsigned char DEVICE_ID = 0x50; +#else unsigned char DEVICE_ID = 0x70; +#endif bool _keepRunning = true; int _rs_fd; @@ -43,6 +50,7 @@ bool isAqualinkDStopping() { return !_keepRunning; } +void process_swg_packet(unsigned char *packet_buffer, const int packet_length); void process_heatpump_packet(unsigned char *packet_buffer, const int packet_length); int main(int argc, char *argv[]) @@ -143,7 +151,11 @@ int main(int argc, char *argv[]) if (packet_buffer[PKT_DEST] == DEVICE_ID) { +#ifdef SWG + process_swg_packet(packet_buffer, packet_length); +#else process_heatpump_packet(packet_buffer, packet_length); +#endif } } } @@ -206,3 +218,36 @@ void process_heatpump_packet(unsigned char *packet_buffer, const int packet_leng } +void process_swg_packet(unsigned char *packet_buffer, const int packet_length) +{ + //(packet[3] = 0x16 + //(packet[4] * 100) = PPM + static unsigned char swg_ack[] = {0x00,0x01,0x00,0x00}; + static unsigned char swg_ppm[] = {0x00, 0x16, 0x1f, 0x00, 0x00, 0x00}; + //static unsigned char swg_id[] = {0x00,0x03,0x00,0x49,0x6e,0x74,0x65,0x6c,0x6c,0x69,0x63,0x68,0x6c,0x6f,0x72,0x2d,0x2d,0x34,0x30}; + //static unsigned char swg_id[] = {0x00,0x03,0x00,0x41,0x71,0x75,0x61,0x50,0x75,0x72,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static unsigned char swg_id[] = {0x00,0x03,0x01,0x41,0x71,0x75,0x61,0x50,0x75,0x72,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + // 0x11 set SWG % + if (packet_buffer[PKT_CMD] == CMD_PROBE) + { + //send_ack(_rs_fd, 0x00); + send_jandy_command(_rs_fd, swg_ack, 4); + LOG(SLOG_LOG, LOG_NOTICE, "Replied to Probe packet to 0x%02hhx with ACK\n",packet_buffer[PKT_DEST]); + } + else if (packet_buffer[3] == 0x11) + { + //int percent = (int)packet_buffer[4]; + send_jandy_command(_rs_fd, swg_ppm, 6); + LOG(SLOG_LOG, LOG_NOTICE, "Received %%=%d, Replied PPM=%d\n",(int)packet_buffer[4],swg_ppm[2] * 100); + } + else if (packet_buffer[3] == 0x14) + { + send_jandy_command(_rs_fd, swg_id, 19); + LOG(SLOG_LOG, LOG_NOTICE, "Receive ID request, replied\n"); + } + else + { + LOG(SLOG_LOG, LOG_ERR, "************* Unknown Request 0x%02hhx *************",packet_buffer[3]); + } +} + diff --git a/source/json_messages.c b/source/json_messages.c index b7c461f..97b027a 100644 --- a/source/json_messages.c +++ b/source/json_messages.c @@ -567,6 +567,8 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool buffer[length] = '\0'; +//printf("%s\n",buffer); + return strlen(buffer); //return length; @@ -1204,6 +1206,9 @@ int json_cfg_element(char* buffer, int size, const char *name, const void *value if (isMASKSET(config_mask, CFG_FORCE_RESTART)) adv_size += sprintf(adv+adv_size,",\"force_restart\": \"yes\""); + + if (isMASKSET(config_mask, CFG_ALLOW_BLANK)) + adv_size += sprintf(adv+adv_size,",\"allow_blank\": \"yes\""); switch(type){ @@ -1487,7 +1492,7 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d } else if (isPLIGHT(aq_data->aqbuttons[i].special_mask)) { - if (((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType > 0) { + if (((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType >= 0) { sprintf(buf,"%s_lightMode", prefix); if ((result = json_cfg_element(buffer+length, size-length, buf, &((clight_detail *)aq_data->aqbuttons[i].special_mask_ptr)->lightType, CFG_INT, 0, NULL, 0)) <= 0) { LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length); diff --git a/source/pda.c b/source/pda.c index 50bec8d..8b4c322 100644 --- a/source/pda.c +++ b/source/pda.c @@ -170,6 +170,10 @@ void set_pda_led(struct aqualinkled *led, char state) { led->state = FLASH; } + else if (state == '%') + { + led->state = ON; + } else { led->state = OFF; @@ -253,7 +257,10 @@ void process_pda_packet_msg_long_temp(const char *msg) // 'AIR ' // ' 86` ' // 'AIR WATER' // In case of single device. - _aqualink_data->temp_units = FAHRENHEIT; // Force FAHRENHEIT + if (_aqualink_data->temp_units == UNKNOWN && !in_programming_mode(_aqualink_data)) { + LOG(PDA_LOG,LOG_NOTICE, "Forcing temperature units to FAHRENHEIT\n"); + _aqualink_data->temp_units = FAHRENHEIT; // Force FAHRENHEIT + } if (stristr(pda_m_line(1), "AIR") != NULL) _aqualink_data->air_temp = atoi(msg); @@ -408,6 +415,27 @@ void process_pda_packet_msg_long_set_time(const char *msg) */ } +// +//PDA Line 2 = POOL HEAT 70`F +//PDA Line 3 = SPA HEAT 98`F +// temp units are last char as above. +void get_pda_temp_units(const char *msg) +{ + if (_aqualink_data->temp_units != UNKNOWN) { + return; + } + + if (msg[15] == 'F') { + _aqualink_data->temp_units = FAHRENHEIT; + LOG(PDA_LOG,LOG_DEBUG, "Set temperature units to FAHRENHEIT\n"); + } else if (msg[15] == 'C') { + _aqualink_data->temp_units = CELSIUS; + LOG(PDA_LOG,LOG_DEBUG, "Set temperature units to CELSIUS\n"); + } else { + LOG(PDA_LOG,LOG_DEBUG, "Unknown temperature units '%c'\n",msg[15]); + } +} + void process_pda_packet_msg_long_set_temp(const char *msg) { LOG(PDA_LOG,LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n"); @@ -416,23 +444,27 @@ void process_pda_packet_msg_long_set_temp(const char *msg) { _aqualink_data->pool_htr_set_point = atoi(msg + 10); LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point); + get_pda_temp_units(msg); } else if (stristr(msg, "SPA HEAT") != NULL) { _aqualink_data->spa_htr_set_point = atoi(msg + 10); LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point); + get_pda_temp_units(msg); } else if (stristr(msg, "TEMP1") != NULL) { setSingleDeviceMode(); _aqualink_data->pool_htr_set_point = atoi(msg + 10); LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point); + get_pda_temp_units(msg); } else if (stristr(msg, "TEMP2") != NULL) { setSingleDeviceMode(); _aqualink_data->spa_htr_set_point = atoi(msg + 10); LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point); + get_pda_temp_units(msg); } @@ -519,7 +551,7 @@ void process_pda_packet_msg_long_unknown(const char *msg) // Lets make a guess here and just see if there is an ON/OFF/ENA/*** at the end of the line // When you turn on/off a piece of equiptment, a clear screen followed by single message is sent. // So we are not in any PDA menu, try to catch that message here so we catch new device state ASAP. - if (msg[AQ_MSGLEN - 1] == 'N' || msg[AQ_MSGLEN - 1] == 'F' || msg[AQ_MSGLEN - 1] == 'A' || msg[AQ_MSGLEN - 1] == '*') + if (msg[AQ_MSGLEN - 1] == 'N' || msg[AQ_MSGLEN - 1] == 'F' || msg[AQ_MSGLEN - 1] == 'A' || msg[AQ_MSGLEN - 1] == '*' || msg[AQ_MSGLEN - 1] == '%') { for (i = 0; i < _aqualink_data->total_buttons; i++) { diff --git a/source/pda_aq_programmer.c b/source/pda_aq_programmer.c index 98b3df9..99198f7 100644 --- a/source/pda_aq_programmer.c +++ b/source/pda_aq_programmer.c @@ -15,6 +15,7 @@ * https://github.com/sfeakes/aqualinkd */ + #define _GNU_SOURCE 1 // for strcasestr & strptime #include #include @@ -34,7 +35,7 @@ #include "config.h" #include "aq_panel.h" #include "rs_msg_utils.h" - +#include "color_lights.h" #ifdef AQ_DEBUG #include "timespec_subtract.h" @@ -44,7 +45,7 @@ bool waitForPDAMessageHighlight(struct aqualinkdata *aq_data, int highlighIndex, bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, int numMessageReceived); bool waitForPDAMessageTypes(struct aqualinkdata *aq_data, unsigned char mtype1, unsigned char mtype2, int numMessageReceived); bool waitForPDAMessageTypesOrMenu(struct aqualinkdata *aq_data, unsigned char mtype1, unsigned char mtype2, int numMessageReceived, char *text, int line); -bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu, bool home_first); +bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu); bool wait_pda_selected_item(struct aqualinkdata *aq_data); bool waitForPDAnextMenu(struct aqualinkdata *aq_data); bool loopover_devices(struct aqualinkdata *aq_data); @@ -247,7 +248,7 @@ bool loopover_devices(struct aqualinkdata *aq_data) { int i; int index = -1; - if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL, false)) { + if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL)) { LOG(PDA_LOG,LOG_ERR, "loopover_devices :- can't goto PM_EQUIPTMENT_CONTROL menu\n"); //cleanAndTerminateThread(threadCtrl); return false; @@ -460,7 +461,7 @@ bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool wa // and 6594 - AquaLink RS Control Panel Installation Manual // https://www.jandy.com/-/media/zodiac/global/downloads/0748-91071/6594.pdf -bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu, bool home_first) { +bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) { bool ret = true; int cnt = 0; @@ -476,26 +477,7 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu, bool home_f LOG(PDA_LOG,LOG_DEBUG, "goto_pda_menu building home menu\n"); waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,15); } - - if (home_first) { - // - // Before start, put back to home menu. Otherwise may get timing issue. - // We can be sending SELECT at EQUIPMNET menu while PDA immediate fall back to HOME - // menu. Also going back to HOME with first menu item highlighted seems to be - // more stable. - send_pda_cmd(KEY_PDA_BACK); - if (!waitForPDAnextMenu(aq_data)) { - LOG(PDA_LOG,LOG_ERR, "PDA goto menu: can't find HOME menu\n"); - return false; - } - if (pda_m_type() == PM_HOME && pda_m_hlightindex() != 4) { - send_pda_cmd(KEY_PDA_BACK); - if (!waitForPDAnextMenu(aq_data)) { - LOG(PDA_LOG,LOG_ERR, "PDA goto menu: can't find HOME menu\n"); - return false; - } - } - } + while (ret && (pda_m_type() != menu) && cnt <= 5) { switch (menu) { @@ -658,7 +640,7 @@ void *set_aqualink_PDA_device_on_off( void *ptr ) LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, device '%s', state %d\n",aq_data->aqbuttons[device].label,state); - if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL, true)) { + if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL)) { LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off :- can't find EQUIPTMENT CONTROL menu\n"); cleanAndTerminateThread(threadCtrl); return ptr; @@ -677,26 +659,37 @@ void *set_aqualink_PDA_device_on_off( void *ptr ) // NSF Added this since DEBUG hitting wrong command //waitfor_pda_queue2empty(); - if ( find_pda_menu_item(aq_data, device_name, 13) ) { + if ( find_pda_menu_item(aq_data, device_name, 12) ) { // Remove 1 char to account for '100%' (4 chars not the usual 3) if (aq_data->aqbuttons[device].led->state != state) { //printf("*** Select State ***\n"); - LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].label,state); + LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].label); force_queue_delete(); // NSF This is a bad thing to do. Need to fix this send_pda_cmd(KEY_PDA_SELECT); while (get_pda_queue_length() > 0) { delay(500); } // If you are turning on a heater there will be a sub menu to set temp if ((state == ON) && ((device == aq_data->pool_heater_index) || (device == aq_data->spa_heater_index))) { - if (! waitForPDAnextMenu(aq_data)) { - LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - waitForPDAnextMenu\n", - aq_data->aqbuttons[device].label); - } else { - send_pda_cmd(KEY_PDA_SELECT); - while (get_pda_queue_length() > 0) { delay(500); } - if (!waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,20)) { - LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_PDA_HIGHLIGHT\n", - aq_data->aqbuttons[device].label); - } + if (! waitForPDAnextMenu(aq_data)) { + LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - waitForPDAnextMenu\n", aq_data->aqbuttons[device].label); + } else { + send_pda_cmd(KEY_PDA_SELECT); + while (get_pda_queue_length() > 0) { delay(500); } + if (!waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,20)) { + LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_PDA_HIGHLIGHT\n",aq_data->aqbuttons[device].label); } + } + } else if ( isPLIGHT(aq_data->aqbuttons[device].special_mask) ) { + // THIS EXTRA ENTER IS ONLY FOR ON, NOT OFF + // PDA Menu Line 0 = Set Color // for color light + // PDA Menu Line 0 = Set // for dimmer light + if ( state == ON ) { + waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5); + if (strncasecmp(pda_m_line(0),"Set", 3) == 0) { + LOG(PDA_LOG,LOG_DEBUG, "PDA Device On/Off, '%s' is programmable light, but no mode using default\n",aq_data->aqbuttons[device].label); + send_pda_cmd(KEY_PDA_SELECT); + } else { + LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: expected Set menu for programmable light '%s', not found\n",aq_data->aqbuttons[device].label); + } + } } else { // not turning on heater wait for line update // worst case spa when pool is running if (!waitForPDAMessageType(aq_data,CMD_MSG_LONG,2)) { @@ -720,6 +713,100 @@ void *set_aqualink_PDA_device_on_off( void *ptr ) } +void *set_aqualink_PDA_light_mode( void *ptr ) +{ + struct programmingThreadCtrl *threadCtrl; + threadCtrl = (struct programmingThreadCtrl *) ptr; + struct aqualinkdata *aq_data = threadCtrl->aq_data; + //int i=0; + //int found; + //char device_name[15]; + + waitForSingleThreadOrTerminate(threadCtrl, AQ_PDA_SET_LIGHT_MODE); + + char *buf = (char*)threadCtrl->thread_args; + const char *mode_name = NULL; + int val = atoi(&buf[0]); + int btn = atoi(&buf[5]); + int typ = atoi(&buf[10]); + bool use_current_mode = false; + + if (btn < 0 || btn >= aq_data->total_buttons ) { + LOG(PDA_LOG, LOG_ERR, "Can't program light mode on button %d\n", btn); + cleanAndTerminateThread(threadCtrl); + return ptr; + } + + aqkey *button = &aq_data->aqbuttons[btn]; + + + if ( ! isPLIGHT(button->special_mask) ) { + LOG(PDA_LOG, LOG_ERR, "Can't program light mode on button %d, it's not a programmable light\n", btn); + cleanAndTerminateThread(threadCtrl); + return ptr; + } + + clight_type lighttype = ((clight_detail *)button->special_mask_ptr)->lightType; + + + if (val <= 0) { + use_current_mode = true; + LOG(PDA_LOG, LOG_INFO, "PDA Light Programming #: %d, on button: %s, color light type: %d, using current mode\n", val, button->label, typ); + } else { + if (lighttype == LC_DIMMER2 || LC_DIMMER2 == LC_DIMMER) { + mode_name = light_mode_name(typ, val-1, AQUAPDA); + } else { + mode_name = light_mode_name(typ, val, AQUAPDA); + } + use_current_mode = false; + if (mode_name == NULL) { + LOG(PDA_LOG, LOG_ERR, "PDA Light Programming #: %d, on button: %s, color light type: %d, couldn't find mode name '%s'\n", val, button->label, typ, mode_name); + cleanAndTerminateThread(threadCtrl); + return ptr; + } else { + LOG(PDA_LOG, LOG_INFO, "PDA Light Programming #: %d, on button: %s, color light type: %d, name '%s'\n", val, button->label, typ, mode_name); + } + } + + if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL)) { + LOG(PDA_LOG,LOG_ERR, "PDA light Programming :- can't find EQUIPTMENT CONTROL menu\n"); + cleanAndTerminateThread(threadCtrl); + return ptr; + } + + if ( find_pda_menu_item(aq_data, button->label, 0) ) { // Remove 1 char to account for '100%' (4 chars not the usual 3) + LOG(PDA_LOG,LOG_INFO, "PDA Light Programming, found device '%s', changing to '%s'\n",button->label,mode_name); + force_queue_delete(); // NSF This is a bad thing to do. Need to fix this + send_pda_cmd(KEY_PDA_SELECT); + waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15); + // if we get `PDA Menu Line 3 = Light will turn ` light is on and we need to press enter again. + // if we get `PDA Menu Line 2 = Dimmer Power ` we need to cycle over 25%/50%/75%/100% + // if we get `Menu Line 0 = Set Color` we can set color. + if (lighttype == LC_DIMMER2 || LC_DIMMER2 == LC_DIMMER) { + + } else { + if (strncasecmp(pda_m_line(3),"Light will turn", 15) == 0) { + send_pda_cmd(KEY_PDA_SELECT); + waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5); + } + if (use_current_mode && mode_name != NULL) { + if (find_pda_menu_item(aq_data,(char *)mode_name,strlen(mode_name))) { + send_pda_cmd(KEY_PDA_SELECT); + } else { + LOG(PDA_LOG,LOG_ERR, "PDA Light Programming, could find mode '%s' for device '%s'\n",mode_name,button->label); + } + } + } + } else { + LOG(PDA_LOG,LOG_ERR, "PDA Light Programming, device '%s' not found\n",button->label); + } + + cleanAndTerminateThread(threadCtrl); + + // just stop compiler error, ptr is not valid as it's just been freed + return ptr; +} + void *get_aqualink_PDA_device_status( void *ptr ) { @@ -730,7 +817,7 @@ void *get_aqualink_PDA_device_status( void *ptr ) waitForSingleThreadOrTerminate(threadCtrl, AQ_PDA_DEVICE_STATUS); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); if (! loopover_devices(aq_data)) { LOG(PDA_LOG,LOG_ERR, "PDA Device Status :- failed\n"); @@ -773,8 +860,11 @@ void *set_aqualink_PDA_init( void *ptr ) //printf("****** Version '%s' ********\n",aq_data->version); LOG(PDA_LOG,LOG_DEBUG, "PDA type=%d, version=%s\n", _PDA_Type, aq_data->version); + // don't wait for version menu to time out press back to get to home menu faster - //send_pda_cmd(KEY_PDA_BACK); + send_pda_cmd(KEY_PDA_BACK); + + //if (! waitForPDAnextMenu(aq_data)) { // waitForPDAnextMenu waits for highlight chars, which we don't get on normal menu if (! waitForPDAMessageType(aq_data,CMD_PDA_CLEAR,10)) { @@ -802,7 +892,7 @@ void *set_aqualink_PDA_init( void *ptr ) pda_reset_sleep(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); cleanAndTerminateThread(threadCtrl); @@ -839,7 +929,7 @@ void *set_aqualink_PDA_wakeinit( void *ptr ) bool _get_PDA_freeze_protect_temp(struct aqualinkdata *aq_data) { if ( _PDA_Type == PDA) { - if (! goto_pda_menu(aq_data, PM_FREEZE_PROTECT, true)) { + if (! goto_pda_menu(aq_data, PM_FREEZE_PROTECT)) { return false; } /* select the freeze protect temp to see which devices are enabled by freeze @@ -853,12 +943,12 @@ bool _get_PDA_freeze_protect_temp(struct aqualinkdata *aq_data) { } bool _get_PDA_aqualink_pool_spa_heater_temps(struct aqualinkdata *aq_data) { - + // Get heater setpoints - if (! goto_pda_menu(aq_data, PM_SET_TEMP, true)) { + if (! goto_pda_menu(aq_data, PM_SET_TEMP)) { LOG(PDA_LOG,LOG_ERR, "Could not get heater setpoints, trying again!\n"); // Going to try this twice. - if (! goto_pda_menu(aq_data, PM_SET_TEMP, false)) { + if (! goto_pda_menu(aq_data, PM_SET_TEMP)) { return false; } } @@ -1071,7 +1161,7 @@ void *set_PDA_aqualink_SWG_setpoint(void *ptr) { int val = atoi((char*)threadCtrl->thread_args); val = setpoint_check(SWG_SETPOINT, val, aq_data); - if (! goto_pda_menu(aq_data, PM_AQUAPURE, true)) { + if (! goto_pda_menu(aq_data, PM_AQUAPURE)) { LOG(PDA_LOG,LOG_ERR, "Error finding SWG setpoints menu\n"); cleanAndTerminateThread(threadCtrl); return ptr; @@ -1093,7 +1183,7 @@ void *set_PDA_aqualink_SWG_setpoint(void *ptr) { } waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); cleanAndTerminateThread(threadCtrl); return ptr; @@ -1110,7 +1200,7 @@ void *set_PDA_aqualink_boost(void *ptr) int val = atoi((char*)threadCtrl->thread_args); - if (! goto_pda_menu(aq_data, PM_BOOST, true)) { + if (! goto_pda_menu(aq_data, PM_BOOST)) { LOG(PDA_LOG,LOG_ERR, "Error finding BOOST menu\n"); return false; } @@ -1133,7 +1223,7 @@ void *set_PDA_aqualink_boost(void *ptr) } waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); cleanAndTerminateThread(threadCtrl); return ptr; } @@ -1168,7 +1258,7 @@ bool set_PDA_aqualink_heater_setpoint(struct aqualinkdata *aq_data, int val, boo return true; } - if (! goto_pda_menu(aq_data, PM_SET_TEMP, true)) { + if (! goto_pda_menu(aq_data, PM_SET_TEMP)) { LOG(PDA_LOG,LOG_ERR, "Error finding heater setpoints menu\n"); return false; } @@ -1193,7 +1283,7 @@ void *set_aqualink_PDA_pool_heater_temps( void *ptr ) set_PDA_aqualink_heater_setpoint(aq_data, val, true); waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); cleanAndTerminateThread(threadCtrl); return ptr; @@ -1213,7 +1303,7 @@ void *set_aqualink_PDA_spa_heater_temps( void *ptr ) set_PDA_aqualink_heater_setpoint(aq_data, val, false); waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); cleanAndTerminateThread(threadCtrl); return ptr; @@ -1235,7 +1325,7 @@ void *set_aqualink_PDA_freeze_protectsetpoint( void *ptr ) if (_PDA_Type != PDA) { LOG(PDA_LOG,LOG_INFO, "In PDA AquaPalm mode, freezepoints not supported\n"); //return false; - } else if (! goto_pda_menu(aq_data, PM_FREEZE_PROTECT, true)) { + } else if (! goto_pda_menu(aq_data, PM_FREEZE_PROTECT)) { LOG(PDA_LOG,LOG_ERR, "Error finding freeze protect setpoints menu\n"); //return false; } else if (! set_PDA_numeric_field_value(aq_data, val, aq_data->frz_protect_set_point, NULL, 1)) { @@ -1246,7 +1336,7 @@ void *set_aqualink_PDA_freeze_protectsetpoint( void *ptr ) } waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); cleanAndTerminateThread(threadCtrl); return ptr; @@ -1261,7 +1351,7 @@ void *set_PDA_aqualink_time( void *ptr ) waitForSingleThreadOrTerminate(threadCtrl, AQ_PDA_SET_TIME); - if (! goto_pda_menu(aq_data, PM_SET_TIME, true)) { + if (! goto_pda_menu(aq_data, PM_SET_TIME)) { LOG(PDA_LOG,LOG_ERR, "Error finding set time menu\n"); goto f_end; } @@ -1321,7 +1411,7 @@ Debug: PDA: PDA Menu Line 9 = to continue. waitForPDAnextMenu(aq_data); waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); f_end: @@ -1345,7 +1435,7 @@ void *get_PDA_aqualink_aux_labels( void *ptr ) { LOG(PDA_LOG,LOG_INFO, "Finding PDA labels, (BETA ONLY)\n"); - if (! goto_pda_menu(aq_data, PM_AUX_LABEL, true)) { + if (! goto_pda_menu(aq_data, PM_AUX_LABEL)) { LOG(PDA_LOG,LOG_ERR, "Error finding aux label menu\n"); goto f_end; } @@ -1360,7 +1450,7 @@ void *get_PDA_aqualink_aux_labels( void *ptr ) { // Read first page of devices and make some assumptions. waitfor_pda_queue2empty(); - goto_pda_menu(aq_data, PM_HOME, false); + goto_pda_menu(aq_data, PM_HOME); f_end: diff --git a/source/pda_aq_programmer.h b/source/pda_aq_programmer.h index 9d668a0..576fb93 100644 --- a/source/pda_aq_programmer.h +++ b/source/pda_aq_programmer.h @@ -43,6 +43,8 @@ void *set_PDA_aqualink_boost(void *ptr); //bool set_PDA_aqualink_time(struct aqualinkdata *aq_data); void *set_PDA_aqualink_time( void *ptr ); +void *set_aqualink_PDA_light_mode( void *ptr ); + /* // These are from aq_programmer.c , exposed here for PDA AQ PROGRAMMER void send_cmd(unsigned char cmd); diff --git a/source/serialadapter.c b/source/serialadapter.c index 0a1b0dc..1d345f3 100644 --- a/source/serialadapter.c +++ b/source/serialadapter.c @@ -363,7 +363,7 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin // CHANGE TO DEBUG BEFORE RELEASE if (aq_data->lights[i].lightType == LC_DIMMER || aq_data->lights[i].lightType == LC_DIMMER2) { - LOG(RSSA_LOG,LOG_DEBUG,"DimmerLight '%s' is %s 0x%02hhx value '%d'%%\n", + LOG(RSSA_LOG,LOG_DEBUG,"DimmerLight '%s' is %s, rawvalue 0x%02hhx value '%d'%%\n", aq_data->lights[i].button->label, packet[6]==0x00?"OFF":"ON", packet[6], diff --git a/source/version.h b/source/version.h index 85a168f..8e623b0 100644 --- a/source/version.h +++ b/source/version.h @@ -4,4 +4,5 @@ #define AQUALINKD_SHORT_NAME "AqualinkD" // Use Magor . Minor . Patch -#define AQUALINKD_VERSION "2.6.8 (dev)" +#define AQUALINKD_VERSION "2.6.8" + \ No newline at end of file diff --git a/web/aqmanager.html b/web/aqmanager.html index 8a387fa..e43b0c6 100644 --- a/web/aqmanager.html +++ b/web/aqmanager.html @@ -501,24 +501,7 @@ } function requestFileDownload(caller) { var msg = {}; - /* - if (caller.id == "logfile") { - var startstop = ""; - if (caller.checked) { - startstop = "start"; - } else { - startstop = "stop"; - } - msg = { - uri: "logfile/" + startstop, - value: 0 - }; - } else if (caller.id == "cleanlog") { - msg = { - uri: "logfile/clean", - value: 0 - }; - } else*/ + if (caller.id == "downloadlog") { //window.location = '/api/debug/download'; downloadFile('/api/logfile/download', "aqualinkd.log", document.getElementById("logsize").value); @@ -592,11 +575,15 @@ values: {} }; - for (var obj in _config) { + //console.log(_config); + for (var obj in _config) { if (_config[obj].value !== undefined) { if (_config[obj].value) { json_ordered.values[obj] = _config[obj].value; + } else if (_config[obj].allow_blank !== undefined && _config[obj].allow_blank == "yes") { + //console.log("----- Add Blank value for "+ obj+"\n"); + json_ordered.values[obj] = ""; } } else if (obj.toString().startsWith("button_") || obj.toString().startsWith("virtual_button_") || obj.toString().startsWith("sensor_") ) { for (var obj1 in _config[obj]) { @@ -1373,7 +1360,7 @@ console.log( _AlertsShown[key]); var key = event.srcElement.getAttribute('key'); var value = event.srcElement.value; - console.log("Config set "+key+" to "+value) + console.log("Config set '"+key+"'' to '"+value+"'"); try { _config[key].value = value; diff --git a/web/controller.html b/web/controller.html index 5533547..2cef738 100644 --- a/web/controller.html +++ b/web/controller.html @@ -961,7 +961,7 @@ function switchTileState(id, details) { if (details) { - console.log("TILE DETAILS WHAY ARE WE HERE??? '" + id + "'"); + console.log("TILE DETAILS WHY ARE WE HERE??? '" + id + "'"); } else { setTileState(id, (document.getElementById(id).getAttribute('status') == 'off')) } @@ -1297,8 +1297,8 @@ } //if (typeof devices !== 'undefined' && devices.indexOf(object.id) < 0) { if (typeof devices !== 'undefined' && caseInsensitiveIndexOf(devices, object.id) < 0) { - console.log("Create tile "+object); - console.log(object); + //console.log("Create tile "+object); + //console.log(object); return; } //if (object.type == 'switch' || object.type == 'switch_program') {