diff --git a/README.md b/README.md
index 6198f8e..0c06d0b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
# Aqualinkd
Linux daemon to control Aqualink RS pool controllers. Provides web UI, MQTT client & HTTP API endpoints. Control your pool equipment from any phone/tablet or computer. Is also compatible with most Home control systems including Apple HomeKit, Home Assistant, Samsung, Alexa, Google, etc.
+
Binaries are supplied for Raspberry Pi both 32 & 64 bit OS, Has been, and can be compiled for many different SBC's, and a Docker is also available.
diff --git a/release/aqualinkd-arm64 b/release/aqualinkd-arm64
index 0b9da61..f2b2acf 100755
Binary files a/release/aqualinkd-arm64 and b/release/aqualinkd-arm64 differ
diff --git a/release/aqualinkd-armhf b/release/aqualinkd-armhf
index 4296d94..a037168 100755
Binary files a/release/aqualinkd-armhf and b/release/aqualinkd-armhf differ
diff --git a/release/serial_logger-arm64 b/release/serial_logger-arm64
index 3028af5..ea486bb 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 ea93ba8..787dc98 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 2b5aede..4732c4a 100644
--- a/source/allbutton_aq_programmer.c
+++ b/source/allbutton_aq_programmer.c
@@ -499,14 +499,14 @@ void *set_allbutton_light_colormode( void *ptr )
use_current_mode = true;
LOG(ALLB_LOG, LOG_INFO, "Light Programming #: %d, on button: %s, color light type: %d, using current mode\n", val, button->label, ((clight_detail *)button->special_mask_ptr)->lightType);
} else {
- mode_name = light_mode_name(((clight_detail *)button->special_mask_ptr)->lightType, val-1, ALLBUTTON);
+ mode_name = light_mode_name(((clight_detail *)button->special_mask_ptr)->lightType, val, ALLBUTTON); // NSF DO NOT -1 from value (check WS logic if you do)
use_current_mode = false;
if (mode_name == NULL) {
LOG(ALLB_LOG, LOG_ERR, "Light Programming #: %d, on button: %s, color light type: %d, couldn't find mode name '%s'\n", val, button->label, ((clight_detail *)button->special_mask_ptr)->lightType, mode_name);
cleanAndTerminateThread(threadCtrl);
return ptr;
} else {
- LOG(ALLB_LOG, LOG_INFO, "Light Programming #: %d, on button: %s, color light type: %d, name '%s'\n", val, button->label, ((clight_detail *)button->special_mask_ptr)->lightType, mode_name);
+ LOG(ALLB_LOG, LOG_INFO, "Light Programming #: %d, on button: %s, color light type: %d, color name '%s'\n", val, button->label, ((clight_detail *)button->special_mask_ptr)->lightType, mode_name);
}
}
/*
diff --git a/source/aq_panel.c b/source/aq_panel.c
index 6a4d6fd..1ee7b0e 100644
--- a/source/aq_panel.c
+++ b/source/aq_panel.c
@@ -28,10 +28,17 @@
#include "allbutton_aq_programmer.h"
#include "rs_msg_utils.h"
#include "iaqualink.h"
+#include "color_lights.h"
+
+
+#define USE_LAST_VALUE 101
void initPanelButtons(struct aqualinkdata *aqdata, bool rspda, int size, bool combo, bool dual);
-void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button);
+
+void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button, bool expectMultiple, request_source source);
void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int deviceIndex, bool expectMultiple, request_source source);
+
+
void printPanelSupport(struct aqualinkdata *aqdata);
uint16_t setPanelSupport(struct aqualinkdata *aqdata);
uint16_t getPanelBitmaskFromName(const char *str);
@@ -458,6 +465,9 @@ uint16_t setPanelSupport(struct aqualinkdata *aqdata)
if (aqdata->panel_rev[0] >= 82) // R in ascii
aqdata->panel_support_options |= RSP_SUP_IAQL;
+ if (aqdata->panel_rev[0] >= 84) // T in ascii
+ aqdata->panel_support_options |= RSP_SUP_CLIT_RSSA;
+
if (aqdata->panel_rev[0] >= 87) {// W in ascii
aqdata->panel_support_options |= RSP_SUP_PLAB;
aqdata->panel_support_options |= RSP_SUP_IAQL3;
@@ -1363,152 +1373,10 @@ int getWaterTemp(struct aqualinkdata *aqdata)
-//bool setDeviceState(aqkey *button, bool isON)
-bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, request_source source)
-{
- aqkey *button = &aqdata->aqbuttons[deviceIndex];
- bool set_pre_state = true;
-
- //if ( button->special_mask & VIRTUAL_BUTTON && button->special_mask & VS_PUMP) {
- if ( isVS_PUMP(button->special_mask) && isVBUTTON(button->special_mask)) {
- // Virtual Button with VSP is always on.
- LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', virtual pump is always on, ignoring", (isON == false ? "OFF" : "ON"), button->name);
- button->led->state = ON;
- return false;
- }
-
- if ((button->led->state == OFF && isON == false) ||
- (isON > 0 && (button->led->state == ON || button->led->state == FLASH ||
- button->led->state == ENABLE))) {
- LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', already '%s', Ignoring\n", (isON == false ? "OFF" : "ON"), button->name, (isON == false ? "OFF" : "ON"));
- //return false;
- } else {
- LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', turning '%s'\n", (isON == false ? "OFF" : "ON"), button->name, (isON == false ? "OFF" : "ON"));
-#ifdef AQ_PDA
- if (isPDA_PANEL) {
- if (button->special_mask & PROGRAM_LIGHT && isPDA_IAQT) {
- // AqualinkTouch in PDA mode, we can program light. (if turing off, use standard AQ_PDA_DEVICE_ON_OFF below)
- programDeviceLightMode(aqdata, (isON?0:-1), deviceIndex); // -1 means off 0 means use current light mode
- } else {
- // If we are using AqualinkTouch with iAqualink enabled, we can send button on/off much faster using that.
- if ( isPDA_IAQT && isIAQL_ACTIVE) {
- set_iaqualink_aux_state(button, isON);
- } else {
-#ifdef NEW_AQ_PROGRAMMER
- aq_programmer(AQ_PDA_DEVICE_ON_OFF, button, (isON == false ? OFF : ON), deviceIndex, aqdata);
-#else
- char msg[PTHREAD_ARG];
- sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
- aq_programmer(AQ_PDA_DEVICE_ON_OFF, msg, aqdata);
-#endif
- }
- }
- } else
-#endif
- {
- // 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 (isPLIGHT(button->special_mask) && isVBUTTON(button->special_mask)) {
- programDeviceLightMode(aqdata, (isON?0:-1), deviceIndex); // -1 means off 0 means use current light mode
- //aq_program(AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE, button, (isON?0:-1), 0, aqdata); // should use this in teh furuter, or get programDeviceLightMode to call it.
- } else if (isPLIGHT(button->special_mask) && button->led->state == OFF) {
- // Full range dimmer can get stuck off on rev T.2 (maybe others), to overcome use allbutton with any % other than 0
- if ( ((clight_detail *)button->special_mask_ptr)->lightType == LC_DIMMER2 ||
- ((clight_detail *)button->special_mask_ptr)->lightType == LC_DIMMER ) // NSF should remove this once figured out Line #1354 programDeviceLightBrightness()
- {
- // programLightBrightness has appropiate code to call allbutton programmer.
- /*
- int val = ((clight_detail *)button->special_mask_ptr)->lastValue>0?((clight_detail *)button->special_mask_ptr)->lastValue:100;
- programDeviceLightBrightness(aqdata, val, deviceIndex, (source==NET_MQTT?true:false), source);
- */
- programDeviceLightBrightness(aqdata, 101, deviceIndex, (source==NET_MQTT?true:false), source);
- set_pre_state = false;
- }
- // 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.
- else if (isRSSA_ENABLED) {
- set_aqualink_rssadapter_aux_state(button, true);
- } else {
- //set_light_mode("0", deviceIndex); // 0 means use current light mode
- programDeviceLightMode(aqdata, 0, deviceIndex); // 0 means use current light mode
- set_pre_state = false;
- }
-
- // If aqualinkd programmable light, it will come on at last state, so set that.
- if ( ((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 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.
-
- if ( isIAQL_ACTIVE && button->rssd_code && button->rssd_code != NUL)
- {
- //LOG(PANL_LOG, LOG_NOTICE, "********** USE iaqualink2 ********\n");
- set_iaqualink_aux_state(button, isON);
- } else {
-#ifdef NEW_AQ_PROGRAMMER
- aq_programmer(AQ_SET_IAQTOUCH_DEVICE_ON_OFF, button, (isON == false ? OFF : ON), deviceIndex, aqdata);
-#else
- char msg[PTHREAD_ARG];
- sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
- aq_programmer(AQ_SET_IAQTOUCH_DEVICE_ON_OFF, msg, aqdata);
-#endif
- set_pre_state = false;
- //} else if (button->rssd_code != VBUTTON_ONETOUCH_RSSD) {
- // LOG(PANL_LOG, LOG_NOTICE, "********** USE AQ_SET_IAQTOUCH_ONETOUCH_ON_OFF ********\n");
- // aq_programmer(AQ_SET_IAQTOUCH_ONETOUCH_ON_OFF, msg, aqdata);
- //} else {
- // LOG(PANL_LOG, LOG_ERR, "Configuration! do not understand code for Virtual Buttons");
- //}
- }
- } else {
- LOG(PANL_LOG, LOG_ERR, "Can only use Aqualink Touch protocol for Virtual Buttons");
- }
- } 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 {
- //set_iaqualink_aux_state(button, isON);
- //set_aqualink_rssadapter_aux_state(button, isON);
- 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 (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
-//#ifdef PRESTATE_ONOFF
- if (_aqconfig_.device_pre_state && set_pre_state) {
- if ((button->code == KEY_POOL_HTR || button->code == KEY_SPA_HTR ||
- button->code == KEY_EXT_AUX) &&
- isON > 0) {
- button->led->state = ENABLE; // if heater and set to on, set pre-status to enable.
- LOG(PANL_LOG, LOG_INFO, "Pre-set state of %s to enable\n",button->label);
- //_aqualink_data->updated = true;
- } else if (isRSSA_ENABLED || ((button->special_mask & PROGRAM_LIGHT) != PROGRAM_LIGHT)) {
- button->led->state = (isON == false ? OFF : ON); // as long as it's not programmable light , pre-set to on/off
- LOG(PANL_LOG, LOG_INFO, "Pre-set state of %s to %s\n",button->label,(isON == false ? "Off" : "On"));
- //_aqualink_data->updated = true;
- }
- }
-//#endif
- }
- }
- return TRUE;
-}
-
+/*
+ Basic programming that are not too involved, ie no Jandy bugs to overcome or aq_programmer can make decision on protocol to use.
+ Simply set them all as unactioned, and let the delayed_request code pick them up and pass to aq_programmer
+*/
bool programDeviceValue(struct aqualinkdata *aqdata, action_type type, int value, int id, bool expectMultiple) // id is only valid for PUMP RPM
{
if (aqdata->unactioned.type != NO_ACTION && type != aqdata->unactioned.type)
@@ -1562,224 +1430,359 @@ bool programDeviceValue(struct aqualinkdata *aqdata, action_type type, int value
}
-void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int deviceIndex, bool expectMultiple, request_source source)
+bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON, request_source source)
{
- // If Value is 101
+ aqkey *button = &aqdata->aqbuttons[deviceIndex];
+ bool set_pre_state = true;
+
+ //if ( button->special_mask & VIRTUAL_BUTTON && button->special_mask & VS_PUMP) {
+ if ( isVS_PUMP(button->special_mask) && isVBUTTON(button->special_mask)) {
+ // Virtual Button with VSP is always on.
+ LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', virtual pump is always on, ignoring", (isON == false ? "OFF" : "ON"), button->name);
+ button->led->state = ON;
+ return false;
+ }
+
+ if ((button->led->state == OFF && isON == false) ||
+ (isON > 0 && (button->led->state == ON || button->led->state == FLASH ||
+ button->led->state == ENABLE))) {
+ LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', already '%s', Ignoring\n", (isON == false ? "OFF" : "ON"), button->name, (isON == false ? "OFF" : "ON"));
+ return false;
+ }
+
+ LOG(PANL_LOG, LOG_INFO, "received '%s' for '%s', turning '%s'\n", (isON == false ? "OFF" : "ON"), button->name, (isON == false ? "OFF" : "ON"));
+#ifdef AQ_PDA
+ if (isPDA_PANEL) {
+ if (button->special_mask & PROGRAM_LIGHT && isPDA_IAQT) {
+ // AqualinkTouch in PDA mode, we can program light. (if turing off, use standard AQ_PDA_DEVICE_ON_OFF below)
+ programDeviceLightMode(aqdata, (isON?USE_LAST_VALUE:0), deviceIndex, (source==NET_MQTT?true:false), source);
+ } else {
+ // If we are using AqualinkTouch with iAqualink enabled, we can send button on/off much faster using that.
+ if ( isPDA_IAQT && isIAQL_ACTIVE) {
+ set_iaqualink_aux_state(button, isON);
+ } else {
+ aq_programmer(AQ_PDA_DEVICE_ON_OFF, button, (isON == false ? OFF : ON), deviceIndex, aqdata);
+ }
+ }
+ } else
+#endif
+ {
+ if (isPLIGHT(button->special_mask)) {
+ //programDeviceLightMode_(aqdata, (isON?USE_LAST_VALUE:0), deviceIndex ,(source==NET_MQTT?true:false), source);
+ // NSF we could let programDeviceLightMode() handle ALL these cases.
+
+ if (isMASK_SET(button->special_mask, VIRTUAL_BUTTON)) {
+ // No quick way to turn on or off and virtual button light.
+ programDeviceLightMode(aqdata, (isON?USE_LAST_VALUE:0), deviceIndex ,(source==NET_MQTT?true:false), source);
+ }
+ else if ( ((clight_detail *)button->special_mask_ptr)->lightType == LC_PROGRAMABLE ) {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s %s with allbutton key\n", button->label, isON?"On":"Off");
+ aq_send_allb_cmd(button->code);
+ if (isON) { // Will come back on in old state.
+ updateButtonLightProgram(aqdata, ((clight_detail *)button->special_mask_ptr)->lastValue, deviceIndex);
+ } else {
+ updateButtonLightProgram(aqdata, 0, deviceIndex);
+ }
+ set_pre_state = false;
+ } else if ( ((clight_detail *)button->special_mask_ptr)->lightType == LC_DIMMER2 ||
+ ((clight_detail *)button->special_mask_ptr)->lightType == LC_DIMMER) {
+ if (isON) { // Dimmer light can get stuck turning on from RSSA, so use allbutton
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s On with allbutton dimmer program\n", button->label);
+ aq_program(AQ_SET_ALLB_LIGHTDIMMER, button, 4, true, aqdata); // 4 = 100% since it uses light mode name
+ set_pre_state = false;
+ } else {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s Off with allbutton key\n", button->label);
+ aq_send_allb_cmd(button->code);
+ }
+ } else if (isRSSA_ENABLED) {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s %s with all RS serial on/off key\n", button->label, isON?"On":"Off");
+ set_aqualink_rssadapter_aux_state(button, isON);
+ } else {
+ if (isON) {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s On with allbutton light mode program\n", button->label);
+ aq_programmer(AQ_SET_LIGHTCOLOR_MODE, button, 1, true, aqdata);
+ set_pre_state = false;
+ } else {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s Off with allbutton key\n", button->label);
+ aq_send_allb_cmd(button->code);
+ }
+ }
+
+ } else if (isVBUTTON(button->special_mask)) {
+ // Virtual buttons only supported with Aqualink Touch
+ 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.
+
+ if ( isIAQL_ACTIVE && button->rssd_code && button->rssd_code != NUL)
+ {
+ //LOG(PANL_LOG, LOG_NOTICE, "********** USE iaqualink2 ********\n");
+ set_iaqualink_aux_state(button, isON);
+ } else {
+ aq_programmer(AQ_SET_IAQTOUCH_DEVICE_ON_OFF, button, (isON == false ? OFF : ON), deviceIndex, aqdata);
+ set_pre_state = false;
+ }
+ } else {
+ LOG(PANL_LOG, LOG_ERR, "Can only use Aqualink Touch protocol for Virtual Buttons");
+ }
+ } else {
+ // Everything else, simply send the button code.
+ //set_iaqualink_aux_state(button, isON);
+ //set_aqualink_rssadapter_aux_state(button, isON);
+ aq_send_allb_cmd(button->code);
+ }
+ }
+
+#ifdef CLIGHT_PANEL_FIX
+ 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
+//#ifdef PRESTATE_ONOFF
+ if (_aqconfig_.device_pre_state && set_pre_state) {
+ if ((button->code == KEY_POOL_HTR || button->code == KEY_SPA_HTR ||
+ button->code == KEY_EXT_AUX) &&
+ isON > 0) {
+ button->led->state = ENABLE; // if heater and set to on, set pre-status to enable.
+ LOG(PANL_LOG, LOG_INFO, "Pre-set state of %s to enable\n",button->label);
+ //_aqualink_data->updated = true;
+ //} else if (isRSSA_ENABLED || ((button->special_mask & PROGRAM_LIGHT) != PROGRAM_LIGHT)) {
+ } else if (isRSSA_ENABLED || !isPLIGHT(button->special_mask)) {
+ button->led->state = (isON == false ? OFF : ON); // as long as it's not programmable light , pre-set to on/off
+ LOG(PANL_LOG, LOG_INFO, "Pre-set state of %s to %s\n",button->label,(isON == false ? "Off" : "On"));
+ //_aqualink_data->updated = true;
+ }
+ }
+//#endif
+
+
+ return TRUE;
+}
+
+
+/*
+ value 0 = off
+ value 101/USE_LAST_VALUE = On use default mode if you can
+ value is % for LC_DIMMER and LC_DIMMER2
+*/
+void programDeviceLightBrightness(struct aqualinkdata *aqdata, int value, int deviceIndex, bool expectMultiple, request_source source)
+{
+ //int extra_value = false;
+
+ if (value < 0 || value > 100) {
+ LOG(PANL_LOG,LOG_ERR, "Dimmer value %d is not valid, using %d\n",value,AQ_CLAMP(value,0,100));
+ value = AQ_CLAMP(value,0,100);
+ }
+
+ if (expectMultiple) {
+ // Queue up a request, this will call us back through with expectMultiple=false
+ time(&aqdata->unactioned.requested);
+ aqdata->unactioned.value = value;
+ aqdata->unactioned.type = LIGHT_BRIGHTNESS;
+ aqdata->unactioned.id = deviceIndex;
+ return;
+ }
clight_detail *light = getProgramableLight(aqdata, deviceIndex);
- // Light mode 10
- //printf("******* Light Brightness *** value=%d device=%d multiple=%d\n",value,deviceIndex,expectMultiple);
- //printf("****** Light %s on/off=%d %s\n",aqdata->aqbuttons[deviceIndex].label, aqdata->aqbuttons[deviceIndex].led->state, aqdata->aqbuttons[deviceIndex].led->state==ON?"on":"off");
-
- // With changes to fix LC_DIMMER2, LC_DIMMER has now started having similar issues.
- // Need to come back and look at why, LC_DIMMER should be removed from below IF once sorted./
- if ( (light->lightType == LC_DIMMER2 || light->lightType == LC_DIMMER) && aqdata->aqbuttons[deviceIndex].led->state == OFF ) {
- // Light is off, we will turn in on but due to Jandy bug on rev T, have to use all button so values of 25/50/75/100.
- // value = 101, means use default (if if it comes on at 33% leave that, if not 100%).
- // value != 25/50/75/100 use all button to turn on, then reset with rssserial adapter.
- LOG(PANL_LOG,LOG_DEBUG, "Using allbutton programmer to set light dimmer\n");
-
- if (value == 101) {
- //Should probably try to get the last value in this case, and use the closest 25% rather than default to 100. (ie 4)
- //int val = ((clight_detail *)button->special_mask_ptr)->lastValue>0?((clight_detail *)button->special_mask_ptr)->lastValue:100;
- aq_program(AQ_SET_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], 4, true, aqdata); // 4 = 100% since it uses light mode name
- } else {
- int calVal = round( (value+12) / 25); // Round up/down
- if (calVal > 4 ) {calVal=4;}
- LOG(PANL_LOG,LOG_INFO, "Rounded dimmer value to %d for on command\n",calVal * 25);
- aq_program(AQ_SET_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], calVal, false, aqdata);
-
- if (light->lightType == LC_DIMMER2 ) {
- if (value != 25 && value !=50 && value !=75 && value != 100) {
- // Setup the rssd to set the light to the right value.
- //printf("Second programming for %%%d\n",value);
- time(&aqdata->unactioned.requested);
- aqdata->unactioned.requested += 5;
- aqdata->unactioned.value = value;
- aqdata->unactioned.type = LIGHT_MODE;
- aqdata->unactioned.id = deviceIndex;
- }
- }
- }
-
- /*
- int calVal = round(value / 25);
- LOG(PANL_LOG,LOG_DEBUG, "Using allbutton programmer to set light\n");
- if (calVal > 4 ) {calVal=4;}
- LOG(PANL_LOG,LOG_INFO, "Rounded dimmer value to %d for on command\n",calVal * 25);
- if (value != 25 && value !=50 && value !=75 && value != 100) {
- aq_program(AQ_SET_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], calVal, false, aqdata);
- } else {
- aq_program(AQ_SET_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], calVal, true, aqdata);
- }*/
- /*
- if (value != 25 && value !=50 && value !=75 && value != 100) {
- printf("Second programming for %%%d\n",value);
- time(&aqdata->unactioned.requested);
- aqdata->unactioned.requested += 5;
- aqdata->unactioned.value = value;
- aqdata->unactioned.type = LIGHT_MODE;
- aqdata->unactioned.id = deviceIndex;
- }
- */
+ if (light == NULL || (light->lightType != LC_DIMMER2 && light->lightType != LC_DIMMER)) {
+ LOG(PANL_LOG,LOG_ERR, "Can not set light brightness on device '%s'\n",aqdata->aqbuttons[deviceIndex].label);
return;
}
+
+ if (!isRSSA_ENABLED && light->lightType == LC_DIMMER2) {
+ LOG(PANL_LOG,LOG_ERR, "Light mode brightness 11 is only supported when `rssa_device_id` is set\n");
+ return;
+ }
+
+ if (value == 0) {
+ // We simply need to turn the light off at this point, so use allbutton key as it's the quickest.
+ // but can't turn off a virtual light.
+ if (light->button->led->state == ON && !isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON)) {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s Off with allbutton key\n", light->button->label);
+ aq_send_allb_cmd(light->button->code);
+ // Could also check isRSSA_ENABLED and use set_aqualink_rssadapter_aux_state(light->button, FALSE);
+ return;
+ } else if (light->button->led->state != ON ) {
+ LOG(PANL_LOG,LOG_WARNING, "Request to turn Light brightness '%s' to 0, already off, ignoring!\n",light->button->label);
+ return;
+ }
+ }
+
+ /*
+ logic.
+ set brightness through RSSA. (RSSA only protocol supports full dimmer range)
+ RSSA has bug / issue. Sometimes panel will lock device forcing a panel delete/re-add of light.
+ to overcome this seems to be turn it on with allbutton, if it's on then use RSSA to set the %.
+
+ if off turn on with allbutton.
+
+ */
+
-
- if (!isRSSA_ENABLED) {
- LOG(PANL_LOG,LOG_ERR, "Light mode brightness is only supported with `rssa_device_id` set\n");
- return;
- }
-
- if (light == NULL) {
- LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",deviceIndex);
- return;
- }
-
- // DIMMER is 0,25,50,100 DIMMER2 is range
- if (light->lightType == LC_DIMMER) {
- value = round(value / 25);
- if (value > 4 ) {value=4;}
- LOG(PANL_LOG,LOG_INFO, "Rounded dimmer value to %d\n",value * 25);
- } else {
-
- }
-
- if (!expectMultiple) {
- if (value <= 0) {
- // Consider this a bad/malformed request to turn the light off.
- panel_device_request(aqdata, ON_OFF, deviceIndex, 0, source);
+ if (aqdata->aqbuttons[deviceIndex].led->state == ON) {
+ // Light is on, Simple set brightness through RSSD if we can
+ if (isRSSA_ENABLED) {
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s to %d with RS Serial extended state\n", light->button->label, value);
+ set_aqualink_rssadapter_aux_extended_state(light->button, value + RSSD_COLOR_LIGHT_OFFSET_WRITE);
} else {
- programDeviceLightMode(aqdata, value, deviceIndex);
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s to %d with allbutton dimmer program\n", light->button->label, value);
+ aq_program(AQ_SET_ALLB_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], dimmer_percent_to_mode_index(value), false, aqdata);
+ }
+ } else {
+ // Light is off, turn on with allbutton then reset the %.
+ if (value == USE_LAST_VALUE) {
+ // 101 is used last value, param #4 of true in ap_program means use default value if can, otherwise use param #3 = 4 = 100%
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s to Last mode with allbutton dimmer program\n", light->button->label);
+ aq_program(AQ_SET_ALLB_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], 4, true, aqdata); // 4 = 100% since it uses light mode name
+ } else {
+ int calVal = dimmer_percent_to_mode_index(value);
+ LOG(PANL_LOG,LOG_INFO, "Rounded dimmer value to %d for on command\n",calVal * 25);
+ LOG(PANL_LOG,LOG_DEBUG, "Turning light %s to %d with allbutton dimmer program\n", light->button->label, calVal);
+ aq_program(AQ_SET_ALLB_LIGHTDIMMER, &aqdata->aqbuttons[deviceIndex], calVal, false, aqdata);
+ if (value != 25 && value !=50 && value !=75 && value != 100 && isRSSA_ENABLED) {
+ // Setup the rssd to set the light to the right value.
+ time(&aqdata->unactioned.requested);
+ aqdata->unactioned.requested += 5; // This should give enough time for the allbutton to finish
+ aqdata->unactioned.value = value;
+ aqdata->unactioned.type = LIGHT_BRIGHTNESS;
+ aqdata->unactioned.id = deviceIndex;
+ }
+
}
- return;
}
- time(&aqdata->unactioned.requested);
- aqdata->unactioned.value = value;
- aqdata->unactioned.type = LIGHT_MODE;
- aqdata->unactioned.id = deviceIndex;
-
return;
}
-
-//void programDeviceLightMode(struct aqualinkdata *aqdata, char *value, int button)
-//void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button)
-void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIndex)
+/*
+ value 0 = off
+ value 101/USE_LAST_VALUE = On use default mode if you can
+*/
+void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIndex, bool expectMultiple, request_source source)
{
-
-#ifdef AQ_PDA
- if (isPDA_PANEL && !isPDA_IAQT) {
- LOG(PANL_LOG,LOG_ERR, "Light mode control not supported in PDA mode\n");
+ int extra_value=false;
+ /*. We should never get multiple requests for mode, only brightness uses slider. But leave here incase we need it in the future
+ if (expectMultiple) {
+ // Queue up a request, this will call us back through with expectMultiple=false
+ time(&aqdata->unactioned.requested);
+ aqdata->unactioned.value = value;
+ aqdata->unactioned.type = LIGHT_MODE;
+ aqdata->unactioned.id = deviceIndex;
return;
}
-#endif
-
-
- /*
- int i;
- clight_detail *light = NULL;
- for (i=0; i < aqdata->num_lights; i++) {
- if (&aqdata->aqbuttons[button] == aqdata->lights[i].button) {
- // Found the programmable light
- light = &aqdata->lights[i];
- break;
- }
- }*/
+ */
clight_detail *light = getProgramableLight(aqdata, deviceIndex);
if (light == NULL) {
- LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n",deviceIndex);
+ LOG(PANL_LOG,LOG_ERR, "Light mode control not configured for button %d\n", deviceIndex);
return;
}
- if (isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON)) {
- // We can only program a light on virtual button on iaqtouch or onetouch
- if (isIAQT_ENABLED ) {
-#ifdef NEW_AQ_PROGRAMMER
- aq_programmer(AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE, light->button, value, AQP_NULL, aqdata);
-#else
- char buf[LIGHT_MODE_BUFER];
- sprintf(buf, "%-5d%-5d%-5d",value, deviceIndex, light->lightType);
- aq_programmer(AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE, buf, aqdata);
-#endif
- } else if (isONET_ENABLED ) {
- LOG(PANL_LOG,LOG_ERR, "Light mode on virtual button not implimented on OneTouch protocol (needs AqualinkTouch)\n");
- } else {
- LOG(PANL_LOG,LOG_ERR, "Light mode on virtual button needs AqualinkTouch protocol\n");
- }
- } else if (light->lightType == LC_PROGRAMABLE ) {
-#ifdef NEW_AQ_PROGRAMMER
- aq_programmer(AQ_SET_LIGHTPROGRAM_MODE, light->button, value, AQP_NULL, aqdata);
-#else
- char buf[LIGHT_MODE_BUFER];
- sprintf(buf, "%-5d%-5d%-5d%-5d%.2f",value,
- deviceIndex,
- _aqconfig_.light_programming_initial_on,
- _aqconfig_.light_programming_initial_off,
- _aqconfig_.light_programming_mode );
- aq_programmer(AQ_SET_LIGHTPROGRAM_MODE, buf, aqdata);
-#endif
- } 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_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)
- if (value >= 1 && value <= 4) {
- unsigned char rssd_value = value * 25;
- //rssd_value +=128;
- set_aqualink_rssadapter_aux_extended_state(light->button, rssd_value);
- } else {
- LOG(PANL_LOG,LOG_ERR, "Light mode %d is not valid for '%s'\n",value, light->button->label);
- set_aqualink_rssadapter_aux_extended_state(light->button, 100);
- }
- } else {
- // Dimmer or any color light can simply be set with value
- set_aqualink_rssadapter_aux_extended_state(light->button, value + 128);
- }
- /*
- } else if (isRSSA_ENABLED && light->lightType == LC_DIMMER2) {
- // Dimmer needs to be turned on before you set dimmer level
- if (light->button->led->state != ON) {
- set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON);
- }
- set_aqualink_rssadapter_aux_extended_state(light->button, value);
- } else if (isRSSA_ENABLED && light->lightType == LC_DIMMER) {
- // Dimmer needs to be turned on first
- if (light->button->led->state != ON) {
- set_aqualink_rssadapter_aux_extended_state(light->button, RS_SA_ON);
- }
- // Value 1 = 25, 2 = 50, 3 = 75, 4 = 100 (need to convert value into binary)
- if (value >= 1 && value <= 4) {
- // If value is not on of those vales, then ignore
- unsigned char rssd_value = value * 25;
- set_aqualink_rssadapter_aux_extended_state(light->button, rssd_value);
- } else {
- LOG(PANL_LOG,LOG_ERR, "Light mode %d is not valid for '%s'\n",value, light->button->label);
- }
- } else if (isRSSA_ENABLED && light->lightType != LC_PROGRAMABLE) {
- // Any programmable COLOR light (that's programmed by panel)
- set_aqualink_rssadapter_aux_extended_state(light->button, value);*/
- } else {
-#ifdef NEW_AQ_PROGRAMMER
- aq_programmer(AQ_SET_LIGHTCOLOR_MODE, light->button, value, AQP_NULL, aqdata);
-#else
- char buf[LIGHT_MODE_BUFER];
- sprintf(buf, "%-5d%-5d%-5d",value, deviceIndex, light->lightType);
- aq_programmer(AQ_SET_LIGHTCOLOR_MODE, buf, aqdata);
-#endif
+ if (! is_valid_light_mode(light->lightType, value)) {
+ LOG(PANL_LOG,LOG_ERR, "Light mode '%d' is not valid for light '%s', %s\n", value, lightTypeName(light->lightType), light->button->label);
+ return;
}
+ if (light->lightType == LC_DIMMER2 || light->lightType == LC_DIMMER) {// DIMMER
+ programDeviceLightBrightness(aqdata, (light->lightType== LC_DIMMER?dimmer_mode_to_percent(value):value), deviceIndex, expectMultiple, source);
+ return;
+ }
+
+ // Turn on a light with no mode set.
+ if (value == USE_LAST_VALUE) {
+ extra_value = true;
+ value = 1; // Do we need to reset this?
+ // Anything but VIRTUAL_BUTTON we can turn on with no mode simply.
+ if (!isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON)) {
+ // for LC_PROGRAMMABLE is a simple ON command, so send it and be done.
+ if (light->lightType == LC_PROGRAMABLE) {
+ aq_send_allb_cmd(light->button->code);
+ light->currentValue = light->lastValue; // will come back on in last mode, so set that.
+ // easiest way is to turn on with RSSA then no questions asked.
+ } else if (isRSSA_ENABLED) {
+ set_aqualink_rssadapter_aux_state(light->button, true);
+ } else {
+ aq_programmer(AQ_SET_LIGHTCOLOR_MODE, light->button, 1, extra_value, aqdata);
+ }
+ return;
+ }
+ } else if (value == 0) {
+ // We simply need to turn the light off at this point, so use allbutton key as it's the quickest.
+ // but can't turn off a virtual light.
+ if (light->button->led->state == ON && !isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON)) {
+ //DPRINTF("allbutton off");
+ aq_send_allb_cmd(light->button->code);
+ // Could also check isRSSA_ENABLED and use set_aqualink_rssadapter_aux_state(light->button, FALSE);
+ return;
+ } else if (light->button->led->state != ON ) {
+ LOG(PANL_LOG,LOG_WARNING, "Request to turn off Light mode '%s' to off, already off, ignoring!\n",light->button->label);
+ return;
+ }
+ }
+
+ // Logic, select one of 3 programming options, RSSD / AllButton / AqualinkTouch
+ // virtual button light can only be done with AqualinkTouch
+ // LC_PROGRAMABLE can only be done with AllButton
+ // user can set a default
+ // dimmer light NEEDS to be turned on with allbutton.
+
+ // Check Virtual Button requires IAQT protocol
+ if (isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON) && !isIAQT_ENABLED)
+ {
+ // Log an error and stop execution if a Virtual Button is used without IAQT.
+ LOG(PANL_LOG, LOG_ERR, "Light mode on virtual button needs AqualinkTouch protocol\n");
+ return;
+ }
+ // Use allbutton if LC_PROGRAMABLE light, or no other protocol options
+ else if (light->lightType == LC_PROGRAMABLE)
+ {
+ //DPRINTF("AQ_SET_LIGHTPROGRAM_MODE");
+ aq_programmer(AQ_SET_LIGHTPROGRAM_MODE, light->button, value, extra_value, aqdata);
+ }
+ // Use allbutton if explicitly set, or no other protocol options
+ else if ((!isRSSA_ENABLED && !isIAQT_ENABLED) ||
+ (_aqconfig_.light_programming_interface == LIGHT_PROTOCOL_ALLB))
+ {
+ //DPRINTF("AQ_SET_ALLB_LIGHTCOLOR_MODE");
+ aq_programmer(AQ_SET_ALLB_LIGHTCOLOR_MODE, light->button, value, extra_value, aqdata);
+ }
+ // Use AqualinkTouch if explicitly set or virtual button.
+ else if (isIAQT_ENABLED &&
+ (_aqconfig_.light_programming_interface == LIGHT_PROTOCOL_AQLT ||
+ isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON)))
+ {
+ //DPRINTF("AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE");
+ // This depends on the button label being accurate with panel.
+ aq_programmer(AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE, light->button, value, extra_value, aqdata);
+ }
+ // Use RS-Serial Adapter protocol
+ else if (isRSSA_ENABLED)
+ {
+ //DPRINTF("set_aqualink_rssadapter_aux_state");
+ unsigned char rssd_value = value + RSSD_COLOR_LIGHT_OFFSET_WRITE;
+ // If light is off, turn it on first
+ if (light->button->led->state != ON)
+ {
+ set_aqualink_rssadapter_aux_state(light->button, TRUE);
+ }
+ // Adjust the value for Dimmer lights (map color index to full range %).
+ if (light->lightType == LC_DIMMER || light->lightType == LC_DIMMER2)
+ {
+ rssd_value = value * 25; // Dimmer is full range % on RSSD
+ }
+ set_aqualink_rssadapter_aux_extended_state(light->button, rssd_value);
+ }
+ // Default Fallback (Should rarely be reached)
+ else {
+ //DPRINTF("AQ_SET_LIGHTCOLOR_MODE");
+ aq_programmer(AQ_SET_LIGHTCOLOR_MODE, light->button, value, extra_value, aqdata);
+ }
+
+
// Use function so can be called from programming thread if we decide to in future.
if (light->lightType != LC_PROGRAMABLE ) {
// Only update if a panel programed light. If AqualinkD programs, the programmer needs to know the last mode.
@@ -1787,6 +1790,7 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIn
}
}
+
/*
deviceIndex = button index on button list (or pumpIndex for VSP action_types)
value = value to set (0=off 1=on, or value for setpoints / rpm / timer) action_type will depend on this value
@@ -1833,6 +1837,7 @@ bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int dev
start_timer(aqdata, deviceIndex, value);
break;
case LIGHT_BRIGHTNESS:
+ // Allow value=0 here (unlike LIGHT_MODE) since we could get multiple requests from a slider. (aka HomeKit)
programDeviceLightBrightness(aqdata, value, deviceIndex, (source==NET_MQTT?true:false), source);
break;
case LIGHT_MODE:
@@ -1840,7 +1845,7 @@ bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int dev
// Consider this a bad/malformed request to turn the light off.
panel_device_request(aqdata, ON_OFF, deviceIndex, 0, source);
} else {
- programDeviceLightMode(aqdata, value, deviceIndex);
+ programDeviceLightMode(aqdata, value, deviceIndex, (source==NET_MQTT?true:false), source);
}
break;
case POOL_HTR_SETPOINT:
diff --git a/source/aq_panel.h b/source/aq_panel.h
index 07a605a..376baf4 100644
--- a/source/aq_panel.h
+++ b/source/aq_panel.h
@@ -57,7 +57,7 @@ const uint32_t PANEL_COMPARISON_MASK = (1U << 12) - 1; // We only care about bi
#define RSP_SUP_PLAB (1 << 11) // Pump VSP by Label and not number
#define RSP_SUP_HPCHIL (1 << 12) // Heat Pump chiller
#define RSP_SUP_PCDOC (1 << 13) // PC Dock
-
+#define RSP_SUP_CLIT_RSSA (1 << 14) // Color Lights can be set over serial adapter.
#define PANEL_CPU (1 << 0)
#define PANEL_REV (1 << 1)
diff --git a/source/aq_programmer.c b/source/aq_programmer.c
index 7fa3bc7..fc6360a 100644
--- a/source/aq_programmer.c
+++ b/source/aq_programmer.c
@@ -73,6 +73,10 @@ const func_ptr _prog_functions[AQP_RSSADAPTER_MAX] = {
[AQ_SET_SWG_PERCENT] = set_allbutton_SWG,
[AQ_GET_AUX_LABELS] = get_allbutton_aux_labels,
[AQ_SET_BOOST] = set_allbutton_boost,
+ // Specific one to force all button for light programming
+ [AQ_SET_ALLB_LIGHTCOLOR_MODE] = set_allbutton_light_colormode,
+ [AQ_SET_ALLB_LIGHTDIMMER] = set_allbutton_light_dimmer,
+
[AQ_SET_ONETOUCH_PUMP_RPM] = set_aqualink_onetouch_pump_rpm,
[AQ_GET_ONETOUCH_FREEZEPROTECT] = get_aqualink_onetouch_freezeprotect,
[AQ_GET_ONETOUCH_SETPOINTS] = get_aqualink_onetouch_setpoints,
@@ -909,9 +913,11 @@ const char *ptypeName(program_type type)
return "Set light color (using AqualinkD)";
break;
case AQ_SET_LIGHTCOLOR_MODE:
- return "Set light color (using Panel)";
+ case AQ_SET_ALLB_LIGHTCOLOR_MODE:
+ return "Set light color";
break;
case AQ_SET_LIGHTDIMMER:
+ case AQ_SET_ALLB_LIGHTDIMMER:
return "Set light dimmer";
break;
case AQ_SET_SWG_PERCENT:
@@ -1004,7 +1010,7 @@ const char *ptypeName(program_type type)
return "Set AqualinkTouch OneTouch On/Off";
break;
case AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE:
- return "Set AqualinkTouch Light Color (using panel)";
+ return "Set AqualinkTouch Light Mode";
break;
case AQ_SET_IAQTOUCH_SWG_BOOST:
return "Set AqualinkTouch Boost";
@@ -1123,6 +1129,8 @@ const char *programtypeDisplayName(program_type type)
case AQ_SET_LIGHTCOLOR_MODE:
case AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE:
case AQ_SET_LIGHTDIMMER:
+ case AQ_SET_ALLB_LIGHTDIMMER:
+ case AQ_SET_ALLB_LIGHTCOLOR_MODE:
return "Programming: setting light mode";
break;
case AQ_SET_SWG_PERCENT:
diff --git a/source/aq_programmer.h b/source/aq_programmer.h
index 021e1a6..5ba619c 100644
--- a/source/aq_programmer.h
+++ b/source/aq_programmer.h
@@ -68,6 +68,9 @@ typedef enum {
AQ_SET_PUMP_RPM,
AQ_SET_PUMP_VS_PROGRAM,
AQ_SET_CHILLER_TEMP,
+ // **** Specific allputon light program. (maybe create all all button in future)
+ AQ_SET_ALLB_LIGHTCOLOR_MODE,
+ AQ_SET_ALLB_LIGHTDIMMER,
// ******** PDA Delimiter make sure to change MAX/MIN below
AQ_PDA_INIT,
AQ_PDA_WAKE_INIT,
diff --git a/source/aqualink.h b/source/aqualink.h
index 4aa56df..5c34dac 100644
--- a/source/aqualink.h
+++ b/source/aqualink.h
@@ -10,8 +10,8 @@
#include "sensors.h"
//#include "aq_panel.h" // Moved to later in file to overcome circular dependancy. (crappy I know)
-//#define PRINTF(format, ...) printf("%s:%d: " format, __FILE__, __LINE__, ##__VA_ARGS__)
-#define PRINTF(format, ...)
+//#define DPRINTF(format, ...) printf("%s:%d: " format, __FILE__, __LINE__, ##__VA_ARGS__)
+//#define DPRINTF(format, ...)
#define isMASK_SET(bitmask, mask) ((bitmask & mask) == mask)
#define setMASK(bitmask, mask) (bitmask |= mask)
diff --git a/source/aqualinkd.c b/source/aqualinkd.c
index eaf8645..0234c75 100644
--- a/source/aqualinkd.c
+++ b/source/aqualinkd.c
@@ -434,6 +434,9 @@ void action_delayed_request()
else if (_aqualink_data.unactioned.type == LIGHT_MODE) {
panel_device_request(&_aqualink_data, LIGHT_MODE, _aqualink_data.unactioned.id, _aqualink_data.unactioned.value, UNACTION_TIMER);
}
+ else if (_aqualink_data.unactioned.type == LIGHT_BRIGHTNESS) {
+ panel_device_request(&_aqualink_data, LIGHT_BRIGHTNESS, _aqualink_data.unactioned.id, _aqualink_data.unactioned.value, UNACTION_TIMER);
+ }
else
{
LOG(AQUA_LOG,LOG_ERR, "Unknown request of type %d\n", _aqualink_data.unactioned.type);
diff --git a/source/color_lights.c b/source/color_lights.c
index f495062..2d34e06 100644
--- a/source/color_lights.c
+++ b/source/color_lights.c
@@ -43,7 +43,7 @@ char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS] =
"Magenta",
"Garnet Red",
"Violet",
- "Color Splash"
+ "Color Splash" // 0x4b
},
{ // 2 = Jandy LED
"Off",
@@ -182,6 +182,28 @@ void setColorLightsPanelVersion(uint8_t supported)
set = true;
}
*/
+
+bool is_valid_light_mode(clight_type type, int index)
+{
+ printf("Checking _color_light_options[%d][%d]\n",type,index);
+
+ if (type == LC_DIMMER2) {
+ if (index >= 0 && index <=100) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (index < 0 || index > LIGHT_COLOR_OPTIONS || _color_light_options[type][index] == NULL ){
+ return false;
+ }
+
+ printf("result = %s\n", _color_light_options[type][index]);
+
+ return true;
+}
+
void clear_aqualinkd_light_modes()
{
//_color_light_options[0] = _aqualinkd_custom_colors;
@@ -271,6 +293,8 @@ const char *get_currentlight_mode_name(clight_detail light, emulation_type proto
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)
@@ -346,6 +370,68 @@ bool set_currentlight_value(clight_detail *light, int index)
return rtn;
}
+ // Take a % and return 0,1,2,3,4 for 0=0, 1=25, 2=50, 3=75, 4=100, ie the index of _color_light_options[10][??]
+int dimmer_percent_to_mode_index(int value)
+{
+ /*
+ value = round(value / 25);
+ if (value > 4 ) {value=4;}
+ */
+ value = round( (value+12) / 25); // Round up/down
+ if (value > 4 ) {value=4;}
+
+ return value;
+}
+
+int dimmer_mode_to_percent(int value)
+{
+ return value * 25;
+}
+
+
+const char* lightTypeName(clight_type type)
+{
+ switch (type) {
+ case LC_PROGRAMABLE:
+ return "AqualinkD Programmable";
+ break;
+ case LC_JANDY:
+ return "Jandy Color";
+ break;
+ case LC_JANDYLED:
+ return "Jandy LED";
+ break;
+ case LC_SAL:
+ return "SAm/SAL";
+ break;
+ case LC_CLOGIG:
+ return "Color Logic";
+ break;
+ case LC_INTELLIB:
+ return "Intelibrite";
+ break;
+ case LC_HAYWCL:
+ return "Haywood Universal";
+ break;
+ case LC_JANDYINFINATE:
+ return "Jandy Infinite";
+ break;
+ case LC_DIMMER:
+ return "Dimmer";
+ break;
+ case LC_DIMMER2:
+ return "Dimmer (full range)";
+ break;
+
+ default:
+ case LC_SPARE_2:
+ case LC_SPARE_3:
+ return "unknown";
+ break;
+ }
+ return "unknown";
+}
+
// Used for dynamic config JS
int build_color_lights_js(struct aqualinkdata *aqdata, char* buffer, int size)
{
diff --git a/source/color_lights.h b/source/color_lights.h
index edfdcd9..d6f7f2d 100644
--- a/source/color_lights.h
+++ b/source/color_lights.h
@@ -11,9 +11,13 @@
//#define LIGHT_COLOR_TYPES LC_DIMMER+1
// The status returned from RS Serial Adapter has this added as a base.
-#define RSSD_COLOR_LIGHT_OFFSET 64
+#define RSSD_COLOR_LIGHT_OFFSET_WRITE 128 // when writing its 128
+#define RSSD_COLOR_LIGHT_OFFSET_READ 64 // when reading is 64
#define RSSD_DIMMER_LIGHT_OFFSET 128
+// When selecting a color light, the Button press keycode add this offset.
+#define IAQ_COLOR_LIGHT_OFFSET 16
+
//#define DIMMER_LIGHT_TYPE_INDEX 10
/*
@@ -24,7 +28,7 @@ typedef enum clight_type {
LC_JANDYLED,
LC_SAL,
LC_CLOGIG,
- LC_INTELLIB
+ LC_INTELLIB,
} clight_type;
*/
//const char *light_mode_name(clight_type type, int index);
@@ -32,9 +36,12 @@ const char *get_currentlight_mode_name(clight_detail light, emulation_type proto
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);
-
+int dimmer_percent_to_mode_index(int value);
+int dimmer_mode_to_percent(int value);
void clear_aqualinkd_light_modes();
bool set_currentlight_value(clight_detail *light, int index);
+bool is_valid_light_mode(clight_type type, int index);
+const char* lightTypeName(clight_type type);
bool set_aqualinkd_light_mode_name(char *name, int index, bool isShow);
const char *get_aqualinkd_light_mode_name(int index, bool *isShow);
diff --git a/source/config.c b/source/config.c
index 6e2806d..bb20b98 100644
--- a/source/config.c
+++ b/source/config.c
@@ -264,6 +264,7 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].name = CFG_N_rssa_device_id;
_cfgParams[_numCfgParams].valid_values = CFG_V_rssa_device_id;
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_unknownHex;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.extended_device_id_programming;
@@ -279,6 +280,7 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].name = CFG_N_extended_device_id;
_cfgParams[_numCfgParams].valid_values = CFG_V_extended_device_id;
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_unknownHex;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.enable_iaqualink;
@@ -286,6 +288,7 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].name = CFG_N_enable_iaqualink;
_cfgParams[_numCfgParams].valid_values = CFG_V_BOOL;
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_false;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
#ifndef AQ_MANAGER
_numCfgParams++;
@@ -311,6 +314,7 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].name = CFG_N_mqtt_user;
_cfgParams[_numCfgParams].default_value = (void *)NULL;
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_passwd;
@@ -319,6 +323,7 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].config_mask |= CFG_PASSWD_MASK;
_cfgParams[_numCfgParams].default_value = (void *)NULL;
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_aq_topic;
@@ -326,6 +331,7 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].name = CFG_N_mqtt_aq_topic;
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_aq_tp;
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_discovery_topic;
@@ -333,12 +339,14 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].name = CFG_N_mqtt_discovery_topic;
_cfgParams[_numCfgParams].default_value = (void *)_dcfg_mqtt_discovery;
_cfgParams[_numCfgParams].config_mask |= CFG_ALLOW_BLANK;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mqtt_discovery_use_mac;
_cfgParams[_numCfgParams].value_type = CFG_BOOL;
_cfgParams[_numCfgParams].name = CFG_N_mqtt_discovery_use_mac;
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_true;
+ _cfgParams[_numCfgParams].config_mask |= CFG_FORCE_RESTART;
#if MG_TLS > 0
@@ -372,6 +380,14 @@ void init_parameters (struct aqconfig * parms)
_cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
_cfgParams[_numCfgParams].default_value = (void *)&_dcfg_light_programming_mode;
+ _numCfgParams++;
+ _cfgParams[_numCfgParams].value_ptr = &_aqconfig_.light_programming_interface;
+ _cfgParams[_numCfgParams].value_type = CFG_INT;
+ _cfgParams[_numCfgParams].name = CFG_N_light_programming_interface;
+ _cfgParams[_numCfgParams].config_mask |= CFG_GRP_ADVANCED;
+ _cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
+ _cfgParams[_numCfgParams].default_value = (void *)&_dcfg_zero;
+
_numCfgParams++;
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.light_programming_initial_on;
_cfgParams[_numCfgParams].value_type = CFG_INT;
@@ -1751,6 +1767,39 @@ void check_print_config (struct aqualinkdata *aqdata)
}
}
+ // Color lights check infinate water color (RS485, is set as vbutton)
+ for (i=1; i < aqdata->num_lights; i++) {
+ if (aqdata->lights[i].lightType == LC_JANDYINFINATE) {
+ // Check we have a virtual light button
+ if ( !isMASK_SET(aqdata->lights[i].button->special_mask, VIRTUAL_BUTTON)) {
+ LOG(AQUA_LOG,LOG_WARNING, "Config error, Light mode %d is only valid for a virtual button\n",LC_JANDYINFINATE);
+ }
+ }
+ }
+
+ // Check valid setting
+ if (_aqconfig_.light_programming_interface > LIGHT_PROTOCOL_AQLD) {
+ if (_aqconfig_.device_id == 0x60) {
+ LOG(AQUA_LOG,LOG_WARNING, "Config error, %s set to %d, not supported in PDA mode",CFG_N_light_programming_interface,_aqconfig_.light_programming_interface);
+ _aqconfig_.light_programming_interface = LIGHT_PROTOCOL_AQLD;
+ }
+
+ if(_aqconfig_.light_programming_interface == LIGHT_PROTOCOL_AQLT) {
+ if (! is_aqualink_touch_id(_aqconfig_.extended_device_id)) {
+ LOG(AQUA_LOG,LOG_WARNING, "Config error, %s set to AqualinkTouch, %s is not set for AqualinkTouch ID",CFG_N_light_programming_interface,CFG_N_extended_device_id);
+ _aqconfig_.light_programming_interface = LIGHT_PROTOCOL_AQLD;
+ }
+ // Below not supported yet
+ //} else if(_aqconfig_.light_programming_interface == LIGHT_PROTOCOL_ONET) {
+ // if (! is_onetouch_id(_aqconfig_.extended_device_id)) {
+ // LOG(AQUA_LOG,LOG_WARNING, "Config error, %s set to OneTouch, %s is not set for OneTouch ID",CFG_N_light_programming_interface,CFG_N_extended_device_id);
+ // _aqconfig_.light_programming_interface = LIGHT_PROTOCOL_AQLD;
+ // }
+ } else if ( _aqconfig_.light_programming_interface > LIGHT_PROTOCOL_ALLB ) {
+ LOG(AQUA_LOG,LOG_WARNING, "Config error, %s set to %d, not supported",CFG_N_light_programming_interface,_aqconfig_.light_programming_interface);
+ _aqconfig_.light_programming_interface = LIGHT_PROTOCOL_AQLD;
+ }
+ }
/*
PDA Mode
diff --git a/source/config.h b/source/config.h
index ac6c51b..cdec5ed 100644
--- a/source/config.h
+++ b/source/config.h
@@ -40,6 +40,22 @@
#define MAX_RSSD_LOG_FILTERS 4
+/*
+#define LIGHT_PROGRAM_INTERFACE_AQLD 0
+#define LIGHT_PROGRAM_INTERFACE_ALLB 1
+#define LIGHT_PROGRAM_INTERFACE_ONET 2
+#define LIGHT_PROGRAM_INTERFACE_AQLT 3
+#define LIGHT_PROGRAM_INTERFACE_IAQL 4
+*/
+// Going to explicitly set these numbers since they come from config file
+typedef enum {
+ LIGHT_PROTOCOL_AQLD = 0,
+ LIGHT_PROTOCOL_ALLB = 1,
+ LIGHT_PROTOCOL_ONET = 2,
+ LIGHT_PROTOCOL_AQLT = 3,
+ LIGHT_PROTOCOL_IAQL = 4
+} light_program_interface;
+
struct aqconfig
{
#if MG_TLS > 0
@@ -77,6 +93,7 @@ struct aqconfig
int light_programming_initial_on;
int light_programming_initial_off;
bool light_programming_advance_mode;
+ light_program_interface light_programming_interface; // 0=let AqualinkD decide, 1=allbutton, 2=onetouch(N/A), 3=AqualinkTouch, 4=iaqualink(N/A)
bool override_freeze_protect;
#ifdef AQ_PDA
bool pda_sleep_mode;
@@ -277,11 +294,12 @@ int _numCfgParams;
#define CFG_N_override_freeze_protect "override_freeze_protect"
#define CFG_N_pda_sleep_mode "pda_sleep_mode"
#define CFG_N_convert_mqtt_temp "mqtt_convert_temp_to_c"
+#define CFG_N_light_programming_interface "light_programming_interface"
#define CFG_N_report_zero_spa_temp "report_zero_spa_temp"
#define CFG_N_report_zero_pool_temp "report_zero_pool_temp"
#define CFG_N_read_RS485_devmask "read_RS485_devmask"
-#define CFG_N_use_panel_aux_labels "use_panel_aux_labels"
+//#define CFG_N_use_panel_aux_labels "use_panel_aux_labels"
#define CFG_N_force_swg "force_swg"
#define CFG_N_force_ps_setpoints "force_ps_setpoints"
#define CFG_N_force_frzprotect_setpoints "force_frzprotect_setpoints"
@@ -308,7 +326,7 @@ int _numCfgParams;
#define CFG_N_event_check_freezeprotectoff "event_freezeprotectoff_check_pump"
#define CFG_N_event_check_boostoff "event_boostoff_check_pump"
#define CFG_N_event_check_pumpon_hour "event_check_pumpon_hour"
-#define CFG_N_event_check_pumpoff_hour "event_check_pumpoff_hour"
+#define CFG_N_event_check_pumpoff_hour "event_check_pumpoff_hour"
#define CFG_N_event_check_usecron "event_check_use_scheduler_times"
#define CFG_N_event_check_booston_device "event_booston_check_device"
diff --git a/source/devices_jandy.c b/source/devices_jandy.c
index 535c249..00215b7 100644
--- a/source/devices_jandy.c
+++ b/source/devices_jandy.c
@@ -53,11 +53,19 @@ typedef enum heatpumpmsgfrom{
void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualinkdata *aqdata, heatpumpmsgfrom from);
+bool shouldPrintJAndyDebugPacket()
+{
+ if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
+ return true;
+ }
+ return false;
+}
void printJandyDebugPacket (const char *msg, const unsigned char *packet, int packet_length)
{
// Only log if we are jandy debug mode and not serial debug (otherwise it'll print twice)
- if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
+ //if (getLogLevel(DJAN_LOG) == LOG_DEBUG && getLogLevel(RSSD_LOG) < LOG_DEBUG ) {
+ if (shouldPrintJAndyDebugPacket()) {
char frame[1024];
//beautifyPacket(frame, 1024, packet, packet_length, true);
@@ -914,28 +922,40 @@ bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_len
bool processPacketToJandyChemFeeder(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
{
+ /*
char msg[1024];
int length = 0;
length += sprintf(msg+length, "Last panel info ");
-
length += sprintf(msg+length, ", pH=%f, ORP=%d",aqdata->ph, aqdata->orp);
-
LOG(DJAN_LOG, LOG_INFO, "%s\n", msg);
+*/
+ LOG(DJAN_LOG, LOG_INFO, "Last panel info : pH=%f, ORP=%d",aqdata->ph, aqdata->orp);
+ if (!shouldPrintJAndyDebugPacket()) {
+ // if we are not going to print the packet as debug, print it here
+ logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
+ }
+
return false;
}
bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to){
+/*
char msg[1024];
int length = 0;
length += sprintf(msg+length, "Last panel info ");
-
length += sprintf(msg+length, ", pH=%f, ORP=%d",aqdata->ph, aqdata->orp);
-
LOG(DJAN_LOG, LOG_INFO, "%s\n", msg);
-
+*/
+ LOG(DJAN_LOG, LOG_INFO, "Last panel info : pH=%f, ORP=%d",aqdata->ph, aqdata->orp);
+
+ if (!shouldPrintJAndyDebugPacket()) {
+ // if we are not going to print the packet as debug, print it here
+ logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
+ }
+
/*
I think the below may be accurate
ph_setpoint = float(raw_data[8]) / 10
@@ -1214,7 +1234,10 @@ bool processPacketToJandyLight(unsigned char *packet_buffer, int packet_length,
LOG(DJAN_LOG, LOG_INFO, "Request to set Jandy Light RGB to %d:%d:%d\n", packet_buffer[6],packet_buffer[7],packet_buffer[8]);
}
- logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
+ if (!shouldPrintJAndyDebugPacket()) {
+ // if we are not going to print the packet as debug, print it here
+ logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
+ }
return true;
}
@@ -1226,7 +1249,10 @@ bool processPacketFromJandyLight(unsigned char *packet_buffer, int packet_length
LOG(DJAN_LOG, LOG_INFO, "Light brightness=%d\n", packet_buffer[38]);
}
- logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
+ if (!shouldPrintJAndyDebugPacket()) {
+ // if we are not going to print the packet as debug, print it here
+ logPacket(DJAN_LOG, LOG_INFO, packet_buffer, packet_length, true);
+ }
return true;
}
diff --git a/source/iaqtouch.c b/source/iaqtouch.c
index 503a765..c7e8ad0 100644
--- a/source/iaqtouch.c
+++ b/source/iaqtouch.c
@@ -356,6 +356,8 @@ void updateAQButtonFromPageButton(struct aqualinkdata *aqdata, struct iaqt_page_
break;
case 0x01:
SET_IF_CHANGED(aqdata->aqbuttons[i].led->state, ON, aqdata->is_dirty);
+ //NSF might want to check virtual light here, if so remove the color mode name, since
+ // we didnt turn the light on, we cant state the color mode
break;
case 0x02:
SET_IF_CHANGED(aqdata->aqbuttons[i].led->state, FLASH, aqdata->is_dirty);
@@ -976,7 +978,7 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
// Set disply message if PDA panel
memset(_popupMsg, 0, AQ_MSGLONGLEN + 1);
rsm_strncpy(_popupMsg, packet + 6, AQ_MSGLONGLEN, length-9);
- LOG(IAQT_LOG,LOG_NOTICE, "Popup message '%s'\n",_popupMsg);
+ LOG(IAQT_LOG,LOG_INFO, "Popup message '%s'\n",_popupMsg);
// Change this message, since you can't press OK. 'Light will turn off in 5 seconds. To change colors press Ok now.'
if ((sp = rsm_strncasestr(_popupMsg, "To change colors press Ok now", strlen(_popupMsg))) != NULL)
diff --git a/source/iaqtouch_aq_programmer.c b/source/iaqtouch_aq_programmer.c
index 07741ae..34f6ca4 100644
--- a/source/iaqtouch_aq_programmer.c
+++ b/source/iaqtouch_aq_programmer.c
@@ -771,7 +771,7 @@ void *set_aqualink_iaqtouch_light_colormode( void *ptr )
// See if it's on the current page
pButton = iaqtFindButtonByLabel(key->label);
-PRINTF("First button find = %s\n",pButton==NULL?"null":pButton->name);
+//DPRINTF("First button find = %s\n",pButton==NULL?"null":pButton->name);
if (pButton == NULL) {
// No luck, go to the device page
@@ -780,22 +780,24 @@ PRINTF("First button find = %s\n",pButton==NULL?"null":pButton->name);
pButton = iaqtFindButtonByLabel(key->label);
-PRINTF("Second button find = %s\n",pButton==NULL?"null":pButton->name);
+//DPRINTF("Second button find = %s\n",pButton==NULL?"null":pButton->name);
// If not found see if page has next
if (pButton == NULL && iaqtFindButtonByIndex(16)->type == 0x03 ) {
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
waitfor_iaqt_nextPage(aqdata);
// This will fail, since not looking at device page 2 buttons
pButton = iaqtFindButtonByLabel(key->label);
-PRINTF("Third button find = %s\n",pButton==NULL?"null":pButton->name);
+//DPRINTF("Third button find = %s\n",pButton==NULL?"null":pButton->name);
}
}
if (pButton == NULL) {
- LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on device list\n", key->label);
+ LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on device list, please check your config line '%s'\n",
+ key->label,
+ isMASK_SET(key->special_mask, VIRTUAL_BUTTON)?"virtual_button_??_label":"button_??_label" );
goto f_end;
}
-PRINTF("FOUND button = %s\n",pButton==NULL?"null":pButton->name);
+//DPRINTF("FOUND button = %s\n",pButton==NULL?"null":pButton->name);
// WE have a iaqualink button, press it.
LOG(IAQT_LOG, LOG_DEBUG, "IAQ Touch found '%s' sending keycode '0x%02hhx'\n", key->label, pButton->keycode);
send_aqt_cmd(pButton->keycode);
@@ -805,18 +807,23 @@ PRINTF("FOUND button = %s\n",pButton==NULL?"null":pButton->name);
// After pressing the button, Just need to wait for 5 seconds and it will :-
// a) if off turn on and default to last color.
// b) if on, turn off. (pain that we need to wait 5 seconds.)
-PRINTF("******** WAIT for next page\n");
+//DPRINTF("******** WAIT for next page\n");
waitfor_iaqt_queue2empty();
waitfor_iaqt_nextPage(aqdata);
if (use_current_mode) {
// Their is no message for this, so give one.
- sprintf(aqdata->last_display_message, "Light will turn on in 5 seconds");
+ sprintf(aqdata->last_display_message, "Light will turn %s in 5 seconds", turn_off?"off":"on");
aqdata->is_display_message_programming = true;
SET_DIRTY(aqdata->is_dirty);
}
// Wait for next page maybe?
// Below needs a timeout.
while (waitfor_iaqt_nextPage(aqdata) == IAQ_PAGE_COLOR_LIGHT);
+
+ // Pre set key to off since it'll take ages
+ if (turn_off)
+ key->led->state = OFF;
+
goto f_end;
}
@@ -841,22 +848,26 @@ PRINTF("******** WAIT for next page\n");
}
LOG(IAQT_LOG, LOG_DEBUG, "IAQ Touch found '%s' sending keycode '0x%02hhx' = '0x%02hhx' for light selection\n", mode_name, pButton->keycode, pButton->keycode+16);
- PRINTF("******** current page is '0x%02hhx'\n",iaqtCurrentPage());
+ //DPRINTF("******** current page is '0x%02hhx'\n",iaqtCurrentPage());
// NSF Key code is +16 for some reason. ie key 0x07=(send 0x17). 0x0a=(send 0x1a)
- send_aqt_cmd(pButton->keycode + 16);
+ send_aqt_cmd(pButton->keycode + IAQ_COLOR_LIGHT_OFFSET);
waitfor_iaqt_queue2empty();
// Wait for popup message to disapera
// This is iAq Popup messag | HEX: 0x10|0x02|0x33|0x2c|0x00|0x01|0x50|0x6c|0x65|0x61|0x73|0x65|0x20|0x77|0x61|0x69|0x74|0x2e|0x2e|0x2e|0x0a|0x20|0x43|0x79|0x63|0x6c|0x69|0x6e|0x67|0x20|0x74|0x6f|0x20|0x63|0x68|0x6f|0x73|0x65|0x6e|0x20|0x63|0x6f|0x6c|0x6f|0x72|0x2e|0x00|0x00|0x00|0x00|0x2e|0x10|0x03|
// This is popup message clear | HEX: 0x10|0x02|0x33|0x2c|0x00|0x00|0x20|0x00|0x00|0x00|0x00|0x91|0x10|0x03|
// 5th bit 0x00 = clear. (anything else message)
+ // Pre set light to on, since it'll take ages after this finished.
+ if (!turn_off)
+ key->led->state = ON;
+
unsigned char msg;
int i=0;
while ( (msg = waitfor_iaqt_nextMessage(aqdata, CMD_IAQ_MSG_LONG)) != NUL) {
const char *pmsg = iaqtPopupMsg();
- PRINTF("******** popupMsg = %s ********\n",pmsg);
+ //DPRINTF("******** popupMsg = %s ********\n",pmsg);
if (pmsg[0] == ' ') {
- PRINTF("******** popupMsg clear ********\n");
+ //DPRINTF("******** popupMsg clear ********\n");
break;
}
if (++i > 5) {
@@ -866,9 +877,9 @@ PRINTF("******** WAIT for next page\n");
}
/*
unsigned char page;
- PRINTF("******** current page is '0x%02hhx'\n",iaqtCurrentPage());
+ DPRINTF("******** current page is '0x%02hhx'\n",iaqtCurrentPage());
while ( (page = waitfor_iaqt_nextPage(aqdata)) != NUL) {
- PRINTF("******** next page is '0x%02hhx'\n",page); // page = 0x48 IAQ_PAGE_COLOR_LIGHT
+ DPRINTF("******** next page is '0x%02hhx'\n",page); // page = 0x48 IAQ_PAGE_COLOR_LIGHT
}
*/
//LOG(IAQT_LOG, LOG_ERR, "IAQ Touch WAIYING FOR 1 MESSAGES\n");
diff --git a/source/iaqtouch_aq_programmer.h b/source/iaqtouch_aq_programmer.h
index 0a2b4df..50f428b 100644
--- a/source/iaqtouch_aq_programmer.h
+++ b/source/iaqtouch_aq_programmer.h
@@ -4,7 +4,6 @@
#define IAQ_TOUCH_PROGRAMMER_H_
-
unsigned char pop_iaqt_cmd(unsigned char receive_type);
void set_iaq_cansend(bool cansend);
diff --git a/source/json_messages.c b/source/json_messages.c
index 9b23147..fd3953d 100644
--- a/source/json_messages.c
+++ b/source/json_messages.c
@@ -1077,6 +1077,7 @@ bool parseJSONrequest(char *buffer, struct JSONkvptr *request)
return true;
}
+/*
bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request)
{
int i=0;
@@ -1148,7 +1149,7 @@ bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request)
return true;
}
-
+*/
/*
int json_cfg_element_OLD(char* buffer, int size, const char *name, const void *value, cfg_value_type type, char *valid_val) {
int result = 0;
diff --git a/source/json_messages.h b/source/json_messages.h
index 0f82596..0b69c02 100644
--- a/source/json_messages.h
+++ b/source/json_messages.h
@@ -49,7 +49,7 @@ const char* getAqualinkDStatusMessage(struct aqualinkdata *aqdata);
int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int size);
int build_aux_labels_JSON(struct aqualinkdata *aqdata, char* buffer, int size);
-bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request);
+//bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request);
bool parseJSONrequest(char *buffer, struct JSONkvptr *request);
int build_logmsg_JSON(char *dest, int loglevel, const char *src, int dest_len, int src_len);
int build_mqtt_status_JSON(char* buffer, int size, int idx, int nvalue, float setpoint/*char *svalue*/);
diff --git a/source/net_services.c b/source/net_services.c
index 01e42eb..8eadca4 100644
--- a/source/net_services.c
+++ b/source/net_services.c
@@ -65,6 +65,14 @@ struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
tolower((unsigned char)(str)[(len)-1]) == tolower((unsigned char)(SUFFIX)[2]) \
)
+#define FAST_SUFFIX_4_CI(str, len, SUFFIX) ( \
+ (len) >= 4 && \
+ tolower((unsigned char)(str)[(len)-4]) == tolower((unsigned char)(SUFFIX)[0]) && \
+ tolower((unsigned char)(str)[(len)-3]) == tolower((unsigned char)(SUFFIX)[1]) && \
+ tolower((unsigned char)(str)[(len)-2]) == tolower((unsigned char)(SUFFIX)[2]) && \
+ tolower((unsigned char)(str)[(len)-1]) == tolower((unsigned char)(SUFFIX)[3]) \
+)
+
/*
#if defined AQ_DEBUG || defined AQ_TM_DEBUG
@@ -1611,7 +1619,8 @@ void action_web_request(struct mg_connection *nc, struct mg_http_message *http_m
// If we have a get request, pass it
if (strncmp(http_msg->uri.buf, "/api", 4 ) != 0) {
DEBUG_TIMER_START(&tid);
- if ( FAST_SUFFIX_3_CI(http_msg->uri.buf, http_msg->uri.len, ".js") ) {
+ //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);
@@ -1754,6 +1763,8 @@ void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm
int i;
char *uri = NULL;
char *value = NULL;
+ //char *id = NULL;
+ //char *text_value = NULL;
char *msg = NULL;
#ifdef AQ_TM_DEBUG
int tid;
@@ -1775,8 +1786,12 @@ void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm
if (jsonkv.kv[i].key != NULL && strncmp(jsonkv.kv[i].key, "uri", 3) == 0)
uri = jsonkv.kv[i].value;
- else if (jsonkv.kv[i].key != NULL && strncmp(jsonkv.kv[i].key, "value", 4) == 0)
+ else if (jsonkv.kv[i].key != NULL && strncmp(jsonkv.kv[i].key, "value", 5) == 0)
value = jsonkv.kv[i].value;
+ //else if (jsonkv.kv[i].key != NULL && strncmp(jsonkv.kv[i].key, "button", 6) == 0)
+ // id = jsonkv.kv[i].value;
+ //else if (jsonkv.kv[i].key != NULL && strncmp(jsonkv.kv[i].key, "text_value", 10) == 0)
+ // text_value = jsonkv.kv[i].value;
}
if (uri == NULL) {
@@ -1784,6 +1799,7 @@ void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm
return;
}
+ // NSF in future change action_URI to accept button and text_value
switch ( action_URI(NET_WS, uri, strlen(uri), (value!=NULL?atof(value):TEMP_UNKNOWN), false, &msg)) {
case uActioned:
sprintf(buffer, "{\"message\":\"ok\"}");
diff --git a/source/serialadapter.c b/source/serialadapter.c
index 821cdaf..c54cd84 100644
--- a/source/serialadapter.c
+++ b/source/serialadapter.c
@@ -372,7 +372,7 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
aqdata->lights[i].button->label,
packet[6]==0x00?"OFF":"ON",
packet[6],
- packet[6]==0x00?"--":light_mode_name( aqdata->lights[i].lightType,(packet[6] - RSSD_COLOR_LIGHT_OFFSET), RSSADAPTER) );
+ packet[6]==0x00?"--":light_mode_name( aqdata->lights[i].lightType,(packet[6] - RSSD_COLOR_LIGHT_OFFSET_READ), RSSADAPTER) );
}
SET_IF_CHANGED(aqdata->lights[i].RSSDstate, (packet[6]==0x00?OFF:ON), aqdata->is_dirty);
@@ -395,7 +395,7 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
rtn |= set_currentlight_value(&aqdata->lights[i], (packet[6] - RSSD_DIMMER_LIGHT_OFFSET));
break;
default:
- rtn |= set_currentlight_value(&aqdata->lights[i], (packet[6] - RSSD_COLOR_LIGHT_OFFSET));
+ rtn |= set_currentlight_value(&aqdata->lights[i], (packet[6] - RSSD_COLOR_LIGHT_OFFSET_READ));
break;
}
/*
diff --git a/source/utils.h b/source/utils.h
index b048c7e..b940e85 100644
--- a/source/utils.h
+++ b/source/utils.h
@@ -73,6 +73,7 @@ typedef int32_t logmask_t;
#define AQ_MAX(x, y) (((x) > (y)) ? (x) : (y))
#define AQ_MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define AQ_CLAMP(value, min_val, max_val) ((value) > (max_val) ? (max_val) : ((value) < (min_val) ? (min_val) : (value)))
/*
diff --git a/source/version.h b/source/version.h
index c1b47a4..e1562a2 100644
--- a/source/version.h
+++ b/source/version.h
@@ -4,5 +4,5 @@
#define AQUALINKD_SHORT_NAME "AqualinkD"
// Use Magor . Minor . Patch
-#define AQUALINKD_VERSION "3.0.0 (beta 2)"
+#define AQUALINKD_VERSION "3.0.0 (beta 3)"
\ No newline at end of file
diff --git a/web/aqmanager.html b/web/aqmanager.html
index c99bcd6..65ae90e 100644
--- a/web/aqmanager.html
+++ b/web/aqmanager.html
@@ -518,24 +518,27 @@