Version 2.2.0

pull/116/head
sfeakes 2020-07-18 11:37:19 -05:00
parent 2ddcfa7f8a
commit 36435205b2
48 changed files with 8054 additions and 1500 deletions

View File

@ -2,9 +2,12 @@
# Options
# Valid flags for AQ_FLAGS
# AQ_DEBUG = true
#AQ_DEBUG = true
AQ_RS16 = true
AQ_PDA = true
AQ_ONETOUCH = true
AQ_IAQTOUCH = true
#AQ_MEMCMP = true // Not implimented correctly yet.
# make EXFLAGS="-D BETA_PDA_AUTOLABEL" // Add compile flags
@ -19,7 +22,7 @@ LIBS := -l pthread -l m
# debug of not
#DBG = -g -O0 -fsanitize=address
#GCCFLAGS = -Wall -O3
# USe below to remove unused functions and global variables.
#LFLAGS = -Wl,--gc-sections,--print-gc-sections
@ -27,7 +30,7 @@ LIBS := -l pthread -l m
# define any compile-time flags
#GCCFLAGS = -Wall -O3 -Wextra
GCCFLAGS = -Wall -O3 $(EXFLAGS)
#GCCFLAGS = -Wall -O3
#GCCFLAGS = -Wall
#CFLAGS = -Wall -g $(LIBS)
@ -42,8 +45,8 @@ CFLAGS = $(GCCFLAGS) $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_
#SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c pda.c pda_menu.c \
# pda_aq_programmer.c devices_jandy.c onetouch.c onetouch_aq_programmer.c packetLogger.c devices_pentair.c color_lights.c mongoose.c
SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c \
devices_jandy.c onetouch.c onetouch_aq_programmer.c packetLogger.c devices_pentair.c color_lights.c mongoose.c
SRCS = aqualinkd.c utils.c config.c aq_serial.c aq_panel.c aq_programmer.c net_services.c json_messages.c rs_msg_utils.c\
devices_jandy.c packetLogger.c devices_pentair.c color_lights.c mongoose.c
DBG_SRC = timespec_subtract.c
ifeq ($(AQ_PDA), true)
@ -51,10 +54,24 @@ ifeq ($(AQ_PDA), true)
CFLAGS := $(CFLAGS) -D AQ_PDA
endif
ifeq ($(AQ_ONETOUCH), true)
SRCS := $(SRCS) onetouch.c onetouch_aq_programmer.c
CFLAGS := $(CFLAGS) -D AQ_ONETOUCH
endif
ifeq ($(AQ_IAQTOUCH), true)
SRCS := $(SRCS) iaqtouch.c iaqtouch_aq_programmer.c
CFLAGS := $(CFLAGS) -D AQ_IAQTOUCH
endif
ifeq ($(AQ_RS16), true)
CFLAGS := $(CFLAGS) -D AQ_RS16
endif
ifeq ($(AQ_MEMCMP), true)
CFLAGS := $(CFLAGS) -D AQ_MEMCMP
endif
ifeq ($(AQ_DEBUG), true)
DEBUG=true
endif
@ -65,7 +82,7 @@ ifeq ($(DEBUG), true)
CFLAGS := -g -O0 $(CFLAGS) -D AQ_DEBUG
endif
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c rs_msg_utils.c
LR_SRC = log_reader.c aq_serial.c utils.c packetLogger.c
PL_EXSRC = aq_serial.c
PL_EXOBJ = aq_serial_player.o
@ -93,7 +110,7 @@ slog: $(SLOG)
@echo: $(SLOG) have been compiled
$(SLOG): $(SL_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(SLOG) $(SL_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(SLOG) $(SL_OBJS) -D SERIAL_LOGGER
logr: $(LOGR)
@echo: $(LOGR) have been compiled

View File

@ -72,6 +72,30 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
* http://aqualink.ip/simulator.html <- (RS8 All Button Control Panel simulator)
* http://aqualink.ip/debug.html <- (Turn on/off debug/serial debug & download logs)
#<a name="release"></a>
# ToDo (future release)
* Allow selecting of pre-defined VSP programs
* Timed based actions (undecided on cron & AqualinkD or use Jandy programs )
* Put back some form of Jandy panel simulator. (existing was removed in V2.2.0)
* RS Serial protocol. AqualinkD has all Jandy control protocols except RS Serial.
* Update homekit-aqualinkd to use new API & features.
# Update in (Pre) Release 2.2.0
* This release WILL require you to make aqualinkd.conf changes. <b>Make sure to read wiki section https://github.com/sfeakes/AqualinkD/wiki#Version_2</b>
* Extensive work to reduce CPU cycles and unnesessary logic.
* iAqualink Touch protocol supported for VSP & extended programming.
* This protocol is a lot faster for programming, ID's are between 0x38 & 0x3B `extended_device_id`, use Serial_logger to find valid ID.
* If your panel supports this it's strongly recomended to use it and also set `extended_device_id_programming=yes`
* New panel config procedure VERY dependant on panel type, you must change config, must set `panel_type` in config.
* Buttons (specifically) heaters will be different from previous versions. (all info in wiki link above)
* Simulator support removed for the moment.
* Few changes in RS protocol and timings.
* Fixed bug with Watts display for VSP.
* Fixed bug with colored lights.
* RS16 panels no longer require `extended_device_id` to be set
* More compile flags. See notes in wiki on compiling.
* Extensive SWG logic changes.
* AqualinkD startup changed to fix some 'systemctl restart' issues.
* More detailed API replys.
# Update in Release 2.1.0
* Big update, lots of core changes, <b>please read wiki section https://github.com/sfeakes/AqualinkD/wiki#Version_2</b>
* Full Variable Speed Pump support. (Can read,set & change RPM,GPM)

BIN
a.out

Binary file not shown.

View File

@ -18,10 +18,9 @@
#include <string.h>
#include "config.h"
#include "domoticz.h"
#include "aq_panel.h"
#ifdef AQ_RS16
void initButtons_RS16(struct aqualinkdata *aqdata);
#endif
void initPanelButtons(struct aqualinkdata *aqdata, bool rspda, int size, bool combo, bool dual);
char *name2label(char *str)
{
@ -40,6 +39,421 @@ char *name2label(char *str)
return newst;
}
void changePanelToMode_Only() {
_aqconfig_.paneltype_mask |= RSP_SINGLE;
_aqconfig_.paneltype_mask &= ~RSP_COMBO;
}
void changePanelToExtendedIDProgramming() {
_aqconfig_.paneltype_mask |= RSP_EXT_PROG;
LOG(AQUA_LOG,LOG_NOTICE, "AqualinkD is using use %s mode for programming (where supported)\n",isONET_ENABLED?"ONETOUCH":"IAQ TOUCH");
}
void addPanelOneTouchInterface() {
_aqconfig_.paneltype_mask |= RSP_ONET;
_aqconfig_.paneltype_mask &= ~RSP_IAQT;
}
void addPanelIAQTouchInterface() {
_aqconfig_.paneltype_mask |= RSP_IAQT;
_aqconfig_.paneltype_mask &= ~RSP_ONET;
}
//bool setPanel(const char *str);
/*
void panneltest() {
setPanel("RS-16 Combo");
setPanel("PD-8 Only");
setPanel("PD-8 Combo");
setPanel("RS-2/14 Dual");
setPanel("RS-2/10 Dual");
setPanel("RS-16 Only");
setPanel("RS-12 Only");
setPanel("RS-16 Combo");
setPanel("RS-12 Combo");
setPanel("RS-2/6 Dual");
setPanel("RS-4 Only");
setPanel("RS-6 Only");
setPanel("RS-8 Only");
setPanel("RS-4 Combo");
setPanel("RS-6 Combo");
setPanel("RS-8 Combo");
}
*/
//bool setPanelByName(const char *str) {
int setSizeMask(int size)
{
int rtn_size = 0;
if ( size > TOTAL_BUTTONS) {
LOG(AQUA_LOG,LOG_ERR, "Panel size is either invalid or too large for compiled parameters, ignoring %d using %d\n",size, TOTAL_BUTTONS);
rtn_size = TOTAL_BUTTONS;
}
switch (size) {
case 4:
_aqconfig_.paneltype_mask |= RSP_4;
break;
case 6:
_aqconfig_.paneltype_mask |= RSP_6;
break;
case 8:
_aqconfig_.paneltype_mask |= RSP_8;
break;
case 10:
_aqconfig_.paneltype_mask |= RSP_10;
break;
case 12:
_aqconfig_.paneltype_mask |= RSP_12;
break;
case 14:
_aqconfig_.paneltype_mask |= RSP_14;
break;
case 16:
_aqconfig_.paneltype_mask |= RSP_16;
break;
default:
LOG(AQUA_LOG,LOG_ERR, "Didn't understand panel size, '%d' setting to size to 8\n",size);
_aqconfig_.paneltype_mask |= RSP_8;
rtn_size = 8;
break;
}
if (rtn_size > 0)
return rtn_size;
return size;
}
void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual)
{
#ifndef AQ_PDA
if (!rs) {
LOG(AQUA_LOG,LOG_ERR, "Can't use PDA mode, AqualinkD has not been compiled with PDA Enabled\n");
rs = true;
}
#endif
_aqconfig_.paneltype_mask = 0;
int nsize = setSizeMask(size);
if (rs)
_aqconfig_.paneltype_mask |= RSP_RS;
else
_aqconfig_.paneltype_mask |= RSP_PDA;
if (combo)
_aqconfig_.paneltype_mask |= RSP_COMBO;
else
_aqconfig_.paneltype_mask |= RSP_SINGLE;
if (dual) { // Dual are combo
_aqconfig_.paneltype_mask |= RSP_DUAL_EQPT;
_aqconfig_.paneltype_mask |= RSP_COMBO;
_aqconfig_.paneltype_mask &= ~RSP_SINGLE;
}
/*
LOG(AQUA_LOG,LOG_ERR, "Panel set to %s%s size=%d type=%s%s %s\n",
(_aqconfig_.paneltype_mask & RSP_RS) == RSP_RS?"RS":"",
(_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA?"PDA":"",
nsize,
(_aqconfig_.paneltype_mask & RSP_COMBO) == RSP_COMBO?"Combo Pool/Spa":"",
(_aqconfig_.paneltype_mask & RSP_SINGLE) == RSP_SINGLE?"Pool/Spa Only":"",
(_aqconfig_.paneltype_mask & RSP_DUAL_EQPT) == RSP_DUAL_EQPT?"Dual Equiptment":"");
*/
initPanelButtons(aqdata, rs, nsize, combo, dual);
}
void setPanelByName(struct aqualinkdata *aqdata, const char *str)
{
int i;
int size = 0;
bool rs = true;
bool combo = true;
bool dual = false;
//int16_t panelbits = 0;
if (str[0] == 'R' && str[1] == 'S') { // RS Panel
rs = true;
if (str[4] == '/')
size = atoi(&str[5]);
else
size = atoi(&str[3]);
} else if (str[0] == 'P' && str[1] == 'D') { // PDA Panel
rs = false;
if (str[2] == '-' || str[2] == ' ') // Account for PD-8
size = atoi(&str[3]);
else // Account for PDA-8
size = atoi(&str[4]);
} else {
LOG(AQUA_LOG,LOG_ERR, "Didn't understand panel type, '%.2s' from '%s' setting to size to RS-8\n",str,str);
rs = true;
size = 8;
}
size = setSizeMask(size);
i=3;
while(str[i] != ' ' && i < strlen(str)) {i++;}
if (str[i+1] == 'O' || str[i+1] == 'o') {
combo = false;
} else if (str[i+1] == 'C' || str[i+1] == 'c') {
combo = true;
} else if (str[i+1] == 'D' || str[i+1] == 'd') {
dual = true;
} else {
LOG(AQUA_LOG,LOG_ERR, "Didn't understand panel type, '%s' from '%s' setting to Combo\n",&str[i+1],str);
combo = true;
}
//setPanelSize(size, combo, dual, pda)
setPanel(aqdata, rs, size, combo, dual);
}
// 4,6,8,10,12,14
void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual) {
int index = 0;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[7-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_PUMP):BTN_PDA_PUMP;
aqdata->aqbuttons[index].name = BTN_PUMP;
aqdata->aqbuttons[index].code = KEY_PUMP;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
if (combo) {
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[6-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_SPA):BTN_PDA_SPA;
aqdata->aqbuttons[index].name = BTN_SPA;
aqdata->aqbuttons[index].code = KEY_SPA;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
}
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[5-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX1):BTN_PDA_AUX1;
aqdata->aqbuttons[index].name = BTN_AUX1;
aqdata->aqbuttons[index].code = KEY_AUX1;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[4-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX2):BTN_PDA_AUX2;
aqdata->aqbuttons[index].name = BTN_AUX2;
aqdata->aqbuttons[index].code = KEY_AUX2;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[3-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX3):BTN_PDA_AUX3;
aqdata->aqbuttons[index].name = BTN_AUX3;
aqdata->aqbuttons[index].code = KEY_AUX3;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
if (size >= 6) {
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[9-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX4):BTN_PDA_AUX4;
aqdata->aqbuttons[index].name = BTN_AUX4;
aqdata->aqbuttons[index].code = KEY_AUX4;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[8-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX5):BTN_PDA_AUX5;
aqdata->aqbuttons[index].name = BTN_AUX5;
aqdata->aqbuttons[index].code = KEY_AUX5;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
}
if (size >= 8) {
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX6):BTN_PDA_AUX6;
aqdata->aqbuttons[index].name = BTN_AUX6;
aqdata->aqbuttons[index].code = KEY_AUX6;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX7):BTN_PDA_AUX7;
aqdata->aqbuttons[index].name = BTN_AUX7;
aqdata->aqbuttons[index].code = KEY_AUX7;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
}
#ifdef AQ_RS16
if (size >= 12) {// NSF This could be 10
// AUX4 to AUX7 use different LED index & button key codes on RS12 & 16, so reset them
aqdata->aqbuttons[index-4].led = &aqdata->aqualinkleds[2-1]; // Change
aqdata->aqbuttons[index-4].code = KEY_RS16_AUX4;
aqdata->aqbuttons[index-3].led = &aqdata->aqualinkleds[11-1]; // Change
aqdata->aqbuttons[index-3].code = KEY_RS16_AUX5;
aqdata->aqbuttons[index-2].led = &aqdata->aqualinkleds[10-1]; // Change
aqdata->aqbuttons[index-2].code = KEY_RS16_AUX6;
aqdata->aqbuttons[index-1].led = &aqdata->aqualinkleds[9-1]; // change
aqdata->aqbuttons[index-1].code = KEY_RS16_AUX7;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[8-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = name2label(BTN_AUXB1); // AUX8
aqdata->aqbuttons[index].name = BTN_AUXB1;
aqdata->aqbuttons[index].code = KEY_AUXB1;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = name2label(BTN_AUXB2); // AUX9
aqdata->aqbuttons[index].name = BTN_AUXB2;
aqdata->aqbuttons[index].code = KEY_AUXB2;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = name2label(BTN_AUXB3); // AUX10
aqdata->aqbuttons[index].name = BTN_AUXB3;
aqdata->aqbuttons[index].code = KEY_AUXB3;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[13-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = name2label(BTN_AUXB4); // AUX11
aqdata->aqbuttons[index].name = BTN_AUXB4;
aqdata->aqbuttons[index].code = KEY_AUXB4;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
}
if (size >= 14) { // Actually RS 16 panel, but also 2/14 dual panel.
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[21-1]; // doesn't actually exist
aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aqdata->aqbuttons[index].label = name2label(BTN_AUXB5);
aqdata->aqbuttons[index].name = BTN_AUXB5;
aqdata->aqbuttons[index].code = KEY_AUXB5;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[22-1]; // doesn't actually exist
aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aqdata->aqbuttons[index].label = name2label(BTN_AUXB6);
aqdata->aqbuttons[index].name = BTN_AUXB6;
aqdata->aqbuttons[index].code = KEY_AUXB6;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[23-1]; // doesn't actually exist
aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aqdata->aqbuttons[index].label = name2label(BTN_AUXB7);
aqdata->aqbuttons[index].name = BTN_AUXB7;
aqdata->aqbuttons[index].code = KEY_AUXB7;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[24-1]; // doesn't actually exist
aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aqdata->aqbuttons[index].label = name2label(BTN_AUXB8);
aqdata->aqbuttons[index].name = BTN_AUXB8;
aqdata->aqbuttons[index].code = KEY_AUXB8;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
}
#endif // AQ_RS16
if (dual) {
//Dual panel 2/6 has Aux6 so add that
if (size == 6) {
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = name2label(BTN_AUX6);
aqdata->aqbuttons[index].name = BTN_AUX6;
aqdata->aqbuttons[index].code = KEY_AUX6;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
}
//Dual panels (2/10 & 2/14) have no AUX7, they go from AUX6 to AUXB1, but the keycodes are the same as other panels
//i.e Button AUX7 on normal panel is identical to AUX_B1 on Dual panel has same Keycode & LED bit but only the label is different.
if (size > 6) {
int i; // Dual panels are combo panels so we can start at index 8
for(i=8; i < index; i++) {
aqdata->aqbuttons[i].name = aqdata->aqbuttons[i+1].name;
aqdata->aqbuttons[i].label = aqdata->aqbuttons[i+1].label;
}
index--;
}
}
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[15-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_POOL_HTR):BTN_PDA_POOL_HTR;
aqdata->aqbuttons[index].name = BTN_POOL_HTR;
aqdata->aqbuttons[index].code = KEY_POOL_HTR;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[17-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_SPA_HTR):BTN_PDA_SPA_HTR;
aqdata->aqbuttons[index].name = BTN_SPA_HTR;
aqdata->aqbuttons[index].code = KEY_SPA_HTR;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[19-1];
aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aqdata->aqbuttons[index].label = rs?name2label(BTN_SOLAR_HTR):BTN_PDA_SOLAR_HTR;
aqdata->aqbuttons[index].name = BTN_SOLAR_HTR;
aqdata->aqbuttons[index].code = KEY_SOLAR_HTR;
aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
index++;
aqdata->total_buttons = index;
//aqdata->single_device = !combo;
#ifdef AQ_RS16
aqdata->rs16_vbutton_start = 13 - (combo?0:1);
aqdata->rs16_vbutton_end = 16 - (combo?0:1);
#endif
#ifdef AQ_PDA
aqdata->pool_heater_index = index-3;
aqdata->spa_heater_index = index-2;
aqdata->solar_heater_index = index-1;
#endif
}
#ifdef DO_NOT_COMPILE
#ifdef AQ_RS16
void initButtons_RS16(struct aqualinkdata *aqdata);
#endif
/*
* Link LED numbers to buttons, this is valid for RS8 and below, RS10 and above are different
* need to update this code in future.
@ -285,7 +699,17 @@ void initButtons_RS16(struct aqualinkdata *aqdata)
#endif
#ifdef DO_NOT_COMPILE
void initButtons_OLD_RS16(struct aqualinkdata *aqdata)
{

69
aq_panel.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef INIT_BUTTONS_H_
#define INIT_BUTTONS_H_
#include "config.h"
#define PUMP_INDEX 0
#define SPA_INDEX 1
/*
#define POOL_HEAT_INDEX 9
#define SPA_HEAT_INDEX 10
*/
// Defined as int16_t so 16 bits to mask
#define RSP_4 (1 << 0) // 1
#define RSP_6 (1 << 1) // 16
#define RSP_8 (1 << 2) // 4
#define RSP_10 (1 << 3) // 2
#define RSP_12 (1 << 4) // 32
#define RSP_14 (1 << 5) // 8
#define RSP_16 (1 << 6) // 64
#define RSP_COMBO (1 << 7) // 128
#define RSP_SINGLE (1 << 8) // 128
#define RSP_DUAL_EQPT (1 << 9) // 128
#define RSP_RS (1 << 10) // 128
#define RSP_PDA (1 << 11) // 128
#define RSP_ONET (1 << 12) // 128
#define RSP_IAQT (1 << 13) // 128
#define RSP_EXT_PROG (1 << 14) // 128
//void initButtons(struct aqualinkdata *aqdata);
void setPanelByName(struct aqualinkdata *aqdata, const char *str);
void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual);
void changePanelToMode_Only();
void addPanelOneTouchInterface();
void addPanelIAQTouchInterface();
void changePanelToExtendedIDProgramming();
//void panneltest();
#define isPDA_PANEL ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
#define isRS_PANEL ((_aqconfig_.paneltype_mask & RSP_RS) == RSP_RS)
#define isCOMBO_PANEL ((_aqconfig_.paneltype_mask & RSP_COMBO) == RSP_COMBO)
#define isSINGLE_DEV_PANEL ((_aqconfig_.paneltype_mask & RSP_SINGLE) == RSP_SINGLE)
#define isDUAL_EQPT_PANEL ((_aqconfig_.paneltype_mask & RSP_DUAL_EQPT) == RSP_DUAL_EQPT)
#define isONET_ENABLED ((_aqconfig_.paneltype_mask & RSP_ONET) == RSP_ONET)
#define isIAQT_ENABLED ((_aqconfig_.paneltype_mask & RSP_IAQT) == RSP_IAQT)
#define isEXTP_ENABLED ((_aqconfig_.paneltype_mask & RSP_EXT_PROG) == RSP_EXT_PROG)
//int PANEL_SIZE();
//
#define PANEL_SIZE ((_aqconfig_.paneltype_mask & RSP_4) == RSP_4)?4:(\
((_aqconfig_.paneltype_mask & RSP_6) == RSP_6)?6:(\
((_aqconfig_.paneltype_mask & RSP_8) == RSP_8)?8:(\
((_aqconfig_.paneltype_mask & RSP_10) == RSP_10)?10:(\
((_aqconfig_.paneltype_mask & RSP_12) == RSP_12)?12:(\
((_aqconfig_.paneltype_mask & RSP_14) == RSP_14)?14:(\
((_aqconfig_.paneltype_mask & RSP_16) == RSP_16)?16:0))))))
#ifndef AQ_RS16
#define TOTAL_BUTTONS 12
#else
#define TOTAL_BUTTONS 20
// This needs to be called AFTER and as well as initButtons
void initButtons_RS16(struct aqualinkdata *aqdata);
#endif
#endif

View File

@ -33,10 +33,12 @@
#include "pda_aq_programmer.h"
#endif
#include "init_buttons.h"
#include "aq_panel.h"
#include "onetouch_aq_programmer.h"
#include "iaqtouch_aq_programmer.h"
#include "color_lights.h"
#include "config.h"
#include "devices_jandy.h"
#ifdef AQ_DEBUG
#include <time.h>
@ -66,9 +68,11 @@ void *set_aqualink_PDA_init( void *ptr );
#endif
void *set_aqualink_SWG( void *ptr );
void *set_aqualink_boost( void *ptr );
void *set_aqualink_pump_rpm( void *ptr );
/*
void *set_aqualink_onetouch_pump_rpm( void *ptr );
void *set_aqualink_onetouch_macro( void *ptr );
void *get_aqualink_onetouch_setpoints( void *ptr );
*/
//void *get_aqualink_PDA_device_status( void *ptr );
//void *set_aqualink_PDA_device_on_off( void *ptr );
@ -238,16 +242,16 @@ int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
switch(type) {
case POOL_HTR_SETOINT:
type_msg = (aqdata->single_device?"Temp1":"Pool");
type_msg = (isSINGLE_DEV_PANEL?"Temp1":"Pool");
if ( aqdata->temp_units == CELSIUS ) {
max = HEATER_MAX_C;
min = (aqdata->single_device?HEATER_MIN_C:HEATER_MIN_C-1);
min = (isSINGLE_DEV_PANEL?HEATER_MIN_C:HEATER_MIN_C-1);
} else {
max = HEATER_MAX_F;
min = (aqdata->single_device?HEATER_MIN_F:HEATER_MIN_F-1);
min = (isSINGLE_DEV_PANEL?HEATER_MIN_F:HEATER_MIN_F-1);
}
// if single device then TEMP1 & 2 (not pool & spa), TEMP1 must be set higher than TEMP2
if (aqdata->single_device &&
if (isSINGLE_DEV_PANEL &&
aqdata->spa_htr_set_point != TEMP_UNKNOWN &&
min <= aqdata->spa_htr_set_point)
{
@ -255,16 +259,16 @@ int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
}
break;
case SPA_HTR_SETOINT:
type_msg = (aqdata->single_device?"Temp2":"Spa");
type_msg = (isSINGLE_DEV_PANEL?"Temp2":"Spa");
if ( aqdata->temp_units == CELSIUS ) {
max = (aqdata->single_device?HEATER_MAX_C:HEATER_MAX_C-1);
max = (isSINGLE_DEV_PANEL?HEATER_MAX_C:HEATER_MAX_C-1);
min = HEATER_MIN_C;
} else {
max = (aqdata->single_device?HEATER_MAX_F:HEATER_MAX_F-1);
max = (isSINGLE_DEV_PANEL?HEATER_MAX_F:HEATER_MAX_F-1);
min = HEATER_MIN_F;
}
// if single device then TEMP1 & 2 (not pool & spa), TEMP2 must be set lower than TEMP1
if (aqdata->single_device &&
if (isSINGLE_DEV_PANEL &&
aqdata->pool_htr_set_point != TEMP_UNKNOWN &&
max >= aqdata->pool_htr_set_point)
{
@ -312,16 +316,25 @@ int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data)
{
// Wait for onetouch if enabeled.
if ( source_type == ALLBUTTON && ( onetouch_enabled() == false || extended_device_id_programming() == false ) ) {
//if ( source_type == ALLBUTTON && ( onetouch_enabled() == false || extended_device_id_programming() == false ) ) {
if ( source_type == ALLBUTTON && ( isEXTP_ENABLED == false || (isONET_ENABLED == false && isIAQT_ENABLED == false)) ) {
aq_send_cmd(NUL);
aq_programmer(AQ_GET_POOL_SPA_HEATER_TEMPS, NULL, aq_data);
aq_programmer(AQ_GET_FREEZE_PROTECT_TEMP, NULL, aq_data);
if (_aqconfig_.use_panel_aux_labels)
aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data);
#ifdef AQ_ONETOUCH
} else if ( source_type == ONETOUCH) {
aq_programmer(AQ_GET_ONETOUCH_SETPOINTS, NULL, aq_data);
if (_aqconfig_.use_panel_aux_labels)
aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data);
#endif
#ifdef AQ_IAQTOUCH
} else if ( source_type == IAQTOUCH) {
aq_programmer(AQ_GET_IAQTOUCH_SETPOINTS, NULL, aq_data);
if (_aqconfig_.use_panel_aux_labels)
aq_programmer(AQ_GET_IAQTOUCH_AUX_LABELS, NULL, aq_data);
#endif
#ifdef AQ_PDA
} else if ( source_type == AQUAPDA) {
aq_programmer(AQ_PDA_INIT, NULL, aq_data);
@ -344,6 +357,22 @@ void kick_aq_program_thread(struct aqualinkdata *aq_data)
}
}
*/
bool in_swg_programming_mode(struct aqualinkdata *aq_data)
{
if ( ( aq_data->active_thread.thread_id != 0 ) &&
( aq_data->active_thread.ptype == AQ_SET_ONETOUCH_SWG_PERCENT ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_SWG_PERCENT ||
aq_data->active_thread.ptype == AQ_SET_SWG_PERCENT ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_BOOST ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_SWG_BOOST ||
aq_data->active_thread.ptype == AQ_SET_BOOST)
) {
return true;
}
return false;
}
bool in_ot_programming_mode(struct aqualinkdata *aq_data)
{
//( type != AQ_SET_PUMP_RPM || type != AQ_SET_OT_MACRO )) {
@ -365,6 +394,37 @@ bool in_ot_programming_mode(struct aqualinkdata *aq_data)
return false;
}
bool in_iaqt_programming_mode(struct aqualinkdata *aq_data)
{
//( type != AQ_SET_PUMP_RPM || type != AQ_SET_OT_MACRO )) {
if ( ( aq_data->active_thread.thread_id != 0 ) &&
( aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_PUMP_RPM ||
aq_data->active_thread.ptype == AQ_GET_IAQTOUCH_VSP_ASSIGNMENT ||
aq_data->active_thread.ptype == AQ_GET_IAQTOUCH_SETPOINTS ||
aq_data->active_thread.ptype == AQ_GET_IAQTOUCH_AUX_LABELS ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_SWG_PERCENT ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_SWG_BOOST ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_POOL_HEATER_TEMP ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_SPA_HEATER_TEMP ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_SET_TIME ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM)
) {
return true;
}
return false;
}
bool in_programming_mode(struct aqualinkdata *aq_data)
{
if ( aq_data->active_thread.thread_id != 0 ) {
return true;
}
return false;
}
void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_type)
{
if ( aq_data->active_thread.thread_id != 0 ) {
@ -377,6 +437,10 @@ void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_
logMessage(LOG_DEBUG, "Kicking RS thread %d,%p message '%s'\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id,aq_data->last_message);
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
else if (source_type == IAQTOUCH && in_iaqt_programming_mode(aq_data)) {
logMessage(LOG_DEBUG, "Kicking IAQ Touch thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
#ifdef AQ_PDA
else if (source_type == AQUAPDA && !in_ot_programming_mode(aq_data)) {
logMessage(LOG_DEBUG, "Kicking PDA thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
@ -392,9 +456,27 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
program_type type = r_type;
if (r_type == AQ_SET_PUMP_RPM) {
if (isONET_ENABLED)
type = AQ_SET_ONETOUCH_PUMP_RPM;
else if (isIAQT_ENABLED)
type = AQ_SET_IAQTOUCH_PUMP_RPM;
else {
logMessage(LOG_ERR, "Can only change pump RPM with an extended device id\n",type);
return;
}
} else if (r_type == AQ_SET_PUMP_VS_PROGRAM) {
if (isIAQT_ENABLED)
type = AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM;
else {
logMessage(LOG_ERR, "Can only change pump VS Program with an iAqualink Touch device id\n",type);
return;
}
}
#ifdef AQ_ONETOUCH
// reset any types if to onetouch if available and if one touch is quicker
// At moment. onetouch is quicker for boost, and slower for heaters
if (onetouch_enabled() && extended_device_id_programming()) {
else if (isONET_ENABLED && isEXTP_ENABLED) {
switch (r_type){
case AQ_GET_POOL_SPA_HEATER_TEMPS:
case AQ_GET_FREEZE_PROTECT_TEMP:
@ -406,6 +488,9 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
case AQ_SET_SPA_HEATER_TEMP:
type = AQ_SET_ONETOUCH_SPA_HEATER_TEMP;
break;
case AQ_SET_SWG_PERCENT:
type = AQ_SET_ONETOUCH_SWG_PERCENT;
break;
case AQ_SET_BOOST:
type = AQ_SET_ONETOUCH_BOOST;
break;
@ -414,10 +499,39 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
break;
}
}
#endif
#ifdef AQ_IAQTOUCH
else if (isIAQT_ENABLED && isEXTP_ENABLED) {
// IAQ Touch programming modes that should overite standard ones.
switch (r_type){
case AQ_GET_POOL_SPA_HEATER_TEMPS:
case AQ_GET_FREEZE_PROTECT_TEMP:
type = AQ_GET_IAQTOUCH_SETPOINTS;
break;
case AQ_SET_SWG_PERCENT:
type = AQ_SET_IAQTOUCH_SWG_PERCENT;
break;
case AQ_SET_BOOST:
type = AQ_SET_IAQTOUCH_SWG_BOOST;
break;
case AQ_SET_POOL_HEATER_TEMP:
type = AQ_SET_IAQTOUCH_POOL_HEATER_TEMP;
break;
case AQ_SET_SPA_HEATER_TEMP:
type = AQ_SET_IAQTOUCH_SPA_HEATER_TEMP;
break;
case AQ_SET_TIME:
type = AQ_SET_IAQTOUCH_SET_TIME;
break;
default:
type = r_type;
break;
}
}
#endif
#ifdef AQ_PDA
// Check we are doing something valid request
if (pda_mode() == true) {
if (isPDA_PANEL) {
pda_reset_sleep();
if (type != AQ_PDA_INIT &&
type != AQ_PDA_WAKE_INIT &&
@ -545,8 +659,9 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
return;
}
break;
#ifdef AQ_ONETOUCH
case AQ_SET_ONETOUCH_PUMP_RPM:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_pump_rpm, (void*)programmingthread) < 0) {
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_pump_rpm, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
@ -593,7 +708,68 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
return;
}
break;
#endif
#ifdef AQ_IAQTOUCH
case AQ_SET_IAQTOUCH_PUMP_RPM:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_pump_rpm, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_IAQTOUCH_VSP_ASSIGNMENT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_vsp_assignments, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_IAQTOUCH_SETPOINTS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_iaqtouch_setpoints, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_IAQTOUCH_AUX_LABELS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_iaqtouch_aux_labels, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_IAQTOUCH_SWG_PERCENT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_swg_percent, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_IAQTOUCH_SWG_BOOST:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_swg_boost, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_IAQTOUCH_POOL_HEATER_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_pool_heater_temp, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_IAQTOUCH_SPA_HEATER_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_spa_heater_temp, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_IAQTOUCH_SET_TIME:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_time, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_pump_vs_program, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
#endif
#ifdef AQ_PDA
case AQ_PDA_INIT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_PDA_init, (void*)programmingthread) < 0) {
@ -641,7 +817,7 @@ void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, pr
int tries = 120;
static int waitTime = 1;
int i=0;
i = 0;
while (get_aq_cmd_length() > 0 && ( i++ <= tries) ) {
logMessage (LOG_DEBUG, "Thread %p (%s) sleeping, waiting command queue to empty\n", &threadCtrl->thread_id, ptypeName(type));
@ -852,7 +1028,7 @@ STOP BOOST POOL
int val = atoi((char*)threadCtrl->thread_args);
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
set_PDA_aqualink_boost(aq_data, val);
cleanAndTerminateThread(threadCtrl);
return ptr;
@ -904,9 +1080,7 @@ STOP BOOST POOL
}
if (i < wait_messages) {
// Takes ages to see bost is off from menu, to set it here.
aq_data->boost = false;
aq_data->boost_msg[0] = '\0';
aq_data->swg_percent = 0;
setSWGboost(aq_data, false);
}
/*
// Extra message overcome.
@ -942,8 +1116,9 @@ void *set_aqualink_SWG( void *ptr )
val = setpoint_check(SWG_SETPOINT, val, aq_data);
#ifdef AQ_PDA
if (pda_mode() == true) {
set_PDA_aqualink_SWG_setpoint(aq_data, val);
if (isPDA_PANEL) {
if (set_PDA_aqualink_SWG_setpoint(aq_data, val))
setSWGpercent(aq_data, val); // Don't use chageSWGpercent as we are in programming mode.
cleanAndTerminateThread(threadCtrl);
return ptr;
}
@ -977,6 +1152,9 @@ void *set_aqualink_SWG( void *ptr )
setAqualinkNumericField_new(aq_data, "POOL SP", val, 5);
}
// Let everyone know we set SWG, if it failed we will update on next message, unless it's 0.
setSWGpercent(aq_data, val); // Don't use chageSWGpercent as we are in programming mode.
/*
if (select_sub_menu_item(aq_data, "SET POOL SP") != true) {
logMessage(LOG_WARNING, "Could not select SWG setpoint menu\n");
@ -1015,7 +1193,7 @@ void *get_aqualink_aux_labels( void *ptr )
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_AUX_LABELS);
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
get_PDA_aqualink_aux_labels(aq_data);
cleanAndTerminateThread(threadCtrl);
return ptr;
@ -1234,7 +1412,7 @@ void *set_aqualink_pool_heater_temps( void *ptr )
val = setpoint_check(POOL_HTR_SETOINT, val, aq_data);
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
set_PDA_aqualink_heater_setpoint(aq_data, val, true);
cleanAndTerminateThread(threadCtrl);
return ptr;
@ -1242,7 +1420,7 @@ void *set_aqualink_pool_heater_temps( void *ptr )
#endif
// NSF IF in TEMP1 / TEMP2 mode, we need C range of 1 to 40 is 2 to 40 for TEMP1, 1 to 39 TEMP2
if (aq_data->single_device == true ){
if (isSINGLE_DEV_PANEL){
name = "TEMP1";
menu_name = "SET TEMP1";
} else {
@ -1268,7 +1446,7 @@ void *set_aqualink_pool_heater_temps( void *ptr )
return ptr;
}
if (aq_data->single_device == true ){
if (isSINGLE_DEV_PANEL){
// Need to get pass this message 'TEMP1 MUST BE SET HIGHER THAN TEMP2'
// and get this message 'TEMP1 20<32>C ~*'
// Before going to numeric field.
@ -1309,7 +1487,7 @@ void *set_aqualink_spa_heater_temps( void *ptr )
val = setpoint_check(SPA_HTR_SETOINT, val, aq_data);
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
set_PDA_aqualink_heater_setpoint(aq_data, val, false);
cleanAndTerminateThread(threadCtrl);
return ptr;
@ -1317,7 +1495,7 @@ void *set_aqualink_spa_heater_temps( void *ptr )
#endif
// NSF IF in TEMP1 / TEMP2 mode, we need C range of 1 to 40 is 2 to 40 for TEMP1, 1 to 39 TEMP2
if (aq_data->single_device == true ){
if (isSINGLE_DEV_PANEL){
name = "TEMP2";
menu_name = "SET TEMP2";
} else {
@ -1343,7 +1521,7 @@ void *set_aqualink_spa_heater_temps( void *ptr )
return ptr;
}
if (aq_data->single_device == true ){
if (isSINGLE_DEV_PANEL){
// Need to get pass this message 'TEMP2 MUST BE SET LOWER THAN TEMP1'
// and get this message 'TEMP2 20<32>C ~*'
// Before going to numeric field.
@ -1386,7 +1564,7 @@ void *set_aqualink_freeze_heater_temps( void *ptr )
logMessage(LOG_DEBUG, "Setting sfreeze protection to %d\n", val);
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
set_PDA_aqualink_freezeprotect_setpoint(aq_data, val);
cleanAndTerminateThread(threadCtrl);
return ptr;
@ -1511,9 +1689,9 @@ void *get_aqualink_pool_spa_heater_temps( void *ptr )
//logMessage(LOG_NOTICE, "Getting pool & spa heat setpoints from aqualink\n");
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
if (!get_PDA_aqualink_pool_spa_heater_temps(aq_data)) {
logMessage(LOG_ERR, "Error Getting PDA pool & spa heat protection setpoints\n");
logMessage(LOG_ERR, "Error Getting PDA pool & spa heater setpoints\n");
}
cleanAndTerminateThread(threadCtrl);
return ptr;
@ -1555,7 +1733,7 @@ void *get_freeze_protect_temp( void *ptr )
//logMessage(LOG_NOTICE, "Getting freeze protection setpoints\n");
#ifdef AQ_PDA
if (pda_mode() == true) {
if (isPDA_PANEL) {
if (! get_PDA_freeze_protect_temp(aq_data)) {
logMessage(LOG_ERR, "Error Getting PDA freeze protection setpoints\n");
}
@ -1671,7 +1849,7 @@ void _waitfor_queue2empty(bool longwait)
if (_pgm_command != NUL) {
#ifdef AQ_PDA
if (pda_mode()) {
if (isPDA_PANEL) {
// Wait for longer in PDA mode since it's slower.
while ( (_pgm_command != NUL) && ( i++ < (150*(longwait?2:1)) ) ) {
delay(100);
@ -2008,6 +2186,13 @@ const char *ptypeName(program_type type)
case AQ_SET_BOOST:
return "SWG Boost";
break;
case AQ_SET_PUMP_RPM:
return "Set Pump RPM";
break;
case AQ_SET_PUMP_VS_PROGRAM:
return "Set Pump VS Program";
break;
#ifdef AQ_ONETOUCH
case AQ_SET_ONETOUCH_PUMP_RPM:
return "Set OneTouch Pump RPM";
break;
@ -2035,6 +2220,39 @@ const char *ptypeName(program_type type)
case AQ_SET_ONETOUCH_SPA_HEATER_TEMP:
return "Set OneTouch Spa Heater Temp";
break;
#endif
#ifdef AQ_IAQTOUCH
case AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM:
return "Set iAqualink Touch Pump VS Program";
break;
case AQ_SET_IAQTOUCH_PUMP_RPM:
return "Set iAqualink Touch Pump RPM";
break;
case AQ_GET_IAQTOUCH_VSP_ASSIGNMENT:
return "Get iAqualink Touch Pump Assignment";
break;
case AQ_GET_IAQTOUCH_SETPOINTS:
return "Get iAqualink Touch Setpoints";
break;
case AQ_GET_IAQTOUCH_AUX_LABELS:
return "Get iAqualink AUX Labels";
break;
case AQ_SET_IAQTOUCH_SWG_PERCENT:
return "Set iAqualink SWG Percent";
break;
case AQ_SET_IAQTOUCH_SWG_BOOST:
return "Set iAqualink Boost";
break;
case AQ_SET_IAQTOUCH_SPA_HEATER_TEMP:
return "Set iAqualink Spa Heater";
break;
case AQ_SET_IAQTOUCH_POOL_HEATER_TEMP:
return "Set iAqualink Pool Heater";
break;
case AQ_SET_IAQTOUCH_SET_TIME:
return "Set iAqualink Set Time";
break;
#endif
#ifdef AQ_PDA
case AQ_PDA_INIT:
return "Init PDA";
@ -2066,11 +2284,13 @@ const char *programtypeDisplayName(program_type type)
case AQ_GET_POOL_SPA_HEATER_TEMPS:
case AQ_GET_ONETOUCH_SETPOINTS:
case AQ_GET_FREEZE_PROTECT_TEMP:
case AQ_GET_IAQTOUCH_SETPOINTS:
#ifdef AQ_PDA
case AQ_PDA_INIT:
#endif
return "Programming: retrieving setpoints";
break;
case AQ_SET_IAQTOUCH_SET_TIME:
case AQ_SET_ONETOUCH_TIME:
case AQ_SET_TIME:
return "Programming: setting time";
@ -2079,6 +2299,8 @@ const char *programtypeDisplayName(program_type type)
case AQ_SET_ONETOUCH_POOL_HEATER_TEMP:
case AQ_SET_SPA_HEATER_TEMP:
case AQ_SET_ONETOUCH_SPA_HEATER_TEMP:
case AQ_SET_IAQTOUCH_SPA_HEATER_TEMP:
case AQ_SET_IAQTOUCH_POOL_HEATER_TEMP:
return "Programming: setting heater";
break;
case AQ_SET_FRZ_PROTECTION_TEMP:
@ -2097,21 +2319,31 @@ const char *programtypeDisplayName(program_type type)
break;
case AQ_SET_SWG_PERCENT:
case AQ_SET_ONETOUCH_SWG_PERCENT:
case AQ_SET_IAQTOUCH_SWG_PERCENT:
return "Programming: setting SWG percent";
break;
case AQ_GET_AUX_LABELS:
case AQ_GET_IAQTOUCH_AUX_LABELS:
return "Programming: retrieving AUX labels";
break;
case AQ_SET_BOOST:
case AQ_SET_ONETOUCH_BOOST:
case AQ_SET_IAQTOUCH_SWG_BOOST:
return "Programming: setting SWG Boost";
break;
case AQ_SET_ONETOUCH_PUMP_RPM:
case AQ_SET_IAQTOUCH_PUMP_RPM:
case AQ_SET_PUMP_RPM:
case AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM:
case AQ_SET_PUMP_VS_PROGRAM:
return "Programming: setting Pump RPM";
break;
case AQ_SET_ONETOUCH_MACRO:
return "Programming: setting OneTouch Macro";
break;
case AQ_GET_IAQTOUCH_VSP_ASSIGNMENT:
return "Get Pump Assignment";
break;
#ifdef AQ_PDA
case AQ_PDA_DEVICE_STATUS:
return "Programming: retrieving PDA Device status";

View File

@ -26,7 +26,9 @@
typedef enum emulation_type{
ALLBUTTON,
ONETOUCH,
AQUAPDA // AQUAPALM and PDA are taken as specific type.
IAQTOUCH,
AQUAPDA, // AQUAPALM and PDA are taken as specific type.
JANDY_DEVICE // Very rarley used.
} emulation_type;
typedef enum {
@ -49,6 +51,8 @@ typedef enum {
AQ_GET_AUX_LABELS,
AQ_PDA_WAKE_INIT,
AQ_SET_BOOST,
AQ_SET_PUMP_RPM,
AQ_SET_PUMP_VS_PROGRAM,
AQ_SET_ONETOUCH_PUMP_RPM,
AQ_SET_ONETOUCH_MACRO,
AQ_GET_ONETOUCH_SETPOINTS,
@ -57,7 +61,17 @@ typedef enum {
AQ_SET_ONETOUCH_FREEZEPROTECT,
AQ_SET_ONETOUCH_TIME,
AQ_SET_ONETOUCH_BOOST,
AQ_SET_ONETOUCH_SWG_PERCENT
AQ_SET_ONETOUCH_SWG_PERCENT,
AQ_SET_IAQTOUCH_PUMP_RPM,
AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM,
AQ_GET_IAQTOUCH_VSP_ASSIGNMENT,
AQ_GET_IAQTOUCH_SETPOINTS,
AQ_GET_IAQTOUCH_AUX_LABELS,
AQ_SET_IAQTOUCH_SWG_PERCENT,
AQ_SET_IAQTOUCH_SWG_BOOST,
AQ_SET_IAQTOUCH_POOL_HEATER_TEMP,
AQ_SET_IAQTOUCH_SPA_HEATER_TEMP,
AQ_SET_IAQTOUCH_SET_TIME
} program_type;
struct programmingThreadCtrl {
@ -79,7 +93,10 @@ typedef enum pump_type {
void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data);
//void kick_aq_program_thread(struct aqualinkdata *aq_data);
void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_type);
bool in_programming_mode(struct aqualinkdata *aq_data);
bool in_ot_programming_mode(struct aqualinkdata *aq_data);
bool in_iaqt_programming_mode(struct aqualinkdata *aq_data);
bool in_swg_programming_mode(struct aqualinkdata *aq_data);
void aq_send_cmd(unsigned char cmd);
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data);
//void queueGetExtendedProgramData(emulation_type source_type, struct aqualinkdata *aq_data, bool labels);

View File

@ -33,6 +33,8 @@
//#define USE_AQ_SERIAL_OLD
#ifndef USE_AQ_SERIAL_OLD // Substansial changes to core component, make sure we can role back easily
static struct termios _oldtio;
@ -46,7 +48,7 @@ bool _onetouch_mode = false;
void set_onetouch_mode(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using Onetouch mode\n");
LOG(RSSD_LOG,LOG_NOTICE, "AqualinkD is using Onetouch mode\n");
_onetouch_mode = mode;
}
@ -57,13 +59,14 @@ bool onetouch_mode()
#endif
*/
/*
#ifdef AQ_PDA
bool _pda_mode = false;
void set_pda_mode(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using PDA mode\n");
LOG(RSSD_LOG,LOG_NOTICE, "AqualinkD is using PDA mode\n");
_pda_mode = mode;
}
@ -72,32 +75,63 @@ bool pda_mode()
return _pda_mode;
}
#endif
*/
/*
bool _onetouch_enabled = false;
bool _iaqtouch_enabled = false;
bool _extended_device_id_programming = false;
void set_onetouch_enabled(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using use ONETOUCH mode for VSP programming\n");
if (mode) {
LOG(RSSD_LOG,LOG_NOTICE, "AqualinkD is using use ONETOUCH mode for VSP programming\n");
_iaqtouch_enabled = false;
}
_onetouch_enabled = mode;
}
bool onetouch_enabled()
{
#ifdef AQ_ONETOUCH
return _onetouch_enabled;
#else
return false;
#endif
}
void set_iaqtouch_enabled(bool mode)
{
if (mode) {
LOG(RSSD_LOG,LOG_NOTICE, "AqualinkD is using use IAQ TOUCH mode for VSP programming\n");
_onetouch_enabled = false;
}
_iaqtouch_enabled = mode;
}
bool iaqtouch_enabled()
{
#ifdef AQ_IAQTOUCH
return _iaqtouch_enabled;
#else
return false;
#endif
}
bool VSP_enabled()
{
// At present this is dependant on onetouch.
return onetouch_enabled();
//return onetouch_enabled();
if (onetouch_enabled() || iaqtouch_enabled())
return true;
return false;
}
void set_extended_device_id_programming(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using use ONETOUCH mode for programming (where supported)\n");
LOG(RSSD_LOG,LOG_NOTICE, "AqualinkD is using use %s mode for programming (where supported)\n",onetouch_enabled()?"ONETOUCH":"IAQ TOUCH");
_extended_device_id_programming = mode;
}
@ -105,6 +139,7 @@ bool extended_device_id_programming()
{
return _extended_device_id_programming;
}
*/
const char* get_packet_type(unsigned char* packet , int length)
{
@ -156,11 +191,23 @@ const char* get_packet_type(unsigned char* packet , int length)
case CMD_PDA_HIGHLIGHTCHARS:
return "PDA HlightChars";
break;
case CMD_IAQ_MSG:
return "iAq Message";
case CMD_IAQ_PAGE_MSG:
if (packet[4] == 0x31)
return "iAq setDevice";
else
return "iAq pMessage";
break;
case CMD_IAQ_MENU_MSG:
return "iAq Menu";
case CMD_IAQ_PAGE_BUTTON:
return "iAq pButton";
break;
case CMD_IAQ_POLL:
return "iAq Poll";
break;
case CMD_IAQ_PAGE_END:
return "iAq PageEnd";
break;
case CMD_IAQ_PAGE_START:
return "iAq PageStart";
break;
default:
sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]);
@ -210,7 +257,7 @@ bool check_pentair_checksum(unsigned char* packet, int length)
// Check against actual # length
if (sum == (packet[n] * 256 + packet[n+1])) {
logMessage(LOG_ERR, "Pentair checksum is accurate but length is not\n");
LOG(RSSD_LOG,LOG_ERR, "Pentair checksum is accurate but length is not\n");
return true;
}
@ -272,17 +319,17 @@ int init_serial_port(const char* tty)
//int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
if (fd < 0) {
logMessage(LOG_ERR, "Unable to open port: %s\n", tty);
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s\n", tty);
return -1;
}
logMessage(LOG_DEBUG_SERIAL, "Openeded serial port %s\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Openeded serial port %s\n",tty);
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK | O_NDELAY);
newtio.c_cc[VMIN]= 0;
newtio.c_cc[VTIME]= 1;
logMessage(LOG_DEBUG_SERIAL, "Set serial port %s to non blocking mode\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Set serial port %s to non blocking mode\n",tty);
tcgetattr(fd, &_oldtio); // save current port settings
// set new port settings for canonical input processing
@ -294,7 +341,7 @@ int init_serial_port(const char* tty)
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
logMessage(LOG_DEBUG_SERIAL, "Set serial port %s io attributes\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Set serial port %s io attributes\n",tty);
return fd;
}
@ -304,7 +351,7 @@ void close_serial_port(int fd)
{
tcsetattr(fd, TCSANOW, &_oldtio);
close(fd);
logMessage(LOG_DEBUG_SERIAL, "Closed serial port\n");
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Closed serial port\n");
}
@ -377,11 +424,11 @@ void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, ackPacket + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
LOG(RSSD_LOG,LOG_ERR, "write to serial port failed\n");
}
//logMessage(LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//tcdrain(fd);
//logMessage(LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
//LOG(RSSD_LOG,LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
#endif
log_packet("Sent ", ackPacket, length);
@ -469,30 +516,52 @@ void send_command(int fd, unsigned char *packet_buffer, int size)
//int i=0;
if (packet_buffer[0] == PCOL_JANDY) {
//logMessage(LOG_ERR, "Only Jandy protocol supported at present!\n");
//LOG(RSSD_LOG,LOG_ERR, "Only Jandy protocol supported at present!\n");
send_jandy_command(fd, &packet_buffer[1], size-1);
return;
}
if (packet_buffer[0] == PCOL_PENTAIR) {
//logMessage(LOG_ERR, "Only Jandy protocol supported at present!\n");
//LOG(RSSD_LOG,LOG_ERR, "Only Jandy protocol supported at present!\n");
send_pentair_command(fd, &packet_buffer[1], size-1);
return;
}
}
void send_packet(int fd, unsigned char *packet, int length)
{
if (_aqconfig_.readahead_b4_write) {
unsigned char byte;
int r;
//int j=0;
do {
//j++;
r = read(fd, &byte, 1);
//printf("*** Peek Read %d 0x%02hhx ***\n",r,byte);
if (r==1 && byte != 0x00) {
LOG(RSSD_LOG,LOG_ERR, "SERIOUS ERROR on RS485, AqualinkD was too slow in replying to message! (please check OS for performance issues)\n");
return;
}
} while (r==1 && byte==0x00);
}
int nwrite, i;
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, packet + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
LOG(RSSD_LOG,LOG_ERR, "write to serial port failed\n");
}
if ( getLogLevel() >= LOG_DEBUG_SERIAL) {
/*
#ifdef AQ_DEBUG
// Need to take this out for release
if ( getLogLevel(RSSD_LOG) >= LOG_DEBUG) {
debuglogPacket(&packet[1], length-2);
}
#endif
*/
if ( getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL) {
// Packet is padded with 0x00, so discard for logging
logMessage(LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
logPacket(&packet[1], length-2);
}
}
@ -575,7 +644,7 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
} else if (bytesRead < 0 && errno == EAGAIN) {
// If we are in the middle of reading a packet, keep going
if (retry > 20) {
logMessage(LOG_WARNING, "Serial read timeout\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read timeout\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
logPacketError(packet, index);
return 0;
@ -672,7 +741,7 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
} else if(bytesRead < 0) {
// Got a read error. Wait one millisecond for the next byte to
// arrive.
logMessage(LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
if(errno == 9) {
// Bad file descriptor. Port has been disconnected for some reason.
// Return a -1.
@ -685,42 +754,63 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
// length.
if (index >= AQ_MAXPKTLEN) {
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial packet too large\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
break;
}
}
//logMessage(LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
// Clean out rest of buffer, make sure their is nothing else
/* Doesn't work for shit due to probe message speed, need to come back and re-think
if (_aqconfig_.readahead_b4_write) {
if (endOfPacket == true) {
do {
bytesRead = read(fd, &byte, 1);
//if (bytesRead==1) { LOG(RSSD_LOG,LOG_ERR, "Cleanout buffer read 0x%02hhx\n",byte); }
if (bytesRead==1 && byte != 0x00) {
LOG(RSSD_LOG,LOG_ERR, "SERIOUS ERROR on RS485, AqualinkD caught packet collision on bus, ignoring!\n");
LOG(RSSD_LOG,LOG_ERR, "Error Cleanout read 0x%02hhx\n",byte);
// Run the buffer out
do {
bytesRead = read(fd, &byte, 1);
if (bytesRead==1) { LOG(RSSD_LOG,LOG_ERR, "Error Cleanout read 0x%02hhx\n",byte); }
} while (bytesRead==1);
return 0;
}
} while (bytesRead==1);
}
}
*/
//LOG(RSSD_LOG,LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
if (jandyPacketStarted) {
if (check_jandy_checksum(packet, index) != true){
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
} else if (pentairPacketStarted) {
if (check_pentair_checksum(packet, index) != true){
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
}
/*
if (generate_checksum(packet, index) != packet[index-3]){
logMessage(LOG_WARNING, "Serial read bad checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
} else*/ if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial read too small\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read too small\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
logPacket(packet, index);
// Return the packet length.
return index;
@ -804,7 +894,7 @@ bool _pda_mode = false;
void set_pda_mode(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using PDA mode\n");
LOG(RSSD_LOG,LOG_NOTICE, "AqualinkD is using PDA mode\n");
_pda_mode = mode;
}
@ -818,7 +908,7 @@ void log_packet(int level, char *init_str, unsigned char* packet, int length)
{
if ( getLogLevel() < level) {
//logMessage(LOG_INFO, "Send '0x%02hhx'|'0x%02hhx' to controller\n", packet[5] ,packet[6]);
//LOG(RSSD_LOG,LOG_INFO, "Send '0x%02hhx'|'0x%02hhx' to controller\n", packet[5] ,packet[6]);
return;
}
@ -834,8 +924,8 @@ void log_packet(int level, char *init_str, unsigned char* packet, int length)
cnt += sprintf(buff+cnt, "0x%02hhx|",packet[i]);
cnt += sprintf(buff+cnt, "\n");
logMessage(level, buff);
//logMessage(LOG_DEBUG_SERIAL, buff);
LOG(RSSD_LOG,level, buff);
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, buff);
}
const char* get_packet_type(unsigned char* packet , int length)
@ -991,23 +1081,23 @@ int init_serial_port(char* tty)
//int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
if (fd < 0) {
logMessage(LOG_ERR, "Unable to open port: %s\n", tty);
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s\n", tty);
return -1;
}
logMessage(LOG_DEBUG_SERIAL, "Openeded serial port %s\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Openeded serial port %s\n",tty);
#ifdef BLOCKING_MODE
fcntl(fd, F_SETFL, 0);
newtio.c_cc[VMIN]= 1;
newtio.c_cc[VTIME]= 0;
logMessage(LOG_DEBUG_SERIAL, "Set serial port %s to blocking mode\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Set serial port %s to blocking mode\n",tty);
#else
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK | O_NDELAY);
newtio.c_cc[VMIN]= 0;
newtio.c_cc[VTIME]= 1;
logMessage(LOG_DEBUG_SERIAL, "Set serial port %s to non blocking mode\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Set serial port %s to non blocking mode\n",tty);
#endif
/*
// Need to change this to flock, but that depends on good exit.
@ -1043,7 +1133,7 @@ int init_serial_port(char* tty)
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
logMessage(LOG_DEBUG_SERIAL, "Set serial port %s io attributes\n",tty);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Set serial port %s io attributes\n",tty);
return fd;
}
@ -1053,7 +1143,7 @@ void close_serial_port(int fd)
{
tcsetattr(fd, TCSANOW, &_oldtio);
close(fd);
logMessage(LOG_DEBUG_SERIAL, "Closed serial port\n");
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Closed serial port\n");
}
void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3)
@ -1076,11 +1166,11 @@ void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, ackPacket + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
LOG(RSSD_LOG,LOG_ERR, "write to serial port failed\n");
}
//logMessage(LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//tcdrain(fd);
//logMessage(LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
//LOG(RSSD_LOG,LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
#endif
log_packet(LOG_DEBUG_SERIAL, "Sent ", ackPacket, length);
@ -1106,11 +1196,11 @@ void send_command(int fd, unsigned char destination, unsigned char b1, unsigned
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, ackPacket + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
LOG(RSSD_LOG,LOG_ERR, "write to serial port failed\n");
}
//logMessage(LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//tcdrain(fd);
//logMessage(LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
//LOG(RSSD_LOG,LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
#endif
if ( getLogLevel() >= LOG_DEBUG_SERIAL) {
@ -1142,11 +1232,11 @@ void send_messaged(int fd, unsigned char destination, char *message)
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, msgPacket + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
LOG(RSSD_LOG,LOG_ERR, "write to serial port failed\n");
}
//logMessage(LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//tcdrain(fd);
//logMessage(LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
//LOG(RSSD_LOG,LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
#endif
log_packet(LOG_DEBUG_SERIAL, "Sent ", msgPacket, length);
@ -1196,7 +1286,7 @@ void _send_ack(int fd, unsigned char ack_type, unsigned char command)
// Send the packet to the master device.
//write(fd, ackPacket, length);
//logMessage(LOG_DEBUG, "Send '0x%02hhx' to controller\n", command);
//LOG(RSSD_LOG,LOG_DEBUG, "Send '0x%02hhx' to controller\n", command);
#ifdef BLOCKING_MODE
write(fd, ackPacket, length);
@ -1205,16 +1295,16 @@ void _send_ack(int fd, unsigned char ack_type, unsigned char command)
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, ackPacket + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
LOG(RSSD_LOG,LOG_ERR, "write to serial port failed\n");
}
logMessage(LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//tcdrain(fd);
#endif
//logMessage(LOG_DEBUG, "Sent '0x%02hhx' to controller\n", command);
//LOG(RSSD_LOG,LOG_DEBUG, "Sent '0x%02hhx' to controller\n", command);
log_packet(LOG_DEBUG_SERIAL, "Sent ", ackPacket, length);
//logMessage(LOG_DEBUG, "Sent '0x%02hhx' to controller \n", command);
//LOG(RSSD_LOG,LOG_DEBUG, "Sent '0x%02hhx' to controller \n", command);
}
@ -1240,7 +1330,7 @@ int get_packet(int fd, unsigned char* packet)
} else if (bytesRead < 0 && errno == EAGAIN) {
// If we are in the middle of reading a packet, keep going
if (retry > 20) {
logMessage(LOG_WARNING, "Serial read timeout\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read timeout\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
@ -1282,7 +1372,7 @@ int get_packet(int fd, unsigned char* packet)
} else if(bytesRead < 0) {
// Got a read error. Wait one millisecond for the next byte to
// arrive.
logMessage(LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
if(errno == 9) {
// Bad file descriptor. Port has been disconnected for some reason.
// Return a -1.
@ -1294,27 +1384,27 @@ int get_packet(int fd, unsigned char* packet)
// Break out of the loop if we exceed maximum packet
// length.
if (index >= AQ_MAXPKTLEN) {
logMessage(LOG_WARNING, "Serial packet too large\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
break;
}
}
//logMessage(LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
//LOG(RSSD_LOG,LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
if (generate_checksum(packet, index) != packet[index-3]){
logMessage(LOG_WARNING, "Serial read bad checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
} else if (index < AQ_MINPKTLEN && packetStarted) { //NSF. Sometimes we get END sequence only, so just ignore.
//} else if (index < AQ_MINPKTLEN) { //NSF. Sometimes we get END sequence only, so just ignore.
logMessage(LOG_WARNING, "Serial read too small\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read too small\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
// Return the packet length.
return index;
}
@ -1352,7 +1442,7 @@ bool check_pentair_checksum(unsigned char* packet, int length)
// Check against actual # length
if (sum == (packet[n] * 256 + packet[n+1])) {
//logMessage(LOG_ERR, "Pentair checksum is accurate but length is not\n");
//LOG(RSSD_LOG,LOG_ERR, "Pentair checksum is accurate but length is not\n");
return true;
}
@ -1415,7 +1505,7 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
} else if (bytesRead < 0 && errno == EAGAIN) {
// If we are in the middle of reading a packet, keep going
if (retry > 20) {
logMessage(LOG_WARNING, "Serial read timeout\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read timeout\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
@ -1506,7 +1596,7 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
} else if(bytesRead < 0) {
// Got a read error. Wait one millisecond for the next byte to
// arrive.
logMessage(LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
if(errno == 9) {
// Bad file descriptor. Port has been disconnected for some reason.
// Return a -1.
@ -1519,42 +1609,42 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
// length.
if (index >= AQ_MAXPKTLEN) {
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial packet too large\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial packet too large\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
break;
}
}
//logMessage(LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
//LOG(RSSD_LOG,LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
if (jandyPacketStarted) {
if (check_jandy_checksum(packet, index) != true){
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
} else if (pentairPacketStarted) {
if (check_pentair_checksum(packet, index) != true){
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
}
/*
if (generate_checksum(packet, index) != packet[index-3]){
logMessage(LOG_WARNING, "Serial read bad checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
} else*/ if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
logPacketError(packet, index);
logMessage(LOG_WARNING, "Serial read too small\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read too small\n");
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
logPacket(packet, index);
// Return the packet length.
return index;
@ -1626,14 +1716,14 @@ int get_packet(int fd, unsigned char* packet_buffer)
}
packet_length--;
logMessage(LOG_DEBUG_SERIAL, "PLAYBACK read %d bytes\n",packet_length);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "PLAYBACK read %d bytes\n",packet_length);
//printf("To 0x%02hhx, type %15.15s, length %2.2d ", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),packet_length);
//fputs ( line, stdout );
if (getProtocolType(packet_buffer)==JANDY) {
if (generate_checksum(packet_buffer, packet_length) != packet_buffer[packet_length-3]) {
logPacketError(packet_buffer, packet_length);
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
} else
logPacket(packet_buffer, packet_length);
} else {
@ -1642,7 +1732,7 @@ int get_packet(int fd, unsigned char* packet_buffer)
//check_pentair_checksum(packet_buffer, packet_length+1);
if (check_pentair_checksum(packet_buffer, packet_length-1) != true) {
logPacketError(packet_buffer, packet_length);
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
} else
logPacket(packet_buffer, packet_length);
}
@ -1693,7 +1783,7 @@ int get_packet_old(int fd, unsigned char* packet)
} else if (bytesRead < 0 && errno == EAGAIN) {
// If we are in the middle of reading a packet, keep going
if (retry > 20) {
logMessage(LOG_WARNING, "Serial read timeout\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read timeout\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
@ -1758,7 +1848,7 @@ int get_packet_old(int fd, unsigned char* packet)
else if(bytesRead < 0) {
// Got a read error. Wait one millisecond for the next byte to
// arrive.
logMessage(LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
if(errno == 9) {
// Bad file descriptor. Port has been disconnected for some reason.
// Return a -1.
@ -1769,18 +1859,18 @@ int get_packet_old(int fd, unsigned char* packet)
}
if (generate_checksum(packet, index) != packet[index-3]){
logMessage(LOG_WARNING, "Serial read bad checksum, ignoring\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read bad checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
} else if (index < AQ_MINPKTLEN) {
logMessage(LOG_WARNING, "Serial read too small\n");
LOG(RSSD_LOG,LOG_WARNING, "Serial read too small\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
//if (_config_parameters.debug_RSProtocol_packets || getLogLevel() >= LOG_DEBUG_SERIAL)
// logPacket(packet_buffer, packet_length);
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
// Return the packet length.
return index;

View File

@ -3,6 +3,7 @@
#define AQ_SERIAL_H_
#include <termios.h>
#include <stdbool.h>
#define CONNECTION_ERROR "ERROR No connection to RS control panel"
@ -62,7 +63,8 @@
// END Pentair
#define AQ_MINPKTLEN 5
#define AQ_MAXPKTLEN 64
//#define AQ_MAXPKTLEN 64
#define AQ_MAXPKTLEN 128 // Max 79 bytes so far, so 128 is a guess at the moment, just seen large packets from iAqualink
#define AQ_PSTLEN 5
#define AQ_MSGLEN 16
#define AQ_MSGLONGLEN 128
@ -74,7 +76,7 @@
#define CMD_STATUS 0x02
#define CMD_MSG 0x03
#define CMD_MSG_LONG 0x04
#define CMD_RS_UNKNOWN 0x08
#define CMD_MSG_LOOP_ST 0x08
/* ACK RETURN COMMANDS */
/*
@ -83,14 +85,17 @@
#define ACK_SCREEN_BUSY_BLOCK 0x03 // Seems to be don't send me any more shit.
*/
// Some keypads use 0x00 some 0x80 (think it's something to do with version, but need to figure it out)
// But if you use 0x80 for ack then you get a start loop cycle CMD_MSG_LOOP_ST
#define ACK_NORMAL 0x80
#define ACK_SCREEN_BUSY_SCROLL 0x81 // Seems to be busy displaying last message, but can cache next message,
#define ACK_SCREEN_BUSY_BLOCK 0x83 // Seems to be don't send me any more shit.
// Remove this and fix all compile errors when get time.
#define ACK_SCREEN_BUSY ACK_SCREEN_BUSY_SCROLL
#define ACK_IAQ_TOUCH 0x00
#define ACK_PDA 0x40
#define ACK_ONETOUCH 0x80
#define ACK_ALLB_SIM 0x80 // Jandy's Allbutton simulator uses this and not ACK_NORMAL
@ -257,6 +262,11 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define MSG_SWG_PCT_LEN 8
#define MSG_SWG_PPM_LEN 4
#define MSG_SWG_NO_FLOW "Check AQUAPURE No Flow"
#define MSG_SWG_LOW_SALT "Check AQUAPURE Low Salt"
#define MSG_SWG_HIGH_SALT "Check AQUAPURE High Salt"
#define MSG_SWG_FAULT "Check AQUAPURE General Fault"
#define MSG_PMP_RPM "RPM:"
#define MSG_PMP_WAT "Watts:"
#define MSG_PMP_GPM "GPM:"
@ -268,8 +278,9 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
//#define SWG_STATUS_OFF 0xFF
//#define SWG_STATUS_OFFLINE 0xFE
#define SWG_STATUS_OFF 0xFF
#define SWG_STATUS_UNKNOWN -128
//#define SWG_STATUS_UNKNOWN -128 // Idiot. unsigned char....Derr.
#define SWG_STATUS_OFF 0xFF // Documented this as off in API, so don't change.
#define SWG_STATUS_UNKNOWN 0xFE
// These are actual from RS485
#define SWG_STATUS_ON 0x00
@ -297,32 +308,84 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
//#define CMD_PDA_0x04 0x04 // No idea, might be building menu
/* iAqualink */
/* None of these are used, just here to gather data for the moment */
#define CMD_IAQ_MSG 0x25 // Equiptment status message??
#define CMD_IAQ_MENU_MSG 0x24
#define CMD_IAQ_MSG_LONG 0x2c // Long status message??
#define CMD_IAQ_PAGE_MSG 0x25
#define CMD_IAQ_TABLE_MSG 0x26 // ??? Some form of table populate
#define CMD_IAQ_PAGE_BUTTON 0x24
#define CMD_IAQ_PAGE_START 0x23 // Start a new menu // wait for 0x28 before sending anything
#define CMD_IAQ_PAGE_END 0x28 // Some kind a finished
#define CMD_IAQ_STARTUP 0x29 // Startup message
#define CMD_IAQ_POLL 0x30 // Poll message or ready to receive command
#define CMD_IAQ_CTRL_READY 0x31 // Get this when we can send big control command
#define CMD_IAQ_PAGE_CONTINUE 0x40 // Seems we get this on AUX device page when there is another page, keeps circuling through pages.
//#define CMD_IAQ_VSP_ERROR 0x2c // Error when setting speed too high
#define CMD_IAQ_MSG_LONG 0x2c // This this is display popup message. Next 2 bytes 0x00|0x01 = wait and then 0x00|0x00 clear
/*
#define CMD_IAQ_MSG_3 0x2d // Equiptment status message??
#define CMD_IAQ_0x30 0x30
#define CMD_IAQ_0x23 0x23
#define CMD_IAQ_0x24 0x24 // Text for labels or maybe buttons (looks like next BIT is placment)
#define CMD_IAQ_0x25 0x25 // Status for labels
#define CMD_IAQ_0x31 0x31 // Some pump speed info
*/
#define ACK_CMD_READY_CTRL 0x80 // Send this before sending big control command
#define IAQ_KEY_PUMP 0x11
#define IAQ_KEY_SPA 0x12
#define IAQ_KEY_POOL_HEAT 0x13
#define IAQ_KEY_SPA_HEAT 0x14
#define IAQ_KEY_CUST_1 0x15
#define IAQ_KEY_CUST_2 0x16
#define IAQ_KEY_CUST_3 0x17
#define IAQ_KEY_AUX1 0x19 // Depending on page this is 0x15
#define IAQ_KEY_AUX2 0x1a
#define IAQ_KEY_AUX3 0x1b
#define IAQ_KEY_AUX4 0x1c
#define IAQ_KEY_AUX5 0x1d
#define IAQ_KEY_AUX6 0x1e
#define IAQ_KEY_AUX7 0x1f
#define KEY_IAQTCH_HOME 0x01
#define KEY_IAQTCH_MENU 0x02
#define KEY_IAQTCH_ONETOUCH 0x03
#define KEY_IAQTCH_HELP 0x04
#define KEY_IAQTCH_BACK 0x05
#define KEY_IAQTCH_STATUS 0x06
#define KEY_IAQTCH_PREV_PAGE 0x20
#define KEY_IAQTCH_NEXT_PAGE 0x21
// PAGE1 (Horosontal keys) (These are duplicate so probable delete)
#define KEY_IAQTCH_HOMEP_KEY01 0x11
#define KEY_IAQTCH_HOMEP_KEY02 0x12
#define KEY_IAQTCH_HOMEP_KEY03 0x13
#define KEY_IAQTCH_HOMEP_KEY04 0x14
#define KEY_IAQTCH_HOMEP_KEY05 0x15
#define KEY_IAQTCH_HOMEP_KEY06 0x16
#define KEY_IAQTCH_HOMEP_KEY07 0x17
#define KEY_IAQTCH_HOMEP_KEY08 0x18 // Other Devices (may not be able to change)
// Numbering is colum then row.
#define KEY_IAQTCH_KEY01 0x11 // Column 1 row 1
#define KEY_IAQTCH_KEY02 0x12 // column 1 row 2
#define KEY_IAQTCH_KEY03 0x13 // column 1 row 3
#define KEY_IAQTCH_KEY04 0x14 // column 1 row 4
#define KEY_IAQTCH_KEY05 0x15 // column 1 row 5
#define KEY_IAQTCH_KEY06 0x16 // column 2 row 1
#define KEY_IAQTCH_KEY07 0x17 // column 2 row 2
#define KEY_IAQTCH_KEY08 0x18 // column 2 row 3
#define KEY_IAQTCH_KEY09 0x19 // column 2 row 4
#define KEY_IAQTCH_KEY10 0x1a // column 2 row 5
#define KEY_IAQTCH_KEY11 0x1b // column 3 row 1
#define KEY_IAQTCH_KEY12 0x1c // column 3 row 2
#define KEY_IAQTCH_KEY13 0x1d // column 3 row 3
#define KEY_IAQTCH_KEY14 0x1e // column 3 row 4
#define KEY_IAQTCH_KEY15 0x1f // column 3 row 5
#define IAQ_PAGE_HOME 0x01
#define IAQ_PAGE_STATUS 0x5b
#define IAQ_PAGE_STATUS2 0x2a // Something get this for Status rather than 0x5b
#define IAQ_PAGE_DEVICES 0x36
#define IAQ_PAGE_DEVICES2 0x35
#define IAQ_PAGE_SET_TEMP 0x39
#define IAQ_PAGE_MENU 0x0f
#define IAQ_PAGE_SET_VSP 0x1e
#define IAQ_PAGE_SET_TIME 0x4b
#define IAQ_PAGE_SET_DATE 0x4e
#define IAQ_PAGE_SET_SWG 0x30
#define IAQ_PAGE_SET_BOOST 0x1d
#define IAQ_PAGE_SET_QBOOST 0x3f
#define IAQ_PAGE_ONETOUCH 0x4d
#define IAQ_PAGE_COLOR_LIGHT 0x48
#define IAQ_PAGE_SYSTEM_SETUP 0x14
#define IAQ_PAGE_VSP_SETUP 0x2d
#define IAQ_PAGE_FREEZE_PROTECT 0x11
#define IAQ_PAGE_LABEL_AUX 0x32
//#define IAQ_PAGE_START_BOOST 0x3f
// At the moment just used for next ack
typedef enum {
@ -360,10 +423,10 @@ typedef enum {
int init_serial_port(const char* tty);
void close_serial_port(int file_descriptor);
#ifdef AQ_PDA
void set_pda_mode(bool mode);
bool pda_mode();
#endif
//#ifdef AQ_PDA
//void set_pda_mode(bool mode);
//bool pda_mode();
//#endif
int generate_checksum(unsigned char* packet, int length);
protocolType getProtocolType(unsigned char* packet);
bool check_jandy_checksum(unsigned char* packet, int length);
@ -380,13 +443,16 @@ int get_packet_lograw(int fd, unsigned char* packet);
//void process_status(void const * const ptr);
void process_status(unsigned char* ptr);
const char* get_packet_type(unsigned char* packet , int length);
/*
void set_onetouch_enabled(bool mode);
bool onetouch_enabled();
void set_iaqtouch_enabled(bool mode);
bool iaqtouch_enabled();
bool VSP_enabled();
void set_extended_device_id_programming(bool mode);
bool extended_device_id_programming();
*/
void send_jandy_command(int fd, unsigned char *packet_buffer, int size);
void send_pentair_command(int fd, unsigned char *packet_buffer, int size);
@ -401,4 +467,4 @@ bool onetouch_mode();
//void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
//void send_command(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
//void send_messaged(int fd, unsigned char destination, char *message);
#endif // AQ_SERIAL_H_
#endif // AQ_SERIAL_H_

View File

@ -6,6 +6,7 @@
#include <stdbool.h>
#include "aq_serial.h"
#include "aq_programmer.h"
#include "aq_panel.h"
#define TIME_CHECK_INTERVAL 3600
#define ACCEPTABLE_TIME_DIFF 120
@ -14,11 +15,11 @@
//#define TIME_CHECK_INTERVAL 100
//#define ACCEPTABLE_TIME_DIFF 10
#define MAX_ZERO_READ_BEFORE_RECONNECT 500
#define MAX_ZERO_READ_BEFORE_RECONNECT 2000 // 500
//#define TOTAL_BUTTONS 12
/*
#ifndef AQ_RS16
#define TOTAL_BUTTONS 12
#else
@ -26,7 +27,7 @@
#define RS16_VBUTTONS_START 13 // RS16 panel has 4 buttons with no LED's, so list them for manual matching to RS messages
#define RS16_VBUTTONS_END 16 // RS16 panel has 4 buttons with no LED's, so list them for manual matching to RS messages
#endif
*/
#define TEMP_UNKNOWN -999
//#define UNKNOWN TEMP_UNKNOWN
#define DATE_STRING_LEN 30
@ -47,9 +48,9 @@ typedef struct aqualinkkey
aqled *led;
char *label;
char *name;
#ifdef AQ_PDA
char *pda_label;
#endif
//#ifdef AQ_PDA
// char *pda_label;
//#endif
unsigned char code;
int dz_idx;
} aqkey;
@ -72,7 +73,8 @@ typedef enum action_type {
FREEZE_SETPOINT,
SWG_SETPOINT,
SWG_BOOST,
PUMP_RPM
PUMP_RPM,
PUMP_VSPROGRAM
} action_type;
struct action {
@ -93,6 +95,13 @@ typedef enum pump_type {
} pump_type;
*/
#define PUMP_PRIMING -1
#define PUMP_OFFLINE -2
#define PUMP_ERROR -3
#define PUMP_OFF_RPM 0
#define PUMP_OFF_GPM PUMP_OFF_RPM
#define PUMP_OFF_WAT PUMP_OFF_RPM
typedef struct pumpd
{
int rpm;
@ -125,38 +134,27 @@ typedef struct clightd
struct aqualinkdata
{
//char crap[AQ_MSGLEN];
char version[AQ_MSGLEN*2];
char date[AQ_MSGLEN];
char time[AQ_MSGLEN];
//char datestr[DATE_STRING_LEN];
char last_message[AQ_MSGLONGLEN+1]; // NSF just temp for PDA crap
//char *last_message; // Be careful using this, can get core dumps.
char last_display_message[AQ_MSGLONGLEN+1];
//bool display_last_message;
unsigned char raw_status[AQ_PSTLEN];
aqled aqualinkleds[TOTAL_LEDS];
aqkey aqbuttons[TOTAL_BUTTONS];
unsigned short total_buttons; // Should probably malloc the above to this in the future
//aqkey *aqbuttons;
unsigned short total_buttons;
int air_temp;
int pool_temp;
int spa_temp;
int temp_units;
bool single_device; // Pool or Spa only, not Pool & Spa (Thermostat setpoints are different)
//bool single_device; // Pool or Spa only, not Pool & Spa (Thermostat setpoints are different)
int battery;
//int freeze_protection;
int frz_protect_set_point;
int pool_htr_set_point;
int spa_htr_set_point;
//unsigned char aq_command;
struct programmingthread active_thread;
struct action unactioned;
int swg_percent;
int swg_ppm;
unsigned char ar_swg_status;
int swg_delayed_percent;
bool simulate_panel;
unsigned char ar_swg_device_status; // Actual state
aqledstate swg_led_state; // Display state for UI's
aqledstate service_mode_state;
aqledstate frz_protect_state;
unsigned char last_packet_type;
@ -164,13 +162,33 @@ struct aqualinkdata
pump_detail pumps[MAX_PUMPS];
int num_lights;
clight_detail lights[MAX_LIGHTS];
int open_websockets;
bool boost;
char boost_msg[10];
float ph;
int orp;
//bool last_msg_was_status;
//bool ar_swg_connected;
// Below this line is not state related. (Future just do a mem compare for change)
//aqkey *orderedbuttons[TOTAL_BUTTONS]; // Future to reduce RS4,6,8,12,16 & spa buttons
//unsigned short total_ordered_buttons;
int swg_delayed_percent;
bool simulate_panel;
int open_websockets;
struct programmingthread active_thread;
struct action unactioned;
unsigned char raw_status[AQ_PSTLEN];
// Multiple threads update this value.
volatile bool updated;
#ifdef AQ_RS16
int rs16_vbutton_start;
int rs16_vbutton_end;
#endif
#ifdef AQ_PDA
int pool_heater_index;
int spa_heater_index;
int solar_heater_index;
#endif
// Timing for DEBUG
#ifdef AQ_DEBUG
struct timespec last_active_time;
struct timespec start_active_time;

File diff suppressed because it is too large Load Diff

742
boost_msg Normal file
View File

@ -0,0 +1,742 @@
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[7-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_PUMP):BTN_PDA_PUMP;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_PUMP;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_PUMP;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[6-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_SPA):BTN_PDA_SPA;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_SPA;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_SPA;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[5-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX1):BTN_PDA_AUX1;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX1;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX1;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[4-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX2):BTN_PDA_AUX2;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX2;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX2;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[3-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX3):BTN_PDA_AUX3;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX3;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX3;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[9-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX4):BTN_PDA_AUX4;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX4;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX4;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[8-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX5):BTN_PDA_AUX5;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX5;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX5;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX6):BTN_PDA_AUX6;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX6;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX6;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_AUX7):BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX7;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX7;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index-4].led = &aqdata->aqualinkleds[2-1]; // Change
aq_panel.c: aqdata->aqbuttons[index-4].code = KEY_RS16_AUX4;
aq_panel.c: aqdata->aqbuttons[index-3].led = &aqdata->aqualinkleds[11-1]; // Change
aq_panel.c: aqdata->aqbuttons[index-3].code = KEY_RS16_AUX5;
aq_panel.c: aqdata->aqbuttons[index-2].led = &aqdata->aqualinkleds[10-1]; // Change
aq_panel.c: aqdata->aqbuttons[index-2].code = KEY_RS16_AUX6;
aq_panel.c: aqdata->aqbuttons[index-1].led = &aqdata->aqualinkleds[9-1]; // change
aq_panel.c: aqdata->aqbuttons[index-1].code = KEY_RS16_AUX7;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[8-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB1); // AUX8
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB1;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB1;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB2); // AUX9
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB2;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB2;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[1-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB3); // AUX10
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB3;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB3;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[13-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB4); // AUX11
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB4;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB4;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[21-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB5);
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB5;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB5;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[22-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB6);
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB6;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB6;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[23-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB7);
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB7;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB7;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[24-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[index].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUXB8);
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUXB8;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUXB8;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[12-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = name2label(BTN_AUX6);
aq_panel.c: aqdata->aqbuttons[index].name = BTN_AUX6;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_AUX6;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[i].name = aqdata->aqbuttons[i+1].name;
aq_panel.c: aqdata->aqbuttons[i].label = aqdata->aqbuttons[i+1].label;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[15-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_POOL_HTR):BTN_PDA_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[17-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_SPA_HTR):BTN_PDA_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[index].led = &aqdata->aqualinkleds[19-1];
aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[index].label = rs?name2label(BTN_SOLAR_HTR):BTN_PDA_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[index].name = BTN_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[index].code = KEY_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[index].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->total_buttons = index;
aq_panel.c: //aqdata->single_device = !combo;
aq_panel.c: aqdata->rs16_vbutton_start = 13 - (combo?0:1);
aq_panel.c: aqdata->rs16_vbutton_end = 16 - (combo?0:1);
aq_panel.c: aqdata->pool_heater_index = index-3;
aq_panel.c: aqdata->spa_heater_index = index-2;
aq_panel.c: aqdata->solar_heater_index = index-1;
aq_panel.c: aqdata->aqbuttons[0].led = &aqdata->aqualinkleds[7-1];
aq_panel.c: aqdata->aqbuttons[0].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[0].label = name2label(BTN_PUMP);
aq_panel.c: aqdata->aqbuttons[0].name = BTN_PUMP;
aq_panel.c: aqdata->aqbuttons[0].code = KEY_PUMP;
aq_panel.c: aqdata->aqbuttons[0].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[1].led = &aqdata->aqualinkleds[6-1];
aq_panel.c: aqdata->aqbuttons[1].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[1].label = name2label(BTN_SPA);
aq_panel.c: aqdata->aqbuttons[1].name = BTN_SPA;
aq_panel.c: aqdata->aqbuttons[1].code = KEY_SPA;
aq_panel.c: aqdata->aqbuttons[1].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[2].led = &aqdata->aqualinkleds[5-1];
aq_panel.c: aqdata->aqbuttons[2].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[2].label = name2label(BTN_AUX1);
aq_panel.c: aqdata->aqbuttons[2].name = BTN_AUX1;
aq_panel.c: aqdata->aqbuttons[2].code = KEY_AUX1;
aq_panel.c: aqdata->aqbuttons[2].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[3].led = &aqdata->aqualinkleds[4-1];
aq_panel.c: aqdata->aqbuttons[3].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[3].label = name2label(BTN_AUX2);
aq_panel.c: aqdata->aqbuttons[3].name = BTN_AUX2;
aq_panel.c: aqdata->aqbuttons[3].code = KEY_AUX2;
aq_panel.c: aqdata->aqbuttons[3].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[4].led = &aqdata->aqualinkleds[3-1];
aq_panel.c: aqdata->aqbuttons[4].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[4].label = name2label(BTN_AUX3);
aq_panel.c: aqdata->aqbuttons[4].name = BTN_AUX3;
aq_panel.c: aqdata->aqbuttons[4].code = KEY_AUX3;
aq_panel.c: aqdata->aqbuttons[4].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[5].led = &aqdata->aqualinkleds[9-1];
aq_panel.c: aqdata->aqbuttons[5].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[5].label = name2label(BTN_AUX4);
aq_panel.c: aqdata->aqbuttons[5].name = BTN_AUX4;
aq_panel.c: aqdata->aqbuttons[5].code = KEY_AUX4;
aq_panel.c: aqdata->aqbuttons[5].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[6].led = &aqdata->aqualinkleds[8-1];
aq_panel.c: aqdata->aqbuttons[6].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[6].label = name2label(BTN_AUX5);
aq_panel.c: aqdata->aqbuttons[6].name = BTN_AUX5;
aq_panel.c: aqdata->aqbuttons[6].code = KEY_AUX5;
aq_panel.c: aqdata->aqbuttons[6].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[7].led = &aqdata->aqualinkleds[12-1];
aq_panel.c: aqdata->aqbuttons[7].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[7].label = name2label(BTN_AUX6);
aq_panel.c: aqdata->aqbuttons[7].name = BTN_AUX6;
aq_panel.c: aqdata->aqbuttons[7].code = KEY_AUX6;
aq_panel.c: aqdata->aqbuttons[7].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[8].led = &aqdata->aqualinkleds[1-1];
aq_panel.c: aqdata->aqbuttons[8].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[8].label = name2label(BTN_AUX7);
aq_panel.c: aqdata->aqbuttons[8].name = BTN_AUX7;
aq_panel.c: aqdata->aqbuttons[8].code = KEY_AUX7;
aq_panel.c: aqdata->aqbuttons[8].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[9].led = &aqdata->aqualinkleds[15-1];
aq_panel.c: aqdata->aqbuttons[9].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[9].label = name2label(BTN_POOL_HTR);
aq_panel.c: aqdata->aqbuttons[9].name = BTN_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[9].code = KEY_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[9].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[10].led = &aqdata->aqualinkleds[17-1];
aq_panel.c: aqdata->aqbuttons[10].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[10].label = name2label(BTN_SPA_HTR);
aq_panel.c: aqdata->aqbuttons[10].name = BTN_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[10].code = KEY_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[10].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[11].led = &aqdata->aqualinkleds[19-1];
aq_panel.c: aqdata->aqbuttons[11].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[11].label = name2label(BTN_SOLAR_HTR);
aq_panel.c: aqdata->aqbuttons[11].name = BTN_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[11].code = KEY_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[11].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[0].pda_label = BTN_PDA_PUMP;
aq_panel.c: aqdata->aqbuttons[1].pda_label = BTN_PDA_SPA;
aq_panel.c: aqdata->aqbuttons[2].pda_label = BTN_PDA_AUX1;
aq_panel.c: aqdata->aqbuttons[3].pda_label = BTN_PDA_AUX2;
aq_panel.c: aqdata->aqbuttons[4].pda_label = BTN_PDA_AUX3;
aq_panel.c: aqdata->aqbuttons[5].pda_label = BTN_PDA_AUX4;
aq_panel.c: aqdata->aqbuttons[6].pda_label = BTN_PDA_AUX5;
aq_panel.c: aqdata->aqbuttons[7].pda_label = BTN_PDA_AUX6;
aq_panel.c: aqdata->aqbuttons[7].pda_label = BTN_PDA_AUX6;
aq_panel.c: aqdata->aqbuttons[8].pda_label = BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[9].pda_label = BTN_PDA_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[10].pda_label = BTN_PDA_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[11].pda_label = BTN_PDA_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[5].led = &aqdata->aqualinkleds[2-1]; // Change
aq_panel.c: aqdata->aqbuttons[5].code = KEY_RS16_AUX4;
aq_panel.c: aqdata->aqbuttons[6].led = &aqdata->aqualinkleds[11-1]; // Change
aq_panel.c: aqdata->aqbuttons[6].code = KEY_RS16_AUX5;
aq_panel.c: aqdata->aqbuttons[7].led = &aqdata->aqualinkleds[10-1]; // Change
aq_panel.c: aqdata->aqbuttons[7].code = KEY_RS16_AUX6;
aq_panel.c: aqdata->aqbuttons[8].led = &aqdata->aqualinkleds[9-1]; // change
aq_panel.c: aqdata->aqbuttons[8].code = KEY_RS16_AUX7;
aq_panel.c: aqdata->aqbuttons[9].led = &aqdata->aqualinkleds[8-1];
aq_panel.c: aqdata->aqbuttons[9].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[9].label = name2label(BTN_AUXB1); // AUX8
aq_panel.c: aqdata->aqbuttons[9].name = BTN_AUXB1;
aq_panel.c: aqdata->aqbuttons[9].code = KEY_AUXB1;
aq_panel.c: aqdata->aqbuttons[9].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[10].led = &aqdata->aqualinkleds[12-1];
aq_panel.c: aqdata->aqbuttons[10].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[10].label = name2label(BTN_AUXB2); // AUX9
aq_panel.c: aqdata->aqbuttons[10].name = BTN_AUXB2;
aq_panel.c: aqdata->aqbuttons[10].code = KEY_AUXB2;
aq_panel.c: aqdata->aqbuttons[10].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[11].led = &aqdata->aqualinkleds[1-1];
aq_panel.c: aqdata->aqbuttons[11].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[11].label = name2label(BTN_AUXB3); // AUX10
aq_panel.c: aqdata->aqbuttons[11].name = BTN_AUXB3;
aq_panel.c: aqdata->aqbuttons[11].code = KEY_AUXB3;
aq_panel.c: aqdata->aqbuttons[11].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[12].led = &aqdata->aqualinkleds[13-1];
aq_panel.c: aqdata->aqbuttons[12].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[12].label = name2label(BTN_AUXB4); // AUX11
aq_panel.c: aqdata->aqbuttons[12].name = BTN_AUXB4;
aq_panel.c: aqdata->aqbuttons[12].code = KEY_AUXB4;
aq_panel.c: aqdata->aqbuttons[12].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[13].led = &aqdata->aqualinkleds[21-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[13].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[13].label = name2label(BTN_AUXB5);
aq_panel.c: aqdata->aqbuttons[13].name = BTN_AUXB5;
aq_panel.c: aqdata->aqbuttons[13].code = KEY_AUXB5;
aq_panel.c: aqdata->aqbuttons[13].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[14].led = &aqdata->aqualinkleds[22-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[14].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[14].label = name2label(BTN_AUXB6);
aq_panel.c: aqdata->aqbuttons[14].name = BTN_AUXB6;
aq_panel.c: aqdata->aqbuttons[14].code = KEY_AUXB6;
aq_panel.c: aqdata->aqbuttons[14].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[15].led = &aqdata->aqualinkleds[23-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[15].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[15].label = name2label(BTN_AUXB7);
aq_panel.c: aqdata->aqbuttons[15].name = BTN_AUXB7;
aq_panel.c: aqdata->aqbuttons[15].code = KEY_AUXB7;
aq_panel.c: aqdata->aqbuttons[15].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[16].led = &aqdata->aqualinkleds[24-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[16].led->state = OFF; // Since there is no LED in data, set to off and allow messages to turn it on
aq_panel.c: aqdata->aqbuttons[16].label = name2label(BTN_AUXB8);
aq_panel.c: aqdata->aqbuttons[16].name = BTN_AUXB8;
aq_panel.c: aqdata->aqbuttons[16].code = KEY_AUXB8;
aq_panel.c: aqdata->aqbuttons[16].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[17].led = &aqdata->aqualinkleds[15-1];
aq_panel.c: aqdata->aqbuttons[17].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[17].label = name2label(BTN_POOL_HTR);
aq_panel.c: aqdata->aqbuttons[17].name = BTN_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[17].code = KEY_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[17].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[18].led = &aqdata->aqualinkleds[17-1];
aq_panel.c: aqdata->aqbuttons[18].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[18].label = name2label(BTN_SPA_HTR);
aq_panel.c: aqdata->aqbuttons[18].name = BTN_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[18].code = KEY_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[18].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[19].led = &aqdata->aqualinkleds[19-1];
aq_panel.c: aqdata->aqbuttons[19].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[19].label = name2label(BTN_SOLAR_HTR);
aq_panel.c: aqdata->aqbuttons[19].name = BTN_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[19].code = KEY_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[19].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[9].pda_label = BTN_PDA_AUX1;
aq_panel.c: aqdata->aqbuttons[10].pda_label = BTN_PDA_AUX2;
aq_panel.c: aqdata->aqbuttons[11].pda_label = BTN_PDA_AUX3;
aq_panel.c: aqdata->aqbuttons[12].pda_label = BTN_PDA_AUX4;
aq_panel.c: aqdata->aqbuttons[13].pda_label = BTN_PDA_AUX5;
aq_panel.c: aqdata->aqbuttons[14].pda_label = BTN_PDA_AUX6;
aq_panel.c: aqdata->aqbuttons[15].pda_label = BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[16].pda_label = BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[17].pda_label = BTN_PDA_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[18].pda_label = BTN_PDA_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[19].pda_label = BTN_PDA_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[0].led = &aqdata->aqualinkleds[7-1];
aq_panel.c: aqdata->aqbuttons[0].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[0].label = name2label(BTN_PUMP);
aq_panel.c: aqdata->aqbuttons[0].name = BTN_PUMP;
aq_panel.c: aqdata->aqbuttons[0].code = KEY_PUMP;
aq_panel.c: aqdata->aqbuttons[0].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[0].pda_label = BTN_PDA_PUMP;
aq_panel.c: aqdata->aqbuttons[1].led = &aqdata->aqualinkleds[6-1];
aq_panel.c: aqdata->aqbuttons[1].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[1].label = name2label(BTN_SPA);
aq_panel.c: aqdata->aqbuttons[1].name = BTN_SPA;
aq_panel.c: aqdata->aqbuttons[1].code = KEY_SPA;
aq_panel.c: aqdata->aqbuttons[1].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[1].pda_label = BTN_PDA_SPA;
aq_panel.c: aqdata->aqbuttons[2].led = &aqdata->aqualinkleds[5-1];
aq_panel.c: aqdata->aqbuttons[2].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[2].label = name2label(BTN_AUX1);
aq_panel.c: aqdata->aqbuttons[2].name = BTN_AUX1;
aq_panel.c: aqdata->aqbuttons[2].code = KEY_AUX1;
aq_panel.c: aqdata->aqbuttons[2].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[2].pda_label = BTN_PDA_AUX1;
aq_panel.c: aqdata->aqbuttons[3].led = &aqdata->aqualinkleds[4-1];
aq_panel.c: aqdata->aqbuttons[3].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[3].label = name2label(BTN_AUX2);
aq_panel.c: aqdata->aqbuttons[3].name = BTN_AUX2;
aq_panel.c: aqdata->aqbuttons[3].code = KEY_AUX2;
aq_panel.c: aqdata->aqbuttons[3].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[3].pda_label = BTN_PDA_AUX2;
aq_panel.c: aqdata->aqbuttons[4].led = &aqdata->aqualinkleds[3-1];
aq_panel.c: aqdata->aqbuttons[4].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[4].label = BTN_AUX3;
aq_panel.c: aqdata->aqbuttons[4].name = BTN_AUX3;
aq_panel.c: aqdata->aqbuttons[4].code = KEY_AUX3;
aq_panel.c: aqdata->aqbuttons[4].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[4].pda_label = BTN_PDA_AUX3;
aq_panel.c: aqdata->aqbuttons[5].led = &aqdata->aqualinkleds[2-1]; // Change
aq_panel.c: aqdata->aqbuttons[5].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[5].label = name2label(BTN_AUX4);
aq_panel.c: aqdata->aqbuttons[5].name = BTN_AUX4;
aq_panel.c: aqdata->aqbuttons[5].code = KEY_AUX4;
aq_panel.c: aqdata->aqbuttons[5].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[5].pda_label = BTN_PDA_AUX4;
aq_panel.c: aqdata->aqbuttons[6].led = &aqdata->aqualinkleds[11-1]; // Change
aq_panel.c: aqdata->aqbuttons[6].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[6].label = name2label(BTN_AUX5);
aq_panel.c: aqdata->aqbuttons[6].name = BTN_AUX5;
aq_panel.c: aqdata->aqbuttons[6].code = KEY_AUX5;
aq_panel.c: aqdata->aqbuttons[6].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[6].pda_label = BTN_PDA_AUX5;
aq_panel.c: aqdata->aqbuttons[7].led = &aqdata->aqualinkleds[10-1]; // Change
aq_panel.c: aqdata->aqbuttons[7].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[7].label = name2label(BTN_AUX6);
aq_panel.c: aqdata->aqbuttons[7].name = BTN_AUX6;
aq_panel.c: aqdata->aqbuttons[7].code = KEY_AUX6;
aq_panel.c: aqdata->aqbuttons[7].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[7].pda_label = BTN_PDA_AUX6;
aq_panel.c: aqdata->aqbuttons[8].led = &aqdata->aqualinkleds[9-1]; // change
aq_panel.c: aqdata->aqbuttons[8].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[8].label = name2label(BTN_AUX7);
aq_panel.c: aqdata->aqbuttons[8].name = BTN_AUX7;
aq_panel.c: aqdata->aqbuttons[8].code = KEY_AUX7;
aq_panel.c: aqdata->aqbuttons[8].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[8].pda_label = BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[9].led = &aqdata->aqualinkleds[8-1];
aq_panel.c: aqdata->aqbuttons[9].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[9].label = name2label(BTN_AUXB1); // AUX8
aq_panel.c: aqdata->aqbuttons[9].name = BTN_AUXB1;
aq_panel.c: aqdata->aqbuttons[9].code = KEY_AUXB1;
aq_panel.c: aqdata->aqbuttons[9].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[9].pda_label = BTN_PDA_AUX1;
aq_panel.c: aqdata->aqbuttons[10].led = &aqdata->aqualinkleds[12-1];
aq_panel.c: aqdata->aqbuttons[10].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[10].label = name2label(BTN_AUXB2); // AUX9
aq_panel.c: aqdata->aqbuttons[10].name = BTN_AUXB2;
aq_panel.c: aqdata->aqbuttons[10].code = KEY_AUXB2;
aq_panel.c: aqdata->aqbuttons[10].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[10].pda_label = BTN_PDA_AUX2;
aq_panel.c: aqdata->aqbuttons[11].led = &aqdata->aqualinkleds[1-1];
aq_panel.c: aqdata->aqbuttons[11].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[11].label = name2label(BTN_AUXB3); // AUX10
aq_panel.c: aqdata->aqbuttons[11].name = BTN_AUXB3;
aq_panel.c: aqdata->aqbuttons[11].code = KEY_AUXB3;
aq_panel.c: aqdata->aqbuttons[11].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[11].pda_label = BTN_PDA_AUX3;
aq_panel.c: aqdata->aqbuttons[12].led = &aqdata->aqualinkleds[13-1];
aq_panel.c: aqdata->aqbuttons[12].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[12].label = name2label(BTN_AUXB4); // AUX11
aq_panel.c: aqdata->aqbuttons[12].name = BTN_AUXB4;
aq_panel.c: aqdata->aqbuttons[12].code = KEY_AUXB4;
aq_panel.c: aqdata->aqbuttons[12].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[12].pda_label = BTN_PDA_AUX4;
aq_panel.c: aqdata->aqbuttons[13].led = &aqdata->aqualinkleds[21-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[13].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[13].label = name2label(BTN_AUXB5);
aq_panel.c: aqdata->aqbuttons[13].name = BTN_AUXB5;
aq_panel.c: aqdata->aqbuttons[13].code = KEY_AUXB5;
aq_panel.c: aqdata->aqbuttons[13].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[13].pda_label = BTN_PDA_AUX5;
aq_panel.c: aqdata->aqbuttons[14].led = &aqdata->aqualinkleds[22-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[14].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[14].label = name2label(BTN_AUXB6);
aq_panel.c: aqdata->aqbuttons[14].name = BTN_AUXB6;
aq_panel.c: aqdata->aqbuttons[14].code = KEY_AUXB6;
aq_panel.c: aqdata->aqbuttons[14].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[14].pda_label = BTN_PDA_AUX6;
aq_panel.c: aqdata->aqbuttons[15].led = &aqdata->aqualinkleds[23-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[15].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[15].label = name2label(BTN_AUXB7);
aq_panel.c: aqdata->aqbuttons[15].name = BTN_AUXB7;
aq_panel.c: aqdata->aqbuttons[15].code = KEY_AUXB7;
aq_panel.c: aqdata->aqbuttons[15].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[15].pda_label = BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[16].led = &aqdata->aqualinkleds[24-1]; // doesn't actually exist
aq_panel.c: aqdata->aqbuttons[16].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[16].label = name2label(BTN_AUXB8);
aq_panel.c: aqdata->aqbuttons[16].name = BTN_AUXB8;
aq_panel.c: aqdata->aqbuttons[16].code = KEY_AUXB8;
aq_panel.c: aqdata->aqbuttons[16].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[16].pda_label = BTN_PDA_AUX7;
aq_panel.c: aqdata->aqbuttons[17].led = &aqdata->aqualinkleds[15-1];
aq_panel.c: aqdata->aqbuttons[17].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[17].label = name2label(BTN_POOL_HTR);
aq_panel.c: aqdata->aqbuttons[17].name = BTN_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[17].code = KEY_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[17].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[17].pda_label = BTN_PDA_POOL_HTR;
aq_panel.c: aqdata->aqbuttons[18].led = &aqdata->aqualinkleds[17-1];
aq_panel.c: aqdata->aqbuttons[18].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[18].label = name2label(BTN_SPA_HTR);
aq_panel.c: aqdata->aqbuttons[18].name = BTN_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[18].code = KEY_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[18].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[18].pda_label = BTN_PDA_SPA_HTR;
aq_panel.c: aqdata->aqbuttons[19].led = &aqdata->aqualinkleds[19-1];
aq_panel.c: aqdata->aqbuttons[19].led->state = LED_S_UNKNOWN;
aq_panel.c: aqdata->aqbuttons[19].label = name2label(BTN_SOLAR_HTR);
aq_panel.c: aqdata->aqbuttons[19].name = BTN_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[19].code = KEY_SOLAR_HTR;
aq_panel.c: aqdata->aqbuttons[19].dz_idx = DZ_NULL_IDX;
aq_panel.c: aqdata->aqbuttons[19].pda_label = BTN_PDA_SOLAR_HTR;
aq_programmer.c: if ( aqdata->temp_units == CELSIUS ) {
aq_programmer.c: aqdata->spa_htr_set_point != TEMP_UNKNOWN &&
aq_programmer.c: min <= aqdata->spa_htr_set_point)
aq_programmer.c: min = aqdata->spa_htr_set_point + 1;
aq_programmer.c: if ( aqdata->temp_units == CELSIUS ) {
aq_programmer.c: aqdata->pool_htr_set_point != TEMP_UNKNOWN &&
aq_programmer.c: max >= aqdata->pool_htr_set_point)
aq_programmer.c: max = aqdata->pool_htr_set_point - 1;
aq_programmer.c: if ( aqdata->temp_units == CELSIUS ) {
aqualinkd.c: // Loop over only aqdata->aqbuttons[13] to aqdata->aqbuttons[16]
config.c: aqdata->aqbuttons[num].label = cleanalloc(indx+1);
config.c: aqdata->aqbuttons[num].dz_idx = strtoul(indx+1, NULL, 10);
config.c: aqdata->aqbuttons[num].pda_label = cleanalloc(indx+1);
config.c: aqdata->aqbuttons[num].label = cleanalloc(value);
config.c: aqdata->aqbuttons[num].dz_idx = strtoul(value, NULL, 10);
config.c: //aqdata->aqbuttons[num].pda_label = cleanalloc(value);
config.c: aqdata->aqbuttons[num].label = cleanalloc(value);
config.c: if (aqdata->num_lights < MAX_LIGHTS) {
config.c: aqdata->lights[aqdata->num_lights].button = &aqdata->aqbuttons[num];
config.c: aqdata->lights[aqdata->num_lights].lightType = type;
config.c: aqdata->num_lights++;
config.c: //aqdata->aqbuttons[num].pda_label = cleanalloc(value);
config.c: aqdata->pumps[pi].button = &aqdata->aqbuttons[num];
config.c: aqdata->pumps[pi].pumpID = strtoul(cleanalloc(value), NULL, 16);
config.c: aqdata->pumps[pi].pumpIndex = pi+1;
config.c: //aqdata->pumps[pi].buttonID = num;
config.c: if (aqdata->pumps[pi].pumpID < 119)
config.c: aqdata->pumps[pi].ptype = PENTAIR;
config.c: aqdata->pumps[pi].ptype = JANDY;
config.c: //aqdata->num_pumps
config.c: for (pi=0; pi < aqdata->num_pumps; pi++) {
config.c: if (aqdata->pumps[pi].button == &aqdata->aqbuttons[button]) {
config.c: return &aqdata->pumps[pi];
config.c: if (aqdata->num_pumps < MAX_PUMPS) {
config.c: aqdata->pumps[aqdata->num_pumps].button = &aqdata->aqbuttons[button];
config.c: aqdata->pumps[aqdata->num_pumps].pumpType = PT_UNKNOWN;
config.c: aqdata->pumps[aqdata->num_pumps].rpm = TEMP_UNKNOWN;
config.c: aqdata->pumps[aqdata->num_pumps].watts = TEMP_UNKNOWN;
config.c: aqdata->pumps[aqdata->num_pumps].gpm = TEMP_UNKNOWN;
config.c: aqdata->num_pumps++;
config.c: return &aqdata->pumps[aqdata->num_pumps-1];
config.c: fprintf(fp, "button_%.2d_label = %s\n", i+1, aqdata->aqbuttons[i].label);
config.c: if (aqdata->aqbuttons[i].dz_idx > 0)
config.c: fprintf(fp, "button_%.2d_dzidx = %d\n", i+1, aqdata->aqbuttons[i].dz_idx);
config.c: if (aqdata->aqbuttons[i].pda_label != NULL)
config.c: fprintf(fp, "button_%.2d_PDA_label = %s\n", i+1, aqdata->aqbuttons[i].pda_label);
config_new.c: indx = sprintf(bufr, "button_%.2d_label = %s\n", i+1, aqdata->aqbuttons[i].label);
config_new.c: indx += sprintf(&bufr[indx], "button_%.2d_dzidx = %d\n", i+1, aqdata->aqbuttons[i].dz_idx);
config_new.c: if (aqdata->aqbuttons[i].pda_label != NULL)
config_new.c: indx += sprintf(&bufr[indx], "button_%.2d_PDA_label = %s\n", i+1, aqdata->aqbuttons[i].pda_label);
config_new.c: if ( aqdata->pumps[pi].button == &aqdata->aqbuttons[i] ) {
config_new.c: indx += sprintf(&bufr[indx],"button_%.2d_pumpID = 0x%02hhx\n", i+1, aqdata->pumps[pi].pumpID);
config_new.c: indx += sprintf(&bufr[indx],"button_%.2d_pumpIndex = %d\n", i+1, aqdata->pumps[pi].pumpIndex);
config_new.c: for (j = 0; j < aqdata->num_pumps; j++) {
config_new.c: if (aqdata->pumps[j].button == &aqdata->aqbuttons[i]) {
config_new.c: sprintf(vsp,"0x%02hhx",aqdata->pumps[j].pumpID);
config_new.c: alid = aqdata->pumps[j].pumpIndex;
config_new.c: aqdata->aqbuttons[i].name, aqdata->aqbuttons[i].label, vsp, alid, aqdata->aqbuttons[i].dz_idx,
config_new.c: aqdata->aqbuttons[i].name, aqdata->aqbuttons[i].label, vsp, alid,
config_new.c: aqdata->aqbuttons[i].pda_label, aqdata->aqbuttons[i].dz_idx );
config_new.c: for (j = 0; j < aqdata->num_pumps; j++) {
config_new.c: if (aqdata->pumps[j].button == &aqdata->aqbuttons[i]) {
config_new.c: vsp = aqdata->pumps[j].pumpID;
config_new.c: alid = aqdata->pumps[j].pumpIndex;
config_new.c: indx += sprintf(&bufr[indx], "{\"button\":\"%d\",\"label\":\"%s\",\"dzidx\":\"%d\"",i,aqdata->aqbuttons[i].label,aqdata->aqbuttons[i].dz_idx);
config_new.c: aqdata->aqbuttons[i].name, aqdata->aqbuttons[i].label, vsp, alid,
config_new.c: aqdata->aqbuttons[i].pda_label, aqdata->aqbuttons[i].dz_idx );
config_new.c: aqdata->aqbuttons[num].label = cleanalloc(value);
config_new.c: aqdata->aqbuttons[num].dz_idx = strtoul(value, NULL, 10);
config_new.c: aqdata->aqbuttons[num].pda_label = cleanalloc(value);
config_new.c: //aqdata->num_pumps
config_new.c: for (pi=0; pi < aqdata->num_pumps; pi++) {
config_new.c: if (aqdata->pumps[pi].button == &aqdata->aqbuttons[button]) {
config_new.c: return &aqdata->pumps[pi];
config_new.c: if (aqdata->num_pumps < MAX_PUMPS) {
config_new.c: aqdata->pumps[aqdata->num_pumps].button = &aqdata->aqbuttons[button];
config_new.c: aqdata->pumps[aqdata->num_pumps].pumpType = PT_UNKNOWN;
config_new.c: aqdata->pumps[aqdata->num_pumps].rpm = TEMP_UNKNOWN;
config_new.c: aqdata->pumps[aqdata->num_pumps].watts = TEMP_UNKNOWN;
config_new.c: aqdata->pumps[aqdata->num_pumps].gpm = TEMP_UNKNOWN;
config_new.c: aqdata->num_pumps++;
config_new.c: return &aqdata->pumps[aqdata->num_pumps-1];
devices_jandy.c: if (packet[3] == CMD_PERCENT && aqdata->active_thread.thread_id == 0 && packet[4] != 0xFF) {
devices_jandy.c: if (aqdata->swg_percent != (int)packet[4]) {
devices_jandy.c: aqdata->swg_percent = (int)packet[4];
devices_jandy.c: if (aqdata->swg_percent != (int)packet[4]) {
devices_jandy.c: aqdata->swg_percent = (int)packet[4];
devices_jandy.c: if (aqdata->swg_percent > 100)
devices_jandy.c: aqdata->boost = true;
devices_jandy.c: aqdata->boost = false;
devices_jandy.c: aqdata->ar_swg_device_status = packet[5];
devices_jandy.c: if (aqdata->swg_delayed_percent != TEMP_UNKNOWN && aqdata->ar_swg_device_status == SWG_STATUS_ON) { // We have a delayed % to set.
devices_jandy.c: snprintf(sval, 9, "%d", aqdata->swg_delayed_percent);
devices_jandy.c: LOG(DJAN_LOG, LOG_NOTICE, "Setting SWG %% to %d, from delayed message\n", aqdata->swg_delayed_percent);
devices_jandy.c: aqdata->swg_delayed_percent = TEMP_UNKNOWN;
devices_jandy.c: aqdata->swg_ppm = packet[4] * 100;
devices_jandy.c: aqdata->boost = false;
devices_jandy.c: aqdata->boost_msg[0] = '\0';
devices_jandy.c: aqdata->swg_percent = 0;
devices_jandy.c: LOG(DJAN_LOG, LOG_DEBUG, "Ignoring set SWG %% to %d due to programming SWG\n", aqdata->swg_percent);
devices_jandy.c: if (aqdata->ar_swg_device_status != SWG_STATUS_OFF || aqdata->swg_led_state != OFF)
devices_jandy.c: aqdata->updated = true;
devices_jandy.c: aqdata->ar_swg_device_status = SWG_STATUS_OFF;
devices_jandy.c: aqdata->swg_led_state = OFF;
devices_jandy.c: if (aqdata->swg_led_state != ENABLE) {
devices_jandy.c: aqdata->updated = true;
devices_jandy.c: aqdata->swg_led_state = ENABLE;
devices_jandy.c: aqdata->swg_percent = percent;
devices_jandy.c: aqdata->updated = true;
devices_jandy.c: if (aqdata->swg_percent > 0) {
devices_jandy.c: aqdata->swg_led_state = ON;
devices_jandy.c: if (aqdata->ar_swg_device_status == SWG_STATUS_UNKNOWN)
devices_jandy.c: aqdata->ar_swg_device_status = SWG_STATUS_ON;
devices_jandy.c: } if ( aqdata->swg_percent == 0 ) {
devices_jandy.c: aqdata->swg_led_state = ENABLE;
devices_jandy.c: if (aqdata->ar_swg_device_status == SWG_STATUS_UNKNOWN)
devices_jandy.c: aqdata->ar_swg_device_status = SWG_STATUS_ON; // Maybe this should be off
devices_jandy.c: LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d, LED=%d, FullStatus=0x%02hhx\n", aqdata->swg_percent, aqdata->swg_led_state, aqdata->ar_swg_device_status);
devices_jandy.c: switch (aqdata->ar_swg_device_status) {
devices_jandy.c: return (aqdata->swg_percent > 0?ON:ENABLE);
devices_jandy.c: return (aqdata->swg_percent > 0?ON:ENABLE);
devices_jandy.c: return (aqdata->swg_percent > 0?ON:ENABLE);
devices_jandy.c: return (aqdata->swg_percent > 0?ON:ENABLE);
devices_jandy.c: return (aqdata->swg_percent > 0?ON:ENABLE);
devices_jandy.c: return (aqdata->swg_percent > 0?ON:ENABLE);
devices_jandy.c: switch (aqdata->ar_swg_device_status) {
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_jandy.c: *status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
devices_pentair.c: if ( aqdata->pumps[i].prclType == PENTAIR && aqdata->pumps[i].pumpID == packet[PEN_PKT_FROM] ) {
devices_pentair.c: aqdata->pumps[i].rpm = (packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM];
devices_pentair.c: aqdata->pumps[i].watts = (packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT];
devices_pentair.c: if ( pumpIndex < aqdata->num_pumps && pumpIndex < 0) {
devices_pentair.c: aqdata->pumps[pumpIndex-1].rpm = atoi((char *) &packet_buffer[13]);
devices_pentair.c: aqdata->pumps[pumpIndex-1].gph = atoi((char *) &packet_buffer[13]);
devices_pentair.c: aqdata->pumps[pumpIndex-1].watts = atoi((char *) &packet_buffer[13]);
json_messages.c: if (aqdata->active_thread.thread_id != 0 && !aqdata->simulate_panel) {
json_messages.c: return programtypeDisplayName(aqdata->active_thread.ptype);
json_messages.c: //if (aqdata->last_message != NULL && stristr(aqdata->last_message, "SERVICE") != NULL ) {
json_messages.c: if (aqdata->service_mode_state == ON) {
json_messages.c: } else if (aqdata->service_mode_state == FLASH) {
json_messages.c: if (aqdata->last_display_message[0] != '\0') {
json_messages.c: for(i=0; i < strlen(aqdata->last_display_message); i++ ) {
json_messages.c: if (aqdata->last_display_message[i] <= 31 || aqdata->last_display_message[i] >= 127) {
json_messages.c: aqdata->last_display_message[i] = ' ';
json_messages.c: switch (aqdata->last_display_message[i]) {
json_messages.c: aqdata->last_display_message[i] = ' ';
json_messages.c: //printf("JSON Sending '%s'\n",aqdata->last_display_message);
json_messages.c: return aqdata->last_display_message;
json_messages.c: if (aqdata->display_last_message == true) {
json_messages.c: return aqdata->last_message;
json_messages.c: for (i=0; i < aqdata->num_pumps; i++) {
json_messages.c: if (button == aqdata->pumps[i].button) {
json_messages.c: aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,
json_messages.c: (aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")));
json_messages.c: for (i=0; i < aqdata->num_lights; i++) {
json_messages.c: if (button == aqdata->lights[i].button) {
json_messages.c: length += sprintf(buffer, ",\"type_ext\": \"switch_program\", \"Light_Type\":\"%d\"", aqdata->lights[i].lightType);
json_messages.c: bool homekit_f = (homekit && aqdata->temp_units==FAHRENHEIT);
json_messages.c: length += sprintf(buffer+length, ",\"date\":\"%s\"",aqdata->date );//"09/01/16 THU",
json_messages.c: length += sprintf(buffer+length, ",\"time\":\"%s\"",aqdata->time );//"1:16 PM",
json_messages.c: if ( aqdata->temp_units == FAHRENHEIT )
json_messages.c: else if ( aqdata->temp_units == CELSIUS )
json_messages.c: for (i=0; i < aqdata->total_buttons; i++)
json_messages.c: if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0 && aqdata->pool_htr_set_point != TEMP_UNKNOWN) {
json_messages.c: aqdata->aqbuttons[i].name,
json_messages.c: aqdata->aqbuttons[i].label,
json_messages.c: aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
json_messages.c: LED2text(aqdata->aqbuttons[i].led->state),
json_messages.c: ((homekit_f)?degFtoC(aqdata->pool_htr_set_point):aqdata->pool_htr_set_point),
json_messages.c: ((homekit_f)?degFtoC(aqdata->pool_temp):aqdata->pool_temp),
json_messages.c: LED2int(aqdata->aqbuttons[i].led->state));
json_messages.c: } else if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name)==0 && aqdata->spa_htr_set_point != TEMP_UNKNOWN) {
json_messages.c: aqdata->aqbuttons[i].name,
json_messages.c: aqdata->aqbuttons[i].label,
json_messages.c: aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
json_messages.c: LED2text(aqdata->aqbuttons[i].led->state),
json_messages.c: ((homekit_f)?degFtoC(aqdata->spa_htr_set_point):aqdata->spa_htr_set_point),
json_messages.c: ((homekit_f)?degFtoC(aqdata->spa_temp):aqdata->spa_temp),
json_messages.c: LED2int(aqdata->aqbuttons[i].led->state));
json_messages.c: get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info);
json_messages.c: aqdata->aqbuttons[i].name,
json_messages.c: aqdata->aqbuttons[i].label,
json_messages.c: aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
json_messages.c: LED2text(aqdata->aqbuttons[i].led->state),
json_messages.c: LED2int(aqdata->aqbuttons[i].led->state),
json_messages.c: aqdata->aqbuttons[i].name,
json_messages.c: aqdata->aqbuttons[i].label,
json_messages.c: aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
json_messages.c: LED2text(aqdata->aqbuttons[i].led->state),
json_messages.c: LED2int(aqdata->aqbuttons[i].led->state));
json_messages.c: if ( get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info)[0] == '\0' ) {
json_messages.c: aqdata->aqbuttons[i].name,
json_messages.c: aqdata->aqbuttons[i].label,
json_messages.c: aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
json_messages.c: LED2text(aqdata->aqbuttons[i].led->state),
json_messages.c: LED2int(aqdata->aqbuttons[i].led->state));
json_messages.c: aqdata->aqbuttons[i].name,
json_messages.c: aqdata->aqbuttons[i].label,
json_messages.c: aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
json_messages.c: LED2text(aqdata->aqbuttons[i].led->state),
json_messages.c: LED2int(aqdata->aqbuttons[i].led->state),
json_messages.c: //get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info));
json_messages.c: if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) {
json_messages.c: aqdata->frz_protect_state==ON?JSON_ON:JSON_OFF,
json_messages.c: aqdata->frz_protect_state==ON?LED2text(ON):LED2text(ENABLE),
json_messages.c: ((homekit_f)?degFtoC(aqdata->frz_protect_set_point):aqdata->frz_protect_set_point),
json_messages.c: ((homekit_f)?degFtoC(aqdata->air_temp):aqdata->air_temp),
json_messages.c: aqdata->frz_protect_state==ON?1:0);
json_messages.c: if (aqdata->swg_led_state != LED_S_UNKNOWN) {
json_messages.c: if ( aqdata->swg_percent != TEMP_UNKNOWN ) {
json_messages.c: //aqdata->ar_swg_status == SWG_STATUS_OFF?JSON_OFF:JSON_ON,
json_messages.c: aqdata->swg_led_state == OFF?JSON_OFF:JSON_ON,
json_messages.c: LED2text(aqdata->swg_led_state),
json_messages.c: ((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent),
json_messages.c: ((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent),
json_messages.c: LED2int(aqdata->swg_led_state) );
json_messages.c: //aqdata->ar_swg_status == SWG_STATUS_OFF?LED2int(OFF):LED2int(ON));
json_messages.c: ((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent));
json_messages.c: aqdata->boost?JSON_ON:JSON_OFF,
json_messages.c: aqdata->boost?JSON_ON:JSON_OFF,
json_messages.c: aqdata->boost?LED2int(ON):LED2int(OFF));
json_messages.c: if ( aqdata->swg_ppm != TEMP_UNKNOWN ) {
json_messages.c: ((homekit_f)?roundf(degFtoC(aqdata->swg_ppm)):aqdata->swg_ppm));
json_messages.c: aqdata->swg_ppm);
json_messages.c: if ( aqdata->ph != TEMP_UNKNOWN ) {
json_messages.c: ((homekit_f)?(degFtoC(aqdata->ph)):aqdata->ph));
json_messages.c: if ( aqdata->orp != TEMP_UNKNOWN ) {
json_messages.c: ((homekit_f)?(degFtoC(aqdata->orp)):aqdata->orp));
json_messages.c: ((homekit_f)?degFtoC(aqdata->air_temp):aqdata->air_temp));
json_messages.c: ((homekit_f)?degFtoC(aqdata->air_temp):aqdata->pool_temp));
json_messages.c: ((homekit_f)?degFtoC(aqdata->air_temp):aqdata->spa_temp));
json_messages.c: //length += sprintf(buffer+length, ",\"message\":\"%s\"",aqdata->message );
json_messages.c: length += sprintf(buffer+length, ",\"version\":\"%s\"",aqdata->version );//8157 REV MMM",
json_messages.c: length += sprintf(buffer+length, ",\"date\":\"%s\"",aqdata->date );//"09/01/16 THU",
json_messages.c: length += sprintf(buffer+length, ",\"time\":\"%s\"",aqdata->time );//"1:16 PM",
json_messages.c: //length += sprintf(buffer+length, ",\"air_temp\":\"%d\"",aqdata->air_temp );//"96",
json_messages.c: //length += sprintf(buffer+length, ",\"pool_temp\":\"%d\"",aqdata->pool_temp );//"86",
json_messages.c: //length += sprintf(buffer+length, ",\"spa_temp\":\"%d\"",aqdata->spa_temp );//" ",
json_messages.c: length += sprintf(buffer+length, ",\"pool_htr_set_pnt\":\"%d\"",aqdata->pool_htr_set_point );//"85",
json_messages.c: length += sprintf(buffer+length, ",\"spa_htr_set_pnt\":\"%d\"",aqdata->spa_htr_set_point );//"99",
json_messages.c: //length += sprintf(buffer+length, ",\"freeze_protection":\"%s\"",aqdata->frz_protect_set_point );//"off",
json_messages.c: length += sprintf(buffer+length, ",\"frz_protect_set_pnt\":\"%d\"",aqdata->frz_protect_set_point );//"0",
json_messages.c: if ( aqdata->air_temp == TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"air_temp\":\"%d\"",aqdata->air_temp );
json_messages.c: if ( aqdata->pool_temp == TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"pool_temp\":\"%d\"",aqdata->pool_temp );
json_messages.c: if ( aqdata->spa_temp == TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"spa_temp\":\"%d\"",aqdata->spa_temp );
json_messages.c: if (aqdata->swg_led_state != LED_S_UNKNOWN) {
json_messages.c: if ( aqdata->swg_percent != TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"swg_percent\":\"%d\"",aqdata->swg_percent );
json_messages.c: if ( aqdata->swg_ppm != TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"swg_ppm\":\"%d\"",aqdata->swg_ppm );
json_messages.c: if ( aqdata->temp_units == FAHRENHEIT )
json_messages.c: else if ( aqdata->temp_units == CELSIUS )
json_messages.c: if (aqdata->battery == OK)
json_messages.c: if ( aqdata->swg_percent == 101 )
json_messages.c: length += sprintf(buffer+length, ",\"swg_boost_msg\":\"%s\"",aqdata->boost_msg );
json_messages.c: if ( aqdata->ph != TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"chem_ph\":\"%.1f\"",aqdata->ph );
json_messages.c: if ( aqdata->orp != TEMP_UNKNOWN )
json_messages.c: length += sprintf(buffer+length, ",\"chem_orp\":\"%d\"",aqdata->orp );
json_messages.c: for (i=0; i < aqdata->total_buttons; i++)
json_messages.c: char *state = LED2text(aqdata->aqbuttons[i].led->state);
json_messages.c: length += sprintf(buffer+length, "\"%s\": \"%s\"", aqdata->aqbuttons[i].name, state);
json_messages.c: if (i+1 < aqdata->total_buttons)
json_messages.c: if ( aqdata->swg_percent != TEMP_UNKNOWN && aqdata->swg_led_state != LED_S_UNKNOWN ) {
json_messages.c: length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_TOPIC, LED2text(aqdata->swg_led_state));
json_messages.c: //length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_TOPIC, aqdata->ar_swg_status == SWG_STATUS_OFF?JSON_OFF:JSON_ON);
json_messages.c: length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_BOOST_TOPIC, aqdata->boost?JSON_ON:JSON_OFF);
json_messages.c: if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN ) {
json_messages.c: length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, aqdata->frz_protect_state==ON?JSON_ON:JSON_ENABLED);
json_messages.c: for (i=0; i < aqdata->num_pumps; i++) {
json_messages.c:printf("Pump Label %s\n",aqdata->pumps[i].button->label);
json_messages.c:printf("Pump Name %s\n",aqdata->pumps[i].button->name);
json_messages.c:printf("Pump RPM %d\n",aqdata->pumps[i].rpm);
json_messages.c:printf("Pump GPM %d\n",aqdata->pumps[i].gpm);
json_messages.c:printf("Pump GPM %d\n",aqdata->pumps[i].watts);
json_messages.c:printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
json_messages.c: if (aqdata->pumps[i].pumpType != PT_UNKNOWN && (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gpm != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN)) {
json_messages.c: i+1,aqdata->pumps[i].button->label,aqdata->pumps[i].button->name,aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,
json_messages.c: (aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")));
json_messages.c: for (i=0; i < aqdata->total_buttons; i++)
json_messages.c: length += sprintf(buffer+length, ",\"%s\": \"%s\"", aqdata->aqbuttons[i].name, aqdata->aqbuttons[i].label);

148
config.c
View File

@ -37,7 +37,7 @@
#include "config.h"
#include "utils.h"
#include "aq_serial.h"
#include "init_buttons.h"
#include "aq_panel.h"
#define MAXCFGLINE 256
@ -46,21 +46,41 @@
char *generate_mqtt_id(char *buf, int len);
pump_detail *getpump(struct aqualinkdata *aqdata, int button);
struct tmpPanelInfo {
int size;
bool rs;
bool combo;
bool dual;
};
struct tmpPanelInfo *_tmpPanel;
/*
* initialize data to default values
*/
void init_parameters (struct aqconfig * parms)
{
// Set default panel if it get's missed from config
_tmpPanel = malloc(sizeof(struct tmpPanelInfo));
_tmpPanel->size = 8;
_tmpPanel->rs = true;
_tmpPanel->combo = true;
_tmpPanel->dual = false;
//int i;
//char *p;
parms->rs_panel_size = 8;
//parms->rs_panel_size = 8;
parms->serial_port = DEFAULT_SERIALPORT;
parms->log_level = DEFAULT_LOG_LEVEL;
parms->socket_port = DEFAULT_WEBPORT;
parms->web_directory = DEFAULT_WEBROOT;
//parms->device_id = strtoul(DEFAULT_DEVICE_ID, &p, 16);
parms->device_id = strtoul(DEFAULT_DEVICE_ID, NULL, 16);
parms->onetouch_device_id = 0x00;
parms->paneltype_mask = 0;
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
parms->extended_device_id = NUL;
parms->extended_device_id_programming = false;
#endif
//sscanf(DEFAULT_DEVICE_ID, "0x%x", &parms->device_id);
parms->override_freeze_protect = FALSE;
@ -84,10 +104,9 @@ void init_parameters (struct aqconfig * parms)
parms->deamonize = true;
parms->log_file = '\0';
#ifdef AQ_PDA
parms->pda_mode = false;
parms->pda_sleep_mode = false;
#endif
parms->onetouch_mode = false;
//parms->onetouch_mode = false;
parms->convert_mqtt_temp = true;
parms->convert_dz_temp = true;
parms->report_zero_pool_temp = false;
@ -101,7 +120,8 @@ void init_parameters (struct aqconfig * parms)
parms->swg_zero_ignore = DEFAILT_SWG_ZERO_IGNORE_COUNT;
parms->display_warnings_web = false;
parms->log_raw_RS_bytes = false;
parms->extended_device_id_programming = false;
parms->readahead_b4_write = false;
parms->sync_panel_time = true;
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
}
@ -325,7 +345,10 @@ void readCfg_OLD (struct aqconfig *config_parameters, struct aqualinkdata *aqdat
bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
bool rtn = false;
if (strncasecmp(param, "socket_port", 11) == 0) {
if (strncasecmp(param, "debug_log_mask", 14) == 0) {
addDebugLogMask(strtoul(value, NULL, 10));
rtn=true;
} else if (strncasecmp(param, "socket_port", 11) == 0) {
_aqconfig_.socket_port = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "serial_port", 11) == 0) {
@ -336,24 +359,38 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
rtn=true;
} else if (strncasecmp(param, "device_id", 9) == 0) {
_aqconfig_.device_id = strtoul(cleanalloc(value), NULL, 16);
rtn=true;
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
} else if (strncasecmp (param, "extended_device_id_programming", 30) == 0) {
// Has to be before the below.
_aqconfig_.extended_device_id_programming = text2bool(value);
rtn=true;
} else if (strncasecmp(param, "extended_device_id", 9) == 0) {
_aqconfig_.onetouch_device_id = strtoul(cleanalloc(value), NULL, 16);
_aqconfig_.extended_device_id = strtoul(cleanalloc(value), NULL, 16);
//_config_parameters.onetouch_device_id != 0x00
rtn=true;
} else if (strncasecmp(param, "rs_panel_size", 13) == 0) {
_aqconfig_.rs_panel_size = strtoul(value, NULL, 10);
if ( _aqconfig_.rs_panel_size > TOTAL_BUTTONS) {
logMessage(LOG_ERR, "Config error, 'rs_panel_size' is either invalid or too large for compiled parameters, reset to %d\n",TOTAL_BUTTONS);
_aqconfig_.rs_panel_size = TOTAL_BUTTONS;
}
#ifdef AQ_RS16 // Need to re-order button hex values
if (_aqconfig_.rs_panel_size >= 12)
initButtons_RS16(aqdata);
#endif
} else if (strncasecmp(param, "panel_type_size", 15) == 0) {
_tmpPanel->size = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "panel_type_combo", 16) == 0) {
_tmpPanel->combo = text2bool(value);
rtn=true;
} else if (strncasecmp(param, "panel_type_dual", 15) == 0) {
_tmpPanel->dual = text2bool(value);
rtn=true;
} else if (strncasecmp(param, "panel_type_pda", 14) == 0) {
_tmpPanel->rs = !text2bool(value);
rtn=true;
} else if (strncasecmp(param, "panel_type_rs", 13) == 0) {
_tmpPanel->rs = text2bool(value);
rtn=true;
} else if (strncasecmp(param, "panel_type", 10) == 0) { // This must be last so it doesn't get picked up by other settings
setPanelByName(aqdata, cleanwhitespace(value));
rtn=true;
} else if (strncasecmp(param, "rs_panel_size", 13) == 0) {
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'rs_panel_size' no longer supported, please use 'panel_type'\n");
_tmpPanel->size = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "web_directory", 13) == 0) {
_aqconfig_.web_directory = cleanalloc(value);
@ -398,12 +435,12 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
_aqconfig_.light_programming_initial_off = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "light_programming_button_spa", 28) == 0) {
logMessage(LOG_ERR, "Config error, 'light_programming_button_spa' no longer supported\n");
LOG(AQUA_LOG,LOG_ERR, "Config error, 'light_programming_button_spa' no longer supported\n");
//_aqconfig_.light_programming_button_spa = strtoul(value, NULL, 10) - 1;
rtn=true;
} else if (strncasecmp(param, "light_programming_button", 24) == 0 ||
strncasecmp(param, "light_programming_button_pool", 29) == 0) {
logMessage(LOG_ERR, "Config error, 'light_programming_button' & 'light_programming_button_pool' are no longer supported\n");
LOG(AQUA_LOG,LOG_ERR, "Config error, 'light_programming_button' & 'light_programming_button_pool' are no longer supported\n");
//_aqconfig_.light_programming_button_pool = strtoul(value, NULL, 10) - 1;
rtn=true;
} else if (strncasecmp(param, "SWG_percent_dzidx", 17) == 0) {
@ -420,8 +457,10 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
rtn=true;
#ifdef AQ_PDA
} else if (strncasecmp(param, "pda_mode", 8) == 0) {
_aqconfig_.pda_mode = text2bool(value);
set_pda_mode(_aqconfig_.pda_mode);
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'pda_mode' is no longer supported, please use rs_panel_type\n");
//_aqconfig_.pda_mode = text2bool(value);
//set_pda_mode(_aqconfig_.pda_mode);
_tmpPanel->rs = !text2bool(value);
rtn=true;
} else if (strncasecmp(param, "pda_sleep_mode", 8) == 0) {
_aqconfig_.pda_sleep_mode = text2bool(value);
@ -466,28 +505,27 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
} else if (strncasecmp (param, "display_warnings_in_web", 23) == 0) {
_aqconfig_.display_warnings_web = text2bool(value);
rtn=true;
}
/*
else if (strncasecmp (param, "use_PDA_auxiliary", 17) == 0) {
_aqconfig_.use_PDA_auxiliary = text2bool(value);
if ( pda_mode() ) {
logMessage(LOG_ERR, "ERROR Can't use `use_PDA_auxiliary` in PDA mode, ignoring'\n");
_aqconfig_.use_PDA_auxiliary = false;
}
} else if (strncasecmp (param, "serial_readahead_b4_write", 25) == 0) {
_aqconfig_.readahead_b4_write = text2bool(value);
rtn=true;
} */
// removed until domoticz has a better virtual thermostat
/*else if (strncasecmp (param, "pool_thermostat_dzidx", 21) == 0) {
_aqconfig_.dzidx_pool_thermostat = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp (param, "spa_thermostat_dzidx", 20) == 0) {
_aqconfig_.dzidx_spa_thermostat = strtoul(value, NULL, 10);
rtn=true;
} */
} else if (strncasecmp (param, "mqtt_timed_update", 17) == 0) {
_aqconfig_.mqtt_timed_update = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "keep_paneltime_synced", 21) == 0) {
_aqconfig_.sync_panel_time = text2bool(value);
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);
int num = strtoul(param + 7, NULL, 10) - 1;
if (strncasecmp(param + 9, "_label", 6) == 0) {
if (num > TOTAL_BUTTONS) {
LOG(AQUA_LOG,LOG_ERR, "Config error, button_%d is out of range\n",num+1);
rtn=false;
} else if (strncasecmp(param + 9, "_label", 6) == 0) {
aqdata->aqbuttons[num].label = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param + 9, "_dzidx", 6) == 0) {
@ -495,21 +533,23 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
rtn=true;
#ifdef AQ_PDA
} else if (strncasecmp(param + 9, "_PDA_label", 10) == 0) {
aqdata->aqbuttons[num].pda_label = cleanalloc(value);
LOG(AQUA_LOG,LOG_WARNING, "Config error, 'button_%d_PDA_label' is no longer supported, please use 'button_%d_label'\n",num,num);
//aqdata->aqbuttons[num].pda_label = cleanalloc(value);
aqdata->aqbuttons[num].label = cleanalloc(value);
rtn=true;
#endif
} else if (strncasecmp(param + 9, "_lightMode", 10) == 0) {
if (aqdata->num_lights < MAX_LIGHTS) {
int type = strtoul(value, NULL, 10);
if (type < LC_PROGRAMABLE || type > LC_INTELLIB) {
logMessage(LOG_ERR, "Config error, unknown light mode '%s'\n",type);
LOG(AQUA_LOG,LOG_ERR, "Config error, unknown light mode '%s'\n",type);
} else {
aqdata->lights[aqdata->num_lights].button = &aqdata->aqbuttons[num];
aqdata->lights[aqdata->num_lights].lightType = type;
aqdata->num_lights++;
}
} else {
logMessage(LOG_ERR, "Config error, (colored|programmable) Lights limited to %d, ignoring %s'\n",MAX_LIGHTS,param);
LOG(AQUA_LOG,LOG_ERR, "Config error, (colored|programmable) Lights limited to %d, ignoring %s'\n",MAX_LIGHTS,param);
}
rtn=true;
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
@ -523,7 +563,7 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
//pump->pumpType = EPUMP; // For testing let the interface set this
}
} else {
logMessage(LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
}
rtn=true;
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
@ -531,7 +571,7 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
if (pump != NULL) {
pump->pumpIndex = strtoul(value, NULL, 10);
} else {
logMessage(LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
}
rtn=true;
}
@ -551,7 +591,7 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
pi++;
} else {
logMessage(LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
LOG(AQUA_LOG,LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
}
rtn=true;
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
@ -609,6 +649,8 @@ void read_config (struct aqualinkdata *aqdata, char *cfgFile)
//int tokenindex = 0;
char *b_ptr;
_aqconfig_.config_file = cleanalloc(cfgFile);
if( (fp = fopen(cfgFile, "r")) != NULL){
@ -625,7 +667,7 @@ void read_config (struct aqualinkdata *aqdata, char *cfgFile)
if ( indx != NULL)
{
if ( ! setConfigValue(aqdata, b_ptr, indx+1))
logMessage(LOG_ERR, "Unknown config parameter '%.*s'\n",strlen(b_ptr)-1, b_ptr);
LOG(AQUA_LOG,LOG_ERR, "Unknown config parameter '%.*s'\n",strlen(b_ptr)-1, b_ptr);
}
}
}
@ -633,10 +675,12 @@ void read_config (struct aqualinkdata *aqdata, char *cfgFile)
fclose(fp);
} else {
/* error processing, couldn't open file */
logMessage(LOG_ERR, "Error reading config file '%s'\n",cfgFile);
LOG(AQUA_LOG,LOG_ERR, "Error reading config file '%s'\n",cfgFile);
displayLastSystemError(cfgFile);
exit (EXIT_FAILURE);
}
free(_tmpPanel);
}
@ -677,7 +721,7 @@ bool remount_root_ro(bool readonly) {
if (readonly) {} // Dummy to stop compile warnings.
/*
if (readonly) {
logMessage(LOG_INFO, "reMounting root RO\n");
LOG(AQUA_LOG,LOG_INFO, "reMounting root RO\n");
mount (NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
return true;
} else {
@ -686,7 +730,7 @@ bool remount_root_ro(bool readonly) {
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
return false;
logMessage(LOG_INFO, "reMounting root RW\n");
LOG(AQUA_LOG,LOG_INFO, "reMounting root RW\n");
mount (NULL, "/", NULL, MS_REMOUNT, NULL);
return true;
}
@ -712,7 +756,7 @@ void writeIntValue (FILE *fp, char *msg, int value)
bool writeCfg (struct aqualinkdata *aqdata)
{
logMessage(LOG_ERR, "writeCfg() not implimented\n");
LOG(AQUA_LOG,LOG_ERR, "writeCfg() not implimented\n");
/*
FILE *fp;
int i;
@ -720,7 +764,7 @@ bool writeCfg (struct aqualinkdata *aqdata)
fp = fopen(_aqconfig_.config_file, "w");
if (fp == NULL) {
logMessage(LOG_ERR, "Open config file failed '%s'\n", _aqconfig_.config_file);
LOG(AQUA_LOG,LOG_ERR, "Open config file failed '%s'\n", _aqconfig_.config_file);
remount_root_ro(true);
//fprintf(stdout, "Open file failed 'sprinkler.cron'\n");
return false;

View File

@ -31,11 +31,12 @@ struct aqconfig
char *socket_port;
char *web_directory;
unsigned char device_id;
unsigned char onetouch_device_id;
int16_t paneltype_mask;
#if defined AQ_ONETOUCH || defined AQ_IAQTOUCH
unsigned char extended_device_id;
bool extended_device_id_programming;
#endif
bool deamonize;
unsigned short rs_panel_size;
//unsigned short rs_panel_size;
char *log_file;
char *mqtt_dz_sub_topic;
char *mqtt_dz_pub_topic;
@ -53,17 +54,12 @@ struct aqconfig
float light_programming_mode;
int light_programming_initial_on;
int light_programming_initial_off;
//int light_programming_button_pool;
//int light_programming_button_spa;
bool override_freeze_protect;
#ifdef AQ_PDA
bool pda_mode;
bool pda_sleep_mode;
#endif
bool onetouch_mode;
bool convert_mqtt_temp;
bool convert_dz_temp;
//bool flash_mqtt_buttons;
bool report_zero_spa_temp;
bool report_zero_pool_temp;
bool read_all_devices;
@ -71,15 +67,12 @@ struct aqconfig
bool force_swg;
int swg_zero_ignore;
bool display_warnings_web;
//bool swg_pool_and_spa;
//bool use_PDA_auxiliary;
bool read_pentair_packets;
bool debug_RSProtocol_packets;
bool log_raw_RS_bytes;
//int dzidx_pool_thermostat; // Domoticz virtual thermostats are crap removed until better
//int dzidx_spa_thermostat; // Domoticz virtual thermostats are crap removed until better
//char mqtt_pub_topic[250];
//char *mqtt_pub_tp_ptr = mqtt_pub_topic[];
bool readahead_b4_write;
bool mqtt_timed_update;
bool sync_panel_time;
};
#ifndef CONFIG_C
@ -87,6 +80,10 @@ extern struct aqconfig _aqconfig_;
#else
struct aqconfig _aqconfig_;
#endif
//#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
/*
#ifndef CONFIG_C
#ifdef AQUALINKD_C

BIN
crap Normal file → Executable file

Binary file not shown.

View File

@ -1,3 +1,18 @@
/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include <stdio.h>
@ -8,6 +23,15 @@
#include "aq_mqtt.h"
#include "packetLogger.h"
/*
All button errors
'Check AQUAPURE No Flow'
'Check AQUAPURE Low Salt'
'Check AQUAPURE High Salt'
'Check AQUAPURE General Fault'
*/
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, int swg_zero_ignore) {
static int swg_zero_cnt = 0;
bool changedAnything = false;
@ -19,23 +43,26 @@ bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualin
// SWG can get ~10 messages to set to 0 then go back again for some reason, so don't go to 0 until 10 messages are received
if (swg_zero_cnt <= swg_zero_ignore && packet[4] == 0x00) {
logMessage(LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet[4],
LOG(DJAN_LOG, LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet[4],
swg_zero_cnt, swg_zero_ignore, packet[4], packet[5]);
swg_zero_cnt++;
} else if (swg_zero_cnt > swg_zero_ignore && packet[4] == 0x00) {
if (aqdata->swg_percent != (int)packet[4]) {
aqdata->swg_percent = (int)packet[4];
changedAnything = true;
aqdata->updated = true;
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d from control panel packet to SWG\n", aqdata->swg_percent);
}
// logMessage(LOG_DEBUG, "SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n",
// LOG(DJAN_LOG, LOG_DEBUG, "SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n",
// (int)packet[4],swg_zero_cnt,SWG_ZERO_IGNORE_COUNT,packet[4],packet[5]); swg_zero_cnt++;
} else {
swg_zero_cnt = 0;
if (aqdata->swg_percent != (int)packet[4]) {
aqdata->swg_percent = (int)packet[4];
changedAnything = true;
aqdata->updated = true;
}
// logMessage(LOG_DEBUG, "SWG set to %d due to packet from control panel to SWG 0x%02hhx 0x%02hhx\n",
// LOG(DJAN_LOG, LOG_DEBUG, "SWG set to %d due to packet from control panel to SWG 0x%02hhx 0x%02hhx\n",
// aqdata.swg_percent,packet[4],packet[5]);
}
@ -51,26 +78,160 @@ bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqual
bool changedAnything = false;
if (packet[PKT_CMD] == CMD_PPM) {
aqdata->ar_swg_status = packet[5];
if (aqdata->swg_delayed_percent != TEMP_UNKNOWN && aqdata->ar_swg_status == SWG_STATUS_ON) { // We have a delayed % to set.
//aqdata->ar_swg_device_status = packet[5];
setSWGdeviceStatus(aqdata, JANDY_DEVICE, packet[5]);
if (aqdata->swg_delayed_percent != TEMP_UNKNOWN && aqdata->ar_swg_device_status == SWG_STATUS_ON) { // We have a delayed % to set.
char sval[10];
snprintf(sval, 9, "%d", aqdata->swg_delayed_percent);
aq_programmer(AQ_SET_SWG_PERCENT, sval, aqdata);
logMessage(LOG_NOTICE, "Setting SWG %% to %d, from delayed message\n", aqdata->swg_delayed_percent);
LOG(DJAN_LOG, LOG_NOTICE, "Setting SWG %% to %d, from delayed message\n", aqdata->swg_delayed_percent);
aqdata->swg_delayed_percent = TEMP_UNKNOWN;
}
aqdata->swg_ppm = packet[4] * 100;
changedAnything = true;
if ( (packet[4] * 100) != aqdata->swg_ppm ) {
aqdata->swg_ppm = packet[4] * 100;
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG PPM to %d from SWG packet\n", aqdata->swg_ppm);
changedAnything = true;
aqdata->updated = true;
}
// logMessage(LOG_DEBUG, "Read SWG PPM %d from ID 0x%02hhx\n", aqdata.swg_ppm, SWG_DEV_ID);
}
return changedAnything;
}
bool isSWGDeviceErrorState(unsigned char status)
{
if (status == SWG_STATUS_NO_FLOW ||
status == SWG_STATUS_CHECK_PCB ||
status == SWG_STATUS_LOW_TEMP ||
status == SWG_STATUS_HIGH_CURRENT ||
status == SWG_STATUS_NO_FLOW)
return true;
else
return false;
}
void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status) {
if (aqdata->ar_swg_device_status == status)
return;
// Check validity of status and set as appropiate
switch (status) {
case SWG_STATUS_ON:
case SWG_STATUS_NO_FLOW:
case SWG_STATUS_LOW_SALT:
case SWG_STATUS_HI_SALT:
case SWG_STATUS_HIGH_CURRENT:
case SWG_STATUS_CLEAN_CELL:
case SWG_STATUS_LOW_VOLTS:
case SWG_STATUS_LOW_TEMP:
case SWG_STATUS_CHECK_PCB:
aqdata->ar_swg_device_status = status;
aqdata->swg_led_state = isSWGDeviceErrorState(status)?ENABLE:ON;
break;
case SWG_STATUS_OFF: // THIS IS OUR OFF STATUS, NOT AQUAPURE
case SWG_STATUS_TURNING_OFF:
aqdata->ar_swg_device_status = status;
aqdata->swg_led_state = OFF;
break;
default:
LOG(DJAN_LOG, LOG_ERR, "Ignoring set SWG device to state '0x%02hhx', state is unknown\n", status);
return;
break;
}
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG device state to '0x%02hhx', request from %d\n", aqdata->ar_swg_device_status, requester);
}
/*
bool updateSWG(struct aqualinkdata *aqdata, emulation_type requester, aqledstate state, int percent)
{
switch (requester) {
case ALLBUTTON: // no insight into 0% (just blank)
break;
case ONETOUCH:
break;
case IAQTOUCH:
break;
case AQUAPDA:
break;
case JANDY_DEVICE:
break;
}
}
*/
bool setSWGboost(struct aqualinkdata *aqdata, bool on) {
if (!on) {
aqdata->boost = false;
aqdata->boost_msg[0] = '\0';
aqdata->swg_percent = 0;
} else {
aqdata->boost = true;
aqdata->swg_percent = 101;
}
}
// Only change SWG percent if we are not in SWG programming
bool changeSWGpercent(struct aqualinkdata *aqdata, int percent) {
if (in_swg_programming_mode(aqdata)) {
LOG(DJAN_LOG, LOG_DEBUG, "Ignoring set SWG %% to %d due to programming SWG\n", aqdata->swg_percent);
return false;
}
setSWGpercent(aqdata, percent);
return true;
}
void setSWGoff(struct aqualinkdata *aqdata) {
if (aqdata->ar_swg_device_status != SWG_STATUS_OFF || aqdata->swg_led_state != OFF)
aqdata->updated = true;
aqdata->ar_swg_device_status = SWG_STATUS_OFF;
aqdata->swg_led_state = OFF;
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG to off\n");
}
void setSWGenabled(struct aqualinkdata *aqdata) {
if (aqdata->swg_led_state != ENABLE) {
aqdata->updated = true;
aqdata->swg_led_state = ENABLE;
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG to Enable\n");
}
}
// force a Change SWG percent.
void setSWGpercent(struct aqualinkdata *aqdata, int percent) {
aqdata->swg_percent = percent;
aqdata->updated = true;
if (aqdata->swg_percent > 0) {
if (aqdata->swg_led_state == OFF || (aqdata->swg_led_state == ENABLE && ! isSWGDeviceErrorState(aqdata->ar_swg_device_status)) ) // Don't change ENABLE / FLASH
aqdata->swg_led_state = ON;
if (aqdata->ar_swg_device_status == SWG_STATUS_UNKNOWN)
aqdata->ar_swg_device_status = SWG_STATUS_ON;
} if ( aqdata->swg_percent == 0 ) {
if (aqdata->swg_led_state == ON)
aqdata->swg_led_state = ENABLE; // Don't change OFF
if (aqdata->ar_swg_device_status == SWG_STATUS_UNKNOWN)
aqdata->ar_swg_device_status = SWG_STATUS_ON; // Maybe this should be off
}
LOG(DJAN_LOG, LOG_DEBUG, "Set SWG %% to %d, LED=%d, FullStatus=0x%02hhx\n", aqdata->swg_percent, aqdata->swg_led_state, aqdata->ar_swg_device_status);
}
aqledstate get_swg_led_state(struct aqualinkdata *aqdata)
{
switch (aqdata->ar_swg_status) {
switch (aqdata->ar_swg_device_status) {
case SWG_STATUS_ON:
return (aqdata->swg_percent > 0?ON:ENABLE);
@ -114,7 +275,7 @@ aqledstate get_swg_led_state(struct aqualinkdata *aqdata)
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert)
{
switch (aqdata->ar_swg_status) {
switch (aqdata->ar_swg_device_status) {
// Level = (0=gray, 1=green, 2=yellow, 3=orange, 4=red)
case SWG_STATUS_ON:
*status = (aqdata->swg_percent > 0?SWG_ON:SWG_OFF);
@ -184,7 +345,7 @@ bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, s
char msg[1000];
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
beautifyPacket(msg, packet_buffer, packet_length);
logMessage(LOG_DEBUG, "To ePump: %s\n", msg);
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s\n", msg);
return false;
}
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
@ -192,7 +353,7 @@ bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length,
char msg[1000];
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
beautifyPacket(msg, packet_buffer, packet_length);
logMessage(LOG_DEBUG, "From ePump: %s\n", msg);
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s\n", msg);
return false;
}

View File

@ -13,4 +13,11 @@ bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length,
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert);
aqledstate get_swg_led_state(struct aqualinkdata *aqdata);
bool changeSWGpercent(struct aqualinkdata *aqdata, int percent);
void setSWGpercent(struct aqualinkdata *aqdata, int percent);
void setSWGoff(struct aqualinkdata *aqdata);
void setSWGenabled(struct aqualinkdata *aqdata);
bool setSWGboost(struct aqualinkdata *aqdata, bool on);
void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status);
#endif // AQUAPURE_H_

View File

@ -42,7 +42,7 @@ bool processPentairPacket(unsigned char *packet, int packet_length, struct aqual
for (i = 0; i < MAX_PUMPS; i++) {
if ( aqdata->pumps[i].prclType == PENTAIR && aqdata->pumps[i].pumpID == packet[PEN_PKT_FROM] ) {
// We found the pump.
logMessage(LOG_INFO, "Pentair Pump Status message = RPM %d | WATTS %d\n",
LOG(DPEN_LOG, LOG_INFO, "Pentair Pump Status message = RPM %d | WATTS %d\n",
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT]);
@ -53,7 +53,7 @@ bool processPentairPacket(unsigned char *packet, int packet_length, struct aqual
break;
}
if (changedAnything != true)
logMessage(LOG_NOTICE, "Pentair Pump found at ID 0x%02hhx with RPM %d | WATTS %d, but not configured, information ignored!\n",
LOG(DPEN_LOG, LOG_NOTICE, "Pentair Pump found at ID 0x%02hhx with RPM %d | WATTS %d, but not configured, information ignored!\n",
packet[PEN_PKT_FROM],
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT]);

900
iaqtouch.c Normal file
View File

@ -0,0 +1,900 @@
/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include <stdio.h>
#include <string.h>
#include "aq_serial.h"
#include "aqualink.h"
#include "utils.h"
#include "packetLogger.h"
#include "iaqtouch.h"
#include "iaqtouch_aq_programmer.h"
#include "aq_programmer.h"
#include "rs_msg_utils.h"
#include "devices_jandy.h"
void temp_debugprintExtraInfo(unsigned char *pk, int length);
#ifdef ATOUCH_TEST
void set_iaq_cansend(bool yes) {}
bool in_iaqt_programming_mode(struct aqualinkdata *aq_data) {return false;}
bool iaqt_queue_cmd(unsigned char cmd) {}
bool in_programming_mode(struct aqualinkdata *aq_data){return false;}
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data){}
void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_type){}
void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data){}
#endif
unsigned char _button_keys[] = { KEY_IAQTCH_KEY01,
KEY_IAQTCH_KEY02,
KEY_IAQTCH_KEY03,
KEY_IAQTCH_KEY04,
KEY_IAQTCH_KEY05,
KEY_IAQTCH_KEY06,
KEY_IAQTCH_KEY07,
KEY_IAQTCH_KEY08,
KEY_IAQTCH_KEY09,
KEY_IAQTCH_KEY10,
KEY_IAQTCH_KEY11,
KEY_IAQTCH_KEY12,
KEY_IAQTCH_KEY13,
KEY_IAQTCH_KEY14,
KEY_IAQTCH_KEY15};
#define IAQ_STATUS_PAGE_LINES 18
#define IAQ_PAGE_BUTTONS 24
#define IAQ_MSG_TABLE_LINES IAQ_STATUS_PAGE_LINES // No idea actual size, so just use this until figured out.
#define IAQT_TABLE_MSGLEN 32
unsigned char _currentPageLoading;
unsigned char _currentPage;
unsigned char _lastMsgType = 0x00;
//unsigned char _last_kick_type = -1;
int _deviceStatusLines = 0;
char _deviceStatus[IAQ_STATUS_PAGE_LINES][AQ_MSGLEN+1];
char _tableInformation[IAQ_MSG_TABLE_LINES][IAQT_TABLE_MSGLEN+1];
struct iaqt_page_button _pageButtons[IAQ_PAGE_BUTTONS];
// Need to cache these two pages, as only get updates after initial load.
struct iaqt_page_button _devicePageButtons[IAQ_PAGE_BUTTONS];
struct iaqt_page_button _devicePage2Buttons[IAQ_PAGE_BUTTONS];
struct iaqt_page_button _deviceSystemSetupButtons[IAQ_PAGE_BUTTONS];
unsigned char iaqtLastMsg()
{
return _lastMsgType;
}
bool wasiaqtThreadKickTypePage()
{
switch(_lastMsgType) {
//case CMD_IAQ_PAGE_MSG:
//case CMD_IAQ_PAGE_BUTTON:
//case CMD_IAQ_PAGE_START:
case CMD_IAQ_PAGE_END:
return true;
break;
default:
return false;
break;
}
return false;
}
unsigned char iaqtCurrentPage()
{
return _currentPage;
}
const char *iaqtGetMessageLine(int index) {
if (index < IAQ_STATUS_PAGE_LINES)
return _deviceStatus[index];
return NULL;
}
const char *iaqtGetTableInfoLine(int index) {
if (index < IAQ_MSG_TABLE_LINES)
return _tableInformation[index];
return NULL;
}
struct iaqt_page_button *iaqtFindButtonByIndex(int index) {
int i;
struct iaqt_page_button *buttons;
// NSF Need to merge this from iaqtFindButtonByLabel function
if (_currentPage == IAQ_PAGE_DEVICES )
buttons = _devicePageButtons;
else if (_currentPage == IAQ_PAGE_DEVICES2 )
buttons = _devicePage2Buttons;
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP )
buttons = _deviceSystemSetupButtons;
else
buttons = _pageButtons;
if (index>=0 && index < IAQ_PAGE_BUTTONS) {
return &buttons[index];
}
return NULL;
}
struct iaqt_page_button *iaqtFindButtonByLabel(char *label) {
int i;
struct iaqt_page_button *buttons;
if (_currentPage == IAQ_PAGE_DEVICES )
buttons = _devicePageButtons;
else if (_currentPage == IAQ_PAGE_DEVICES2 )
buttons = _devicePage2Buttons;
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP )
buttons = _deviceSystemSetupButtons;
else
buttons = _pageButtons;
for (i=0; i < IAQ_PAGE_BUTTONS; i++) {
//if (_pageButtons[i].state != 0 || _pageButtons[i].type != 0 || _pageButtons[i].unknownByte != 0)
if (rsm_strcmp((char *)buttons[i].name,label) == 0)
return &buttons[i];
}
return NULL;
}
int num2iaqtRSset (unsigned char* packetbuffer, int num, bool pad4unknownreason)
{
//unsigned int score = 42; // Works for score in [0, UINT_MAX]
//unsigned char tmp;
//printf ("num via printf: %u\n", num); // For validation
int bcnt = 0;
int digits = 0;
unsigned int div = 1;
unsigned int digit_count = 1;
while ( div <= num / 10 ) {
digit_count++;
div *= 10;
}
while ( digit_count > 0 ) {
packetbuffer[bcnt] = (num / div + 0x30); // 48 = 0x30 base number for some reason. (ie 48=0)
num %= div;
div /= 10;
digit_count--;
bcnt++;
}
for (digits = bcnt; bcnt < 6; bcnt++) { // Note setting digits to bcnt is correct. Saving current count to different int
if (bcnt == 4 && digits <= 3 ) // Less than 4 digits (<1000), need to add a 0x30
packetbuffer[bcnt] = 0x30;
else
packetbuffer[bcnt] = NUL;
}
return bcnt;
}
int char2iaqtRSset(unsigned char* packetbuffer, char *msg, int msg_len)
{
int bcnt=0;
for (bcnt=0; bcnt < msg_len; bcnt++ ){
packetbuffer[bcnt] = msg[bcnt];
}
packetbuffer[bcnt] = 0x00;
return ++bcnt;
}
void createDeviceUpdatePacket() {
unsigned char packets[AQ_MAXPKTLEN];
int cnt;
packets[0] = DEV_MASTER;
packets[1] = 0x24;
packets[2] = 0x31;
cnt = num2iaqtRSset(&packets[3], 1000, true);
for(cnt = cnt+3; cnt <= 18; cnt++)
packets[cnt] = 0xcd;
//printHex(packets, 19);
//printf("\n");
//send_jandy_command(NULL, packets, cnt);
}
void processPageMessage(unsigned char *message, int length)
{
if ( (int)message[PKT_IAQT_MSGINDX] >= IAQ_STATUS_PAGE_LINES ) {
LOG(IAQT_LOG,LOG_ERR, "Run out of IAQT message buffer, need %d have %d\n",(int)message[PKT_IAQT_MSGINDX],IAQ_STATUS_PAGE_LINES);
return;
}
// 2nd page of device status doesn;t gine us new page message
if (_currentPageLoading == IAQ_PAGE_STATUS || _currentPage == IAQ_PAGE_STATUS) {
//sprintf(_deviceStatus[(int)message[4]], message[5], AQ_MSGLEN);
//strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], (char *)message + PKT_IAQT_MSGDATA, AQ_MSGLEN);
rsm_strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], &message[PKT_IAQT_MSGDATA], AQ_MSGLEN, length-PKT_IAQT_MSGDATA-3);
} else {
//strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], (char *)message + PKT_IAQT_MSGDATA, AQ_MSGLEN);
rsm_strncpy(_deviceStatus[(int)message[PKT_IAQT_MSGINDX]], &message[PKT_IAQT_MSGDATA], AQ_MSGLEN, length-PKT_IAQT_MSGDATA-3);
//LOG(IAQT_LOG,LOG_ERR, "Request to assign message to unknown page,'%.*s'\n",AQ_MSGLEN,(char *)message + PKT_IAQT_MSGDATA);
}
//LOG(IAQT_LOG,LOG_DEBUG, "Message :- '%d' '%.*s'\n",(int)message[PKT_IAQT_MSGINDX], length-PKT_IAQT_MSGDATA-3, &message[PKT_IAQT_MSGDATA]);
}
void processTableMessage(unsigned char *message, int length)
{
if ( (int)message[5] < IAQ_MSG_TABLE_LINES )
rsm_strncpy(_tableInformation[(int)message[5]], &message[6], IAQT_TABLE_MSGLEN, length-PKT_IAQT_MSGDATA-3);
else
LOG(IAQT_LOG,LOG_ERR, "Run out of IAQT table buffer, need %d have %d\n",(int)message[5],IAQ_MSG_TABLE_LINES);
}
void processPageButton(unsigned char *message, int length)
{
struct iaqt_page_button *button;
int index = (int)message[PKT_IAQT_BUTINDX];
if (_currentPageLoading == IAQ_PAGE_DEVICES )
button = &_devicePageButtons[index];
else if (_currentPageLoading == IAQ_PAGE_DEVICES2 )
button = &_devicePage2Buttons[index];
else if (_currentPageLoading == IAQ_PAGE_SYSTEM_SETUP )
button = &_deviceSystemSetupButtons[index];
else
button = &_pageButtons[index];
button->state = message[PKT_IAQT_BUTSTATE];
button->type = message[PKT_IAQT_BUTTYPE];
button->unknownByte = message[PKT_IAQT_BUTUNKNOWN];
if (message[PKT_IAQT_BUTSTATE] == 0x0d)
button->keycode = message[PKT_IAQT_BUTTYPE];
else if (index < 15) {
button->keycode = _button_keys[index];
}
// This doesn't work with return which is 0x00
//strncpy(&button->name, (char *)message + PKT_IAQT_BUTDATA, AQ_MSGLEN);
rsm_strncpy_nul2sp((char *)button->name, &message[PKT_IAQT_BUTDATA], IAQT_MSGLEN, length-PKT_IAQT_BUTDATA-3);
LOG(IAQT_LOG,LOG_DEBUG, "Added Button %d %s\n",index,button->name);
/*
_pageButtons[index].state = (int)message[5];
_pageButtons[index].type = (int)message[7];
_pageButtons[index].unknownByte = (int)message[6];
// This doesn't work with return which is 0x00
strncpy(&_pageButtons[index].name, (char *)message + 8, AQ_MSGLEN);
LOG(IAQT_LOG,LOG_NOTICE, "Added Button %d %s\n",index,_pageButtons[index].name);
*/
}
// Log if we saw a pump in a device page cycle.
void iaqt_pump_update(struct aqualinkdata *aq_data, int updated) {
const int bitmask[MAX_PUMPS] = {1,2,4,8};
static unsigned char updates = '\0';
int i;
if (updated == -1) {
for(i=0; i < MAX_PUMPS; i++) {
if ((updates & bitmask[i]) != bitmask[i]) {
aq_data->pumps[i].rpm = PUMP_OFF_RPM;
aq_data->pumps[i].gpm = PUMP_OFF_GPM;
aq_data->pumps[i].watts = PUMP_OFF_WAT;
LOG(IAQT_LOG,LOG_DEBUG, "Clearing pump %d\n",i);
aq_data->updated =true;
}
}
updates = '\0';
} else if (updated >=0 && updated < MAX_PUMPS) {
updates |= bitmask[updated];
LOG(IAQT_LOG,LOG_DEBUG, "Got pump update message for pump %d\n",updated);
}
}
void passDeviceStatusPage(struct aqualinkdata *aq_data)
{
int i;
int pi;
pump_detail *pump = NULL;
//bool found_swg = false;
//int pump_index = 0;
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ ) {
//LOG(IAQT_LOG,LOG_NOTICE, "Passing message %.2d| %s\n",i,_deviceStatus[i]);
if (rsm_strcmp(_deviceStatus[i],"Intelliflo VS") == 0 ||
rsm_strcmp(_deviceStatus[i],"Intelliflo VF") == 0 ||
rsm_strcmp(_deviceStatus[i],"Jandy ePUMP") == 0)
{
int pump_index = rsm_atoi(&_deviceStatus[i][14]);
for (pi=0; pi < aq_data->num_pumps; pi++) {
if (aq_data->pumps[pi].pumpIndex == pump_index) {
iaqt_pump_update(aq_data, pi); // Log that we saw a pump
pump = &aq_data->pumps[pi];
aq_data->updated =true;
if (pump->pumpType == PT_UNKNOWN){
if (rsm_strcmp(_deviceStatus[i],"Intelliflo VS") == 0)
pump->pumpType = VSPUMP;
else if (rsm_strcmp(_deviceStatus[i],"Intelliflo VF") == 0)
pump->pumpType = VFPUMP;
else if (rsm_strcmp(_deviceStatus[i],"Jandy ePUMP") == 0)
pump->pumpType = EPUMP;
}
}
}
if (pump == NULL)
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump at index %d\n",_deviceStatus[i],pump_index);
continue;
} else if (rsm_strcmp(_deviceStatus[i],"RPM:") == 0) {
if (pump != NULL)
pump->rpm = rsm_atoi(&_deviceStatus[i][9]);
else
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
continue;
} else if (rsm_strcmp(_deviceStatus[i],"GPM:") == 0) {
if (pump != NULL)
pump->gpm = rsm_atoi(&_deviceStatus[i][9]);
else
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
continue;
} else if (rsm_strcmp(_deviceStatus[i],"Watts:") == 0) {
if (pump != NULL)
pump->watts = rsm_atoi(&_deviceStatus[i][9]);
else
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
continue;
} else if (rsm_strcmp(_deviceStatus[i],"*** Priming ***") == 0) {
if (pump != NULL)
pump->rpm = PUMP_PRIMING;
else
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
continue;
} else if (rsm_strcmp(_deviceStatus[i],"(Offline)") == 0) {
if (pump != NULL)
pump->rpm = PUMP_OFFLINE;
else
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
continue;
} else if (rsm_strcmp(_deviceStatus[i],"(Priming Error)") == 0) {
if (pump != NULL)
pump->rpm = PUMP_ERROR;
else
LOG(IAQT_LOG,LOG_ERR, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]);
continue;
// Need to catch messages like
// *** Priming ***
// (Priming Error)
// (Offline)
} else {
pump = NULL;
}
if (rsm_strcmp(_deviceStatus[i],"AQUAPURE") == 0) {
//aq_data->swg_percent = rsm_atoi(&_deviceStatus[i][9]);
if (changeSWGpercent(aq_data, rsm_atoi(&_deviceStatus[i][9])))
LOG(IAQT_LOG,LOG_DEBUG, "Set swg %% to %d from message'%s'\n",aq_data->swg_percent,_deviceStatus[i]);
} else if (rsm_strcmp(_deviceStatus[i],"salt") == 0) {
aq_data->swg_ppm = rsm_atoi(&_deviceStatus[i][5]);
LOG(IAQT_LOG,LOG_DEBUG, "Set swg PPM to %d from message'%s'\n",aq_data->swg_ppm,_deviceStatus[i]);
} else if (rsm_strcmp(_deviceStatus[i],"Boost Pool") == 0) {
aq_data->boost = true;
// Let RS pickup time remaing message.
} else if (rsm_strcmp(_deviceStatus[i],"Chemlink") == 0) {
/* Info: = Chemlink 1
Info: = ORP 750/PH 7.0 */
i++;
if (rsm_strcmp(_deviceStatus[i],"ORP") == 0) {
int orp = rsm_atoi(&_deviceStatus[i][4]);
char *indx = strchr(_deviceStatus[i], '/');
float ph = rsm_atof(indx+3);
if (aq_data->ph != ph || aq_data->orp != orp) {
aq_data->ph = ph;
aq_data->orp = orp;
}
LOG(IAQT_LOG,LOG_INFO, "Set Cemlink ORP = %d PH = %f from message '%s'\n",orp,ph,_deviceStatus[i]);
}
}
} // for
}
void debugPrintButtons(struct iaqt_page_button buttons[])
{
int i;
for (i=0; i < IAQ_PAGE_BUTTONS; i++) {
if (buttons[i].state != 0 || buttons[i].type != 0 || buttons[i].unknownByte != 0 || buttons[i].keycode != 0)
LOG(IAQT_LOG,LOG_INFO, "Button %.2d| %21.21s | type=0x%02hhx | state=0x%02hhx | unknown=0x%02hhx | keycode=0x%02hhx\n",i,buttons[i].name,buttons[i].type,buttons[i].state,buttons[i].unknownByte,buttons[i].keycode);
}
}
void processPage(struct aqualinkdata *aq_data)
{
int i;
LOG(IAQT_LOG,LOG_INFO, "Page: %s | 0x%02hhx\n",iaqt_page_name(_currentPage),_currentPage);
switch(_currentPage) {
case IAQ_PAGE_STATUS:
case IAQ_PAGE_STATUS2:
//LOG(IAQT_LOG,LOG_INFO, "Status Page:-\n");
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ )
if (strlen(_deviceStatus[i]) > 1)
LOG(IAQT_LOG,LOG_INFO, "Status page %.2d| %s\n",i,_deviceStatus[i]);
debugPrintButtons(_pageButtons);
passDeviceStatusPage(aq_data);
// If button 1 is type 0x02 then there is a next page. Since status page isn't used for programming, hit the next page button.
if (_pageButtons[1].type == 0x02)
iaqt_queue_cmd(KEY_IAQTCH_KEY02);
else
iaqt_pump_update(aq_data, -1); // Reset pumps.
break;
case IAQ_PAGE_DEVICES:
//LOG(IAQT_LOG,LOG_INFO, "Devices Page #1:-\n");
debugPrintButtons(_devicePageButtons);
break;
case IAQ_PAGE_DEVICES2:
//LOG(IAQT_LOG,LOG_INFO, "Devices Page #2:-\n");
debugPrintButtons(_devicePage2Buttons);
break;
case IAQ_PAGE_COLOR_LIGHT:
//LOG(IAQT_LOG,LOG_INFO, "Color Light Page :-\n");
debugPrintButtons(_pageButtons);
break;
case IAQ_PAGE_HOME:
//LOG(IAQT_LOG,LOG_INFO, "Home Page :-\n");
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ )
if (_deviceStatus[i][0] != 0)
LOG(IAQT_LOG,LOG_INFO, "Status page %.2d| %s\n",i,_deviceStatus[i]);
debugPrintButtons(_pageButtons);
break;
case IAQ_PAGE_SYSTEM_SETUP:
//LOG(IAQT_LOG,LOG_INFO, "System Setup :-\n");
debugPrintButtons(_deviceSystemSetupButtons);
break;
case IAQ_PAGE_SET_VSP:
debugPrintButtons(_pageButtons);
break;
default:
//LOG(IAQT_LOG,LOG_INFO, "** UNKNOWN PAGE 0x%02hhx **\n",_currentPage);
for (i=0; i <IAQ_STATUS_PAGE_LINES; i++ )
if (_deviceStatus[i][0] != 0)
LOG(IAQT_LOG,LOG_INFO, "Page %.2d| %s\n",i,_deviceStatus[i]);
debugPrintButtons(_pageButtons);
break;
}
for (i=0; i < IAQ_MSG_TABLE_LINES; i++) {
if (strlen((char *)_tableInformation[i]) > 0)
LOG(IAQT_LOG,LOG_INFO, "Table Messages %.2d| %s\n",i,_tableInformation[i]);
}
}
bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
{
static int cnt = 0;
char buff[1024];
if (packet[PKT_CMD] == CMD_IAQ_PAGE_START) {
LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND off\n");
set_iaq_cansend(false);
_currentPageLoading = packet[PKT_IAQT_PAGTYPE];
_currentPage = NUL;
memset(_pageButtons, 0, IAQ_PAGE_BUTTONS * sizeof(struct iaqt_page_button));
memset(_deviceStatus, 0, sizeof(char) * IAQ_STATUS_PAGE_LINES * AQ_MSGLEN+1 );
memset(_tableInformation, 0, sizeof(char) * IAQ_MSG_TABLE_LINES * AQ_MSGLEN+1 );
//[IAQ_STATUS_PAGE_LINES][AQ_MSGLEN+1];
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_END) {
set_iaq_cansend(true);
LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND on\n");
if (_currentPageLoading != NUL) {
_currentPage = _currentPageLoading;
_currentPageLoading = NUL;
} else {
LOG(IAQT_LOG,LOG_DEBUG, "Page end message without proceding page start, ignoring!\n");
}
processPage(aq_data);
} else if (packet[PKT_CMD] == CMD_IAQ_TABLE_MSG) {
processTableMessage(packet, length);
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_MSG) {
processPageMessage(packet, length);
} else if (packet[PKT_CMD] == CMD_IAQ_PAGE_BUTTON) {
processPageButton(packet, length);
// Second page on status doesn't send start & end, but button is message, so use that to kick off next page.
if (_currentPage == IAQ_PAGE_STATUS) {
/* Notice: Added Button 1
* Notice: To 0x33 of type iAq pBut | HEX: 0x10|0x02|0x33|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x6a|0x10|0x03|
* Button | 1 | 0x00 | |-| |-| -off-
*
* SHOULD PROBABLY USE ABOVE TO CHECK.
*/
//if (packet[PKT_IAQT_BUTTYPE] == 0x02 )
processPage(aq_data);
}
// if we get a button with 0x00 state on Light Page, that's the end of page.
if (_currentPageLoading == IAQ_PAGE_COLOR_LIGHT) {
if (packet[7] == 0x00) {
printf("** MANUAL PAGE END\n");
_currentPage = _currentPageLoading;
_currentPageLoading = NUL;
processPage(aq_data);
set_iaq_cansend(true);
// Also END page here, as you can send commands.
// NEED to rethink this approach. ie, selecting light needs to hold open while showing page, no page end, then select light color, then message "please wait", the finally done
}
}
}
if (packet[3] == 0x29) {
printf("***** iAqualink Touch STARTUP Message ******* \n");
queueGetProgramData(IAQTOUCH, aq_data);
//aq_programmer(AQ_SET_IAQTOUCH_SET_TIME, NULL, aq_data);
}
// Standard ack/poll not interested in printing or kicking threads
if (packet[3] == 0x30) {
// Load status page every 1000 messages
//if (cnt++ > 50 && in_iaqt_programming_mode(aq_data) == false ) {
// Let's not confuse any message data, only grab status if not in any from of programming mode
/*
if (cnt++ == 50 && in_programming_mode(aq_data) == false ) {
//iaqt_queue_cmd(KEY_IAQTCH_STATUS);
//aq_programmer(AQ_GET_IAQTOUCH_VSP_ASSIGNMENT, NULL, aq_data);
//cnt = 0;
queueGetProgramData(IAQTOUCH, aq_data);
}
else*/ if (cnt++ > 100 && in_programming_mode(aq_data) == false ) {
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
//aq_programmer(AQ_GET_IAQTOUCH_VSP_ASSIGNMENT, NULL, aq_data);
cnt = 0;
}
return false;
}
//debuglogPacket(IAQT_LOG ,packet, length);
_lastMsgType = packet[PKT_CMD];
debuglogPacket(IAQT_LOG ,packet, length);
//beautifyPacket(buff, packet, length);
//LOG(IAQT_LOG,LOG_DEBUG, "%s", buff);
//temp_debugprintExtraInfo(packet, length);
kick_aq_program_thread(aq_data, IAQTOUCH);
return false;
}
const char *iaqt_page_name(const unsigned char page)
{
switch (page){
case IAQ_PAGE_HOME:
return "HOME";
break;
case IAQ_PAGE_STATUS:
return "Status";
break;
case IAQ_PAGE_STATUS2:
return "Status (diff ID)";
break;
case IAQ_PAGE_DEVICES:
return "Devices #1";
break;
case IAQ_PAGE_DEVICES2:
return "Devices #2";
break;
case IAQ_PAGE_SET_TEMP:
return "Set Temp";
break;
case IAQ_PAGE_MENU:
return "MENU";
break;
case IAQ_PAGE_SET_VSP:
return "Set VSP";
break;
case IAQ_PAGE_SET_TIME:
return "Set Time";
break;
case IAQ_PAGE_SET_DATE:
return "Set Date";
break;
case IAQ_PAGE_SET_SWG:
return "Set Aquapure";
break;
case IAQ_PAGE_SET_BOOST:
return "Set Boost";
break;
case IAQ_PAGE_SET_QBOOST:
return "Set Quick Boost";
break;
case IAQ_PAGE_ONETOUCH:
return "OneTouch";
break;
case IAQ_PAGE_COLOR_LIGHT:
return "Color Lights";
break;
case IAQ_PAGE_SYSTEM_SETUP:
return "System Setup";
break;
case IAQ_PAGE_VSP_SETUP:
return "VSP Setup";
break;
case IAQ_PAGE_FREEZE_PROTECT:
return "Freeze Protect";
break;
case IAQ_PAGE_LABEL_AUX:
return "Label Aux";
break;
default:
return "** Unknown **";
break;
}
return "";
}
void temp_debugprintExtraInfo(unsigned char *pk, int length)
{
if (pk[PKT_CMD] == CMD_IAQ_PAGE_MSG) {
int i;
printf(" Message | %d | ",(int)pk[4]);
// Byte #4 is line index on status page at least
// 1 bytes unknown #4.
// Message starts at 5
for (i=5;i<length-3;i++)
printf("%c",pk[i]);
printf("\n");
}
else if (pk[PKT_CMD] == CMD_IAQ_TABLE_MSG) {
int i;
printf(" Table Msg | %d | ",(int)pk[5]);
for (i=6;i<length-3;i++)
printf("%c",pk[i]);
printf("\n");
}
else if (pk[PKT_CMD] == CMD_IAQ_PAGE_BUTTON) {
int i;
printf(" Button | %d | 0x%02hhx | ",(int)pk[4],pk[7]);
// byte 4 is button index.
// byte 5 is status 0x00 off (0x01, 0x02, 0x03)
// byte 6
// byte 7
// 6 & 7 0x01|0x00 for normal stuff
// 6 & 7 0x00|0x0c for lights with 7 incrementing.
// 7 = Key to send in ACK to select, at least for Light modes.
// (Might also be in pk5=0x0d) Think if pk6 = 0x01, pk7 not used, if pk=0x00 then pk7 is keycode to send if you select that option.
// Byte 7 0x03 PAGE DOWN / 0x02 PAGE UP
// 2 bytes unknown #5 and #6.
// Message starts at 8
// if pk[5] == 0x0d start at 8
for (i=8;i<length-3;i++) {
// If we get a 0x00 looks like a return.
if (pk[i] == 0x00)
printf(" |-| ");
printf("%c",pk[i]);
}
if (pk[5] == 0x00)
printf(" -off- ");
else if (pk[5] == 0xff)
printf(" -blank/unknown- ");
else if (pk[5] == 0x03)
printf(" -Enabeled- ");
else if (pk[5] == 0x01)
printf(" -on- ");
else if (pk[5] == 0x0d)
printf(" -Light something 0x0d|0x%02hhx|0x%02hhx %d - ",pk[6],pk[7],(int)pk[7]);
else
printf(" -?- 0x%02hhx ",pk[5]);
printf("\n");
}
else if (pk[PKT_CMD] == CMD_IAQ_PAGE_START) {
if (pk[4] == IAQ_PAGE_STATUS)
printf(" New Page | Status\n");
else if (pk[4] == IAQ_PAGE_HOME)
printf(" New Page | Home\n");
else if (pk[4] == IAQ_PAGE_DEVICES)
printf(" New Page | Other Devices\n");
else if (pk[4] == IAQ_PAGE_DEVICES2)
printf(" New Page | Other Devices page 2\n");
else if (pk[4] == IAQ_PAGE_SET_TEMP)
printf(" New Page | Set Temp\n");
else if (pk[4] == IAQ_PAGE_MENU)
printf(" New Page | MENU\n");
else if (pk[4] == IAQ_PAGE_SET_VSP)
printf(" New Page | VSP Adjust\n");
else if (pk[4] == IAQ_PAGE_SET_TIME)
printf(" New Page | Set Time\n");
else if (pk[4] == IAQ_PAGE_SET_DATE)
printf(" New Page | Set Date\n");
else if (pk[4] == IAQ_PAGE_SET_SWG)
printf(" New Page | Set Aquapure\n");
else if (pk[4] == IAQ_PAGE_SET_BOOST)
printf(" New Page | Set BOOST\n");
else if (pk[4] == IAQ_PAGE_SET_QBOOST)
printf(" New Page | Set Quick BOOST\n");
else if (pk[4] == IAQ_PAGE_ONETOUCH)
printf(" New Page | One Touch\n");
else if (pk[4] == IAQ_PAGE_COLOR_LIGHT)
printf(" New Page | Color Light\n");
else
printf(" New Page | unknown 0x%02hhx\n",pk[4]);
}
else if (pk[PKT_CMD] == CMD_IAQ_PAGE_END) {
printf(" New Page | Finished\n");
}
}
/*
Notice: Turning IAQ SEND off
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x23|0x5b|0xc1|0x10|0x03|
New Page | Status
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x2d|0x45|0x71|0x75|0x69|0x70|0x6d|0x65|0x6e|0x74|0x20|0x53|0x74|0x61|0x74|0x75|0x73|0x00|0xcc|0x10|0x03|
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x00|0x46|0x69|0x6c|0x74|0x65|0x72|0x20|0x50|0x75|0x6d|0x70|0x00|0x90|0x10|0x03|
Message | 0 | Filter Pump
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x01|0x53|0x6f|0x6c|0x61|0x72|0x20|0x48|0x65|0x61|0x74|0x20|0x45|0x4e|0x41|0x00|0x00|0x10|0x03|
Message | 1 | Solar Heat ENA
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x02|0x41|0x75|0x78|0x31|0x00|0xc9|0x10|0x03|
Message | 2 | Aux1
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x03|0x41|0x75|0x78|0x32|0x00|0xcb|0x10|0x03|
Message | 3 | Aux2
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x04|0x50|0x6f|0x6f|0x6c|0x20|0x4c|0x69|0x67|0x68|0x74|0x00|0x1e|0x10|0x03|
Message | 4 | Pool Light
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x05|0x41|0x75|0x78|0x36|0x00|0xd1|0x10|0x03|
Message | 5 | Aux6
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x06|0x4a|0x61|0x6e|0x64|0x79|0x20|0x65|0x50|0x55|0x4d|0x50|0x20|0x20|0x20|0x31|0x00|0xbc|0x10|0x03|
Message | 6 | Jandy ePUMP 1
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x07|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x37|0x35|0x30|0x00|0x06|0x10|0x03|
Message | 7 | RPM: 2750
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x08|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x30|0x00|0x4d|0x10|0x03|
Message | 8 | Watts: 0
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x09|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x46|0x20|0x32|0x00|0x91|0x10|0x03|
Message | 9 | Intelliflo VF 2
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0a|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x32|0x35|0x30|0x00|0x04|0x10|0x03|
Message | 10 | RPM: 2250
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0b|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x31|0x30|0x30|0x00|0xb1|0x10|0x03|
Message | 11 | Watts: 100
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0c|0x20|0x20|0x20|0x20|0x47|0x50|0x4d|0x3a|0x20|0x31|0x30|0x30|0x00|0xc3|0x10|0x03|
Message | 12 | GPM: 100
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0d|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x53|0x20|0x33|0x00|0xa3|0x10|0x03|
Message | 13 | Intelliflo VS 3
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0e|0x28|0x4f|0x66|0x66|0x6c|0x69|0x6e|0x65|0x29|0x00|0x8a|0x10|0x03|
Message | 14 | (Offline)
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0f|0x20|0x00|0x97|0x10|0x03|
Message | 15 |
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x10|0x20|0x00|0x98|0x10|0x03|
Message | 16 |
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x11|0x20|0x00|0x99|0x10|0x03|
Message | 17 |
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
Button | 1 | |-| |-| |-| -off-
Notice: Turning IAQ SEND on
*/
/*
Notice: Turning IAQ SEND off
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x23|0x5b|0xc1|0x10|0x03|
New Page | Status
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x2d|0x45|0x71|0x75|0x69|0x70|0x6d|0x65|0x6e|0x74|0x20|0x53|0x74|0x61|0x74|0x75|0x73|0x00|0xcc|0x10|0x03|
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x00|0x46|0x69|0x6c|0x74|0x65|0x72|0x20|0x50|0x75|0x6d|0x70|0x00|0x90|0x10|0x03|
Message | 0 | Filter Pump
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x01|0x41|0x75|0x78|0x31|0x00|0xc8|0x10|0x03|
Message | 1 | Aux1
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x02|0x41|0x75|0x78|0x32|0x00|0xca|0x10|0x03|
Message | 2 | Aux2
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x03|0x50|0x6f|0x6f|0x6c|0x20|0x4c|0x69|0x67|0x68|0x74|0x00|0x1d|0x10|0x03|
Message | 3 | Pool Light
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x04|0x41|0x75|0x78|0x36|0x00|0xd0|0x10|0x03|
Message | 4 | Aux6
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x05|0x4a|0x61|0x6e|0x64|0x79|0x20|0x65|0x50|0x55|0x4d|0x50|0x20|0x20|0x20|0x31|0x00|0xbb|0x10|0x03|
Message | 5 | Jandy ePUMP 1
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x06|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x37|0x35|0x30|0x00|0x05|0x10|0x03|
Message | 6 | RPM: 2750
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x07|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x30|0x00|0x4c|0x10|0x03|
Message | 7 | Watts: 0
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x08|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x46|0x20|0x32|0x00|0x90|0x10|0x03|
Message | 8 | Intelliflo VF 2
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x09|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x32|0x32|0x35|0x30|0x00|0x03|0x10|0x03|
Message | 9 | RPM: 2250
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0a|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x31|0x30|0x33|0x00|0xb3|0x10|0x03|
Message | 10 | Watts: 103
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0b|0x20|0x20|0x20|0x20|0x47|0x50|0x4d|0x3a|0x20|0x31|0x30|0x30|0x00|0xc2|0x10|0x03|
Message | 11 | GPM: 100
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0c|0x49|0x6e|0x74|0x65|0x6c|0x6c|0x69|0x66|0x6c|0x6f|0x20|0x56|0x53|0x20|0x33|0x00|0xa2|0x10|0x03|
Message | 12 | Intelliflo VS 3
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0d|0x20|0x20|0x20|0x20|0x52|0x50|0x4d|0x3a|0x20|0x31|0x37|0x35|0x30|0x00|0x0b|0x10|0x03|
Message | 13 | RPM: 1750
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0e|0x20|0x20|0x57|0x61|0x74|0x74|0x73|0x3a|0x20|0x33|0x34|0x00|0x8a|0x10|0x03|
Message | 14 | Watts: 34
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x0f|0x41|0x51|0x55|0x41|0x50|0x55|0x52|0x45|0x20|0x33|0x30|0x25|0x00|0x83|0x10|0x03|
Message | 15 | AQUAPURE 30%
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x10|0x53|0x61|0x6c|0x74|0x20|0x33|0x38|0x30|0x30|0x20|0x50|0x50|0x4d|0x00|0x04|0x10|0x03|
Message | 16 | Salt 3800 PPM
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x25|0x11|0x20|0x00|0x99|0x10|0x03|
Message | 17 |
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
Button | 1 | |-| |-| |-| -off-
Notice: Turning IAQ SEND on
*/
/*
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00|0x6a|0x10|0x03|
No next page
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
Button | 1 | 0x00 | |-| |-| -off-
Get next page
Debug: To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x12|0x25|0x10|0x03|
Has next page
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00|0x6a|0x10|0x03|
Button | 1 | 0x02 | |-| |-| -off-
Can go up
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
Button | 1 | 0x00 | |-| |-| -off-
*/
/*
No Next page
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x00|0x00|0x00|0x68|0x10|0x03|
Button | 1 | 0x00 | |-| |-| -off-
Next Page
Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00|0x6a|0x10|0x03|
Button | 1 | 0x02 | |-| |-| -off-
*/

1698
iaqtouch.h Normal file

File diff suppressed because it is too large Load Diff

1043
iaqtouch_aq_programmer.c Normal file

File diff suppressed because it is too large Load Diff

25
iaqtouch_aq_programmer.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef IAQ_TOUCH_PROGRAMMER_H_
#define IAQ_TOUCH_PROGRAMMER_H_
unsigned char pop_iaqt_cmd(unsigned char receive_type);
void set_iaq_cansend(bool cansend);
bool iaqt_queue_cmd(unsigned char cmd);
void *set_aqualink_iaqtouch_pump_rpm( void *ptr );
void *set_aqualink_iaqtouch_vsp_assignments( void *ptr );
void *get_aqualink_iaqtouch_setpoints( void *ptr );
void *get_aqualink_iaqtouch_aux_labels( void *ptr );
void *set_aqualink_iaqtouch_swg_percent( void *ptr );
void *set_aqualink_iaqtouch_swg_boost( void *ptr );
void *set_aqualink_iaqtouch_spa_heater_temp( void *ptr );
void *set_aqualink_iaqtouch_pool_heater_temp( void *ptr );
void *set_aqualink_iaqtouch_time( void *ptr );
void *set_aqualink_iaqtouch_pump_vs_program( void *ptr );
int ref_iaqt_control_cmd(unsigned char **cmd);
void rem_iaqt_control_cmd(unsigned char *cmd);
#endif // IAQ_TOUCH_PROGRAMMER_H_

View File

@ -1,20 +0,0 @@
#ifndef INIT_BUTTONS_H_
#define INIT_BUTTONS_H_
#define PUMP_INDEX 0
#define SPA_INDEX 1
#define POOL_HEAT_INDEX 9
#define SPA_HEAT_INDEX 10
void initButtons(struct aqualinkdata *aqdata);
#ifndef AQ_RS16
#define TOTAL_BUTONS 12
#else
#define TOTAL_BUTONS 20
// This needs to be called AFTER and as well as initButtons
void initButtons_RS16(struct aqualinkdata *aqdata);
#endif
#endif

View File

@ -295,44 +295,47 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
aqdata->frz_protect_state==ON?1:0);
}
if ( aqdata->swg_percent != TEMP_UNKNOWN ) {
length += sprintf(buffer+length, "{\"type\": \"setpoint_swg\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
if (aqdata->swg_led_state != LED_S_UNKNOWN) {
if ( aqdata->swg_percent != TEMP_UNKNOWN ) {
length += sprintf(buffer+length, "{\"type\": \"setpoint_swg\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
SWG_TOPIC,
"Salt Water Generator",
aqdata->ar_swg_status == SWG_STATUS_OFF?JSON_OFF:JSON_ON,
//aqdata->ar_swg_status == SWG_STATUS_OFF?JSON_OFF:JSON_ON,
LED2text(get_swg_led_state(aqdata)),
aqdata->swg_led_state == OFF?JSON_OFF:JSON_ON,
//LED2text(get_swg_led_state(aqdata)),
LED2text(aqdata->swg_led_state),
((homekit)?2:0),
((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent),
((homekit)?2:0),
((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent),
aqdata->ar_swg_status == SWG_STATUS_OFF?LED2int(OFF):LED2int(ON));
LED2int(aqdata->swg_led_state) );
//aqdata->ar_swg_status == SWG_STATUS_OFF?LED2int(OFF):LED2int(ON));
//length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%d\" },",
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
((homekit_f)?SWG_PERCENT_F_TOPIC:SWG_PERCENT_TOPIC),
"Salt Water Generator Percent",
"on",
((homekit_f)?2:0),
((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent));
if (!homekit) { // For the moment keep boost off homekit
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\"},",
if (!homekit) { // For the moment keep boost off homekit
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\"},",
SWG_BOOST_TOPIC,
"SWG Boost",
aqdata->boost?JSON_ON:JSON_OFF,
aqdata->boost?JSON_ON:JSON_OFF,
aqdata->boost?LED2int(ON):LED2int(OFF));
}
}
}
if ( aqdata->swg_ppm != TEMP_UNKNOWN ) {
if ( aqdata->swg_ppm != TEMP_UNKNOWN ) {
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
((homekit_f)?SWG_PPM_F_TOPIC:SWG_PPM_TOPIC),
"Salt Level PPM",
"on",
((homekit)?2:0),
((homekit_f)?roundf(degFtoC(aqdata->swg_ppm)):aqdata->swg_ppm));
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
((homekit_f)?SWG_PPM_F_TOPIC:SWG_PPM_TOPIC),
"Salt Level PPM",
"on",
((homekit)?2:0),
((homekit_f)?roundf(degFtoC(aqdata->swg_ppm)):aqdata->swg_ppm));
/*
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%d\" },",
@ -342,6 +345,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
aqdata->swg_ppm);
*/
}
}
if ( aqdata->ph != TEMP_UNKNOWN ) {
@ -390,7 +394,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
*/
length += sprintf(buffer+length, "]}");
logMessage(LOG_DEBUG, "WEB: homebridge used %d of %d", length, size);
LOG(NET_LOG,LOG_DEBUG, "WEB: homebridge used %d of %d\n", length, size);
buffer[length] = '\0';
@ -440,11 +444,13 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
else
length += sprintf(buffer+length, ",\"spa_temp\":\"%d\"",aqdata->spa_temp );
if ( aqdata->swg_percent != TEMP_UNKNOWN )
length += sprintf(buffer+length, ",\"swg_percent\":\"%d\"",aqdata->swg_percent );
if (aqdata->swg_led_state != LED_S_UNKNOWN) {
if ( aqdata->swg_percent != TEMP_UNKNOWN )
length += sprintf(buffer+length, ",\"swg_percent\":\"%d\"",aqdata->swg_percent );
if ( aqdata->swg_ppm != TEMP_UNKNOWN )
length += sprintf(buffer+length, ",\"swg_ppm\":\"%d\"",aqdata->swg_ppm );
if ( aqdata->swg_ppm != TEMP_UNKNOWN )
length += sprintf(buffer+length, ",\"swg_ppm\":\"%d\"",aqdata->swg_ppm );
}
if ( aqdata->temp_units == FAHRENHEIT )
length += sprintf(buffer+length, ",\"temp_units\":\"%s\"",JSON_FAHRENHEIT );
@ -477,9 +483,9 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
length += sprintf(buffer+length, "," );
}
if ( aqdata->swg_percent != TEMP_UNKNOWN ) {
length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_TOPIC, LED2text(get_swg_led_state(aqdata)));
if ( aqdata->swg_percent != TEMP_UNKNOWN && aqdata->swg_led_state != LED_S_UNKNOWN ) {
//length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_TOPIC, LED2text(get_swg_led_state(aqdata)));
length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_TOPIC, LED2text(aqdata->swg_led_state));
//length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_TOPIC, aqdata->ar_swg_status == SWG_STATUS_OFF?JSON_OFF:JSON_ON);
length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_BOOST_TOPIC, aqdata->boost?JSON_ON:JSON_OFF);
}
@ -493,6 +499,15 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
// NSF Check below needs to be for VSP Pump (any state), not just known state
for (i=0; i < aqdata->num_pumps; i++) {
/* NSF There is a problem here that needs to be fixed.
printf("Loop %d Message '%s'\n",i,buffer);
printf("Pump Label %s\n",aqdata->pumps[i].button->label);
printf("Pump Name %s\n",aqdata->pumps[i].button->name);
printf("Pump RPM %d\n",aqdata->pumps[i].rpm);
printf("Pump GPM %d\n",aqdata->pumps[i].gpm);
printf("Pump GPM %d\n",aqdata->pumps[i].watts);
printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
*/
if (aqdata->pumps[i].pumpType != PT_UNKNOWN && (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gpm != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN)) {
length += sprintf(buffer+length, "\"Pump_%d\":{\"name\":\"%s\",\"id\":\"%s\",\"RPM\":\"%d\",\"GPM\":\"%d\",\"Watts\":\"%d\",\"Pump_Type\":\"%s\"},",
i+1,aqdata->pumps[i].button->label,aqdata->pumps[i].button->name,aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,20 @@
/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@ -13,6 +30,8 @@
#include "aq_programmer.h"
#include "aqualink.h"
#include "config.h"
#include "rs_msg_utils.h"
#include "devices_jandy.h"
//#include "pda_menu.h"
@ -24,6 +43,8 @@ struct ot_macro _macros[3];
void set_macro_status();
void pump_update(struct aqualinkdata *aq_data, int updated);
bool log_heater_setpoints(struct aqualinkdata *aq_data);
#ifdef AQ_RS16
void rs16led_update(struct aqualinkdata *aq_data, int updated);
#endif
@ -33,15 +54,15 @@ void print_onetouch_menu()
int i;
for (i=0; i < ONETOUCH_LINES; i++) {
//printf("PDA Line %d = %s\n",i,_menu[i]);
logMessage(LOG_INFO, "OneTouch Menu Line %d = %s\n",i,_menu[i]);
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu Line %d = %s\n",i,_menu[i]);
}
if (_ot_hlightcharindexstart > -1) {
logMessage(LOG_INFO, "OneTouch Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
_ot_hlightindex,_menu[_ot_hlightindex],
(_ot_hlightcharindexstart - _ot_hlightcharindexstop + 1), &_menu[_ot_hlightindex][_ot_hlightcharindexstart]);
} else if (_ot_hlightindex > -1) {
logMessage(LOG_INFO, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
}
}
@ -57,7 +78,8 @@ char *onetouch_menu_hlight()
char *onetouch_menu_hlightchars(int *len)
{
*len = _ot_hlightcharindexstart - _ot_hlightcharindexstop + 1;
//*len = _ot_hlightcharindexstart - _ot_hlightcharindexstop + 1;
*len = _ot_hlightcharindexstop - _ot_hlightcharindexstart + 1;
return &_menu[_ot_hlightindex][_ot_hlightcharindexstart];
}
@ -76,16 +98,36 @@ int onetouch_menu_find_index(char *text)
int i;
for (i = 0; i < ONETOUCH_LINES; i++) {
if (ot_strcmp(onetouch_menu_line(i), text) == 0)
//if (ot_strcmp(onetouch_menu_line(i), text, limit) == 0)
if (rsm_strcmp(onetouch_menu_line(i), text) == 0)
//if (rsm_strcmp(onetouch_menu_line(i), text, limit) == 0)
return i;
}
return -1;
}
/*
One Touch: OneTouch Menu Line 3 = Set Pool to: 20%
One Touch: OneTouch Menu Line 4 = Set Spa to:100%
*/
void log_programming_information(struct aqualinkdata *aq_data)
{
switch(get_onetouch_memu_type()){
case OTM_SET_AQUAPURE:
if (isCOMBO_PANEL && aq_data->aqbuttons[SPA_INDEX].led->state == ON)
setSWGpercent(aq_data, rsm_atoi(&_menu[4][13])); // use spa
else
setSWGpercent(aq_data, rsm_atoi(&_menu[3][13])); // use pool
bool process_onetouch_menu_packet(unsigned char* packet, int length)
LOG(ONET_LOG,LOG_INFO, "SWG Set to %d\n",aq_data->swg_percent);
break;
case OTM_SET_TEMP:
log_heater_setpoints(aq_data);
break;
}
}
bool process_onetouch_menu_packet(struct aqualinkdata *aq_data, unsigned char* packet, int length)
{
bool rtn = true;
signed char first_line;
@ -95,6 +137,7 @@ bool process_onetouch_menu_packet(unsigned char* packet, int length)
switch (packet[PKT_CMD]) {
case CMD_PDA_CLEAR:
log_programming_information(aq_data);
_ot_hlightindex = -1;
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
@ -119,7 +162,7 @@ bool process_onetouch_menu_packet(unsigned char* packet, int length)
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
}
logMessage(LOG_DEBUG, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
break;
case CMD_PDA_HIGHLIGHTCHARS:
@ -132,7 +175,7 @@ bool process_onetouch_menu_packet(unsigned char* packet, int length)
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
}
logMessage(LOG_DEBUG, "OneTouch Menu highlighted line = %d, '%s' chars '%.*s'\n",
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Menu highlighted line = %d, '%s' chars '%.*s'\n",
_ot_hlightindex,_menu[_ot_hlightindex],
(_ot_hlightcharindexstart - _ot_hlightcharindexstop + 1), &_menu[_ot_hlightindex][_ot_hlightcharindexstart]);
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
@ -145,7 +188,7 @@ bool process_onetouch_menu_packet(unsigned char* packet, int length)
first_line = (signed char)(packet[4]);
last_line = (signed char)(packet[5]);
line_shift = (signed char)(packet[6]);
logMessage(LOG_DEBUG, "\n");
LOG(ONET_LOG,LOG_DEBUG, "\n");
if (line_shift < 0) {
for (i = first_line-line_shift; i <= last_line; i++) {
memcpy(_menu[i+line_shift], _menu[i], AQ_MSGLEN+1);
@ -162,6 +205,7 @@ bool process_onetouch_menu_packet(unsigned char* packet, int length)
return rtn;
}
void setUnits_ot(char *str, struct aqualinkdata *aq_data)
{
// NSF This needs to use setUnits from aqualinkd.c
@ -173,7 +217,7 @@ void setUnits_ot(char *str, struct aqualinkdata *aq_data)
else
aq_data->temp_units = UNKNOWN;
logMessage(LOG_INFO, "Temp Units set to %d (F=0, C=1, Unknown=2)\n", aq_data->temp_units);
LOG(ONET_LOG,LOG_INFO, "Temp Units set to %d (F=0, C=1, Unknown=2)\n", aq_data->temp_units);
}
}
@ -181,15 +225,28 @@ bool log_heater_setpoints(struct aqualinkdata *aq_data)
{
bool rtn = false;
if (ot_strcmp(_menu[2], "Pool Heat") == 0)
aq_data->pool_htr_set_point = ot_atoi(&_menu[2][10]);
if (ot_strcmp(_menu[3], "Spa Heat") == 0 )
aq_data->spa_htr_set_point = ot_atoi(&_menu[3][9]);
if (rsm_strcmp(_menu[2], "Pool Heat") == 0)
aq_data->pool_htr_set_point = rsm_atoi(&_menu[2][10]);
if (rsm_strcmp(_menu[3], "Spa Heat") == 0 )
aq_data->spa_htr_set_point = rsm_atoi(&_menu[3][9]);
else {
if (rsm_strcmp(_menu[2], "Temp1") == 0) {
aq_data->pool_htr_set_point = rsm_atoi(&_menu[2][10]);
if (isSINGLE_DEV_PANEL != true)
{
changePanelToMode_Only();
LOG(AQRS_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
}
}
if (rsm_strcmp(_menu[3], "Temp2") == 0 )
aq_data->spa_htr_set_point = rsm_atoi(&_menu[3][9]);
}
setUnits_ot(_menu[2], aq_data);
logMessage(LOG_DEBUG, "POOL HEATER SETPOINT %d\n",aq_data->pool_htr_set_point);
logMessage(LOG_DEBUG, "SPA HEATER SETPOINT %d\n",aq_data->spa_htr_set_point);
LOG(ONET_LOG,LOG_INFO, "POOL HEATER SETPOINT %d\n",aq_data->pool_htr_set_point);
LOG(ONET_LOG,LOG_INFO, "SPA HEATER SETPOINT %d\n",aq_data->spa_htr_set_point);
aq_data->updated = true;
return rtn;
}
@ -216,7 +273,7 @@ bool log_panelversion(struct aqualinkdata *aq_data)
// Write new null terminator
*(end+1) = 0;
logMessage(LOG_DEBUG, "**** '%s' ****\n",aq_data->version);
LOG(ONET_LOG,LOG_DEBUG, "**** '%s' ****\n",aq_data->version);
return true;
}
@ -226,45 +283,49 @@ bool log_freeze_setpoints(struct aqualinkdata *aq_data)
{
bool rtn = false;
if (ot_strcmp(_menu[3], "Temp") == 0)
aq_data->frz_protect_set_point = ot_atoi(&_menu[3][11]);
if (rsm_strcmp(_menu[3], "Temp") == 0)
aq_data->frz_protect_set_point = rsm_atoi(&_menu[3][11]);
setUnits_ot(_menu[3], aq_data);
logMessage(LOG_DEBUG, "FREEZE PROTECT SETPOINT %d\n",aq_data->frz_protect_set_point);
LOG(ONET_LOG,LOG_INFO, "FREEZE PROTECT SETPOINT %d\n",aq_data->frz_protect_set_point);
return rtn;
}
bool log_qeuiptment_status(struct aqualinkdata *aq_data)
{
int i;
bool rtn = false;
if (ot_strcmp(_menu[2],"Intelliflo VS") == 0 ||
ot_strcmp(_menu[2],"Intelliflo VF") == 0 ||
ot_strcmp(_menu[2],"Jandy ePUMP") == 0) {
if (rsm_strcmp(_menu[2],"Intelliflo VS") == 0 ||
rsm_strcmp(_menu[2],"Intelliflo VF") == 0 ||
rsm_strcmp(_menu[2],"Jandy ePUMP") == 0) {
rtn = true;
int rpm = 0;
int watts = 0;
int gpm = 0;
int pump_index = ot_atoi(&_menu[2][14]);
int pump_index = rsm_atoi(&_menu[2][14]);
// RPM displays differently depending on 3 or 4 digit rpm.
if (ot_strcmp(_menu[3],"RPM:") == 0){
rpm = ot_atoi(&_menu[3][10]);
if (ot_strcmp(_menu[4],"Watts:") == 0) {
watts = ot_atoi(&_menu[4][11]);
if (rsm_strcmp(_menu[3],"RPM:") == 0){
rpm = rsm_atoi(&_menu[3][10]);
if (rsm_strcmp(_menu[4],"Watts:") == 0) {
watts = rsm_atoi(&_menu[4][10]);
}
if (ot_strcmp(_menu[5],"GPM:") == 0) {
gpm = ot_atoi(&_menu[5][11]);
if (rsm_strcmp(_menu[5],"GPM:") == 0) {
gpm = rsm_atoi(&_menu[5][10]);
}
} else if (ot_strcmp(_menu[3],"*** Priming ***") == 0){
} else if (rsm_strcmp(_menu[3],"*** Priming ***") == 0){
rpm = PUMP_PRIMING;
} else if (ot_strcmp(_menu[3],"(Offline)") == 0){
} else if (rsm_strcmp(_menu[3],"(Offline)") == 0){
rpm = PUMP_OFFLINE;
} else if (rsm_strcmp(_menu[3],"(Priming Error)") == 0){
rpm = PUMP_ERROR;
}
logMessage(LOG_DEBUG, "OneTouch Pump %s, Index %d, RPM %d, Watts %d, GPM %d\n",_menu[2],pump_index,rpm,watts,gpm);
LOG(ONET_LOG,LOG_INFO, "OneTouch Pump %s, Index %d, RPM %d, Watts %d, GPM %d\n",_menu[2],pump_index,rpm,watts,gpm);
for (i=0; i < aq_data->num_pumps; i++) {
if (aq_data->pumps[i].pumpIndex == pump_index) {
@ -275,46 +336,44 @@ bool log_qeuiptment_status(struct aqualinkdata *aq_data)
aq_data->pumps[i].watts = watts;
aq_data->pumps[i].gpm = gpm;
if (aq_data->pumps[i].pumpType == PT_UNKNOWN){
if (ot_strcmp(_menu[2],"Intelliflo VS") == 0)
if (rsm_strcmp(_menu[2],"Intelliflo VS") == 0)
aq_data->pumps[i].pumpType = VSPUMP;
else if (ot_strcmp(_menu[2],"Intelliflo VF") == 0)
else if (rsm_strcmp(_menu[2],"Intelliflo VF") == 0)
aq_data->pumps[i].pumpType = VFPUMP;
else if (ot_strcmp(_menu[2],"Jandy ePUMP") == 0)
else if (rsm_strcmp(_menu[2],"Jandy ePUMP") == 0)
aq_data->pumps[i].pumpType = EPUMP;
}
//printf ("Set Pump Type to %d\n",aq_data->pumps[i].pumpType);
}
}
} else if (ot_strcmp(_menu[2],"AQUAPURE") == 0) {
} else if (rsm_strcmp(_menu[2],"AQUAPURE") == 0) {
/* Info: OneTouch Menu Line 0 = Equipment Status
Info: OneTouch Menu Line 1 =
Info: OneTouch Menu Line 2 = AQUAPURE 60%
Info: OneTouch Menu Line 3 = Salt 7600 PPM */
int swgp = atoi(&_menu[2][11]);
int swgp = atoi(&_menu[2][10]);
if ( aq_data->swg_percent != swgp ) {
aq_data->swg_percent = swgp;
//aq_data->swg_percent = swgp;
if (changeSWGpercent(aq_data, swgp))
LOG(ONET_LOG,LOG_INFO, "OneTouch SWG = %d\n",swgp);
rtn = true;
}
logMessage(LOG_DEBUG, "OneTouch SWG = %d\n",swgp);
if (ot_strcmp(_menu[3],"Salt") == 0) {
if (rsm_strcmp(_menu[3],"Salt") == 0) {
int ppm = atoi(&_menu[3][6]);
if ( aq_data->swg_ppm != ppm ) {
aq_data->swg_ppm = ppm;
rtn = true;
}
logMessage(LOG_DEBUG, "OneTouch PPM = %d\n",ppm);
LOG(ONET_LOG,LOG_INFO, "OneTouch PPM = %d\n",ppm);
}
// If it's off, turn it on.
if (aq_data->ar_swg_status == SWG_STATUS_OFF || aq_data->ar_swg_status == SWG_STATUS_UNKNOWN)
aq_data->ar_swg_status = SWG_STATUS_ON;
} else if (ot_strcmp(_menu[2],"Chemlink") == 0) {
} else if (rsm_strcmp(_menu[2],"Chemlink") == 0) {
/* Info: OneTouch Menu Line 0 = Equipment Status
Info: OneTouch Menu Line 1 =
Info: OneTouch Menu Line 2 = Chemlink 1
Info: OneTouch Menu Line 3 = ORP 750/PH 7.0 */
if (ot_strcmp(_menu[3],"ORP") == 0) {
if (rsm_strcmp(_menu[3],"ORP") == 0) {
int orp = atoi(&_menu[3][4]);
char *indx = strchr(_menu[3], '/');
float ph = atof(indx+3);
@ -323,18 +382,18 @@ bool log_qeuiptment_status(struct aqualinkdata *aq_data)
aq_data->orp = orp;
return true;
}
logMessage(LOG_INFO, "OneTouch Cemlink ORP = %d PH = %f\n",orp,ph);
LOG(ONET_LOG,LOG_INFO, "OneTouch Cemlink ORP = %d PH = %f\n",orp,ph);
}
}
#ifdef AQ_RS16
else if (_aqconfig_.rs_panel_size >= 16 ) { // Run over devices that have no status LED's on RS12&16 panels.
else if (PANEL_SIZE >= 16 ) { // Run over devices that have no status LED's on RS12&16 panels.
int j;
for (i=2; i <= ONETOUCH_LINES; i++) {
for (j = RS16_VBUTTONS_START; j <= RS16_VBUTTONS_END; j++) {
if ( ot_strcmp(_menu[i], aq_data->aqbuttons[j].label) == 0 ) {
for (j = aq_data->rs16_vbutton_start; j <= aq_data->rs16_vbutton_end; j++) {
if ( rsm_strcmp(_menu[i], aq_data->aqbuttons[j].label) == 0 ) {
//Matched must be on.
logMessage(LOG_DEBUG, "OneTouch equiptment status '%s' matched '%s'\n",_menu[i],aq_data->aqbuttons[j].label);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch equiptment status '%s' matched '%s'\n",_menu[i],aq_data->aqbuttons[j].label);
rs16led_update(aq_data, j);
aq_data->aqbuttons[j].led->state = ON;
}
@ -350,27 +409,29 @@ bool log_qeuiptment_status(struct aqualinkdata *aq_data)
ot_menu_type get_onetouch_memu_type()
{
if (ot_strcmp(_menu[11],"SYSTEM") == 0)
if (rsm_strcmp(_menu[11],"SYSTEM") == 0)
return OTM_ONETOUCH;
else if (ot_strcmp(_menu[0],"Jandy AquaLinkRS") == 0)
else if (rsm_strcmp(_menu[0],"Jandy AquaLinkRS") == 0)
return OTM_SYSTEM;
else if (ot_strcmp(_menu[0],"EQUIPMENT STATUS") == 0)
else if (rsm_strcmp(_menu[0],"EQUIPMENT STATUS") == 0)
return OTM_EQUIPTMENT_STATUS;
else if (ot_strcmp(_menu[0],"Select Speed") == 0)
else if (rsm_strcmp(_menu[0],"Select Speed") == 0)
return OTM_SELECT_SPEED;
else if (ot_strcmp(_menu[0],"Menu") == 0)
else if (rsm_strcmp(_menu[0],"Menu") == 0)
return OTM_MENUHELP;
else if (ot_strcmp(_menu[0],"Set Temp") == 0)
else if (rsm_strcmp(_menu[0],"Set Temp") == 0)
return OTM_SET_TEMP;
else if (ot_strcmp(_menu[0],"Set Time") == 0)
else if (rsm_strcmp(_menu[0],"Set Time") == 0)
return OTM_SET_TIME;
else if (ot_strcmp(_menu[0],"System Setup") == 0)
else if (rsm_strcmp(_menu[0],"System Setup") == 0)
return OTM_SYSTEM_SETUP;
else if (ot_strcmp(_menu[0],"Freeze Protect") == 0)
else if (rsm_strcmp(_menu[0],"Freeze Protect") == 0)
return OTM_FREEZE_PROTECT;
else if (ot_strcmp(_menu[0],"Boost Pool") == 0)
else if (rsm_strcmp(_menu[0],"Boost Pool") == 0)
return OTM_BOOST;
else if (ot_strcmp(_menu[7],"REV ") == 0) // NSF Need a better check.
else if (rsm_strcmp(_menu[0],"Set AQUAPURE") == 0)
return OTM_SET_AQUAPURE;
else if (rsm_strcmp(_menu[7],"REV ") == 0) // NSF Need a better check.
return OTM_VERSION;
return OTM_UNKNOWN;
@ -384,9 +445,9 @@ void pump_update(struct aqualinkdata *aq_data, int updated) {
if (updated == -1) {
for(i=0; i < MAX_PUMPS; i++) {
if ((updates & bitmask[i]) != bitmask[i]) {
aq_data->pumps[i].rpm = TEMP_UNKNOWN;
aq_data->pumps[i].gpm = TEMP_UNKNOWN;
aq_data->pumps[i].watts = TEMP_UNKNOWN;
aq_data->pumps[i].rpm = PUMP_OFF_RPM;
aq_data->pumps[i].gpm = PUMP_OFF_GPM;
aq_data->pumps[i].watts = PUMP_OFF_WAT;
}
}
updates = '\0';
@ -397,25 +458,25 @@ void pump_update(struct aqualinkdata *aq_data, int updated) {
#ifdef AQ_RS16
void rs16led_update(struct aqualinkdata *aq_data, int updated) {
//logMessage(LOG_INFO, "******* VLED check %d ******\n",updated);
//LOG(ONET_LOG,LOG_INFO, "******* VLED check %d ******\n",updated);
const int bitmask[4] = {1,2,4,8};
static unsigned char updates = '\0';
int i;
if (_aqconfig_.rs_panel_size < 16)
if (PANEL_SIZE < 16)
return;
if (updated == -1) {
for(i=RS16_VBUTTONS_START; i <= RS16_VBUTTONS_END; i++) {
if ((updates & bitmask[i-RS16_VBUTTONS_START]) != bitmask[i-RS16_VBUTTONS_START]) {
for(i=aq_data->rs16_vbutton_start; i <= aq_data->rs16_vbutton_start; i++) {
if ((updates & bitmask[i-aq_data->rs16_vbutton_start]) != bitmask[i-aq_data->rs16_vbutton_end]) {
aq_data->aqbuttons[i].led->state = OFF;
//logMessage(LOG_INFO, "******* Turning off VLED %d ******\n",i);
//LOG(ONET_LOG,LOG_INFO, "******* Turning off VLED %d ******\n",i);
}
}
updates = '\0';
} else if (updated >= RS16_VBUTTONS_START && updated <= RS16_VBUTTONS_END) {
updates |= bitmask[updated - RS16_VBUTTONS_START];
//logMessage(LOG_INFO, "******* Updated VLED status %d ******\n",updated);
} else if (updated >= aq_data->rs16_vbutton_start && updated <= aq_data->rs16_vbutton_end) {
updates |= bitmask[updated - aq_data->rs16_vbutton_start];
//LOG(ONET_LOG,LOG_INFO, "******* Updated VLED status %d ******\n",updated);
}
}
#endif
@ -452,7 +513,7 @@ bool new_menu(struct aqualinkdata *aq_data)
break;
case OTM_VERSION:
rtn = log_panelversion(aq_data);
logMessage(LOG_DEBUG, "**** ONETOUCH INIT ****");
LOG(ONET_LOG,LOG_DEBUG, "**** ONETOUCH INIT ****\n");
queueGetProgramData(ONETOUCH, aq_data);
//set_aqualink_onetouch_pool_heater_temp()
//aq_programmer(AQ_SET_ONETOUCH_POOL_HEATER_TEMP, "95", aq_data);
@ -467,7 +528,7 @@ bool new_menu(struct aqualinkdata *aq_data)
// End of equiptment status chain of menus, reset any pump that wasn't listed in menus
pump_update(aq_data, -1);
#ifdef AQ_RS16
if (_aqconfig_.rs_panel_size >= 16)
if (PANEL_SIZE >= 16)
rs16led_update(aq_data, -1);
#endif
}
@ -495,9 +556,9 @@ void set_macro_status()
chopwhitespace(_macros[2].name);
_macros[2].ison = (_menu[8][15] == 'N'?true:false);
logMessage(LOG_DEBUG, "Macro #1 '%s' is %s\n",_macros[0].name,_macros[0].ison?"On":"Off");
logMessage(LOG_DEBUG, "Macro #2 '%s' is %s\n",_macros[1].name,_macros[1].ison?"On":"Off");
logMessage(LOG_DEBUG, "Macro #3 '%s' is %s\n",_macros[2].name,_macros[2].ison?"On":"Off");
LOG(ONET_LOG,LOG_DEBUG, "Macro #1 '%s' is %s\n",_macros[0].name,_macros[0].ison?"On":"Off");
LOG(ONET_LOG,LOG_DEBUG, "Macro #2 '%s' is %s\n",_macros[1].name,_macros[1].ison?"On":"Off");
LOG(ONET_LOG,LOG_DEBUG, "Macro #3 '%s' is %s\n",_macros[2].name,_macros[2].ison?"On":"Off");
}
}
@ -526,10 +587,10 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
//process_pda_packet(packet, length);
//logMessage(LOG_DEBUG, "RS Received ONETOUCH 0x%02hhx\n", packet[PKT_CMD]);
//LOG(ONET_LOG,LOG_DEBUG, "RS Received ONETOUCH 0x%02hhx\n", packet[PKT_CMD]);
//debuglogPacket(packet, length);
process_onetouch_menu_packet(packet, length);
process_onetouch_menu_packet(aq_data, packet, length);
// Check for new menu.
// Usually PDA_CLEAR bunch of CMD_MSG_LONG then a CMD_PDA_HIGHLIGHT or CMD_PDA_HIGHLIGHTCHARS
@ -549,8 +610,9 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
_last_kick_type = KICKT_CMD;
}
if (packet[PKT_CMD] == CMD_PDA_CLEAR)
if (packet[PKT_CMD] == CMD_PDA_CLEAR) {
filling_menu = true;
}
/*
//if (_last_msg_type == CMD_MSG_LONG && packet[PKT_CMD] != CMD_MSG_LONG) {
@ -569,10 +631,12 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
// Receive 0x04 while building menu
if ( packet[PKT_CMD] == CMD_MSG_LONG)
logMessage(LOG_DEBUG, "RS received ONETOUCH packet of type %s length %d '%.*s'\n", get_packet_type(packet, length), length, AQ_MSGLEN, (char*)packet+PKT_DATA+1);
else
logMessage(LOG_DEBUG, "RS received ONETOUCH packet of type %s length %d\n", get_packet_type(packet, length), length);
if (getLogLevel(ONET_LOG) == LOG_DEBUG){
if ( packet[PKT_CMD] == CMD_MSG_LONG)
LOG(ONET_LOG,LOG_DEBUG, "RS received ONETOUCH packet of type %s length %d '%.*s'\n", get_packet_type(packet, length), length, AQ_MSGLEN, (char*)packet+PKT_DATA+1);
else
LOG(ONET_LOG,LOG_DEBUG, "RS received ONETOUCH packet of type %s length %d\n", get_packet_type(packet, length), length);
}
//debuglogPacket(packet, length);
@ -583,7 +647,7 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
switch (packet[PKT_CMD])
{
case CMD_ACK:
//logMessage(LOG_DEBUG, "RS Received ACK length %d.\n", length);
//LOG(ONET_LOG,LOG_DEBUG, "RS Received ACK length %d.\n", length);
break;
//case CMD_PDA_HIGHLIGHT: // This doesn't work for end of menu, if menu is complete then get a change line, highlight isn't sent.
@ -592,7 +656,7 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
case 0x04:
case 0x08:
logMessage(LOG_DEBUG, "RS Received MENU complete\n");
LOG(ONET_LOG,LOG_DEBUG, "RS Received MENU complete\n");
set_macro_status();
break;
@ -600,11 +664,11 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
case CMD_MSG_LONG:
msg = (char *)packet + PKT_DATA + 1;
logMessage(LOG_DEBUG, "RS Received message data 0x%02hhx string '%s'\n",packet[PKT_DATA],msg);
LOG(ONET_LOG,LOG_DEBUG, "RS Received message data 0x%02hhx string '%s'\n",packet[PKT_DATA],msg);
break;
default:
//logMessage(LOG_DEBUG, "RS Received 0x%02hhx\n", packet[PKT_CMD]);
//LOG(ONET_LOG,LOG_DEBUG, "RS Received 0x%02hhx\n", packet[PKT_CMD]);
break;
}
*/
@ -612,49 +676,6 @@ bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkd
}
// Check s2 exists in s1
int ot_strcmp(const char *s1, const char *s2)
{
char *sp1 = (char *)s1;
char *sp2 = (char *)s2;
//int i=0;
// Get rid of all padding
while(isspace(*sp1)) sp1++;
while(isspace(*sp2)) sp2++;
// Need to write this myself for speed
//logMessage(LOG_DEBUG, "OneTouch compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2);
return strncasecmp(sp1, sp2, strlen(sp2));
}
#define INT_MAX +2147483647
#define INT_MIN -2147483647
// atoi that can have blank start
int ot_atoi(const char* str)
{
int sign = 1, base = 0, i = 0;
// if whitespaces then ignore.
while (str[i] == ' ') {
i++;
}
// checking for valid input
while (str[i] >= '0' && str[i] <= '9') {
// handling overflow test case
if (base > INT_MAX / 10 || (base == INT_MAX / 10 && str[i] - '0' > 7)) {
if (sign == 1)
return INT_MAX;
else
return INT_MIN;
}
base = 10 * base + (str[i++] - '0');
}
return base * sign;
}
/*
Version something like
Info: OneTouch Menu Line 0 =

View File

@ -7,8 +7,7 @@
#define ONETOUCH_LINES 12
#define PUMP_PRIMING -1
#define PUMP_OFFLINE -2
#define KICKT_CMD 0
#define KICKT_MENU 1

View File

@ -1,3 +1,18 @@
/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include <stdio.h>
#include <stdlib.h>
@ -7,6 +22,9 @@
#include "aq_programmer.h"
#include "onetouch.h"
#include "aqualink.h"
#include "rs_msg_utils.h"
#include "config.h"
#include "devices_jandy.h"
unsigned char _ot_pgm_command = NUL;
@ -30,7 +48,7 @@ unsigned char pop_ot_cmd(unsigned char receive_type)
_ot_pgm_command = NUL;
}
logMessage(LOG_DEBUG, "OneTouch Sending '0x%02hhx' to controller\n", cmd);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Sending '0x%02hhx' to controller\n", cmd);
return cmd;
}
@ -50,7 +68,7 @@ void waitfor_ot_queue2empty()
}
if (_ot_pgm_command != NUL) {
logMessage(LOG_WARNING, "OneTouch Send command Queue did not empty, timeout\n");
LOG(ONET_LOG,LOG_WARNING, "OneTouch Send command Queue did not empty, timeout\n");
}
}
@ -62,19 +80,19 @@ void send_ot_cmd(unsigned char cmd)
ot_queue_cmd(cmd);
logMessage(LOG_INFO, "OneTouch Queue send '0x%02hhx' to controller (programming)\n", _ot_pgm_command);
LOG(ONET_LOG,LOG_INFO, "OneTouch Queue send '0x%02hhx' to controller (programming)\n", _ot_pgm_command);
}
bool waitForOT_MessageTypes(struct aqualinkdata *aq_data, unsigned char mtype1, unsigned char mtype2, int numMessageReceived)
{
//logMessage(LOG_DEBUG, "waitForOT_MessageType 0x%02hhx || 0x%02hhx\n",mtype1,mtype2);
//LOG(ONET_LOG,LOG_DEBUG, "waitForOT_MessageType 0x%02hhx || 0x%02hhx\n",mtype1,mtype2);
int i=0;
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
while( ++i <= numMessageReceived)
{
logMessage(LOG_DEBUG, "waitForOT_MessageType 0x%02hhx||0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype1,mtype2,*last_onetouch_packet(),i,numMessageReceived);
LOG(ONET_LOG,LOG_DEBUG, "waitForOT_MessageType 0x%02hhx||0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype1,mtype2,*last_onetouch_packet(),i,numMessageReceived);
if (*last_onetouch_packet() == mtype1 || *last_onetouch_packet() == mtype2) break;
@ -84,11 +102,11 @@ bool waitForOT_MessageTypes(struct aqualinkdata *aq_data, unsigned char mtype1,
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if (*last_onetouch_packet() != mtype1 && *last_onetouch_packet() != mtype2) {
//logMessage(LOG_ERR, "Could not select MENU of Aqualink control panel\n");
logMessage(LOG_DEBUG, "waitForOT_MessageType: did not receive 0x%02hhx||0x%02hhx\n",mtype1,mtype2);
//LOG(ONET_LOG,LOG_ERR, "Could not select MENU of Aqualink control panel\n");
LOG(ONET_LOG,LOG_DEBUG, "waitForOT_MessageType: did not receive 0x%02hhx||0x%02hhx\n",mtype1,mtype2);
return false;
} else
logMessage(LOG_DEBUG, "waitForOT_MessageType: received 0x%02hhx\n",*last_onetouch_packet());
LOG(ONET_LOG,LOG_DEBUG, "waitForOT_MessageType: received 0x%02hhx\n",*last_onetouch_packet());
return true;
}
@ -104,7 +122,7 @@ bool waitForNextOT_Menu(struct aqualinkdata *aq_data) {
while( ++i <= 20)
{
logMessage(LOG_DEBUG, "waitForNextOT_Menu (%d of %d)\n",i,numMessageReceived);
LOG(ONET_LOG,LOG_DEBUG, "waitForNextOT_Menu (%d of %d)\n",i,numMessageReceived);
//if(thread_kick_type() == KICKT_MENU) break;
@ -129,12 +147,12 @@ bool highlight_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
// Also need page up and down " ^^ More vv"
if ( (index = onetouch_menu_find_index(item)) != -1) {
cnt = index - onetouch_menu_hlightindex();
logMessage(LOG_DEBUG, "OneTouch menu caculator selected=%d, wanted=%d, move=%d timesn",onetouch_menu_hlightindex(),index,cnt);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch menu caculator selected=%d, wanted=%d, move=%d times\n",onetouch_menu_hlightindex(),index,cnt);
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_DOWN);
waitfor_ot_queue2empty();
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,3);
if (ot_strcmp(onetouch_menu_hlight(), item) == 0) {
if (rsm_strcmp(onetouch_menu_hlight(), item) == 0) {
// We got here early, probably because blank menu item
break;
}
@ -142,8 +160,8 @@ bool highlight_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
// check if it's quicker to go up rather than down, if second page can't go up.
// This doesn;t work yet, not all versions of control panels have the same amount of items.
/*
if (cnt <= 5 || ot_strcmp(onetouch_menu_line(10), " ^^ More", 10) == 0 ) {
logMessage(LOG_DEBUG, "OneTouch device programmer pressing down %d times\n",cnt);
if (cnt <= 5 || rsm_strcmp(onetouch_menu_line(10), " ^^ More", 10) == 0 ) {
LOG(ONET_LOG,LOG_DEBUG, "OneTouch device programmer pressing down %d times\n",cnt);
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_DOWN);
//waitfor_ot_queue2empty();
@ -151,7 +169,7 @@ bool highlight_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
}
} else {
cnt = 11 - cnt;
logMessage(LOG_DEBUG, "OneTouch device programmer pressing up %d times\n",cnt);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch device programmer pressing up %d times\n",cnt);
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_UP);
//waitfor_ot_queue2empty();
@ -163,7 +181,7 @@ bool highlight_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
} else {
// Is their another page to search
if (ot_strcmp(onetouch_menu_line(10), "^^ More") == 0) {
if (rsm_strcmp(onetouch_menu_line(10), "^^ More") == 0) {
char first_item[AQ_MSGLEN+1];
do {
send_ot_cmd(KEY_ONET_PAGE_DN);
@ -175,12 +193,12 @@ bool highlight_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
// Need to get menu item 1.
// Hit page down until menu item matches 1.
} else
logMessage(LOG_ERR, "OneTouch device programmer menu item '%s' does not exist\n",item);
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer menu item '%s' does not exist\n",item);
//print_onetouch_menu();
}
if ( ot_strcmp(onetouch_menu_hlight(), item) != 0) {
logMessage(LOG_ERR, "OneTouch device programmer menu item '%s' not selected\n",item);
if ( rsm_strcmp(onetouch_menu_hlight(), item) != 0) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer menu item '%s' not selected\n",item);
//print_onetouch_menu();
return false;
} else {
@ -220,7 +238,7 @@ bool goto_onetouch_system_menu(struct aqualinkdata *aq_data)
} else if (get_onetouch_memu_type() == OTM_ONETOUCH) {
//printf("*** ONE TOUCH MENU ***\n");
// Can only be one of 2 options in this menu, so if it's not the one we want, hit down first
if ( ot_strcmp(onetouch_menu_hlight(), "System") != 0) {
if ( rsm_strcmp(onetouch_menu_hlight(), "System") != 0) {
send_ot_cmd(KEY_ONET_DOWN);
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
}
@ -229,12 +247,12 @@ bool goto_onetouch_system_menu(struct aqualinkdata *aq_data)
waitForNextOT_Menu(aq_data);
//return false;
} else {
logMessage(LOG_ERR, "OneTouch device programmer couldn't get to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer couldn't get to System menu\n");
return false;
}
if (get_onetouch_memu_type() != OTM_SYSTEM) {
logMessage(LOG_ERR, "OneTouch device programmer couldn't get to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer couldn't get to System menu\n");
return false;
}
@ -249,10 +267,10 @@ bool goto_onetouch_menu(struct aqualinkdata *aq_data, ot_menu_type menu)
char *second_menu = false;
char *third_menu = false;
logMessage(LOG_DEBUG, "OneTouch device programmer request for menu %d\n",menu);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch device programmer request for menu %d\n",menu);
if ( ! goto_onetouch_system_menu(aq_data) ) {
logMessage(LOG_ERR, "OneTouch device programmer failed to get system menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get system menu\n");
return false;
}
@ -295,7 +313,7 @@ bool goto_onetouch_menu(struct aqualinkdata *aq_data, ot_menu_type menu)
break;
case OTM_EQUIPTMENT_ONOFF:
if ( select_onetouch_menu_item(aq_data, "Equipment ON/OFF") == false ) {
logMessage(LOG_ERR, "OneTouch device programmer couldn't select 'Equipment ON/OFF' menu %d\n",menu);
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer couldn't select 'Equipment ON/OFF' menu %d\n",menu);
equErr = true;
}
break;
@ -307,7 +325,7 @@ bool goto_onetouch_menu(struct aqualinkdata *aq_data, ot_menu_type menu)
case OTM_BOOST:
case OTM_SYSTEM_SETUP:
if ( select_onetouch_menu_item(aq_data, "Menu / Help") == false ) {
logMessage(LOG_ERR, "OneTouch device programmer couldn't select menu %d\n",menu);
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer couldn't select menu %d\n",menu);
break;
}
if (second_menu)
@ -316,7 +334,7 @@ bool goto_onetouch_menu(struct aqualinkdata *aq_data, ot_menu_type menu)
select_onetouch_menu_item(aq_data, third_menu);
break;
default:
logMessage(LOG_ERR, "OneTouch device programmer doesn't know how to access menu %d\n",menu);
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer doesn't know how to access menu %d\n",menu);
break;
}
@ -325,6 +343,11 @@ bool goto_onetouch_menu(struct aqualinkdata *aq_data, ot_menu_type menu)
return !equErr;
}
// Need to wait a bit longer for set temp menu if single device (nag screen temp1 higher than temp2)
if ( menu == OTM_SET_TEMP && get_onetouch_memu_type() != menu) {
waitForNextOT_Menu(aq_data);
}
if (get_onetouch_memu_type() != menu)
return false;
@ -371,7 +394,7 @@ bool intPress(int diff) {
PROGRAMMING FUNCTIONS
*/
void *set_aqualink_pump_rpm( void *ptr )
void *set_aqualink_onetouch_pump_rpm( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
@ -388,7 +411,7 @@ void *set_aqualink_pump_rpm( void *ptr )
for (structIndex=0; structIndex < aq_data->num_pumps; structIndex++) {
if (aq_data->pumps[structIndex].pumpIndex == pumpIndex) {
if (aq_data->pumps[structIndex].pumpType == PT_UNKNOWN) {
logMessage(LOG_ERR, "Can't set Pump RPM/GPM until type is known\n");
LOG(ONET_LOG,LOG_ERR, "Can't set Pump RPM/GPM until type is known\n");
cleanAndTerminateThread(threadCtrl);
return ptr;
}
@ -400,11 +423,11 @@ void *set_aqualink_pump_rpm( void *ptr )
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_PUMP_RPM);
logMessage(LOG_INFO, "OneTouch Set Pump %d to RPM %d\n",pumpIndex,pumpRPM);
LOG(ONET_LOG,LOG_INFO, "OneTouch Set Pump %d to RPM %d\n",pumpIndex,pumpRPM);
if (! goto_onetouch_menu(aq_data, OTM_EQUIPTMENT_ONOFF) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get Equiptment on/off menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't get Equiptment on/off menu\n");
}
sprintf(VSPstr, "VSP%1d Spd Adj",pumpIndex);
@ -434,6 +457,7 @@ void *set_aqualink_pump_rpm( void *ptr )
break;
}
}
//OneTouch Menu Line 3 = set to 50 GPM
//OneTouch Menu Line 3 = set to 50 GPM
//OneTouch Menu Line 3 = set to 1750 RPM
if ( strstr(onetouch_menu_hlight(), "set to") != NULL ) {
@ -442,65 +466,67 @@ void *set_aqualink_pump_rpm( void *ptr )
// RPM 3450 & 600 max & min
// Panel will change 2nd,3rd & 4th digits depending on previos digit
// so reget the RPM after every change.
int RPM = ot_atoi(&onetouch_menu_hlight()[7]);
int RPM = rsm_atoi(&onetouch_menu_hlight()[7]);
intPress(digitDiff(RPM, pumpRPM, 10000));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
RPM = ot_atoi(&onetouch_menu_hlight()[7]);
RPM = rsm_atoi(&onetouch_menu_hlight()[7]);
intPress(digitDiff(RPM, pumpRPM, 1000));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
RPM = ot_atoi(&onetouch_menu_hlight()[7]);
RPM = rsm_atoi(&onetouch_menu_hlight()[7]);
intPress(digitDiff(RPM, pumpRPM, 100));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
RPM = ot_atoi(&onetouch_menu_hlight()[7]);
RPM = rsm_atoi(&onetouch_menu_hlight()[7]);
intPress(digitDiff(RPM, pumpRPM, 10));
// Get the new RPM.
aq_data->pumps[structIndex].rpm = ot_atoi(&onetouch_menu_hlight()[7]);
aq_data->pumps[structIndex].rpm = rsm_atoi(&onetouch_menu_hlight()[7]);
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitfor_ot_queue2empty();
waitForOT_MessageTypes(aq_data,CMD_MSG_LONG,CMD_PDA_HIGHLIGHTCHARS,5);
} else if (strstr(onetouch_menu_hlight(), "GPM") != NULL ) {
// GPM 130 max, GPM 15 min
for (i=0; i < 24 ; i++) { // Max of 23 key presses to get from max to min
int GPM = ot_atoi(&onetouch_menu_hlight()[8]);
int GPM = rsm_atoi(&onetouch_menu_hlight()[8]);
//printf ("*** GPM = %d | Setting to %d\n",GPM,pumpRPM);
if ( GPM > pumpRPM ) {
send_ot_cmd(KEY_ONET_DOWN);
} else if (GPM < pumpRPM) {
send_ot_cmd(KEY_ONET_UP);
} else {
aq_data->pumps[structIndex].gpm = ot_atoi(&onetouch_menu_hlight()[8]);;
aq_data->pumps[structIndex].gpm = rsm_atoi(&onetouch_menu_hlight()[8]);;
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
break;
}
waitfor_ot_queue2empty();
// This really does slow it down, but we hit up.down once too ofter without it, need to fix.
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5);
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5);
waitForOT_MessageTypes(aq_data,CMD_MSG_LONG,CMD_PDA_HIGHLIGHTCHARS,5);
// Reset the pump GPM
aq_data->pumps[structIndex].rpm = GPM;
//aq_data->pumps[structIndex].rpm = GPM;
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_MSG_LONG,5);
//waitForNextOT_Menu(aq_data);
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer Not sure how to set '%s'\n",onetouch_menu_hlight());
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer Not sure how to set '%s'\n",onetouch_menu_hlight());
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer didn't select VSP\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't select VSP\n");
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer Couldn't find Select Speed menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer Couldn't find Select Speed menu\n");
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer Couldn't find VSP in Equiptment on/off menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer Couldn't find VSP in Equiptment on/off menu\n");
}
//printf( "Menu Index %d\n", onetouch_menu_find_index(VSPstr));
//printf("**** GOT THIS FAR, NOW LET'S GO BACK ****\n");
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
//printf("**** CLEAN EXIT ****\n");
@ -525,9 +551,9 @@ void *set_aqualink_onetouch_macro( void *ptr )
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_MACRO);
logMessage(LOG_DEBUG, "OneTouch Marco\n");
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Marco\n");
logMessage(LOG_ERR, "OneTouch Macro not implimented (device=%d|state=%d)\n",device,state);
LOG(ONET_LOG,LOG_ERR, "OneTouch Macro not implimented (device=%d|state=%d)\n",device,state);
cleanAndTerminateThread(threadCtrl);
@ -543,28 +569,20 @@ void *get_aqualink_onetouch_setpoints( void *ptr )
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_ONETOUCH_SETPOINTS);
logMessage(LOG_DEBUG, "OneTouch get heater temps\n");
LOG(ONET_LOG,LOG_DEBUG, "OneTouch get heater temps\n");
if ( !goto_onetouch_menu(aq_data, OTM_SET_TEMP) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
}
if ( !goto_onetouch_menu(aq_data, OTM_FREEZE_PROTECT) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get freeze protect menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get freeze protect menu\n");
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
/*
logMessage(LOG_DEBUG, "*** OneTouch device programmer TEST page down ***\n");
goto_onetouch_menu(aq_data, OTM_SYSTEM_SETUP);
highlight_onetouch_menu_item(aq_data, "About");
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForNextOT_Menu(aq_data);
logMessage(LOG_DEBUG, "*** OneTouch device programmer END TEST page down ***\n");
*/
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
@ -581,18 +599,32 @@ void set_aqualink_onetouch_heater_setpoint( struct aqualinkdata *aq_data, bool i
unsigned char direction;
if ( !goto_onetouch_menu(aq_data, OTM_SET_TEMP) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
}
if(ispool){
if (!highlight_onetouch_menu_item(aq_data, "Pool Heat")) {
logMessage(LOG_ERR, "OneTouch device programmer failed to get pool heater temp menu\n");
return;
if (isCOMBO_PANEL) {
if (!highlight_onetouch_menu_item(aq_data, "Pool Heat")) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get pool heater temp menu\n");
return;
}
} else {
if (!highlight_onetouch_menu_item(aq_data, "Temp1")) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get Temp1 temp menu\n");
return;
}
}
} else {
if (!highlight_onetouch_menu_item(aq_data, "Spa Heat")) {
logMessage(LOG_ERR, "OneTouch device programmer failed to get spa heater temp menu\n");
return;
if (isCOMBO_PANEL) {
if (!highlight_onetouch_menu_item(aq_data, "Spa Heat")) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get spa heater temp menu\n");
return;
}
} else {
if (!highlight_onetouch_menu_item(aq_data, "Temp2")) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get Temp2 temp menu\n");
return;
}
}
}
@ -602,7 +634,7 @@ void set_aqualink_onetouch_heater_setpoint( struct aqualinkdata *aq_data, bool i
{
char *st = onetouch_menu_hlightchars(&len);
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlighted='%.*s'\n", len, st);
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set heater temp highlighted='%.*s'\n", len, st);
}
cval = atoi(onetouch_menu_hlightchars(&len));
@ -614,7 +646,7 @@ void set_aqualink_onetouch_heater_setpoint( struct aqualinkdata *aq_data, bool i
diff=-diff;
}
logMessage(LOG_DEBUG, "** OneTouch set heater temp diff='%d'\n", diff);
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set heater temp diff='%d'\n", diff);
for (i=0; i < diff; i++) {
send_ot_cmd(direction);
@ -627,10 +659,10 @@ void set_aqualink_onetouch_heater_setpoint( struct aqualinkdata *aq_data, bool i
waitfor_ot_queue2empty();
/*
logMessage(LOG_DEBUG, "** OneTouch set heater temp line='%s'\n", onetouch_menu_line(line));
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlight='%d'\n", onetouch_menu_hlightindex());
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlightline='%s'\n", onetouch_menu_line(onetouch_menu_hlightindex()));
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlightchars='%s'\n", onetouch_menu_hlight());
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set heater temp line='%s'\n", onetouch_menu_line(line));
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set heater temp highlight='%d'\n", onetouch_menu_hlightindex());
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set heater temp highlightline='%s'\n", onetouch_menu_line(onetouch_menu_hlightindex()));
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set heater temp highlightchars='%s'\n", onetouch_menu_hlight());
*/
//onetouch_menu_line(line)
//onetouch_menu_hlightindex
@ -648,7 +680,7 @@ void *set_aqualink_onetouch_pool_heater_temp( void *ptr )
int val = atoi((char*)threadCtrl->thread_args);
val = setpoint_check(POOL_HTR_SETOINT, val, aq_data);
logMessage(LOG_DEBUG, "OneTouch set pool heater temp to %d\n", val);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch set pool heater temp to %d\n", val);
set_aqualink_onetouch_heater_setpoint(aq_data, true, val);
cleanAndTerminateThread(threadCtrl);
@ -668,7 +700,7 @@ void *set_aqualink_onetouch_spa_heater_temp( void *ptr )
int val = atoi((char*)threadCtrl->thread_args);
val = setpoint_check(SPA_HTR_SETOINT, val, aq_data);
logMessage(LOG_DEBUG, "OneTouch set spa heater temp to %d\n", val);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch set spa heater temp to %d\n", val);
set_aqualink_onetouch_heater_setpoint(aq_data, false, val);
cleanAndTerminateThread(threadCtrl);
@ -687,39 +719,37 @@ void *set_aqualink_onetouch_boost( void *ptr )
int val = atoi((char*)threadCtrl->thread_args);
logMessage(LOG_DEBUG, "OneTouch request set Boost to '%d'\n",val==true?"On":"Off");
LOG(ONET_LOG,LOG_DEBUG, "OneTouch request set Boost to '%d'\n",val==true?"On":"Off");
if ( !goto_onetouch_menu(aq_data, OTM_BOOST) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get BOOST menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get BOOST menu\n");
} else {
if ( ot_strcmp(onetouch_menu_hlight(), "Start") == 0 ) {
if ( rsm_strcmp(onetouch_menu_hlight(), "Start") == 0 ) {
if (val) {
logMessage(LOG_DEBUG, "OneTouch Boost is Off, turning On\n");
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Boost is Off, turning On\n");
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
} else {
logMessage(LOG_INFO, "OneTouch Boost is Off, ignore request\n");
LOG(ONET_LOG,LOG_INFO, "OneTouch Boost is Off, ignore request\n");
}
} else if ( ot_strcmp(onetouch_menu_hlight(), "Pause") == 0 ) {
} else if ( rsm_strcmp(onetouch_menu_hlight(), "Pause") == 0 ) {
if (! val) {
logMessage(LOG_DEBUG, "OneTouch set Boost is ON, turning Off\n");
LOG(ONET_LOG,LOG_DEBUG, "OneTouch set Boost is ON, turning Off\n");
highlight_onetouch_menu_item(aq_data, "Stop");
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
// Takes ages to see bost is off from menu, to set it here.
aq_data->boost = false;
aq_data->boost_msg[0] = '\0';
aq_data->swg_percent = 0;
setSWGboost(aq_data, false);
} else {
logMessage(LOG_INFO, "OneTouch Boost is On, ignore request\n");
LOG(ONET_LOG,LOG_INFO, "OneTouch Boost is On, ignore request\n");
}
} else {
logMessage(LOG_ERR, "OneTouch Boost unknown menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch Boost unknown menu\n");
}
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
cleanAndTerminateThread(threadCtrl);
@ -733,19 +763,91 @@ void *set_aqualink_onetouch_swg_percent( void *ptr )
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
int cval;
int diff;
int i;
int len;
unsigned char direction;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_SWG_PERCENT);
logMessage(LOG_DEBUG, "OneTouch set SWG Percent\n");
int val = atoi((char*)threadCtrl->thread_args);
val = setpoint_check(SWG_SETPOINT, val, aq_data);
LOG(ONET_LOG,LOG_DEBUG, "OneTouch set SWG Percent to %d\n",val);
if ( !goto_onetouch_menu(aq_data, OTM_SET_AQUAPURE) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get Aquapure menu\n");
} else {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get Aquapure menu\n");
goto f_end;
}
//OneTouch Menu Line 3 = Set Pool to: 50%
//OneTouch Menu Line 4 = Set Spa to: 0%
// Only have option for both on ComboPanel, and us
if (isCOMBO_PANEL) {
if (aq_data->aqbuttons[SPA_INDEX].led->state == OFF) {
if (!highlight_onetouch_menu_item(aq_data, "Set Pool")) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get Pool swg percent\n");
goto f_end;
}
} else {
if (!highlight_onetouch_menu_item(aq_data, "Set Spa")) {
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get Spa swg percent\n");
goto f_end;
}
}
} else {
// NSF Need to check text for congle panel.
}
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHTCHARS,0x00,15); // CMD_PDA_0x04 is just a packer.
{
i=0;
char *st = onetouch_menu_hlightchars(&len);
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set SWG Percent highlighted='%.*s' len=%d st=%s\n", len, st, len, st);
while (len > 5 || len < 0 && i < 5) {
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set SWG Percent highlighted waiting again\n");
delay(50);
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHTCHARS,0x00,5); // CMD_PDA_0x04 is just a packer.
st = onetouch_menu_hlightchars(&len);
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set SWG Percent highlighted='%.*s' len=%d st=%s\n", len, st, len, st);
i++;
}
}
cval = atoi(onetouch_menu_hlightchars(&len));
diff = (val - cval) / 5;
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set SWG Percent val=%d cval=%d diff=%d \n", val,cval,diff);
if (diff > 0) {
direction = KEY_ONET_UP;
} else if (diff < 0) {
direction = KEY_ONET_DOWN;
diff=-diff;
}
LOG(ONET_LOG,LOG_DEBUG, "** OneTouch set SWG Percent diff='%d'\n", diff);
for (i=0; i < diff; i++) {
send_ot_cmd(direction);
waitfor_ot_queue2empty();
}
/*
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHTCHARS,0x00,15); // CMD_PDA_0x04 is just a packer.
setSWGpercent(aq_data,atoi(onetouch_menu_hlightchars(&len)));
*/
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
send_ot_cmd(KEY_ONET_BACK);
waitfor_ot_queue2empty();
f_end:
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
cleanAndTerminateThread(threadCtrl);
@ -767,18 +869,18 @@ void *set_aqualink_onetouch_time( void *ptr )
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_TIME);
logMessage(LOG_ERR, "OneTouch set time not implimented\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch set time not implimented\n");
logMessage(LOG_DEBUG, "OneTouch set time\n");
LOG(ONET_LOG,LOG_DEBUG, "OneTouch set time\n");
if ( !goto_onetouch_menu(aq_data, OTM_SET_TIME) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get time menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get time menu\n");
} else {
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
cleanAndTerminateThread(threadCtrl);

View File

@ -7,7 +7,7 @@ bool ot_queue_cmd(unsigned char cmd);
//bool in_ot_programming_mode(struct aqualinkdata *aq_data);
void *set_aqualink_pump_rpm( void *ptr );
void *set_aqualink_onetouch_pump_rpm( void *ptr );
void *set_aqualink_onetouch_macro( void *ptr );
void *get_aqualink_onetouch_setpoints( void *ptr );
void *set_aqualink_onetouch_spa_heater_temp( void *ptr );

View File

@ -1,17 +1,19 @@
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include "packetLogger.h"
#include "aq_serial.h"
#include "utils.h"
static FILE *_packetLogFile = NULL;
static FILE *_byteLogFile = NULL;
static bool _log2file = false;
static bool _includePentair = false;
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error, bool force);
void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force);
int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool error);
void startPacketLogger(bool debug_RSProtocol_packets, bool read_pentair_packets) {
@ -38,21 +40,22 @@ void writePacketLog(char *buffer) {
}
void logPacket(unsigned char *packet_buffer, int packet_length) {
_logPacket(packet_buffer, packet_length, false, false);
_logPacket(RSSD_LOG, packet_buffer, packet_length, false, false);
}
void logPacketError(unsigned char *packet_buffer, int packet_length) {
_logPacket(packet_buffer, packet_length, true, false);
_logPacket(RSSD_LOG, packet_buffer, packet_length, true, false);
}
void debuglogPacket(unsigned char *packet_buffer, int packet_length) {
_logPacket(packet_buffer, packet_length, false, true);
void debuglogPacket(int16_t from, unsigned char *packet_buffer, int packet_length) {
if ( getLogLevel(from) >= LOG_DEBUG )
_logPacket(from, packet_buffer, packet_length, false, true);
}
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error, bool force)
void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force)
{
// No point in continuing if loglevel is < debug_serial and not writing to file
if ( force == false && error == false && getLogLevel() < LOG_DEBUG_SERIAL && _log2file == false)
if ( force == false && error == false && getLogLevel(from) < LOG_DEBUG_SERIAL && _log2file == false)
return;
char buff[1000];
@ -76,12 +79,12 @@ void _logPacket(unsigned char *packet_buffer, int packet_length, bool error, boo
writePacketLog(buff);
if (error == true)
logMessage(LOG_WARNING, "%s", buff);
LOG(from,LOG_WARNING, "%s", buff);
else {
if (force)
logMessage(LOG_DEBUG, "%s", buff);
LOG(from,LOG_DEBUG, "%s", buff);
else
logMessage(LOG_DEBUG_SERIAL, "%s", buff);
LOG(from,LOG_DEBUG_SERIAL, "%s", buff);
}
}

View File

@ -2,6 +2,7 @@
#define PACKETLOGGER_H_
#include <stdbool.h>
#include <stdint.h>
#define RS485LOGFILE "/tmp/RS485.log"
#define RS485BYTELOGFILE "/tmp/RS485raw.log"
@ -14,7 +15,8 @@ void logPacketError(unsigned char *packet_buffer, int packet_length);
void logPacketByte(unsigned char *byte);
// Only use for manual debugging
void debuglogPacket(unsigned char *packet_buffer, int packet_length);
//void debuglogPacket(unsigned char *packet_buffer, int packet_length);
void debuglogPacket(int16_t from, unsigned char *packet_buffer, int packet_length);
int beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length);
#endif //PACKETLOGGER_H_

159
pda.c
View File

@ -23,12 +23,12 @@
#include "aqualink.h"
#include "init_buttons.h"
#include "pda.h"
#include "pda_menu.h"
#include "utils.h"
#include "aq_panel.h"
#include "packetLogger.h"
#include "devices_jandy.h"
// static struct aqualinkdata _aqualink_data;
static struct aqualinkdata *_aqualink_data;
@ -42,25 +42,16 @@ static bool _initWithRS = false;
#define PDA_WAKE_FOR 6 // ~1 seconds
#ifdef BETA_PDA_AUTOLABEL
//static struct aqconfig *_aqconfig_;
void init_pda(struct aqualinkdata *aqdata)
{
_aqualink_data = aqdata;
//_aqconfig_ = aqconfig;
set_pda_mode(true);
//set_pda_mode(true);
}
#else
void init_pda(struct aqualinkdata *aqdata)
{
_aqualink_data = aqdata;
set_pda_mode(true);
}
#endif
bool pda_shouldSleep() {
//logMessage(LOG_DEBUG, "PDA loop count %d, will sleep at %d\n",_pda_loop_cnt,PDA_LOOP_COUNT);
//LOG(PDA_LOG,LOG_DEBUG, "PDA loop count %d, will sleep at %d\n",_pda_loop_cnt,PDA_LOOP_COUNT);
if (_pda_loop_cnt++ < PDA_WAKE_FOR) {
return false;
} else if (_pda_loop_cnt > PDA_WAKE_FOR + PDA_SLEEP_FOR) {
@ -70,7 +61,7 @@ bool pda_shouldSleep() {
// NSF NEED TO CHECK ACTIVE THREADS.
if (_aqualink_data->active_thread.thread_id != 0) {
logMessage(LOG_DEBUG, "PDA can't sleep as thread %d,%p is active",
LOG(PDA_LOG,LOG_DEBUG, "PDA can't sleep as thread %d,%p is active\n",
_aqualink_data->active_thread.ptype,
_aqualink_data->active_thread.thread_id);
@ -80,7 +71,7 @@ bool pda_shouldSleep() {
// Last see if there are any open websockets. (don't sleep if the web UI is open)
if ( _aqualink_data->open_websockets > 0 ) {
logMessage(LOG_DEBUG, "PDA can't sleep as websocket is active");
LOG(PDA_LOG,LOG_DEBUG, "PDA can't sleep as websocket is active\n");
return false;
}
@ -89,7 +80,7 @@ bool pda_shouldSleep() {
/*
bool pda_shouldSleep() {
//logMessage(LOG_DEBUG, "PDA loop count %d, will sleep at %d\n",_pda_loop_cnt,PDA_LOOP_COUNT);
//LOG(PDA_LOG,LOG_DEBUG, "PDA loop count %d, will sleep at %d\n",_pda_loop_cnt,PDA_LOOP_COUNT);
if (_pda_loop_cnt++ < PDA_LOOP_COUNT) {
return false;
} else if (_pda_loop_cnt > PDA_LOOP_COUNT*2) {
@ -136,7 +127,7 @@ void set_pda_led(struct aqualinkled *led, char state)
}
if (old_state != led->state)
{
logMessage(LOG_DEBUG, "set_pda_led from %d to %d\n", old_state, led->state);
LOG(PDA_LOG,LOG_DEBUG, "set_pda_led from %d to %d\n", old_state, led->state);
}
}
@ -178,7 +169,7 @@ void pass_pda_equiptment_status_item(char *msg)
// Loop through all buttons and match the PDA text.
if ((index = strcasestr(msg, "CHECK AquaPure")) != NULL)
{
logMessage(LOG_DEBUG, "CHECK AquaPure\n");
LOG(PDA_LOG,LOG_DEBUG, "CHECK AquaPure\n");
}
else if ((index = strcasestr(msg, "FREEZE PROTECT")) != NULL)
{
@ -186,25 +177,26 @@ void pass_pda_equiptment_status_item(char *msg)
}
else if ((index = strcasestr(msg, MSG_SWG_PCT)) != NULL)
{
_aqualink_data->swg_percent = atoi(index + strlen(MSG_SWG_PCT));
if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;}
logMessage(LOG_DEBUG, "AquaPure = %d\n", _aqualink_data->swg_percent);
changeSWGpercent(_aqualink_data, atoi(index + strlen(MSG_SWG_PCT)));
//_aqualink_data->swg_percent = atoi(index + strlen(MSG_SWG_PCT));
//if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;}
LOG(PDA_LOG,LOG_DEBUG, "AquaPure = %d\n", _aqualink_data->swg_percent);
}
else if ((index = strcasestr(msg, MSG_SWG_PPM)) != NULL)
{
_aqualink_data->swg_ppm = atoi(index + strlen(MSG_SWG_PPM));
if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;}
logMessage(LOG_DEBUG, "SALT = %d\n", _aqualink_data->swg_ppm);
//if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;}
LOG(PDA_LOG,LOG_DEBUG, "SALT = %d\n", _aqualink_data->swg_ppm);
}
else if ((index = strcasestr(msg, MSG_PMP_RPM)) != NULL)
{ // Default to pump 0, should check for correct pump
_aqualink_data->pumps[0].rpm = atoi(index + strlen(MSG_PMP_RPM));
logMessage(LOG_DEBUG, "RPM = %d\n", _aqualink_data->pumps[0].rpm);
LOG(PDA_LOG,LOG_DEBUG, "RPM = %d\n", _aqualink_data->pumps[0].rpm);
}
else if ((index = strcasestr(msg, MSG_PMP_WAT)) != NULL)
{ // Default to pump 0, should check for correct pump
_aqualink_data->pumps[0].watts = atoi(index + strlen(MSG_PMP_WAT));
logMessage(LOG_DEBUG, "Watts = %d\n", _aqualink_data->pumps[0].watts);
LOG(PDA_LOG,LOG_DEBUG, "Watts = %d\n", _aqualink_data->pumps[0].watts);
}
else
{
@ -214,19 +206,19 @@ void pass_pda_equiptment_status_item(char *msg)
if (strcasecmp(msg, "POOL HEAT ENA") == 0)
{
_aqualink_data->aqbuttons[POOL_HEAT_INDEX].led->state = ENABLE;
_aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE;
}
else if (strcasecmp(msg, "SPA HEAT ENA") == 0)
{
_aqualink_data->aqbuttons[SPA_HEAT_INDEX].led->state = ENABLE;
_aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE;
}
else
{
for (i = 0; i < _aqualink_data->total_buttons; i++)
{
if (strcasecmp(msg, _aqualink_data->aqbuttons[i].pda_label) == 0)
if (strcasecmp(msg, _aqualink_data->aqbuttons[i].label) == 0)
{
logMessage(LOG_DEBUG, "*** Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].pda_label, AQ_MSGLEN, msg);
LOG(PDA_LOG,LOG_DEBUG, "*** Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg);
// It's on (or delayed) if it's listed here.
if (_aqualink_data->aqbuttons[i].led->state != FLASH)
{
@ -302,27 +294,28 @@ void process_pda_packet_msg_long_equipment_control(const char *msg)
strncpy(labelBuff, msg, AQ_MSGLEN - 4);
labelBuff[AQ_MSGLEN - 4] = 0;
logMessage(LOG_DEBUG, "*** Checking Equiptment '%s'\n", labelBuff);
LOG(PDA_LOG,LOG_DEBUG, "*** Checking Equiptment '%s'\n", labelBuff);
for (i = 0; i < _aqualink_data->total_buttons; i++)
{
if (strcasecmp(stripwhitespace(labelBuff), _aqualink_data->aqbuttons[i].pda_label) == 0)
if (strcasecmp(stripwhitespace(labelBuff), _aqualink_data->aqbuttons[i].label) == 0)
{
logMessage(LOG_DEBUG, "*** Found EQ CTL Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].pda_label, AQ_MSGLEN, msg);
LOG(PDA_LOG,LOG_DEBUG, "*** Found EQ CTL Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg);
set_pda_led(_aqualink_data->aqbuttons[i].led, msg[AQ_MSGLEN - 1]);
}
}
// Force SWG off if pump is off.
if (_aqualink_data->aqbuttons[0].led->state == OFF )
_aqualink_data->ar_swg_status = SWG_STATUS_OFF;
setSWGoff(_aqualink_data);
//_aqualink_data->ar_swg_status = SWG_STATUS_OFF;
// NSF I think we need to check TEMP1 and TEMP2 and set Pool HEater and Spa heater directly, to support single device.
if (_aqualink_data->single_device){
if (isSINGLE_DEV_PANEL){
if (strcasecmp(stripwhitespace(labelBuff), "TEMP1") == 0)
set_pda_led(_aqualink_data->aqbuttons[POOL_HEAT_INDEX].led, msg[AQ_MSGLEN - 1]);
set_pda_led(_aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led, msg[AQ_MSGLEN - 1]);
if (strcasecmp(stripwhitespace(labelBuff), "TEMP2") == 0)
set_pda_led(_aqualink_data->aqbuttons[SPA_HEAT_INDEX].led, msg[AQ_MSGLEN - 1]);
set_pda_led(_aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led, msg[AQ_MSGLEN - 1]);
}
}
@ -342,7 +335,7 @@ void process_pda_packet_msg_long_home(const char *msg)
}
else if (stristr(msg, "POOL HEATER") != NULL)
{
set_pda_led(_aqualink_data->aqbuttons[POOL_HEAT_INDEX].led, msg[AQ_MSGLEN - 1]);
set_pda_led(_aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led, msg[AQ_MSGLEN - 1]);
}
else if (stristr(msg, "SPA MODE") != NULL)
{
@ -364,44 +357,44 @@ void process_pda_packet_msg_long_home(const char *msg)
}
else if (stristr(msg, "SPA HEATER") != NULL)
{
set_pda_led(_aqualink_data->aqbuttons[SPA_HEAT_INDEX].led, msg[AQ_MSGLEN - 1]);
set_pda_led(_aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led, msg[AQ_MSGLEN - 1]);
}
}
void setSingleDeviceMode()
{
if (_aqualink_data->single_device != true)
if (isSINGLE_DEV_PANEL != true)
{
_aqualink_data->single_device = true;
logMessage(LOG_NOTICE, "AqualinkD set to 'Pool OR Spa Only' mode\n");
changePanelToMode_Only();
LOG(AQRS_LOG,LOG_ERR, "AqualinkD set to 'Combo Pool & Spa' but detected 'Only Pool OR Spa' panel, please change config\n");
}
}
void process_pda_packet_msg_long_set_temp(const char *msg)
{
logMessage(LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n");
LOG(PDA_LOG,LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n");
if (stristr(msg, "POOL HEAT") != NULL)
{
_aqualink_data->pool_htr_set_point = atoi(msg + 10);
logMessage(LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
}
else if (stristr(msg, "SPA HEAT") != NULL)
{
_aqualink_data->spa_htr_set_point = atoi(msg + 10);
logMessage(LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
}
else if (stristr(msg, "TEMP1") != NULL)
{
setSingleDeviceMode();
_aqualink_data->pool_htr_set_point = atoi(msg + 10);
logMessage(LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
}
else if (stristr(msg, "TEMP2") != NULL)
{
setSingleDeviceMode();
_aqualink_data->spa_htr_set_point = atoi(msg + 10);
logMessage(LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
}
@ -411,12 +404,12 @@ void process_pda_packet_msg_long_spa_heat(const char *msg)
{
if (strncasecmp(msg, " ENABLED ", 16) == 0)
{
_aqualink_data->aqbuttons[SPA_HEAT_INDEX].led->state = ENABLE;
_aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE;
}
else if (strncasecmp(msg, " SET TO", 8) == 0)
{
_aqualink_data->spa_htr_set_point = atoi(msg + 8);
logMessage(LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
LOG(PDA_LOG,LOG_DEBUG, "spa_htr_set_point = %d\n", _aqualink_data->spa_htr_set_point);
}
}
@ -424,12 +417,12 @@ void process_pda_packet_msg_long_pool_heat(const char *msg)
{
if (strncasecmp(msg, " ENABLED ", 16) == 0)
{
_aqualink_data->aqbuttons[POOL_HEAT_INDEX].led->state = ENABLE;
_aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE;
}
else if (strncasecmp(msg, " SET TO", 8) == 0)
{
_aqualink_data->pool_htr_set_point = atoi(msg + 8);
logMessage(LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
LOG(PDA_LOG,LOG_DEBUG, "pool_htr_set_point = %d\n", _aqualink_data->pool_htr_set_point);
}
}
@ -438,7 +431,7 @@ void process_pda_packet_msg_long_freeze_protect(const char *msg)
if (strncasecmp(msg, "TEMP ", 10) == 0)
{
_aqualink_data->frz_protect_set_point = atoi(msg + 10);
logMessage(LOG_DEBUG, "frz_protect_set_point = %d\n", _aqualink_data->frz_protect_set_point);
LOG(PDA_LOG,LOG_DEBUG, "frz_protect_set_point = %d\n", _aqualink_data->frz_protect_set_point);
}
}
@ -454,14 +447,16 @@ void process_pda_packet_msg_long_SWG(const char *msg)
if (_aqualink_data->aqbuttons[SPA_INDEX].led->state != OFF) {
if (strncasecmp(msg, "SET SPA TO:", 11) == 0)
{
_aqualink_data->swg_percent = atoi(msg + 13);
logMessage(LOG_DEBUG, "SPA swg_percent = %d\n", _aqualink_data->swg_percent);
//_aqualink_data->swg_percent = atoi(msg + 13);
setSWGpercent(_aqualink_data, atoi(msg + 13));
LOG(PDA_LOG,LOG_DEBUG, "SPA swg_percent = %d\n", _aqualink_data->swg_percent);
}
} else {
if (strncasecmp(msg, "SET POOL TO:", 12) == 0)
{
_aqualink_data->swg_percent = atoi(msg + 13);
logMessage(LOG_DEBUG, "POOL swg_percent = %d\n", _aqualink_data->swg_percent);
//_aqualink_data->swg_percent = atoi(msg + 13);
setSWGpercent(_aqualink_data, atoi(msg + 13));
LOG(PDA_LOG,LOG_DEBUG, "POOL swg_percent = %d\n", _aqualink_data->swg_percent);
}
}
}
@ -476,9 +471,9 @@ void process_pda_packet_msg_long_unknown(const char *msg)
{
for (i = 0; i < _aqualink_data->total_buttons; i++)
{
if (stristr(msg, _aqualink_data->aqbuttons[i].pda_label) != NULL)
if (stristr(msg, _aqualink_data->aqbuttons[i].label) != NULL)
{
printf("*** UNKNOWN Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].pda_label, AQ_MSGLEN, msg);
printf("*** UNKNOWN Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg);
// set_pda_led(_aqualink_data->aqbuttons[i].led, msg[AQ_MSGLEN-1]);
}
}
@ -511,9 +506,9 @@ void process_pda_packet_msg_long_level_aux_device(const char *msg)
str = cleanwhitespace(pda_m_line(3));
label = (char*)malloc(strlen(str)+1);
strcpy ( label, str );
_aqualink_data->aqbuttons[li-1].pda_label = label;
_aqualink_data->aqbuttons[li-1].label = label;
} else {
logMessage(LOG_ERR, "PDA couldn't get AUX? number\n", pda_m_line(0));
LOG(PDA_LOG,LOG_ERR, "PDA couldn't get AUX? number\n", pda_m_line(0));
}
}
#endif
@ -532,12 +527,12 @@ void process_pda_freeze_protect_devices()
// PDA Line 8 = EXTRA AUX
// PDA Line 9 =
int i;
logMessage(LOG_DEBUG, "process_pda_freeze_protect_devices\n");
LOG(PDA_LOG,LOG_DEBUG, "process_pda_freeze_protect_devices\n");
for (i = 1; i < PDA_LINES; i++)
{
if (pda_m_line(i)[AQ_MSGLEN - 1] == 'X')
{
logMessage(LOG_DEBUG, "PDA freeze protect enabled by %s\n", pda_m_line(i));
LOG(PDA_LOG,LOG_DEBUG, "PDA freeze protect enabled by %s\n", pda_m_line(i));
if (_aqualink_data->frz_protect_state == OFF)
{
_aqualink_data->frz_protect_state = ENABLE;
@ -554,6 +549,19 @@ bool process_pda_packet(unsigned char *packet, int length)
char *msg;
//static bool init = false;
if (getLogLevel(PDA_LOG) == LOG_DEBUG) {
char buff[1024];
beautifyPacket(buff, packet, length);
LOG(PDA_LOG,LOG_DEBUG, "%s", buff);
}
/*
// Some panels don't give the startup messages we used to key the init sequence, so check here
// need to put this in a better spot some time in the future
if (_initWithRS == false && pda_m_type() == PM_FW_VERSION && packet[PKT_CMD] == CMD_PDA_CLEAR ) {
_initWithRS == true;
queueGetProgramData(AQUAPDA, _aqualink_data);
}
*/
process_pda_menu_packet(packet, length);
// NSF.
@ -566,14 +574,15 @@ bool process_pda_packet(unsigned char *packet, int length)
{
case CMD_ACK:
logMessage(LOG_DEBUG, "RS Received ACK length %d.\n", length);
LOG(PDA_LOG,LOG_DEBUG, "RS Received ACK length %d.\n", length);
//if (init == false)
/*
if (_initWithRS == false)
{
logMessage(LOG_DEBUG, "Running PDA_INIT\n");
LOG(PDA_LOG,LOG_DEBUG, "Running PDA_INIT\n");
aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data);
//init = true;
}
}*/
break;
case CMD_STATUS:
@ -588,8 +597,11 @@ bool process_pda_packet(unsigned char *packet, int length)
if (_aqualink_data->frz_protect_state == ON)
_aqualink_data->frz_protect_state = ENABLE;
if (_aqualink_data->ar_swg_status == SWG_STATUS_ON)
_aqualink_data->ar_swg_status = SWG_STATUS_OFF;
//if (_aqualink_data->ar_swg_status == SWG_STATUS_ON)
// _aqualink_data->ar_swg_status = SWG_STATUS_OFF;
if (_aqualink_data->swg_led_state == ON)
setSWGenabled(_aqualink_data);
if (pda_m_line(PDA_LINES - 1)[0] == '\0')
{
@ -603,7 +615,7 @@ bool process_pda_packet(unsigned char *packet, int length)
}
else
{
logMessage(LOG_DEBUG, "PDA Equipment status may be truncated.\n");
LOG(PDA_LOG,LOG_DEBUG, "PDA Equipment status may be truncated.\n");
}
for (i = 1; i < PDA_LINES; i++)
{
@ -674,7 +686,7 @@ bool process_pda_packet(unsigned char *packet, int length)
}
// printf("** Line index='%d' Highligh='%s' Message='%.*s'\n",pda_m_hlightindex(), pda_m_hlight(), AQ_MSGLEN, msg);
logMessage(LOG_INFO, "PDA Menu '%d' Selectedline '%s', Last line received '%.*s'\n", pda_m_type(), pda_m_hlight(), AQ_MSGLEN, msg);
LOG(PDA_LOG,LOG_INFO, "PDA Menu '%d' Selectedline '%s', Last line received '%.*s'\n", pda_m_type(), pda_m_hlight(), AQ_MSGLEN, msg);
break;
}
case CMD_PDA_0x1B:
@ -685,7 +697,7 @@ bool process_pda_packet(unsigned char *packet, int length)
if (_initWithRS == false)
{
_initWithRS = true;
logMessage(LOG_DEBUG, "**** PDA INIT ****");
LOG(PDA_LOG,LOG_DEBUG, "**** PDA INIT ****\n");
//aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data);
queueGetProgramData(AQUAPDA, _aqualink_data);
delay(50); // Make sure this one runs first.
@ -695,7 +707,7 @@ bool process_pda_packet(unsigned char *packet, int length)
#endif
aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data);
} else {
logMessage(LOG_DEBUG, "**** PDA WAKE INIT ****");
LOG(PDA_LOG,LOG_DEBUG, "**** PDA WAKE INIT ****\n");
aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data);
}
}
@ -710,5 +722,8 @@ bool process_pda_packet(unsigned char *packet, int length)
// We processed the next message, kick any threads waiting on the message.
kick_aq_program_thread(_aqualink_data, AQUAPDA);
}
return rtn;
}

9
pda.h
View File

@ -3,13 +3,8 @@
#ifndef PDA_H_
#define PDA_H_
#ifdef BETA_PDA_AUTOLABEL
#include "aqualink.h"
#include "config.h"
void init_pda(struct aqualinkdata *aqdata, struct aqconfig *aqconfig);
#else
void init_pda(struct aqualinkdata *aqdata);
#endif
void init_pda(struct aqualinkdata *aqdata);
bool process_pda_packet(unsigned char* packet, int length);
bool pda_shouldSleep();

View File

@ -30,8 +30,8 @@
#include "pda.h"
#include "pda_menu.h"
#include "pda_aq_programmer.h"
#include "init_buttons.h"
#include "config.h"
#include "aq_panel.h"
#ifdef AQ_DEBUG
@ -83,16 +83,16 @@ void pda_programming_thread_check(struct aqualinkdata *aq_data)
#ifdef AQ_DEBUG
clock_gettime(CLOCK_REALTIME, &now);
timespec_subtract(&elapsed, &now, &start);
logMessage(LOG_ERR, "Thread %d,%p FAILED to finished in reasonable time, %d.%03ld sec, killing it.\n",
LOG(PDA_LOG,LOG_ERR, "Thread %d,%p FAILED to finished in reasonable time, %d.%03ld sec, killing it.\n",
aq_data->active_thread.ptype,
aq_data->active_thread.thread_id,
elapsed.tv_sec, elapsed.tv_nsec / 1000000L);
#else
logMessage(LOG_ERR, "Thread %d,%p FAILED to finished in reasonable time, killing it!\n", aq_data->active_thread.ptype, aq_data->active_thread.thread_id)
LOG(PDA_LOG,LOG_ERR, "Thread %d,%p FAILED to finished in reasonable time, killing it!\n", aq_data->active_thread.ptype, aq_data->active_thread.thread_id)
#endif
if (pthread_cancel(*aq_data->active_thread.thread_id) != 0)
logMessage(LOG_ERR, "Thread kill failed\n");
LOG(PDA_LOG,LOG_ERR, "Thread kill failed\n");
else {
}
@ -135,7 +135,7 @@ bool loopover_devices(struct aqualinkdata *aq_data) {
int index = -1;
if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL)) {
logMessage(LOG_ERR, "loopover_devices :- can't goto PM_EQUIPTMENT_CONTROL menu\n");
LOG(PDA_LOG,LOG_ERR, "loopover_devices :- can't goto PM_EQUIPTMENT_CONTROL menu\n");
//cleanAndTerminateThread(threadCtrl);
return false;
}
@ -147,7 +147,7 @@ bool loopover_devices(struct aqualinkdata *aq_data) {
waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_MSG_LONG,8);
}
if (index == -1) {
logMessage(LOG_ERR, "loopover_devices :- can't find ALL OFF\n");
LOG(PDA_LOG,LOG_ERR, "loopover_devices :- can't find ALL OFF\n");
return false;
}
@ -165,7 +165,7 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli
int index = -1;
int cnt = 0;
logMessage(LOG_DEBUG, "PDA Device programmer looking for menu text '%s'\n",menuText);
LOG(PDA_LOG,LOG_DEBUG, "PDA Device programmer looking for menu text '%s' (limit=%d)\n",menuText,charlimit);
if (charlimit == 0)
index = pda_find_m_index(menuText);
@ -193,11 +193,11 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli
}
}
if (index < 0) {
logMessage(LOG_ERR, "PDA Device programmer couldn't find menu item on any page '%s'\n",menuText);
LOG(PDA_LOG,LOG_ERR, "PDA Device programmer couldn't find menu item on any page '%s'\n",menuText);
return false;
}
} else {
logMessage(LOG_ERR, "PDA Device programmer couldn't find menu item '%s' in menu %d index %d\n", menuText, pda_m_type(), index);
LOG(PDA_LOG,LOG_ERR, "PDA Device programmer couldn't find menu item '%s' in menu %d index %d\n", menuText, pda_m_type(), index);
return false;
}
}
@ -246,7 +246,7 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli
}
}
logMessage(LOG_DEBUG, "find_pda_menu_item i=%d idx=%d min=%d max=%d\n",
LOG(PDA_LOG,LOG_DEBUG, "find_pda_menu_item i=%d idx=%d min=%d max=%d\n",
i, index, min_index, max_index);
if (i < index) {
@ -286,18 +286,19 @@ bool select_pda_menu_item_loose(struct aqualinkdata *aq_data, char *menuText, bo
}
bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool waitForNextMenu, bool loose) {
int matchType = loose?-1:0;
//int matchType = loose?-1:0;
int matchType = loose?-1:1;
if ( find_pda_menu_item(aq_data, menuText, matchType) ) {
send_cmd(KEY_PDA_SELECT);
logMessage(LOG_DEBUG, "PDA Device programmer selected menu item '%s'\n",menuText);
LOG(PDA_LOG,LOG_DEBUG, "PDA Device programmer selected menu item '%s'\n",menuText);
if (waitForNextMenu)
waitForPDAnextMenu(aq_data);
return true;
}
logMessage(LOG_ERR, "PDA Device programmer couldn't select menu item '%s' menu %d\n",menuText, pda_m_type());
LOG(PDA_LOG,LOG_ERR, "PDA Device programmer couldn't select menu item '%s' menu %d\n",menuText, pda_m_type());
return false;
}
@ -310,16 +311,16 @@ bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool wa
bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
bool ret = true;
logMessage(LOG_DEBUG, "PDA Device programmer request for menu %d\n",menu);
LOG(PDA_LOG,LOG_DEBUG, "PDA Device programmer request for menu %d\n",menu);
if (pda_m_type() == PM_FW_VERSION) {
logMessage(LOG_DEBUG, "goto_pda_menu at FW version menu\n");
LOG(PDA_LOG,LOG_DEBUG, "goto_pda_menu at FW version menu\n");
send_cmd(KEY_PDA_BACK);
if (! waitForPDAnextMenu(aq_data)) {
logMessage(LOG_ERR, "PDA Device programmer wait for next menu failed");
LOG(PDA_LOG,LOG_ERR, "PDA Device programmer wait for next menu failed\n");
}
} else if (pda_m_type() == PM_BUILDING_HOME) {
logMessage(LOG_DEBUG, "goto_pda_menu building home menu\n");
LOG(PDA_LOG,LOG_DEBUG, "goto_pda_menu building home menu\n");
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,15);
}
@ -361,7 +362,7 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
ret = waitForPDAnextMenu(aq_data);
}
} else {
logMessage(LOG_ERR, "PDA in AquaPlalm mode, there is no SYSTEM SETUP / LABEL AUX menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA in AquaPlalm mode, there is no SYSTEM SETUP / LABEL AUX menu\n");
}
break;
case PM_SYSTEM_SETUP:
@ -375,7 +376,7 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
ret = waitForPDAnextMenu(aq_data);
}
} else {
logMessage(LOG_ERR, "PDA in AquaPlalm mode, there is no SYSTEM SETUP menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA in AquaPlalm mode, there is no SYSTEM SETUP menu\n");
}
break;
case PM_FREEZE_PROTECT:
@ -391,7 +392,7 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
ret = waitForPDAnextMenu(aq_data);
}
} else {
logMessage(LOG_ERR, "PDA in AquaPlalm mode, there is no SYSTEM SETUP / FREEZE PROTECT menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA in AquaPlalm mode, there is no SYSTEM SETUP / FREEZE PROTECT menu\n");
}
break;
case PM_AQUAPURE:
@ -419,11 +420,11 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
if (pda_m_type() == PM_HOME) {
ret = select_pda_menu_item(aq_data, "MENU", true);
} else if (pda_m_type() == PM_MAIN) {
if (aq_data->single_device != true) {
if (isCOMBO_PANEL) {
ret = select_pda_menu_item(aq_data, "SET TEMP", true);
} else {
// Depending on control panel config, may get an extra menu asking to press any key
logMessage(LOG_DEBUG, "PDA in single device mode, \n");
LOG(PDA_LOG,LOG_DEBUG, "PDA in single device mode, \n");
ret = select_pda_menu_item(aq_data, "SET TEMP", false);
// We could press enter here, but I can't test it, so just wait for message to dissapear.
ret = waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,25);
@ -446,14 +447,14 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
}
break;
default:
logMessage(LOG_ERR, "PDA Device programmer didn't understand requested menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA Device programmer didn't understand requested menu\n");
return false;
break;
}
logMessage(LOG_DEBUG, "PDA Device programmer request for menu %d, current %d\n", menu, pda_m_type());
LOG(PDA_LOG,LOG_DEBUG, "PDA Device programmer request for menu %d, current %d\n", menu, pda_m_type());
}
if (pda_m_type() != menu) {
logMessage(LOG_ERR, "PDA Device programmer didn't find a requested menu %d, current %d\n", menu, pda_m_type());
LOG(PDA_LOG,LOG_ERR, "PDA Device programmer didn't find a requested menu %d, current %d\n", menu, pda_m_type());
return false;
}
@ -476,61 +477,61 @@ void *set_aqualink_PDA_device_on_off( void *ptr )
unsigned int state = atoi(&buf[5]);
if (device > aq_data->total_buttons) {
logMessage(LOG_ERR, "PDA Device On/Off :- bad device number '%d'\n",device);
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off :- bad device number '%d'\n",device);
cleanAndTerminateThread(threadCtrl);
return ptr;
}
logMessage(LOG_INFO, "PDA Device On/Off, device '%s', state %d\n",aq_data->aqbuttons[device].pda_label,state);
LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, device '%s', state %d\n",aq_data->aqbuttons[device].label,state);
if (! goto_pda_menu(aq_data, PM_EQUIPTMENT_CONTROL)) {
logMessage(LOG_ERR, "PDA Device On/Off :- can't find EQUIPTMENT CONTROL menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off :- can't find EQUIPTMENT CONTROL menu\n");
cleanAndTerminateThread(threadCtrl);
return ptr;
}
// If single config (Spa OR pool) rather than (Spa AND pool) heater is TEMP1 and TEMP2
if (aq_data->single_device == TRUE && device == POOL_HEAT_INDEX) { // rename Heater and Spa
if (isSINGLE_DEV_PANEL && device == aq_data->pool_heater_index) { // rename Heater and Spa
sprintf(device_name,"%-13s\n","TEMP1");
} else if (aq_data->single_device == TRUE && device == SPA_HEAT_INDEX) {// rename Heater and Spa
} else if (isSINGLE_DEV_PANEL && device == aq_data->spa_heater_index) {// rename Heater and Spa
sprintf(device_name,"%-13s\n","TEMP2");
} else {
//Pad name with spaces so something like "SPA" doesn't match "SPA BLOWER"
sprintf(device_name,"%-13s\n",aq_data->aqbuttons[device].pda_label);
sprintf(device_name,"%-13s\n",aq_data->aqbuttons[device].label);
}
if ( find_pda_menu_item(aq_data, device_name, 13) ) {
if (aq_data->aqbuttons[device].led->state != state) {
//printf("*** Select State ***\n");
logMessage(LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].pda_label,state);
LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].label,state);
send_cmd(KEY_PDA_SELECT);
while (get_aq_cmd_length() > 0) { delay(500); }
// If you are turning on a heater there will be a sub menu to set temp
if ((state == ON) && ((device == POOL_HEAT_INDEX) || (device == SPA_HEAT_INDEX))) {
if ((state == ON) && ((device == aq_data->pool_heater_index) || (device == aq_data->spa_heater_index))) {
if (! waitForPDAnextMenu(aq_data)) {
logMessage(LOG_ERR, "PDA Device On/Off: %s on - waitForPDAnextMenu\n",
aq_data->aqbuttons[device].pda_label);
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - waitForPDAnextMenu\n",
aq_data->aqbuttons[device].label);
} else {
send_cmd(KEY_PDA_SELECT);
while (get_aq_cmd_length() > 0) { delay(500); }
if (!waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,20)) {
logMessage(LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_PDA_HIGHLIGHT\n",
aq_data->aqbuttons[device].pda_label);
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_PDA_HIGHLIGHT\n",
aq_data->aqbuttons[device].label);
}
}
} else { // not turning on heater wait for line update
// worst case spa when pool is running
if (!waitForPDAMessageType(aq_data,CMD_MSG_LONG,2)) {
logMessage(LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_MSG_LONG\n",
aq_data->aqbuttons[device].pda_label);
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off: %s on - wait for CMD_MSG_LONG\n",
aq_data->aqbuttons[device].label);
}
}
} else {
logMessage(LOG_INFO, "PDA Device On/Off, found device '%s', not changing state, is same\n",aq_data->aqbuttons[device].pda_label,state);
LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', not changing state, is same\n",aq_data->aqbuttons[device].label,state);
}
} else {
logMessage(LOG_ERR, "PDA Device On/Off, device '%s' not found\n",aq_data->aqbuttons[device].pda_label);
LOG(PDA_LOG,LOG_ERR, "PDA Device On/Off, device '%s' not found\n",aq_data->aqbuttons[device].label);
}
cleanAndTerminateThread(threadCtrl);
@ -554,7 +555,7 @@ void *get_aqualink_PDA_device_status( void *ptr )
goto_pda_menu(aq_data, PM_HOME);
if (! loopover_devices(aq_data)) {
logMessage(LOG_ERR, "PDA Device Status :- failed\n");
LOG(PDA_LOG,LOG_ERR, "PDA Device Status :- failed\n");
}
cleanAndTerminateThread(threadCtrl);
@ -574,9 +575,9 @@ void *set_aqualink_PDA_init( void *ptr )
//int val = atoi((char*)threadCtrl->thread_args);
//logMessage(LOG_DEBUG, "PDA Init\n", val);
//LOG(PDA_LOG,LOG_DEBUG, "PDA Init\n", val);
logMessage(LOG_DEBUG, "PDA Init\n");
LOG(PDA_LOG,LOG_DEBUG, "PDA Init\n");
if (pda_m_type() == PM_FW_VERSION) {
// check pda_m_line(1) to "AquaPalm"
@ -593,30 +594,30 @@ void *set_aqualink_PDA_init( void *ptr )
snprintf(aq_data->version, (AQ_MSGLEN*2)-1, "%s %s",stripwhitespace(ptr1),stripwhitespace(ptr2));
//printf("****** Version '%s' ********\n",aq_data->version);
logMessage(LOG_DEBUG, "PDA type=%d, version=%s\n", _PDA_Type, aq_data->version);
LOG(PDA_LOG,LOG_DEBUG, "PDA type=%d, version=%s\n", _PDA_Type, aq_data->version);
// don't wait for version menu to time out press back to get to home menu faster
send_cmd(KEY_PDA_BACK);
if (! waitForPDAnextMenu(aq_data)) {
logMessage(LOG_ERR, "PDA Init :- wait for next menu failed");
LOG(PDA_LOG,LOG_ERR, "PDA Init :- wait for next menu failed\n");
}
}
else {
logMessage(LOG_ERR, "PDA Init :- should be called when on FW VERSION menu.\n");
LOG(PDA_LOG,LOG_ERR, "PDA Init :- should be called when on FW VERSION menu.\n");
}
/*
// Get status of all devices
if (! loopover_devices(aq_data)) {
logMessage(LOG_ERR, "PDA Init :- can't find menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA Init :- can't find menu\n");
}
*/
// Get heater setpoints
if (! get_PDA_aqualink_pool_spa_heater_temps(aq_data)) {
logMessage(LOG_ERR, "PDA Init :- Error getting heater setpoints\n");
LOG(PDA_LOG,LOG_ERR, "PDA Init :- Error getting heater setpoints\n");
}
// Get freeze protect setpoint, AquaPalm doesn't have freeze protect in menu.
if (_PDA_Type != AQUAPALM && ! get_PDA_freeze_protect_temp(aq_data)) {
logMessage(LOG_ERR, "PDA Init :- Error getting freeze setpoints\n");
LOG(PDA_LOG,LOG_ERR, "PDA Init :- Error getting freeze setpoints\n");
}
pda_reset_sleep();
@ -639,11 +640,11 @@ void *set_aqualink_PDA_wakeinit( void *ptr )
// it means the wake was called due to changing a device.
waitForSingleThreadOrTerminate(threadCtrl, AQ_PDA_WAKE_INIT);
logMessage(LOG_DEBUG, "PDA Wake Init\n");
LOG(PDA_LOG,LOG_DEBUG, "PDA Wake Init\n");
// Get status of all devices
if (! loopover_devices(aq_data)) {
logMessage(LOG_ERR, "PDA Init :- can't find menu\n");
LOG(PDA_LOG,LOG_ERR, "PDA Init :- can't find menu\n");
}
cleanAndTerminateThread(threadCtrl);
@ -664,7 +665,7 @@ bool get_PDA_freeze_protect_temp(struct aqualinkdata *aq_data) {
send_cmd(KEY_PDA_SELECT);
return waitForPDAnextMenu(aq_data);
} else {
logMessage(LOG_INFO, "In PDA AquaPalm mode, freezepoints not supported\n");
LOG(PDA_LOG,LOG_INFO, "In PDA AquaPalm mode, freezepoints not supported\n");
return false;
}
}
@ -681,7 +682,7 @@ bool get_PDA_aqualink_pool_spa_heater_temps(struct aqualinkdata *aq_data) {
bool waitForPDAMessageHighlight(struct aqualinkdata *aq_data, int highlighIndex, int numMessageReceived)
{
logMessage(LOG_DEBUG, "waitForPDAMessageHighlight index %d\n",highlighIndex);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageHighlight index %d\n",highlighIndex);
if(pda_m_hlightindex() == highlighIndex) return true;
@ -690,7 +691,7 @@ bool waitForPDAMessageHighlight(struct aqualinkdata *aq_data, int highlighIndex,
while( ++i <= numMessageReceived)
{
logMessage(LOG_DEBUG, "waitForPDAMessageHighlight last = 0x%02hhx : index %d : (%d of %d)\n",aq_data->last_packet_type,pda_m_hlightindex(),i,numMessageReceived);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageHighlight last = 0x%02hhx : index %d : (%d of %d)\n",aq_data->last_packet_type,pda_m_hlightindex(),i,numMessageReceived);
if (aq_data->last_packet_type == CMD_PDA_HIGHLIGHT && pda_m_hlightindex() == highlighIndex) break;
@ -700,11 +701,11 @@ bool waitForPDAMessageHighlight(struct aqualinkdata *aq_data, int highlighIndex,
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if (pda_m_hlightindex() != highlighIndex) {
//logMessage(LOG_ERR, "Could not select MENU of Aqualink control panel\n");
logMessage(LOG_DEBUG, "waitForPDAMessageHighlight: did not receive index '%d'\n",highlighIndex);
//LOG(PDA_LOG,LOG_ERR, "Could not select MENU of Aqualink control panel\n");
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageHighlight: did not receive index '%d'\n",highlighIndex);
return false;
} else
logMessage(LOG_DEBUG, "waitForPDAMessageHighlight: received index '%d'\n",highlighIndex);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageHighlight: received index '%d'\n",highlighIndex);
return true;
}
@ -712,14 +713,14 @@ bool waitForPDAMessageHighlight(struct aqualinkdata *aq_data, int highlighIndex,
bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, int numMessageReceived)
{
logMessage(LOG_DEBUG, "waitForPDAMessageType 0x%02hhx\n",mtype);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageType 0x%02hhx\n",mtype);
int i=0;
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
while( ++i <= numMessageReceived)
{
logMessage(LOG_DEBUG, "waitForPDAMessageType 0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype,aq_data->last_packet_type,i,numMessageReceived);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageType 0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype,aq_data->last_packet_type,i,numMessageReceived);
if (aq_data->last_packet_type == mtype) break;
@ -729,11 +730,11 @@ bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, in
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if (aq_data->last_packet_type != mtype) {
//logMessage(LOG_ERR, "Could not select MENU of Aqualink control panel\n");
logMessage(LOG_DEBUG, "waitForPDAMessageType: did not receive 0x%02hhx\n",mtype);
//LOG(PDA_LOG,LOG_ERR, "Could not select MENU of Aqualink control panel\n");
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageType: did not receive 0x%02hhx\n",mtype);
return false;
} else
logMessage(LOG_DEBUG, "waitForPDAMessageType: received 0x%02hhx\n",mtype);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageType: received 0x%02hhx\n",mtype);
return true;
}
@ -741,7 +742,7 @@ bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, in
// Wait for Message, hit return on particular menu.
bool waitForPDAMessageTypesOrMenu(struct aqualinkdata *aq_data, unsigned char mtype1, unsigned char mtype2, int numMessageReceived, char *text, int line)
{
logMessage(LOG_DEBUG, "waitForPDAMessageTypes 0x%02hhx or 0x%02hhx\n",mtype1,mtype2);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageTypes 0x%02hhx or 0x%02hhx\n",mtype1,mtype2);
int i=0;
bool gotmenu = false;
@ -753,10 +754,10 @@ bool waitForPDAMessageTypesOrMenu(struct aqualinkdata *aq_data, unsigned char mt
if (stristr(pda_m_line(line), text) != NULL) {
send_cmd(KEY_PDA_SELECT);
gotmenu = true;
logMessage(LOG_DEBUG, "waitForPDAMessageTypesOrMenu saw '%s' and line %d\n",text,line);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageTypesOrMenu saw '%s' and line %d\n",text,line);
}
}
logMessage(LOG_DEBUG, "waitForPDAMessageTypes 0x%02hhx | 0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype1,mtype2,aq_data->last_packet_type,i,numMessageReceived);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageTypes 0x%02hhx | 0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype1,mtype2,aq_data->last_packet_type,i,numMessageReceived);
if (aq_data->last_packet_type == mtype1 || aq_data->last_packet_type == mtype2) break;
@ -766,11 +767,11 @@ bool waitForPDAMessageTypesOrMenu(struct aqualinkdata *aq_data, unsigned char mt
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if (aq_data->last_packet_type != mtype1 && aq_data->last_packet_type != mtype2) {
//logMessage(LOG_ERR, "Could not select MENU of Aqualink control panel\n");
logMessage(LOG_ERR, "waitForPDAMessageTypes: did not receive 0x%02hhx or 0x%02hhx\n",mtype1,mtype2);
//LOG(PDA_LOG,LOG_ERR, "Could not select MENU of Aqualink control panel\n");
LOG(PDA_LOG,LOG_ERR, "waitForPDAMessageTypes: did not receive 0x%02hhx or 0x%02hhx\n",mtype1,mtype2);
return false;
} else
logMessage(LOG_DEBUG, "waitForPDAMessageTypes: received 0x%02hhx\n",aq_data->last_packet_type);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageTypes: received 0x%02hhx\n",aq_data->last_packet_type);
return true;
}
@ -784,7 +785,7 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int *cur
int i=0;
if (val == *cur_val) {
logMessage(LOG_INFO, "PDA %s value : already at %d\n", select_label, val);
LOG(PDA_LOG,LOG_INFO, "PDA %s value : already at %d\n", select_label, val);
return true;
}
if (select_label != NULL) {
@ -796,7 +797,7 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int *cur
delay(500); // Last message probably was CMD_PDA_HIGHLIGHT, so wait before checking.
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,2);
if (i > 10) {
logMessage(LOG_ERR, "PDA numeric selector could not find string '%s'\n", select_label);
LOG(PDA_LOG,LOG_ERR, "PDA numeric selector could not find string '%s'\n", select_label);
return false;
}
i++;
@ -805,23 +806,23 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int *cur
}
if (val < *cur_val) {
logMessage(LOG_DEBUG, "PDA %s value : lower from %d to %d\n", select_label, *cur_val, val);
LOG(PDA_LOG,LOG_DEBUG, "PDA %s value : lower from %d to %d\n", select_label, *cur_val, val);
for (i = *cur_val; i > val; i=i-step) {
send_cmd(KEY_PDA_DOWN);
}
} else if (val > *cur_val) {
logMessage(LOG_DEBUG, "PDA %s value : raise from %d to %d\n", select_label, *cur_val, val);
LOG(PDA_LOG,LOG_DEBUG, "PDA %s value : raise from %d to %d\n", select_label, *cur_val, val);
for (i = *cur_val; i < val; i=i+step) {
send_cmd(KEY_PDA_UP);
}
} else {
logMessage(LOG_INFO, "PDA %s value : already at %d\n", select_label, val);
LOG(PDA_LOG,LOG_INFO, "PDA %s value : already at %d\n", select_label, val);
send_cmd(KEY_PDA_BACK);
return true;
}
send_cmd(KEY_PDA_SELECT);
logMessage(LOG_DEBUG, "PDA %s value : set to %d\n", select_label, *cur_val);
LOG(PDA_LOG,LOG_DEBUG, "PDA %s value : set to %d\n", select_label, *cur_val);
return true;
}
@ -829,7 +830,7 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int *cur
bool set_PDA_aqualink_SWG_setpoint(struct aqualinkdata *aq_data, int val) {
if (! goto_pda_menu(aq_data, PM_AQUAPURE)) {
logMessage(LOG_ERR, "Error finding SWG setpoints menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding SWG setpoints menu\n");
}
if (aq_data->aqbuttons[SPA_INDEX].led->state != OFF)
@ -843,7 +844,7 @@ bool set_PDA_aqualink_SWG_setpoint(struct aqualinkdata *aq_data, int val) {
bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val)
{
if (! goto_pda_menu(aq_data, PM_BOOST)) {
logMessage(LOG_ERR, "Error finding BOOST menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding BOOST menu\n");
return false;
}
@ -854,7 +855,7 @@ bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val)
if (strstr(pda_m_hlight(), "START") != NULL)
send_cmd(KEY_PDA_SELECT);
else {
logMessage(LOG_ERR, "Error finding BOOST START menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding BOOST START menu\n");
return false;
}
} else {
@ -870,7 +871,7 @@ bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val)
}
}
if (i >= 6)
logMessage(LOG_ERR, "Error finding BOOST STOP menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding BOOST STOP menu\n");
// Should be select options PAUSE | RESTART | STOP
// so press down twice then select
*/
@ -887,7 +888,7 @@ bool set_PDA_aqualink_heater_setpoint(struct aqualinkdata *aq_data, int val, boo
char label[10];
int *cur_val;
if ( aq_data->single_device != true ) {
if ( isCOMBO_PANEL ) {
if (isPool) {
sprintf(label, "POOL HEAT");
cur_val = &aq_data->pool_htr_set_point;
@ -906,13 +907,13 @@ bool set_PDA_aqualink_heater_setpoint(struct aqualinkdata *aq_data, int val, boo
}
if (val == *cur_val) {
logMessage(LOG_INFO, "PDA %s setpoint : temp already %d\n", label, val);
LOG(PDA_LOG,LOG_INFO, "PDA %s setpoint : temp already %d\n", label, val);
send_cmd(KEY_PDA_BACK);
return true;
}
if (! goto_pda_menu(aq_data, PM_SET_TEMP)) {
logMessage(LOG_ERR, "Error finding heater setpoints menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding heater setpoints menu\n");
return false;
}
@ -924,13 +925,13 @@ bool set_PDA_aqualink_heater_setpoint(struct aqualinkdata *aq_data, int val, boo
bool set_PDA_aqualink_freezeprotect_setpoint(struct aqualinkdata *aq_data, int val) {
if (_PDA_Type != PDA) {
logMessage(LOG_INFO, "In PDA AquaPalm mode, freezepoints not supported\n");
LOG(PDA_LOG,LOG_INFO, "In PDA AquaPalm mode, freezepoints not supported\n");
return false;
} else if (! goto_pda_menu(aq_data, PM_FREEZE_PROTECT)) {
logMessage(LOG_ERR, "Error finding freeze protect setpoints menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding freeze protect setpoints menu\n");
return false;
} else if (! set_PDA_numeric_field_value(aq_data, val, &aq_data->frz_protect_set_point, NULL, 1)) {
logMessage(LOG_ERR, "Error failed to set freeze protect temp value\n");
LOG(PDA_LOG,LOG_ERR, "Error failed to set freeze protect temp value\n");
return false;
} else {
return waitForPDAnextMenu(aq_data);
@ -943,10 +944,10 @@ bool get_PDA_aqualink_aux_labels(struct aqualinkdata *aq_data) {
int i=0;
char label[10];
logMessage(LOG_INFO, "Finding PDA labels, (BETA ONLY)\n");
LOG(PDA_LOG,LOG_INFO, "Finding PDA labels, (BETA ONLY)\n");
if (! goto_pda_menu(aq_data, PM_AUX_LABEL)) {
logMessage(LOG_ERR, "Error finding aux label menu\n");
LOG(PDA_LOG,LOG_ERR, "Error finding aux label menu\n");
return false;
}
@ -965,7 +966,7 @@ bool get_PDA_aqualink_aux_labels(struct aqualinkdata *aq_data) {
/*
bool waitForPDAMessage(struct aqualinkdata *aq_data, int numMessageReceived, unsigned char packettype)
{
logMessage(LOG_DEBUG, "waitForPDAMessage %s %d\n",message,numMessageReceived);
LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessage %s %d\n",message,numMessageReceived);
int i=0;
pthread_mutex_init(&aq_data->active_thread.thread_mutex, NULL);
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
@ -982,14 +983,14 @@ bool waitForPDAMessage(struct aqualinkdata *aq_data, int numMessageReceived, uns
while( ++i <= numMessageReceived)
{
if (message != NULL)
logMessage(LOG_DEBUG, "Programming mode: loop %d of %d looking for '%s' received message '%s'\n",i,numMessageReceived,message,aq_data->last_message);
LOG(PDA_LOG,LOG_DEBUG, "Programming mode: loop %d of %d looking for '%s' received message '%s'\n",i,numMessageReceived,message,aq_data->last_message);
else
logMessage(LOG_DEBUG, "Programming mode: loop %d of %d waiting for next message, received '%s'\n",i,numMessageReceived,aq_data->last_message);
LOG(PDA_LOG,LOG_DEBUG, "Programming mode: loop %d of %d waiting for next message, received '%s'\n",i,numMessageReceived,aq_data->last_message);
if (message != NULL) {
ptr = stristr(aq_data->last_message, msgS);
if (ptr != NULL) { // match
logMessage(LOG_DEBUG, "Programming mode: String MATCH\n");
LOG(PDA_LOG,LOG_DEBUG, "Programming mode: String MATCH\n");
if (msgS == message) // match & don't care if first char
break;
else if (ptr == aq_data->last_message) // match & do care if first char
@ -997,20 +998,20 @@ bool waitForPDAMessage(struct aqualinkdata *aq_data, int numMessageReceived, uns
}
}
//logMessage(LOG_DEBUG, "Programming mode: looking for '%s' received message '%s'\n",message,aq_data->last_message);
//LOG(PDA_LOG,LOG_DEBUG, "Programming mode: looking for '%s' received message '%s'\n",message,aq_data->last_message);
pthread_cond_init(&aq_data->active_thread.thread_cond, NULL);
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
//logMessage(LOG_DEBUG, "Programming mode: loop %d of %d looking for '%s' received message '%s'\n",i,numMessageReceived,message,aq_data->last_message);
//LOG(PDA_LOG,LOG_DEBUG, "Programming mode: loop %d of %d looking for '%s' received message '%s'\n",i,numMessageReceived,message,aq_data->last_message);
}
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if (message != NULL && ptr == NULL) {
//logMessage(LOG_ERR, "Could not select MENU of Aqualink control panel\n");
logMessage(LOG_DEBUG, "Programming mode: did not find '%s'\n",message);
//LOG(PDA_LOG,LOG_ERR, "Could not select MENU of Aqualink control panel\n");
LOG(PDA_LOG,LOG_DEBUG, "Programming mode: did not find '%s'\n",message);
return false;
} else if (message != NULL)
logMessage(LOG_DEBUG, "Programming mode: found message '%s' in '%s'\n",message,aq_data->last_message);
LOG(PDA_LOG,LOG_DEBUG, "Programming mode: found message '%s' in '%s'\n",message,aq_data->last_message);
return true;
}

View File

@ -33,12 +33,12 @@ void print_menu()
int i;
for (i=0; i < PDA_LINES; i++) {
//printf("PDA Line %d = %s\n",i,_menu[i]);
logMessage(LOG_DEBUG, "PDA Menu Line %d = %s\n",i,_menu[i]);
LOG(PDA_LOG,LOG_DEBUG, "PDA Menu Line %d = %s\n",i,_menu[i]);
}
if (_hlightindex > -1) {
//printf("PDA highlighted line = %d = %s\n",_hlightindex,_menu[_hlightindex]);
logMessage(LOG_DEBUG, "PDA Menu highlighted line = %d = %s\n",_hlightindex,_menu[_hlightindex]);
LOG(PDA_LOG,LOG_DEBUG, "PDA Menu highlighted line = %d = %s\n",_hlightindex,_menu[_hlightindex]);
}
}
@ -203,7 +203,7 @@ bool process_pda_menu_packet(unsigned char* packet, int length)
strncpy(_menu[packet[PKT_DATA]], (char*)packet+PKT_DATA+1, AQ_MSGLEN);
_menu[packet[PKT_DATA]][AQ_MSGLEN] = '\0';
}
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
case CMD_PDA_HIGHLIGHT:
// when switching from hlight to hlightchars index 255 is sent to turn off hlight
@ -212,7 +212,7 @@ bool process_pda_menu_packet(unsigned char* packet, int length)
} else {
_hlightindex = -1;
}
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
case CMD_PDA_HIGHLIGHTCHARS:
if (packet[4] <= PDA_LINES) {
@ -220,7 +220,7 @@ bool process_pda_menu_packet(unsigned char* packet, int length)
} else {
_hlightindex = -1;
}
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
case CMD_PDA_SHIFTLINES:
/// press up from top - shift menu down by 1
@ -230,17 +230,19 @@ bool process_pda_menu_packet(unsigned char* packet, int length)
first_line = (signed char)(packet[4]);
last_line = (signed char)(packet[5]);
line_shift = (signed char)(packet[6]);
logMessage(LOG_DEBUG, "\n");
LOG(PDA_LOG,LOG_DEBUG, "\n");
if (line_shift < 0) {
for (i = first_line-line_shift; i <= last_line; i++) {
memcpy(_menu[i+line_shift], _menu[i], AQ_MSGLEN+1);
}
_menu[last_line][0] = '\0';
} else {
for (i = last_line; i >= first_line+line_shift; i--) {
memcpy(_menu[i], _menu[i-line_shift], AQ_MSGLEN+1);
}
_menu[first_line][0] = '\0';
}
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
}
@ -272,10 +274,10 @@ bool NEW_process_pda_menu_packet_NEW(unsigned char* packet, int length)
_menu[packet[PKT_DATA]][AQ_MSGLEN] = '\0';
}
if (packet[PKT_DATA] == _hlightindex) {
logMessage(LOG_DEBUG, "process_pda_menu_packet: hlight changed from shift or up/down value\n");
LOG(PDA_LOG,LOG_DEBUG, "process_pda_menu_packet: hlight changed from shift or up/down value\n");
pthread_cond_signal(&_pda_menu_hlight_change_cond);
}
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
update_pda_menu_type();
break;
case CMD_PDA_HIGHLIGHT:
@ -286,7 +288,7 @@ bool NEW_process_pda_menu_packet_NEW(unsigned char* packet, int length)
_hlightindex = -1;
}
pthread_cond_signal(&_pda_menu_hlight_change_cond);
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
case CMD_PDA_HIGHLIGHTCHARS:
if (packet[4] <= PDA_LINES) {
@ -295,7 +297,7 @@ bool NEW_process_pda_menu_packet_NEW(unsigned char* packet, int length)
_hlightindex = -1;
}
pthread_cond_signal(&_pda_menu_hlight_change_cond);
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
case CMD_PDA_SHIFTLINES:
// press up from top - shift menu down by 1
@ -305,7 +307,7 @@ bool NEW_process_pda_menu_packet_NEW(unsigned char* packet, int length)
first_line = (signed char)(packet[4]);
last_line = (signed char)(packet[5]);
line_shift = (signed char)(packet[6]);
logMessage(LOG_DEBUG, "\n");
LOG(PDA_LOG,LOG_DEBUG, "\n");
if (line_shift < 0) {
for (i = first_line-line_shift; i <= last_line; i++) {
memcpy(_menu[i+line_shift], _menu[i], AQ_MSGLEN+1);
@ -315,7 +317,7 @@ bool NEW_process_pda_menu_packet_NEW(unsigned char* packet, int length)
memcpy(_menu[i], _menu[i-line_shift], AQ_MSGLEN+1);
}
}
if (getLogLevel() >= LOG_DEBUG){print_menu();}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
}

View File

@ -66,8 +66,8 @@ typedef enum pda_menu_type {
PM_SET_AQUAPURE
} pda_menu_type;
*/
bool pda_mode();
void set_pda_mode(bool val);
//bool pda_mode();
//void set_pda_mode(bool val);
bool process_pda_menu_packet(unsigned char* packet, int length);
int pda_m_hlightindex();
char *pda_m_hlight();

Binary file not shown.

View File

@ -16,9 +16,10 @@ web_directory=/var/www/aqualinkd/
# so, NOTICE also prints WARNING & ERROR
# DEBUG_SERIAL would print everything possible
log_level=DEBUG
#log_level=DEBUG
#log_level=INFO
#log_level=NOTICE
log_level=NOTICE
#log_level=WARNING
# Display any ERROR & Warning messages in web interface.
display_warnings_in_web=true
@ -30,18 +31,65 @@ socket_port=80
# The serial port the daemon access to read the Aqualink RS8
serial_port=/dev/ttyUSB0
# Your RS panel size. ie 4, 6, 8, 12 or 16 relates to RS4, RS6, RS8, RS12 or RS16.
# VERY important that you select 12 or 16, if you have either of those size panels.
# Also don't think setting a 12 when you have a 8 will give you 4 more accessories to control, it won't the
# panel information is needed as different panels use different bits within the RS protocol for status and key
# presses.
# serial_logger will get the panel type string if you don't know it, below are examples.
# Must be in format `XX-N ????` (XX=RS or PD, N=Circuits, ????=Combo or Only or Dual)
panel_type = RS-8 Combo
#panel_type = PD-8 Combo
#panel_type = RS-16 Combo
#panel_type = RS-2/14 Dual
#panel_type = RS-4 Combo
#panel_type = RS-8 Only
#
# If serial_logger doesn't give you a type string in the format above, you can use the next options to set the specifics.
# (Number of supported accessories / buttons)
# panel_type_size = (6, 8, 10, 12, 14 or 16)
# panel_type_combo = (yes or no) (combo panels support BOTH pool & spa)
# panel_type_dual = (yes or no) (dual circuit panel)
# panel_type_pda = (yes or no) (PDA panel. only set this if you have to. Panel ONLY supports the PDA protocol)
# panel_type_rs = (yes or no) (RS panel. Panel Supports all protocols)
# The id of the Aqualink terminal device. Devices probed by RS8 master are:
# 08-0b, 10-13, 18-1b, 20-23, 28-2b, 30-33, 38-3b, 40-43
# Working RS ID's are 0x0a 0x0b 0x09 0x08 <- 0x08 is usually taken
# If your panel is a PDA only model, then PDA device ID's are 0x60, 0x61, 0x62, 0x63.
# (These are NOT recomended to use unless you absolutly have no other option)
device_id=0x0a
# The ID for extended settings to allow for faster programming
# VARIABLE SPEED PUMP are only supported with this option.
# Do not enable this if you don't use either, you'll just waste memory and cpu cycles
# Valid ID's are 0x40, 0x41, 0x42 & 0x43. for ONE Touch
# Valid ID's are 0x30, 0x31, 0x32 & 0x33. for Aqualink Touch
#extended_device_id=0x31
# 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.
# If you are using Aqualink Touch protocol for extended_device_id then this is highly recomended
# as it will speed up programming substantially. if One Touch it's 50/50.
#extended_device_id_programming = yes
# Keep the panel time synced with systemtime. Make sure to set systemtime / NTP correctly.
keep_paneltime_synced = yes
# If equiptment is in freeze protect mode some commands like pump_off / spa_on are
# ignored. You can force these to work by setting the below.
override_freeze_protect = no
# Confert Deg F to Deg C when posting to Domoticz or MQTT.
# If using homebridge-aqualinkd convert_mqtt_temp_to_c must be set to yes.
convert_mqtt_temp_to_c = yes
convert_dz_temp_to_c = yes
# default is to use pool water temp as spa water temp when spa is off (and there for not able to report water temp)
# enable below to report 0 as the spa temp when spa is off.
# This is for MQTT cnnections only, WEB socket and WEB API always report TEMP_UNKNOWN (-999) allowing the consumer to
# decide how to report.
# decide how to report.
report_zero_spa_temp = no
# default is to not report changes to pool temp when the filter pump is off or in spa mode
@ -57,41 +105,24 @@ report_zero_pool_temp = no
#mqtt_dz_pub_topic = domoticz/in
#mqtt_dz_sub_topic = domoticz/out
#mqtt_aq_topic = aqualinkd
# The id of the Aqualink terminal device. Devices probed by RS8 master are:
# 08-0b, 10-13, 18-1b, 20-23, 28-2b, 30-33, 38-3b, 40-43
# Working RS ID's are 0x0a 0x0b 0x09 0x08 <- 0x08 is usually taken
# You can use 0x00 and AqualinkD will find an ID for you, but this makes a slow startup
device_id=0x0a
# If your panel is a PDA only model, then PDA device ID's are 0x60, 0x61, 0x62, 0x63.
# (These are NOT recomended to use unless you absolutly have no other option)
# The ID for extended settings, These are ONE TOUCH MACROS & VARIABLE SPEED PUMP RPM
# Do not enable this if you don't use either, you'll just waste memory and cpu cycles
# Valid ID's are 0x40, 0x41, 0x42 & 0x43.
# If you have a one touch remote do not use Ox40
#extended_device_id=0x41
# 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.
# At the moment only heater setpoints & swg boost is on the extended device programming
#extended_device_id_programming = yes
# MQTT will only post updated information, this option AqualinkD will re-post all MQTT information every ~5 minutes.
#mqtt_timed_update = no
# Please see forum for this, only set to yes when logging information to support
# new devices. Inflrmation will be written to /tmp/RS485.log
#debug_RSProtocol_packets = no
# Not documented, only use if asked to for problem solving purposes.
#serial_readahead_b4_write = yes
#Only for PDA mode
# set PDA mode
#pda_mode = yes
#
# Put AqualinkD to sleep when in PDA mode after inactivity.
# Ignore if you are not using PDA mode.
# If you have Jandy PDA then this MUST be set to yes as the controller can only support one PDA.
# If you don't have a Jandy PDA leave this at no as AqualinkD will be a lot quicker.
#pda_sleep_mode = yes
# Read status information from other devices on the RS485 bus.
# At the moment Salt Water Generators and some VSP are supported.
# At the moment Salt Water Generators and VSP are supported.
read_all_devices = yes
# IF you have Pantair variable speed pump, set to yes othersise set to no.
@ -134,9 +165,43 @@ light_programming_initial_off=12
# it dows NOT work in PDA mode.
use_panel_aux_labels=no
# These are all the button labels you want to use for the web interface and Domoticz virtual sensors.
# Simply change these to your setup, comment out ones that ent in _dzidx if you don't use Domoticz.
# If using PDA mode, PDA Labels below are of the utmost importance, the PDA labels MUST match the labels in the "EQUIPTMENT ON/OFF" menu of the PDA device.
# These are all the button labels / options / pump and light configurations you want to use.
# Simply change these to your setup, valid options for wach button are :-
# None of these are mandatory unless you have PDA or RS16 panel, then _label is mandatory
# button_??_label=Filter Pump <Label you want to see>
# button_??_dzidx=37 <Domoticz IDX>
# button_??_pumpID=0x60 <RS485 ID of VSP>
# button_??_pumpIndex=1 <Pump index Jandy panel is configured to use>
# button_??_lightMode=4 <Color light mode>
#
# If using PDA mode, The Labels below are of the utmost importance, the labels MUST match the labels in the "EQUIPTMENT ON/OFF" menu of the PDA device.
# RS 16 Panels have no protocol bit representation for AUXB5 to AUXB8, only text, so as with PDA Those labels MUST match the control panel
#
# Below is an example of how different Panels map into the buttons.
#
# | RS-6 Combo | RS-6 Only | RS-8 Combo | RS-2/6 Dual | RS-2/10 Dual | RS-16 Combo |
# --------------------------------------------------------------------------------------------
# Button_01 | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump | Filter Pump |
# Button_02 | Spa | Aux_1 | Spa | Spa | Spa | Spa |
# Button_03 | Aux 1 | Aux 2 | Aux 1 | Aux 1 | Aux 1 | Aux 1 |
# Button_04 | Aux 2 | Aux 3 | Aux 2 | Aux 2 | Aux 2 | Aux 2 |
# Button_05 | Aux 3 | Aux 4 | Aux 3 | Aux 3 | Aux 3 | Aux 3 |
# Button_06 | Aux 4 | Aux 5 | Aux 4 | Aux 4 | Aux 4 | Aux 4 |
# Button_07 | Aux 5 | Temp 1 | Aux 5 | Aux 5 | Aux 5 | Aux 5 |
# Button_08 | Pool Heater | Temp 2 | Aux 6 | Aux 6 | Aux 6 | Aux 6 |
# Button_09 | Spa Heater | Solar Heater | Aux 7 | Pool Heater | Aux B1 | Aux 7 |
# Button_10 | Solar Heater | | Pool Heater | Spa Heater | Aux B2 | Aux B1 |
# Button_11 | | | Spa Heater | Solar Heater | Aux B3 | Aux B2 |
# Button_12 | | | Solar Heater | | Aux B4 | Aux B3 |
# Button_13 | | | | | Pool Heater | Aux B4 |
# Button_14 | | | | | Spa Heater | Aux B5 |
# Button_15 | | | | | Solar Heater | Aux B6 |
# Button_16 | | | | | | Aux B7 |
# Button_17 | | | | | | Aux B8 |
# Button_18 | | | | | | Pool Heater |
# Button_19 | | | | | | Spa Heater |
# Button_20 | | | | | | Solar Heater |
#
# Optional, ( button_01_pumpID & button_01_pumpIndex )
# If you have a Variable Speed Pump, then assign the RS485 ID to the button below so RPM/GPH/WATTS are displayed
@ -150,55 +215,30 @@ use_panel_aux_labels=no
# If you have assigned this pump an index number in your Aqualink control panel, (Between 1 & 4), put it here for VSP, RPM, Primp information to be captured.
#
# Labels for standard butons (shown in web UI), and domoticz idx's
# Labels for standard butons RS-8 Combo panel used as example.
button_01_label=Filter Pump
#button_01_dzidx=37
#button_01_PDA_label=FILTER PUMP
#button_01_pumpID=0x60
#button_01_pumpIndex=1
button_02_label=Spa Mode
#button_02_dzidx=38
#button_02_PDA_label=SPA
button_03_label=Cleaner
#button_03_dzidx=39
#button_03_PDA_label=AUX1
button_04_label=Waterfall
#button_04_dzidx=40
#button_04_PDA_label=AUX2
#button_04_pumpID=0x61
#button_04_pumpIndex=2
button_05_label=Spa Blower
#button_05_dzidx=41
#button_05_PDA_label=AUX3
button_06_label=Pool Light
#button_06_dzidx=42
#button_06_PDA_label=AUX4
#button_05_lightMode=0
button_07_label=Spa Light
#button_07_dzidx=43
#button_07_PDA_label=AUX5
#button_05_lightMode=0
button_08_label=NONE
#button_08_dzidx=NONE
#button_08_PDA_label=AUX6
button_09_label=NONE
#button_09_dzidx=NONE
#button_09_PDA_label=AUX7
button_10_label=Pool Heater
#button_10_dzidx=44
#button_10_PDA_label=POOL HEAT
button_11_label=Spa Heater
#button_11_dzidx=56
#button_11_PDA_label=SPA HEAT
button_12_label=Solar Heater
#button_12_dzidx=NONE
#button_12_PDA_label=EXTRA AUX

Binary file not shown.

144
rs_msg_utils.c Normal file
View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see <http://www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "utils.h"
/*
int check_panel_conf(char *panel)
{
"RS-16 Combo"
"PD-8 Only"
"PD-8 Combo"
"RS-2/14 Dual"
"RS-2/10 Dual"
"RS-16 Only"
"RS-12 Only"
"RS-16 Combo"
"RS-12 Combo"
"RS-2/6 Dual"
"RS-4 Only"
"RS-6 Only"
"RS-8 Only"
"RS-4 Combo"
"RS-6 Combo"
"RS-8 Combo"
}
*/
// Check s2 exists in s1
int rsm_strcmp(const char *s1, const char *s2)
{
char *sp1 = (char *)s1;
char *sp2 = (char *)s2;
//int i=0;
// Get rid of all padding
while(isspace(*sp1)) sp1++;
while(isspace(*sp2)) sp2++;
if (strlen(sp1) == 0 || strlen(sp2) == 0)
return -1;
// Need to write this myself for speed
//LOG(AQUA_LOG,LOG_DEBUG, "Compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2);
return strncasecmp(sp1, sp2, strlen(sp2));
}
int _rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len, bool nulspace)
{
int i;
int end = dest_len < src_len ? dest_len:src_len;
//0x09 is Tab and means next field on table.
for(i=0; i < end; i++) {
//0x00 on button is space
//0x00 on message is end
if (src[i] == 0x00 && nulspace)
dest[i] = ' ';
else if (src[i] == 0x00 && !nulspace)
{
dest[i] = '\0';
break;
}
else if ( (src[i] < 32 || src[i] > 126) && src[1] != 10 ) // only printable chars
dest[i] = ' ';
else
dest[i] = src[i];
//printf("Char %c to %c\n",src[i],dest[i]);
}
//printf("--'%s'--\n",dest);
if (dest[i] != '\0') {
if (i < (dest_len-1))
i++;
dest[i] = '\0';
}
return i;
}
int rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len)
{
return _rsm_strncpy(dest, src, dest_len, src_len, false);
}
int rsm_strncpy_nul2sp(char *dest, const unsigned char *src, int dest_len, int src_len)
{
return _rsm_strncpy(dest, src, dest_len, src_len, true);
}
#define INT_MAX +2147483647
#define INT_MIN -2147483647
// atoi that can have blank start
int rsm_atoi(const char* str)
{
int sign = 1, base = 0, i = 0;
// if whitespaces then ignore.
if (str == NULL)
return -1;
while (str[i] == ' ') {
i++;
}
// checking for valid input
while (str[i] >= '0' && str[i] <= '9') {
// handling overflow test case
if (base > INT_MAX / 10 || (base == INT_MAX / 10 && str[i] - '0' > 7)) {
if (sign == 1)
return INT_MAX;
else
return INT_MIN;
}
base = 10 * base + (str[i++] - '0');
}
return base * sign;
}
float rsm_atof(const char* str)
{
int i=0;
while (str[i] == ' ') {
i++;
}
return atof(&str[i]);
}

10
rs_msg_utils.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef RS_MSG_UTILS_H_
#define RS_MSG_UTILS_H_
int rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len);
int rsm_strcmp(const char *s1, const char *s2);
int rsm_strncpy_nul2sp(char *dest, const unsigned char *src, int dest_len, int src_len);
int rsm_atoi(const char* str);
float rsm_atof(const char* str);
#endif //RS_MSG_UTILS_H_

View File

@ -29,11 +29,12 @@
#include "aq_serial.h"
#include "utils.h"
#include "packetLogger.h"
#include "rs_msg_utils.h"
#define SLOG_MAX 80
#define PACKET_MAX 600
#define VERSION "serial_logger V1.2"
#define VERSION "serial_logger V1.3"
/*
typedef enum used {
@ -43,6 +44,17 @@ typedef enum used {
} used;
*/
// Bogus config to keep aq_serial.c happy
struct aqconfig
{
bool readahead_b4_write;
};
struct aqconfig _aqconfig_;
char _panelType[AQ_MSGLEN];
char _panelRev[AQ_MSGLEN];
typedef struct serial_id_log {
unsigned char ID;
bool inuse;
@ -53,6 +65,7 @@ bool _keepRunning = true;
unsigned char _goodID[] = {0x0a, 0x0b, 0x08, 0x09};
unsigned char _goodPDAID[] = {0x60, 0x61, 0x62, 0x63};
unsigned char _goodONETID[] = {0x40, 0x41, 0x42, 0x43};
unsigned char _goodIAQTID[] = {0x30, 0x31, 0x32, 0x33};
unsigned char _filter[10];
int _filters=0;
bool _rawlog=false;
@ -158,6 +171,10 @@ bool canUse(unsigned char ID) {
if (ID == _goodONETID[i])
return true;
}
for (i = 0; i < 4; i++) {
if (ID == _goodIAQTID[i])
return true;
}
return false;
}
char* canUseExtended(unsigned char ID) {
@ -174,6 +191,10 @@ char* canUseExtended(unsigned char ID) {
if (ID == _goodONETID[i])
return " <-- can use for Aqualinkd (Extended Device ID)";
}
for (i = 0; i < 4; i++) {
if (ID == _goodIAQTID[i])
return " <-- can use for Aqualinkd (Prefered Extended Device ID)";
}
return "";
}
@ -250,6 +271,39 @@ void printPacket(unsigned char ID, unsigned char *packet_buffer, int packet_leng
printf("\n");
}
void getPanelInfo(int rs_fd, unsigned char *packet_buffer, int packet_length)
{
static unsigned char getPanelRev[] = {0x00,0x14,0x01};
static unsigned char getPanelType[] = {0x00,0x14,0x02};
static int msgcnt=0;
//int i;
if (packet_buffer[PKT_CMD] == CMD_PROBE) {
if (msgcnt == 0)
send_ack(rs_fd, 0x00);
else if (msgcnt == 1)
send_jandy_command(rs_fd, getPanelRev, 3);
else if (msgcnt == 2)
send_jandy_command(rs_fd, getPanelType, 3);
msgcnt++;
} else if (packet_buffer[PKT_CMD] == CMD_MSG) {
send_ack(rs_fd, 0x00);
if (msgcnt == 2)
rsm_strncpy(_panelRev, packet_buffer+4, AQ_MSGLEN, packet_length-5);
else if (msgcnt == 3)
rsm_strncpy(_panelType, packet_buffer+4, AQ_MSGLEN, packet_length-5);
/*
for(i=4; i < packet_length-3; i++) {
if (packet_buffer[i] == 0x00)
break;
else if (packet_buffer[i] >= 32 && packet_buffer[i] <= 126)
printf("%c",packet_buffer[i]);
}
printf("\n");
*/
}
}
int main(int argc, char *argv[]) {
int rs_fd;
int packet_length;
@ -265,11 +319,15 @@ int main(int argc, char *argv[]) {
int logPackets = PACKET_MAX;
int logLevel = LOG_NOTICE;
bool rsRawDebug = false;
bool panleProbe = true;
//bool playback_file = false;
//int logLevel;
//char buffer[256];
//bool idMode = true;
// Keep bogus crap happy for aq_serial.c
_aqconfig_.readahead_b4_write = false;
printf("AqualinkD %s\n",VERSION);
@ -282,6 +340,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "ERROR, first param must be valid serial port, ie:-\n\t%s /dev/ttyUSB0\n\n", argv[0]);
//fprintf(stderr, "Optional parameters are -d (debug) & -p <number> (log # packets) & -i <ID> & -r (raw) ie:=\n\t%s /dev/ttyUSB0 -d -p 1000 -i 0x08\n\n", argv[0]);
fprintf(stderr, "Optional parameters are :-\n");
fprintf(stderr, "\t-n (Do not probe panel for type/rev info)\n");
fprintf(stderr, "\t-d (debug)\n");
fprintf(stderr, "\t-p <number> (log # packets)\n");
fprintf(stderr, "\t-i <ID> (just log these ID's, can use multiple -i)\n");
@ -311,6 +370,8 @@ int main(int argc, char *argv[]) {
_playback_file = true;
} else if (strcmp(argv[i], "-rsrd") == 0) {
rsRawDebug = true;
} else if (strcmp(argv[i], "-n") == 0) {
panleProbe = false;
}
}
@ -330,13 +391,13 @@ int main(int argc, char *argv[]) {
signal(SIGINT, intHandler);
signal(SIGTERM, intHandler);
logMessage(LOG_NOTICE, "Logging serial information!\n");
LOG(RSSD_LOG, LOG_NOTICE, "Logging serial information!\n");
if (logLevel < LOG_DEBUG)
printf("Please wait.");
while (_keepRunning == true) {
if (rs_fd < 0) {
logMessage(LOG_ERR, "ERROR, serial port disconnect\n");
LOG(RSSD_LOG, LOG_ERR, "ERROR, serial port disconnect\n");
}
//packet_length = get_packet(rs_fd, packet_buffer);
@ -347,7 +408,7 @@ int main(int argc, char *argv[]) {
if (packet_length == -1) {
// Unrecoverable read error. Force an attempt to reconnect.
logMessage(LOG_ERR, "ERROR, on serial port\n");
LOG(RSSD_LOG, LOG_ERR, "ERROR, on serial port\n");
_keepRunning = false;
} else if (packet_length == 0) {
// Nothing read
@ -385,7 +446,7 @@ int main(int argc, char *argv[]) {
sindex++;
}
}
if (packet_buffer[PKT_DEST] == DEV_MASTER /*&& packet_buffer[PKT_CMD] == CMD_ACK*/) {
//logMessage(LOG_NOTICE, "ID is in use 0x%02hhx %x\n", lastID, lastID);
for (i = 0; i <= sindex; i++) {
@ -395,6 +456,10 @@ int main(int argc, char *argv[]) {
}
}
}
if (panleProbe && packet_buffer[PKT_DEST] == 0x58 ) {
getPanelInfo(rs_fd, packet_buffer, packet_length);
}
lastID = packet_buffer[PKT_DEST];
}
@ -423,33 +488,36 @@ int main(int argc, char *argv[]) {
//sleep(1);
}
logMessage(LOG_DEBUG, "\n\n");
LOG(RSSD_LOG, LOG_DEBUG, "\n\n");
if (logLevel < LOG_DEBUG)
printf("\n\n");
if (sindex >= SLOG_MAX)
logMessage(LOG_ERR, "Ran out of storage, some ID's were not captured, please increase SLOG_MAX and recompile\n");
LOG(RSSD_LOG, LOG_ERR, "Ran out of storage, some ID's were not captured, please increase SLOG_MAX and recompile\n");
logMessage(LOG_NOTICE, "Jandy ID's found\n");
LOG(RSSD_LOG, LOG_NOTICE, "Jandy Control Panel Model : %s\n", _panelType);
LOG(RSSD_LOG, LOG_NOTICE, "Jandy Control Panel Version : %s\n", _panelRev);
LOG(RSSD_LOG, LOG_NOTICE, "Jandy ID's found\n");
for (i = 0; i < sindex; i++) {
//logMessage(LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
// (slog[i].inuse == false && canUse(slog[i].ID) == true)? " <-- can use for Aqualinkd" : "");
if (logLevel >= LOG_DEBUG || slog[i].inuse == true || canUse(slog[i].ID) == true) {
logMessage(LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
(slog[i].inuse == false)?canUseExtended(slog[i].ID):getDevice(slog[i].ID));
}
}
if (pent_sindex > 0) {
logMessage(LOG_NOTICE, "\n\n");
logMessage(LOG_NOTICE, "Pentair ID's found\n");
LOG(RSSD_LOG, LOG_NOTICE, "\n\n");
LOG(RSSD_LOG, LOG_NOTICE, "Pentair ID's found\n");
}
for (i=0; i < pent_sindex; i++) {
logMessage(LOG_NOTICE, "ID 0x%02hhx is %s %s\n", pent_slog[i].ID, (pent_slog[i].inuse == true) ? "in use" : "not used",
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", pent_slog[i].ID, (pent_slog[i].inuse == true) ? "in use" : "not used",
(pent_slog[i].inuse == false)?canUseExtended(pent_slog[i].ID):getPentairDevice(pent_slog[i].ID));
}
logMessage(LOG_NOTICE, "\n\n");
LOG(RSSD_LOG, LOG_NOTICE, "\n\n");
return 0;
}

132
utils.c
View File

@ -53,6 +53,8 @@ static bool _cfg_log2file;
static int _cfg_log_level;
static char *_loq_display_message = NULL;
int16_t _logforcemask = 0;
//static char _log_filename[256];
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages)
@ -73,8 +75,11 @@ void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_mes
}
}
int getLogLevel()
int getLogLevel(int16_t from)
{
if ( ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL)
return LOG_DEBUG;
return _log_level;
}
@ -241,6 +246,10 @@ char *stripwhitespace(char *str)
char *end;
char *start = str;
if(*start == 0 || strlen(str) <= 0 ) // All spaces?
return str;
// Trim leading space
while(isspace(*start)) start++;
@ -338,9 +347,15 @@ void test(int msg_level, char *msg)
}
void logMessage(int msg_level, char *format, ...)
void addDebugLogMask(int16_t flag)
{
_logforcemask |= flag;
}
void _LOG(int16_t from, int msg_level, char * message);
void logMessage(int msg_level, const char *format, ...)
{
// Simply return ASAP.
if (msg_level > _log_level) {
return;
}
@ -348,53 +363,108 @@ void logMessage(int msg_level, char *format, ...)
char buffer[1024];
va_list args;
va_start(args, format);
strncpy(buffer, " ", 8);
vsprintf (&buffer[8], format, args);
strncpy(buffer, " ", 20);
vsprintf (&buffer[20], format, args);
va_end(args);
_LOG(AQUA_LOG, msg_level, buffer);
}
void LOG(int16_t from, int msg_level, const char * format, ...)
{
if (msg_level > _log_level && ((_logforcemask & from) == 0) ) { // from NOT set in _logforcemask
return;
}
char buffer[1024];
va_list args;
va_start(args, format);
strncpy(buffer, " ", 20);
vsprintf (&buffer[20], format, args);
va_end(args);
_LOG(from, msg_level, buffer);
}
void _LOG(int16_t from, int msg_level, char * message)
{
int i;
//test(msg_level, buffer);
//fprintf (stderr, buffer);
// Make all printable chars
for(i = 8; i < strlen(buffer); i++) {
if ( (buffer[i] < 0 || buffer[i] > 125) && buffer[1] != 10 )
buffer[i] = ' ';
for(i = 8; i+8 < strlen(&message[8]) && i < 1024; i++) {
if ( (message[i] < 32 || message[i] > 125) && message[i] != 10 ) {
//printf ("Change %c to %c in %s\n",message[i], ' ', message);
message[i] = ' ';
}
}
if (message[i] != '\n') {
message[i] = '\n';
message[i+1] = '\0';
}
//if ( buffer[i] != '\n' )
// buffer[i+1] = '\n';
switch (from) {
case NET_LOG:
strncpy(&message[9], "NetService:", 11);
break;
case AQRS_LOG:
strncpy(&message[9], "RS Allbtn: ", 11);
break;
case ONET_LOG:
strncpy(&message[9], "One Touch: ", 11);
break;
case IAQT_LOG:
strncpy(&message[9], "iAQ Touch: ", 11);
break;
case PDA_LOG:
strncpy(&message[9], "PDA: ", 11);
break;
case DJAN_LOG:
strncpy(&message[9], "JandyDvce: ", 11);
break;
case DPEN_LOG:
strncpy(&message[9], "PentaDvce: ", 11);
break;
case RSSD_LOG:
strncpy(&message[9], "RS Serial: ", 11);
break;
case AQUA_LOG:
default:
strncpy(&message[9], "AqualinkD: ", 11);
break;
}
// Logging has not been setup yet, so STD error & syslog
if (_log_level == -1) {
fprintf (stderr, buffer);
syslog (msg_level, "%s", &buffer[8]);
fprintf (stderr, message);
syslog (msg_level, "%s", &message[9]);
closelog ();
}
if (_daemonise == TRUE)
{
if (msg_level > LOG_DEBUG) // Let's not confuse syslog with custom levels
syslog (LOG_DEBUG, "%s", &buffer[8]);
syslog (LOG_DEBUG, "%s", &message[9]);
else
syslog (msg_level, "%s", &buffer[8]);
syslog (msg_level, "%s", &message[9]);
closelog ();
//return;
}
//int len;
message[8] = ' ';
char *strLevel = elevel2text(msg_level);
strncpy(buffer, strLevel, strlen(strLevel));
//len = strlen(buffer);
strncpy(message, strLevel, strlen(strLevel));
//len = strlen(message);
/*
if ( buffer[len-1] != '\n') {
strcat(buffer, "\n");
if ( message[len-1] != '\n') {
strcat(message, "\n");
}
*/
// Sent the log to the UI if configured.
if (msg_level <= LOG_ERR && _loq_display_message != NULL) {
snprintf(_loq_display_message, 127, buffer);
snprintf(_loq_display_message, 127, message);
}
if (_log2file == TRUE && _log_filename != NULL) {
@ -403,29 +473,29 @@ void logMessage(int msg_level, char *format, ...)
if (fp != -1) {
timestamp(time);
write(fp, time, strlen(time) );
write(fp, buffer, strlen(buffer) );
write(fp, message, strlen(message) );
close(fp);
} else {
if (_daemonise == TRUE)
syslog(LOG_ERR, "Can't open log file\n %s", buffer);
syslog(LOG_ERR, "Can't open log file\n %s", message);
else
fprintf (stderr, "Can't open debug log\n %s", buffer);
fprintf (stderr, "Can't open debug log\n %s", message);
}
}
if (_daemonise == FALSE) {
if (msg_level == LOG_ERR) {
fprintf(stderr, "%s", buffer);
fprintf(stderr, "%s", message);
} else {
#ifndef AD_DEBUG
printf("%s", buffer);
printf("%s", message);
#else
struct timespec tspec;
struct tm localtm;
clock_gettime(CLOCK_REALTIME, &tspec);
char timeStr[TIMESTAMP_LENGTH];
strftime(timeStr, sizeof(timeStr), "%H:%M:%S", localtime_r(&tspec.tv_sec, &localtm));
printf("%s.%03ld %s", timeStr, tspec.tv_nsec / 1000000L, buffer);
printf("%s.%03ld %s", timeStr, tspec.tv_nsec / 1000000L, message);
#endif
}
}
@ -579,7 +649,7 @@ char* stristr(const char* haystack, const char* needle) {
} while (*haystack++);
return 0;
}
/*
int ascii(char *destination, char *source) {
unsigned int i;
for(i = 0; i < strlen(source); i++) {
@ -598,7 +668,7 @@ int ascii(char *destination, char *source) {
destination[i] = '\0';
return i;
}
*/
char *prittyString(char *str)
{
char *ptr = str;

27
utils.h
View File

@ -1,5 +1,6 @@
#include <syslog.h>
#include <stdbool.h>
#include <stdint.h>
#ifndef UTILS_H_
#define UTILS_H_
@ -21,6 +22,19 @@
#define round(a) (int) (a+0.5) // 0 decimal places
#define roundf(a) (float) ((a*100)/100) // 2 decimal places
// Defined as int16_t so 16 bits to mask
#define AQUA_LOG (1 << 0) // Aqualink Generic / catchall
#define NET_LOG (1 << 1) // Network
// Control protocols
#define AQRS_LOG (1 << 2) // Allbutton RS Keypad
#define ONET_LOG (1 << 3) // OneTouch
#define IAQT_LOG (1 << 4) // iAqualinkTouch
#define PDA_LOG (1 << 5) // PDA
// Message PRotocols
#define DJAN_LOG (1 << 6) // Jange Device
#define DPEN_LOG (1 << 7) // Pentair Device
// misc
#define RSSD_LOG (1 << 8) // Serial
/*
typedef enum
{
@ -29,11 +43,18 @@ typedef enum
*/
//void setLoggingPrms(int level , bool deamonized, char* log_file);
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages);
int getLogLevel();
int getLogLevel(int16_t from);
void daemonise ( char *pidFile, void (*main_function)(void) );
//void debugPrint (char *format, ...);
void displayLastSystemError (const char *on_what);
void logMessage(int level, char *format, ...);
void addDebugLogMask(int16_t flag);
//#define logMessage(msg_level, format, ...) LOG (1, msg_level, format, ##__VA_ARGS__)
void logMessage(int level, const char *format, ...);
//void LOG(int from, int level, char *format, ...);
void LOG(int16_t from, int msg_level, const char *format, ...);
int count_characters(const char *str, char character);
//void readCfg (char *cfgFile);
int text2elevel(char* level);
@ -51,7 +72,7 @@ void delay (unsigned int howLong);
float degFtoC(float degF);
float degCtoF(float degC);
char* stristr(const char* haystack, const char* needle);
int ascii(char *destination, char *source);
//int ascii(char *destination, char *source);
char *prittyString(char *str);
//void writePacketLog(char *buff);
//void closePacketLog();

View File

@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
#define AQUALINKD_VERSION "2.1.0"
#define AQUALINKD_VERSION "2.2.0"

View File

@ -27,7 +27,7 @@
"SWG",
//"SWG/Percent",
"SWG/PPM",
"SWG/Boost",
//"SWG/Boost",
"Temperature/Air",
"Temperature/Pool",
"Temperature/Spa",

View File

@ -829,7 +829,7 @@
setTileOn(id, 'on');
}
} catch (e) {
console.log('ERROR id=' + id + ' Line 829 | element = '+document.getElementById(id));
console.log('ERROR id=' + id + ' Line 832 | element = '+document.getElementById(id));
}
//document.getElementById(id + '_tile_icon_value').textContent = value;
var tile;
@ -1006,8 +1006,11 @@
}
// Other switch_program types (other than light_type) GO HERE
} else if (typeof object.type_ext !== 'undefined' && object.type_ext == 'switch_vsp') {
if (typeof object.Pump_RPM !== 'undefined' && object.Pump_RPM) {
if (object.Pump_RPM == -2) {
if (typeof object.Pump_RPM !== 'undefined' && object.Pump_RPM) {
if (object.Pump_RPM == -3) {
setTileOnText(object.id, 'Pump ERROR'); // Small txt
document.getElementById(object.id).setAttribute('setpoint', 0);
} else if (object.Pump_RPM == -2) {
setTileOnText(object.id, 'Pump Offline'); // Small txt
document.getElementById(object.id).setAttribute('setpoint', 0);
} else if (object.Pump_RPM == -1) {
@ -1333,13 +1336,18 @@
// The ID's should ultimatly come from json
setThermostatTile("Pool_Heater", data.pool_temp, data.pool_htr_set_pnt);
setThermostatTile("Spa_Heater", data.spa_temp, data.spa_htr_set_pnt);
setThermostatTile("SWG", data.swg_percent, data.swg_percent);
setThermostatTile("Freeze_Protect", data.air_temp, data.frz_protect_set_pnt);
setTileValue("SWG/PPM", data.swg_ppm);
setTileValue("Temperature/Air", data.air_temp);
setTileValue("Temperature/Pool", data.pool_temp);
setTileValue("Temperature/Spa", data.spa_temp);
if (typeof(data.swg_percent) !== 'undefined')
setThermostatTile("SWG", data.swg_percent, data.swg_percent);
if (typeof(data.swg_ppm) !== 'undefined')
setTileValue("SWG/PPM", data.swg_ppm);
if (typeof(data.chem_ph) !== 'undefined')
setTileValue("CHEM/pH", data.chem_ph);
if (typeof(data.chem_orp) !== 'undefined')
@ -1382,7 +1390,9 @@
while (i < 5) {
//console.log(data["Pump_"+i].RPM);
if ((typeof data["Pump_"+i] !== 'undefined') && (typeof data["Pump_"+i].RPM !== 'undefined')) {
if (data["Pump_"+i].RPM == -2) {
if (data["Pump_"+i].RPM == -3) {
setTileOnText(data["Pump_"+i].id, 'Pump ERROR');
} else if (data["Pump_"+i].RPM == -2) {
setTileOnText(data["Pump_"+i].id, 'Pump Offline');
} else if (data["Pump_"+i].RPM == -1) {
setTileOnText(data["Pump_"+i].id, 'Pump Priming');

View File

@ -63,13 +63,15 @@ Button style taken from https://github.com/ubuwaits/css3-buttons */
} else if (element.id == "clean") {
document.getElementById('messages').innerHTML = "Cleaning Debug File!"
} else if (element.id == "download") {
window.location = location.href + '?command=debug&value=download';
//window.location = location.href + '?command=debug&value=download';
window.location = '/api/debug/download';
} else {
return;
}
var http = new XMLHttpRequest();
http.open('GET', location.href + '?command=debug&value='+element.id);
//http.open('GET', location.href + '?command=debug&value='+element.id);
http.open('GET', '/api/debug/'+element.id);
http.send(null);
setTimeout(function () {
@ -123,7 +125,8 @@ Button style taken from https://github.com/ubuwaits/css3-buttons */
}
};
http.open('GET', location.href + '?command=debug&value=status');
//http.open('GET', location.href + '?command=debug&value=status');
http.open('GET', '/api/debug/status');
http.send(null);
_poller = setTimeout(update, 5000);
}