diff --git a/README.md b/README.md index aaf76e4..a18baeb 100644 --- a/README.md +++ b/README.md @@ -136,14 +136,17 @@ NEED TO FIX FOR THIS RELEASE. * PDA panel Rev 6.0 of newer WITH a Jandy iAqualink device attached can use `read_RS485_iAqualink = yes` to speed up device state change detection. * Added MQTT vsp_pump/speed/set for setting speed (RPM/GPM) by %, for automation hubs. * Added full dimmer range support for dimmable lights (not limited to 0,25,50,75,100 anymore) -* Added vsp and dimmer to hassio and homebridge-aqualinkd plugin as full range dimmer controls. +* Added vsp and dimmer to Hassio and homebridge-aqualinkd plugin as full range dimmer controls. +* Added color lights & dimmer to Hassio as selectors. * Updated UI for support fullrange dimmer. * cleaned up code for spa_mode and spa for newer pannels. * Allow VSP to be asigned to virtual button. * Fixed bug with timer not starting. * Increase Speed of detecting device state changes. * Added iAqualink2 protocol support. -* Faster OneTouch device support +* Chaged color light logic. +* Faster OneTouch device support. + # Updates in Release 2.4.0 * WARNING Breaking change if you use dimmer (please change button_??_lightMode from 6 to 10) diff --git a/release/aqualinkd-amd64 b/release/aqualinkd-amd64 index fddb6d4..90e4728 100755 Binary files a/release/aqualinkd-amd64 and b/release/aqualinkd-amd64 differ diff --git a/release/aqualinkd-arm64 b/release/aqualinkd-arm64 index a140aa0..d49db63 100755 Binary files a/release/aqualinkd-arm64 and b/release/aqualinkd-arm64 differ diff --git a/release/aqualinkd-armhf b/release/aqualinkd-armhf index 4ce4cda..1f7dc0d 100755 Binary files a/release/aqualinkd-armhf and b/release/aqualinkd-armhf differ diff --git a/release/aqualinkd.conf b/release/aqualinkd.conf index f3ce9bd..967299c 100755 --- a/release/aqualinkd.conf +++ b/release/aqualinkd.conf @@ -77,6 +77,9 @@ device_id=0x00 # Valid ID's are 0x30, 0x31, 0x32 & 0x33. for Aqualink Touch #extended_device_id=0x31 +# If using 0x30 to 0x33 for extended_device_id, then enable below if you want to use virtual buttons +#enable_iaqualink=yes + # If you have extended_device_id set, then you can also use that ID for programming some features. # This means that you can turn things on/off while AqualinkD is programming certian features. diff --git a/release/serial_logger-arm64 b/release/serial_logger-arm64 index d297ad9..49320c1 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 8e4475f..fda09fb 100755 Binary files a/release/serial_logger-armhf and b/release/serial_logger-armhf differ diff --git a/source/allbutton.c b/source/allbutton.c index 701db55..30dcdd3 100644 --- a/source/allbutton.c +++ b/source/allbutton.c @@ -8,6 +8,7 @@ #include "rs_msg_utils.h" #include "devices_jandy.h" #include "allbutton_aq_programmer.h" +#include "color_lights.h" /* Below can also be called from serialadapter.c */ void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmask_t from) @@ -66,6 +67,17 @@ void processLEDstate(struct aqualinkdata *aq_data, unsigned char *packet, logmas aq_data->lights[i].button->led->state = aq_data->lights[i].RSSDstate; //LOG(from,LOG_WARNING,"Fix Jandy bug, color light '%s' is on, setting status to match!\n", aq_data->lights[i].button->label); } + + // Below is for aqualinkd programmable light, set color mode to last if something else turns it on or off. + if (aq_data->lights[i].lightType == LC_PROGRAMABLE && ! in_light_programming_mode(aq_data)) { + if (aq_data->lights[i].button->led->state == OFF && aq_data->lights[i].currentValue != 0) { + set_currentlight_value(&aq_data->lights[i], 0); + //LOG(ALLB_LOG,LOG_NOTICE,"****** SET LIGHT MODE 0 ******\n"); + } else if (aq_data->lights[i].button->led->state == ON && aq_data->lights[i].currentValue == 0 && aq_data->lights[i].lastValue != 0) { + set_currentlight_value(&aq_data->lights[i], aq_data->lights[i].lastValue); + //LOG(ALLB_LOG,LOG_NOTICE,"****** SET LIGHT MODE %d ******\n",aq_data->lights[i].lastValue); + } + } } #endif } diff --git a/source/aq_panel.c b/source/aq_panel.c index 46aa762..d4b178a 100644 --- a/source/aq_panel.c +++ b/source/aq_panel.c @@ -803,7 +803,7 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req { // Check for panel programmable light. if so simple ON isn't going to work well // Could also add "light mode" check, as this is only valid for panel configured light not aqualinkd configured light. - if ((button->special_mask & PROGRAM_LIGHT) == PROGRAM_LIGHT && button->led->state == OFF) { + if (isPLIGHT(button->special_mask) && button->led->state == OFF) { // OK Programable light, and no light mode selected. Now let's work out best way to turn it on. serial_adapter protocol will to it without questions, // all other will require programmig. if (isRSSA_ENABLED) { @@ -812,9 +812,14 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req //set_light_mode("0", deviceIndex); // 0 means use current light mode programDeviceLightMode(aqdata, 0, deviceIndex); // 0 means use current light mode } + + // If aqualinkd programmable light, it will come on at last state, so set that. + if ( /*isPLIGHT(button->special_mask) &&*/ ((clight_detail *)button->special_mask_ptr)->lightType == LC_PROGRAMABLE ) { + ((clight_detail *)button->special_mask_ptr)->currentValue = ((clight_detail *)button->special_mask_ptr)->lastValue; + } } else if (isVBUTTON(button->special_mask)) { // Virtual buttons only supported with Aqualink Touch - LOG(PANL_LOG, LOG_INFO, "Set state for Vitrual Button %s code=0x%02hhx iAqualink2 enabled=%sn",button->name, button->rssd_code, isIAQT_ENABLED?"Yes":"No"); + LOG(PANL_LOG, LOG_INFO, "Set state for Virtual Button %s code=0x%02hhx iAqualink2 enabled=%s\n",button->name, button->rssd_code, isIAQT_ENABLED?"Yes":"No"); if (isIAQT_ENABLED) { // If it's one of the pre-defined onces & iaqualink is enabled, we can set it easile with button. @@ -845,7 +850,7 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req //} else if ( source == NET_TIMER && isRSSA_ENABLED ) { // Timer will sometimes send duplicate, so use RSSA since that protocol has on/off rather than toggle // set_aqualink_rssadapter_aux_state(button, isON); - } else if (button->special_mask & PROGRAM_LIGHT && isRSSA_ENABLED) { + } else if (isPLIGHT(button->special_mask) && isRSSA_ENABLED) { // If off and program light, use the RS serial adapter since that is overiding the state now. set_aqualink_rssadapter_aux_state(button, isON); } else { @@ -854,8 +859,16 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, req aq_send_allb_cmd(button->code); } + + // If we turned off a aqualinkd programmable light, set the mode to 0 + if (isPLIGHT(button->special_mask) && ! isON && ((clight_detail *)button->special_mask_ptr)->lightType == LC_PROGRAMABLE ) { + updateButtonLightProgram(aqdata, 0, deviceIndex); + } + #ifdef CLIGHT_PANEL_FIX - if (isRSSA_ENABLED) {get_aqualink_rssadapter_colorlight_statuses(aqdata);} + if (isPLIGHT(button->special_mask) && isRSSA_ENABLED) { + get_aqualink_rssadapter_button_status(button); + } #endif // Pre set device to state, next status will correct if state didn't take, but this will stop multiple ON messages setting on/off @@ -1125,7 +1138,9 @@ void updateButtonLightProgram(struct aqualinkdata *aqdata, int value, int button return; } - light->currentValue = value; + light->currentValue = value; + if (value > 0) + light->lastValue = value; } clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button) diff --git a/source/aq_programmer.c b/source/aq_programmer.c index 63b67b8..f20272b 100644 --- a/source/aq_programmer.c +++ b/source/aq_programmer.c @@ -94,7 +94,7 @@ const func_ptr _prog_functions[AQP_RSSADAPTER_MAX] = { [AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM] = set_aqualink_iaqtouch_pump_vs_program, [AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE] = set_aqualink_iaqtouch_light_colormode, [AQ_SET_IAQTOUCH_DEVICE_ON_OFF] = set_aqualink_iaqtouch_device_on_off, - [AQ_SET_IAQTOUCH_ONETOUCH_ON_OFF] = set_aqualink_iaqtouch_onetouch_on_off, + //[AQ_SET_IAQTOUCH_ONETOUCH_ON_OFF] = set_aqualink_iaqtouch_onetouch_on_off, // Not finished and not needed [AQ_PDA_INIT] = set_aqualink_PDA_init, [AQ_PDA_WAKE_INIT] = set_aqualink_PDA_wakeinit, [AQ_PDA_DEVICE_STATUS] = get_aqualink_PDA_device_status, diff --git a/source/aqualink.h b/source/aqualink.h index 22a4e51..e85d42c 100644 --- a/source/aqualink.h +++ b/source/aqualink.h @@ -237,6 +237,7 @@ typedef struct clightd clight_type lightType; aqkey *button; int currentValue; + int lastValue; // Used for AqualinkD self programming aqledstate RSSDstate; // state from rs serial adapter } clight_detail; diff --git a/source/aqualinkd.c b/source/aqualinkd.c index 7d9f1fc..b93c81b 100644 --- a/source/aqualinkd.c +++ b/source/aqualinkd.c @@ -931,7 +931,8 @@ void main_loop() } for (i=0; i < MAX_LIGHTS; i++) { - _aqualink_data.lights[i].currentValue = TEMP_UNKNOWN; + //_aqualink_data.lights[i].currentValue = TEMP_UNKNOWN; + _aqualink_data.lights[i].currentValue = 0; _aqualink_data.lights[i].RSSDstate = OFF; } diff --git a/source/color_lights.c b/source/color_lights.c index 4cab45e..1c8f228 100644 --- a/source/color_lights.c +++ b/source/color_lights.c @@ -18,13 +18,13 @@ Haywood Universal Color */ /****** This list MUST be in order of clight_type enum *******/ -const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] = +char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] = //char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] = { // AqualnkD Colors ignored as no names in control panel. - { "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18" }, + { "Off", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18" }, { // Jandy Color - "", + "Off", "Alpine White", // 0x41 "Sky Blue", "Cobalt Blue", @@ -38,7 +38,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] "Color Splash" }, { // Jandy LED - "", + "Off", "Alpine White", "Sky Blue", "Cobalt Blue", @@ -55,7 +55,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] "Disco Tech" }, { // SAm/SAL - "", + "Off", "White", "Light Green", "Green", @@ -65,7 +65,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] "Magenta" }, { // Color Logic - "", + "Off", "Voodoo Lounge", // 0x41 (both home and sim) "Deep Blue Sea", // 0x42 (both gome and sim) "Afternoon Skies", // 0x44 home // 0x43 sim // 'Afternoon Sky' on allbutton, Skies on iaqtouch @@ -80,7 +80,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] "Cool Cabaret" // 0x51 (home panel) // 0x4c }, { // IntelliBrite - "", + "Off", "SAm", "Party", "Romance", @@ -95,7 +95,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] "Magenta" }, { // Haywood Universal Color - "", + "Off", "Voodoo Lounge", // 0x41 (both home and sim) // Looks like 28 + = 0x41 = 1st index "Deep Blue Sea", // 0x42 (both gome and sim) "Royal Blue", // // 0x43 home // non @@ -118,7 +118,7 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] {/*Spare 2*/}, {/*Spare 3*/}, { // Dimmer // From manual this is 0 for off, 128+ so 153 = 25% = 0x99 - "", + "Off", "25%", // 0x99 (simulator) = 153 dec "50%", // 0xb2 (simulator) = 178 dec same as (0x99 + 25) "75%", // 0xcb (simulator) = 203 dec @@ -158,9 +158,55 @@ void setColorLightsPanelVersion(uint8_t supported) } */ +bool set_aqualinkd_light_mode_name(char *name, int index, bool isShow) +{ + static bool reset = false; + + // Reset all options only once. + if (!reset) { + reset = true; + for (int i=1; iled->state == OFF) { + return "Off"; + } + */ + + // Programmable light that's on but no mode, just return blank + if (light.lightType == LC_PROGRAMABLE && light.button->led->state == ON && light.currentValue == 0) { + return ""; + } + + if (light.currentValue < 0 || light.currentValue > LIGHT_COLOR_OPTIONS ){ + return ""; + } + + // Rename any modes depending on emulation type + if (protocol == ALLBUTTON) { + if (strcmp(_color_light_options[light.lightType][light.currentValue],"Afternoon Skies") == 0) { + return "Afternoon Sky"; + } + } + + return _color_light_options[light.lightType][light.currentValue]; +} + +// This should not be uses for getting current lightmode name since it doesn;t have full logic + const char *light_mode_name(clight_type type, int index, emulation_type protocol) { - if (index <= 0 || index > LIGHT_COLOR_OPTIONS ){ + if (index < 0 || index > LIGHT_COLOR_OPTIONS ){ return ""; } @@ -174,6 +220,7 @@ const char *light_mode_name(clight_type type, int index, emulation_type protocol return _color_light_options[type][index]; } + bool isShowMode(const char *mode) { if (strcmp(mode, "Color Splash") == 0 || @@ -209,13 +256,16 @@ void set_currentlight_value(clight_detail *light, int index) light->currentValue = index; } else { // We want to leave the last color, so if 0 don't do anything, but set to 0 if bad value - if (index < 0 || index > LIGHT_COLOR_OPTIONS) + if (index <= 0 || index > LIGHT_COLOR_OPTIONS) { light->currentValue = 0; - else if (index > 0 && index < LIGHT_COLOR_OPTIONS) + } else if (index > 0 && index < LIGHT_COLOR_OPTIONS) { light->currentValue = index; + //light->lastValue = index; + } } } +// Used for dynamic config JS int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size) { memset(&buffer[0], 0, size); @@ -223,9 +273,15 @@ int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size) int i, j; length += sprintf(buffer+length, "var _light_program = [];\n"); - length += sprintf(buffer+length, "_light_program[0] = light_program;\n"); + + if ( strcmp(_color_light_options[0][1], "1") == 0) { + length += sprintf(buffer+length, "_light_program[0] = light_program;\n"); + i=1; + } else { + i=0; + } - for (i=1; i < NUMBER_LIGHT_COLOR_TYPES; i++) { + for (; i < NUMBER_LIGHT_COLOR_TYPES; i++) { length += sprintf(buffer+length, "_light_program[%d] = [ ", i); for (j=1; j < LIGHT_COLOR_OPTIONS; j++) { // Start a 1 since index 0 is blank if (_color_light_options[i][j] != NULL) @@ -238,3 +294,19 @@ int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size) return length; } +int build_color_light_jsonarray(int index, char* buffer, int size) +{ + memset(&buffer[0], 0, size); + int i; + int length=0; + + for (i=0; i < LIGHT_COLOR_OPTIONS; i++) { // Start a 1 since index 0 is blank + if (_color_light_options[index][i] != NULL) { + length += sprintf(buffer+length, "\"%s\",", _color_light_options[index][i] ); + } + } + buffer[--length] = '\0'; + + return length; +} + diff --git a/source/color_lights.h b/source/color_lights.h index 70c91b3..df40bbc 100644 --- a/source/color_lights.h +++ b/source/color_lights.h @@ -27,10 +27,14 @@ typedef enum clight_type { } clight_type; */ //const char *light_mode_name(clight_type type, int index); +const char *get_currentlight_mode_name(clight_detail light, emulation_type protocol); const char *light_mode_name(clight_type type, int index, emulation_type protocol); int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size); +int build_color_light_jsonarray(int index, char* buffer, int size); + void set_currentlight_value(clight_detail *light, int index); +bool set_aqualinkd_light_mode_name(char *name, int index, bool isShow); //char *_color_light_options_[LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS][LIGHT_COLOR_NAME]; diff --git a/source/config.c b/source/config.c index 4c8afe0..e9013e2 100644 --- a/source/config.c +++ b/source/config.c @@ -41,6 +41,7 @@ #include "aq_panel.h" #include "aqualink.h" #include "iaqualink.h" +#include "color_lights.h" #define MAXCFGLINE 256 @@ -673,9 +674,22 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) { } else if (strncasecmp (param, "device_pre_state", 16) == 0) { _aqconfig_.device_pre_state = text2bool(value); rtn=true; - } - - else if (strncasecmp(param, "button_", 7) == 0) { + } else if (strncasecmp(param, "light_program_", 14) == 0) { + int num = strtoul(param + 14, NULL, 10); + if ( num >= LIGHT_COLOR_OPTIONS ) { + LOG(AQUA_LOG,LOG_ERR, "Config error, light_program_%d is out of range\n",num); + } + char *name = cleanalloc(value); + int len = strlen(name); + if ( strncmp(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); + } + rtn=true; + } else if (strncasecmp(param, "button_", 7) == 0) { // Check we have inichalized panel information, if not use any settings we may have if (_aqconfig_.paneltype_mask == 0) setPanel(aqdata, _tmpPanel->rs, _tmpPanel->size, _tmpPanel->combo, _tmpPanel->dual); @@ -781,8 +795,8 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) { vbutton->rssd_code = IAQ_ONETOUCH_5; break; case 6: - vbutton->code = IAQ_ONETOUCH_5; - vbutton->rssd_code = IAQ_ONETOUCH_5; + vbutton->code = IAQ_ONETOUCH_6; + vbutton->rssd_code = IAQ_ONETOUCH_6; break; default: vbutton->code = NUL; diff --git a/source/hassio.c b/source/hassio.c index 8c06c2a..1e099a3 100644 --- a/source/hassio.c +++ b/source/hassio.c @@ -10,6 +10,7 @@ #include "aq_mqtt.h" #include "rs_msg_utils.h" #include "config.h" +#include "color_lights.h" #include "version.h" @@ -50,9 +51,7 @@ const char *HASSIO_CLIMATE_DISCOVER = "{" "\"temperature_command_topic\": \"%s/%s/setpoint/set\"," "\"temperature_state_topic\": \"%s/%s/setpoint\"," /*"\"temperature_state_template\": \"{{ value_json }}\","*/ - "%s," - "\"qos\": 1," - "\"retain\": false" + "%s" "}"; const char *HASSIO_FREEZE_PROTECT_DISCOVER = "{" @@ -126,9 +125,7 @@ const char *HASSIO_VSP_DISCOVER = "{" //"\"percentage_value_template\": \"{%% if value | float(0) > %d %%} {{ (((value | float(0) - %d) / %d) * 100) | int }}{%% else %%} 1{%% endif %%}\"," // min,min,(max-min) //"\"percentage_command_template\": \"{{ ((value | float(0) / 100) * %d) + %d | int }}\"," // (3450-130), 600 "\"speed_range_max\": 100," - "\"speed_range_min\": 1," // 18|12 600rpm|15gpm - "\"qos\": 1," - "\"retain\": false" + "\"speed_range_min\": 1" // 18|12 600rpm|15gpm "}"; @@ -146,9 +143,21 @@ const char *HASSIO_DIMMER_DISCOVER = "{" "\"payload_off\": \"0\"," "\"brightness_command_topic\": \"%s/%s%s/set\"," // aqualinkd,Aux_5,/brightness "\"brightness_state_topic\": \"%s/%s%s\"," // aqualinkd/Aux_5,/brightness - "\"brightness_scale\": 100," - "\"qos\": 1," - "\"retain\": false" + "\"brightness_scale\": 100" +"}"; + +const char *HASSIO_SELECTOR_DISCOVER = "{" + "\"device\": {" HASS_DEVICE "}," + "\"availability\": {" HASS_AVAILABILITY "}," + "\"type\": \"select\"," + "\"unique_id\": \"aqualinkd_%s_selector\"," // Aux_5 + "\"name\": \"%s program\"," // light name + "\"state_topic\": \"%s/%s/program/name\"," // aqualinkd,Aux_5 + "\"state_template\": \"{{ this.attributes.options(value) }}\"," + "\"command_topic\": \"%s/%s/program/set\"," // aqualinkd,Aux_5 + "\"options\": [ %s ]," // "Off", "Voodoo Lounge", "Deep Blue Sea" + "\"command_template\": \"{{ this.attributes.options.index(value) }}\"," + "\"icon\": \"%s\"" "}"; // Need to add timer attributes to the switches, once figure out how to use in homeassistant @@ -167,8 +176,7 @@ const char *HASSIO_SWITCH_DISCOVER = "{" "\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\"," "\"payload_on\": \"1\"," "\"payload_off\": \"0\"," - "\"qos\": 1," - "\"retain\": false" + "\"icon\": \"%s\"" "}"; const char *HASSIO_TEMP_SENSOR_DISCOVER = "{" @@ -176,7 +184,7 @@ const char *HASSIO_TEMP_SENSOR_DISCOVER = "{" "\"availability\": {" HASS_AVAILABILITY "}," "\"type\": \"sensor\"," "\"state_class\": \"measurement\"," - "\"unique_id\": \"aqualinkd_%s\"," + "\"unique_id\": \"aqualinkd_%s_temp\"," "\"name\": \"%s Temp\"," "\"state_topic\": \"%s/%s\"," "\"value_template\": \"{{ value_json }}\"," @@ -404,6 +412,36 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name,LIGHT_DIMMER_VALUE_TOPIC); sprintf(topic, "%s/light/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name); send_mqtt(nc, topic, msg); + } else if ( isPLIGHT(aqdata->aqbuttons[i].special_mask) ) { + // Color Lights & Dimmer as selector switch + // Build the + + char buf[512]; + build_color_light_jsonarray(((clight_detail *)aqdata->aqbuttons[i].special_mask_ptr)->lightType, buf, 512 ); + sprintf(msg,HASSIO_SELECTOR_DISCOVER, + _aqconfig_.mqtt_aq_topic, + aqdata->aqbuttons[i].name, + aqdata->aqbuttons[i].label, + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + buf, + "mdi:lightbulb"); + sprintf(topic, "%s/select/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name); + send_mqtt(nc, topic, msg); + + // Duplicate normal switch as we want a duplicate + sprintf(msg, HASSIO_SWITCH_DISCOVER, + _aqconfig_.mqtt_aq_topic, + aqdata->aqbuttons[i].name, + aqdata->aqbuttons[i].label, + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + "mdi:lightbulb"); + sprintf(topic, "%s/switch/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name); + send_mqtt(nc, topic, msg); + } else { // Switches //sprintf(msg,"{\"type\": \"switch\",\"unique_id\": \"%s\",\"name\": \"%s\",\"state_topic\": \"aqualinkd/%s\",\"command_topic\": \"aqualinkd/%s/set\",\"json_attributes_topic\": \"aqualinkd/%s/delay\",\"json_attributes_topic\": \"aqualinkd/%s/delay\",\"json_attributes_template\": \"{{ {'delay': value|int} | tojson }}\",\"payload_on\": \"1\",\"payload_off\": \"0\",\"qos\": 1,\"retain\": false}" , @@ -414,7 +452,8 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, - _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name); + _aqconfig_.mqtt_aq_topic,aqdata->aqbuttons[i].name, + "mdi:toggle-switch-variant"); sprintf(topic, "%s/switch/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, aqdata->aqbuttons[i].name); send_mqtt(nc, topic, msg); } @@ -458,7 +497,8 @@ void publish_mqtt_hassio_discover(struct aqualinkdata *aqdata, struct mg_connect _aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC, _aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC, _aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC, - _aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC); + _aqconfig_.mqtt_aq_topic,SWG_BOOST_TOPIC, + "mdi:toggle-switch-variant"); sprintf(topic, "%s/switch/aqualinkd/aqualinkd_%s/config", _aqconfig_.mqtt_hass_discover_topic, idbuf); send_mqtt(nc, topic, msg); diff --git a/source/iaqtouch.c b/source/iaqtouch.c index eba37ab..81a9072 100644 --- a/source/iaqtouch.c +++ b/source/iaqtouch.c @@ -555,7 +555,7 @@ pump_detail *matchPump(const logmask_t from, struct aqualinkdata *aq_data, char { if (pump == NULL) { - LOG(from, LOG_WARNING, "Got pump message '%s' but can't find pump # %d, please update aqualinkd.conf\n", name, pi); + LOG(from, LOG_INFO, "Got pump message '%s' but can't find pump # %d, please update aqualinkd.conf\n", name, pi); } else if (pump->pumpType == PT_UNKNOWN) { @@ -627,7 +627,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) pump->pStatus = PS_OK; aq_data->updated = true; } else - LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); + LOG(IAQT_LOG,LOG_INFO, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"GPM:") == 0) { if (pump != NULL) { @@ -635,7 +635,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) pump->pStatus = PS_OK; aq_data->updated = true; } else - LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); + LOG(IAQT_LOG,LOG_INFO, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"Watts:") == 0) { if (pump != NULL) { @@ -643,7 +643,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) //pump->ppStatus = DON"T SET, WE GET WATTS IN PRIMING aq_data->updated = true; } else - LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); + LOG(IAQT_LOG,LOG_INFO, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"*** Priming ***") == 0) { pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi); @@ -653,7 +653,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) pump->pStatus = PS_PRIMING; aq_data->updated = true; } else - LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); + LOG(IAQT_LOG,LOG_INFO, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"(Offline)") == 0) { pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi); @@ -663,7 +663,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) pump->pStatus = PS_OFFLINE; aq_data->updated = true; } else - LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); + LOG(IAQT_LOG,LOG_INFO, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"(Priming Error)") == 0) { pump = matchPump(IAQT_LOG, aq_data, _deviceStatus[i-1], &pi); @@ -673,7 +673,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) pump->pStatus = PS_ERROR; aq_data->updated = true; } else - LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); + LOG(IAQT_LOG,LOG_INFO, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; // Need to catch messages like // *** Priming *** diff --git a/source/iaqtouch_aq_programmer.c b/source/iaqtouch_aq_programmer.c index ce27d6d..19078a6 100644 --- a/source/iaqtouch_aq_programmer.c +++ b/source/iaqtouch_aq_programmer.c @@ -560,7 +560,8 @@ void *set_aqualink_iaqtouch_device_on_off( void *ptr ) return ptr; } - +/* + // Not complete, and not needed with void *set_aqualink_iaqtouch_onetouch_on_off( void *ptr ) { struct programmingThreadCtrl *threadCtrl; @@ -590,6 +591,7 @@ void *set_aqualink_iaqtouch_onetouch_on_off( void *ptr ) return ptr; } +*/ diff --git a/source/json_messages.c b/source/json_messages.c index 3b59b76..d7c81cd 100644 --- a/source/json_messages.c +++ b/source/json_messages.c @@ -278,7 +278,8 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff length += sprintf(buffer, ",\"type_ext\": \"switch_program\", \"Light_Type\":\"%d\", \"Light_Program\":\"%d\", \"Program_Name\":\"%s\" ", aqdata->lights[i].lightType, aqdata->lights[i].currentValue, - light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, ALLBUTTON)); + get_currentlight_mode_name(aqdata->lights[i], ALLBUTTON)); + //light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, ALLBUTTON)); } return buffer; } @@ -733,7 +734,8 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType); if (aqdata->lights[i].lightType == LC_DIMMER2) { length += sprintf(buffer+length, "\"%s\": \"%d%%\",", aqdata->lights[i].button->name, aqdata->lights[i].currentValue ); } else { - length += sprintf(buffer+length, "\"%s\": \"%s\",", aqdata->lights[i].button->name, light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, RSSADAPTER) ); + //length += sprintf(buffer+length, "\"%s\": \"%s\",", aqdata->lights[i].button->name, light_mode_name(aqdata->lights[i].lightType, aqdata->lights[i].currentValue, RSSADAPTER) ); + length += sprintf(buffer+length, "\"%s\": \"%s\",", aqdata->lights[i].button->name, get_currentlight_mode_name(aqdata->lights[i], RSSADAPTER) ); } } if (buffer[length-1] == ',') diff --git a/source/net_services.c b/source/net_services.c index 93830ba..5403863 100644 --- a/source/net_services.c +++ b/source/net_services.c @@ -950,6 +950,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc) // Loop over programmable lights for (i=0; i < _aqualink_data->num_lights; i++) { + //LOG(NET_LOG,LOG_NOTICE, "Light %10s | %d | lmode=%.2d cmode=%.2d | name=%s\n",_aqualink_data->lights[i].button->label,_aqualink_data->lights[i].button->led->state,_aqualink_data->lights[i].lastValue,_aqualink_data->lights[i].currentValue,get_currentlight_mode_name(_aqualink_data->lights[i], RSSADAPTER)); char topic[50]; if ( _aqualink_data->lights[i].currentValue != TEMP_UNKNOWN && _aqualink_data->lights[i].currentValue != _last_mqtt_aqualinkdata.lights[i].currentValue ) { _last_mqtt_aqualinkdata.lights[i].currentValue = _aqualink_data->lights[i].currentValue; @@ -961,7 +962,8 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc) sprintf(message, "%d%%", _aqualink_data->lights[i].currentValue); send_mqtt_string_msg(nc, topic, message); } else { - send_mqtt_string_msg(nc, topic, light_mode_name(_aqualink_data->lights[i].lightType, _aqualink_data->lights[i].currentValue, ALLBUTTON)); + //send_mqtt_string_msg(nc, topic, light_mode_name(_aqualink_data->lights[i].lightType, _aqualink_data->lights[i].currentValue, RSSADAPTER)); + send_mqtt_string_msg(nc, topic, get_currentlight_mode_name(_aqualink_data->lights[i], RSSADAPTER)); } /* if (_aqualink_data->lights[i].lightType == LC_DIMMER) { diff --git a/source/serialadapter.c b/source/serialadapter.c index 4650284..006cfd1 100644 --- a/source/serialadapter.c +++ b/source/serialadapter.c @@ -11,7 +11,7 @@ #include "color_lights.h" #include "allbutton.h" -#define RSSA_QLEN 20 +#define RSSA_QLEN 40 unsigned char _rssa_queue[RSSA_QLEN][4]; int _rssa_q_length = 0; @@ -43,7 +43,6 @@ void processRSSALEDstate(struct aqualinkdata *aq_data, unsigned char *packet) bool push_rssa_cmd(unsigned char *cmd) { - if (_rssa_q_length >= RSSA_QLEN ) { LOG(RSSA_LOG,LOG_ERR, "Queue overflow, last command ignored!\n"); return false; @@ -219,8 +218,13 @@ void set_aqualink_rssadapter_spa_setpoint(char *args, struct aqualinkdata *aqdat } -#ifdef CLIGHT_PANEL_FIX +#ifdef CLIGHT_PANEL_FIX /* This is to overcome Jandy bug where panel doesn;t show the state of color light */ +void get_aqualink_rssadapter_button_status(aqkey *button) +{ + if (button->rssd_code != NUL) + rssadapter_device_state(button->rssd_code, 0x00); +} void get_aqualink_rssadapter_colorlight_statuses(struct aqualinkdata *aq_data) { for (int i=0; i < aq_data->num_lights; i++) { diff --git a/source/serialadapter.h b/source/serialadapter.h index caa9603..b4a899e 100644 --- a/source/serialadapter.h +++ b/source/serialadapter.h @@ -23,6 +23,7 @@ void increase_aqualink_rssadapter_spa_setpoint(char *args, struct aqualinkdata * #ifdef CLIGHT_PANEL_FIX void get_aqualink_rssadapter_colorlight_statuses(struct aqualinkdata *aqdata); + void get_aqualink_rssadapter_button_status(aqkey *button); #endif /* diff --git a/source/version.h b/source/version.h index 9a2b6d2..748eb27 100644 --- a/source/version.h +++ b/source/version.h @@ -4,4 +4,4 @@ #define AQUALINKD_SHORT_NAME "AqualinkD" // Use Magor . Minor . Patch -#define AQUALINKD_VERSION "2.5.0 (Dev 0.2)" +#define AQUALINKD_VERSION "2.5.0 (dev 0.3)" diff --git a/web/config.js b/web/config.js index b23dc95..5cf1b3f 100644 --- a/web/config.js +++ b/web/config.js @@ -56,6 +56,7 @@ ]; // This get's picked up by dynamic_config.js and used as mode 0 + // As version 2.5.0 Please use aqualinkd.conf for this configuration. var light_program = [ "Voodoo Lounge - Show", "Blue Sea", diff --git a/web/controller.html b/web/controller.html index 740e4b5..1a45851 100644 --- a/web/controller.html +++ b/web/controller.html @@ -1708,7 +1708,7 @@ var x; for (x = 0; x < radio.length; x++) { if (radio[x].checked == true) { - console.log("Light Current= "+(getTileSPvalue(id)+1)+" - "+getTileOnText(id)+" Selected="+radio[x].value+" - "+document.getElementById('pswitch_option_switch_text_value').innerHTML); + //console.log("Light Current= "+(getTileSPvalue(id)+1)+" - "+getTileOnText(id)+" Selected="+radio[x].value+" - "+document.getElementById('pswitch_option_switch_text_value').innerHTML); if (getTileSPvalue(id)+1 != radio[x].value) { send_light_mode(radio[x].value, id, document.getElementById('pswitch_option_switch_text_value').innerHTML); } @@ -2275,12 +2275,16 @@ var light_mode = -1; // If aqualinkd programmed light, need to convert int to text index, if not value is text try { - var light_type = document.getElementById(obj.toString()).getAttribute('lighttype'); + var light_type = document.getElementById(obj.toString()).getAttribute('lighttype'); if (light_type == "0") { light_mode = parseInt(data.light_program_names[obj])-1; - var light_mode_name = _light_program[light_type][light_mode]; - if (light_mode_name.endsWith(" - Show")) { - light_mode_name = light_mode_name.slice(0, -7); + // For backward compatibility we could get a name here or number (number is is lights modes are in config.js vs aqualinkd.conf) + //console.log("Light "+light_mode); + if (! isNaN(light_mode)) { + light_mode_name = _light_program[light_type][light_mode]; + if (light_mode_name.endsWith(" - Show")) { + light_mode_name = light_mode_name.slice(0, -7); + } } } else if (/*light_type == 10 ||*/ light_type == 11) { // Fo Dimmer Lights. @@ -2291,7 +2295,8 @@ } } catch (e) { /*console.log(e);*/ } - setTileOnText(obj.toString(),light_mode_name); + if (light_mode_name != "-999%" && light_mode_name != "Off") + setTileOnText(obj.toString(),light_mode_name); try { document.getElementById(obj.toString()).setAttribute('spvalue', light_mode);