Few bugs left to fix

Most of work adding aqualinktouch protocol to PDA is complete.
PDA-Update
sfeakes 2024-05-05 17:29:37 -05:00
parent 54c8584c3f
commit d042fd481a
17 changed files with 393 additions and 86 deletions

View File

@ -85,10 +85,23 @@ Designed to mimic AqualinkRS devices, used to fully configure the master control
* Create iAqualink Touch Simulator
# Update in Release 2.3.5
* Added support for reading extended information for Jandy JXi heaters
* NEED TO FIX
* Not saying programming mode
* Not always doing on/off
* serial_logger
* Add wiki documentation
* about Heat vs Heater
* Panel version
* can't use iaquatouch panel / wireless
* Added support for reading extended information for Jandy JXi heaters.
* Added Color Light to iAqualinkTouch protocol.
* Added iAqualinkTouch support for PDA only panels that can use that protocol.
* PDA panel needs to be Rev 6.0 or newer.
* This makes the PDA only panels quicker and less error prone.
* Introduces color light support and VSP
* Consider this PDA support Beta.
* Read PDA Wiki
* Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min)
# Update in Release 2.3.4

View File

@ -525,9 +525,14 @@ bool setDeviceState(struct aqualinkdata *aqdata, int deviceIndex, bool isON)
LOG(AQUA_LOG, LOG_INFO, "received '%s' for '%s', turning '%s'\n", (isON == false ? "OFF" : "ON"), button->name, (isON == false ? "OFF" : "ON"));
#ifdef AQ_PDA
if (isPDA_PANEL) {
char msg[PTHREAD_ARG];
sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
aq_programmer(AQ_PDA_DEVICE_ON_OFF, msg, aqdata);
if (button->special_mask & PROGRAM_LIGHT && isPDA_IAQT) {
// AqualinkTouch in PDA mode, we can program light. (if turing off, use standard AQ_PDA_DEVICE_ON_OFF below)
programDeviceLightMode(aqdata, (isON?0:-1), deviceIndex); // -1 means off 0 means use current light mode
} else {
char msg[PTHREAD_ARG];
sprintf(msg, "%-5d%-5d", deviceIndex, (isON == false ? OFF : ON));
aq_programmer(AQ_PDA_DEVICE_ON_OFF, msg, aqdata);
}
} else
#endif
{
@ -598,7 +603,7 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button)
int i;
clight_detail *light = NULL;
#ifdef AQ_PDA
if (isPDA_PANEL) {
if (isPDA_PANEL && !isPDA_IAQT) {
LOG(AQUA_LOG,LOG_ERR, "Light mode control not supported in PDA mode\n");
return;
}
@ -642,7 +647,7 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int button)
//bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int deviceIndex, int value, int subIndex, bool fromMQTT)
bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int deviceIndex, int value, request_source source)
{
//LOG(AQUA_LOG,LOG_NOTICE, "Device request type %d for deviceindex %d of value %d from %d\n",type,deviceIndex, value, source);
LOG(AQUA_LOG,LOG_INFO, "Device request type %d for deviceindex %d of value %d from %d\n",type,deviceIndex, value, source);
switch (type) {
case ON_OFF:
//setDeviceState(&aqdata->aqbuttons[deviceIndex], value<=0?false:true, deviceIndex );

View File

@ -475,7 +475,8 @@ bool in_light_programming_mode(struct aqualinkdata *aq_data)
{
if ( ( aq_data->active_thread.thread_id != 0 ) &&
( aq_data->active_thread.ptype == AQ_SET_LIGHTPROGRAM_MODE ||
aq_data->active_thread.ptype == AQ_SET_LIGHTCOLOR_MODE)
aq_data->active_thread.ptype == AQ_SET_LIGHTCOLOR_MODE ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE)
) {
return true;
}
@ -535,7 +536,8 @@ bool in_iaqt_programming_mode(struct aqualinkdata *aq_data)
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 ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_DEVICE_ON_OFF)
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_DEVICE_ON_OFF ||
aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE)
) {
return true;
}
@ -754,6 +756,9 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
type = AQ_SET_IAQTOUCH_DEVICE_ON_OFF;
}
break;
case AQ_SET_LIGHTCOLOR_MODE:
type = AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE;
break;
default:
type = r_type;
break;
@ -1045,6 +1050,12 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat
return;
}
break;
case AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_light_colormode, (void*)programmingthread) < 0) {
LOG(PROG_LOG, LOG_ERR, "could not create thread\n");
return;
}
break;
#endif
#ifdef AQ_PDA
case AQ_PDA_INIT:
@ -2639,7 +2650,10 @@ const char *ptypeName(program_type type)
return "Set iAqualink Set Time";
break;
case AQ_SET_IAQTOUCH_DEVICE_ON_OFF:
return "Set iAqualink Device On/Off";
return "Set iAqualink Device On/Off";
break;
case AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE:
return "Set iAqualink Light Color (using panel)";
break;
#endif
#ifdef AQ_PDA
@ -2706,6 +2720,7 @@ const char *programtypeDisplayName(program_type type)
break;
case AQ_SET_LIGHTPROGRAM_MODE:
case AQ_SET_LIGHTCOLOR_MODE:
case AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE:
return "Programming: setting light color";
break;
case AQ_SET_SWG_PERCENT:

View File

@ -84,6 +84,7 @@ typedef enum {
AQ_SET_IAQTOUCH_SPA_HEATER_TEMP,
AQ_SET_IAQTOUCH_SET_TIME,
AQ_SET_IAQTOUCH_DEVICE_ON_OFF,
AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE,
AQ_GET_RSSADAPTER_SETPOINTS,
AQ_SET_RSSADAPTER_POOL_HEATER_TEMP,
AQ_SET_RSSADAPTER_SPA_HEATER_TEMP,

View File

@ -143,6 +143,9 @@ const char* get_packet_type(unsigned char* packet , int length)
case CMD_IAQ_TITLE_MESSAGE:
return "iAq ProductName";
break;
case CMD_IAQ_MSG_LONG:
return "iAq Popup message";
break;
case RSSA_DEV_STATUS:
// This is a fail reply 0x10|0x02|0x48|0x13|0x02|0x00|0x10|0x00|0x7f|0x10|0x03|
// Rather than check all, just check 0x02 and checksum sin't I'm not sure 0x10 means faiure without 0x00 around it.

View File

@ -359,6 +359,7 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define KEY_IAQTCH_STATUS 0x06
#define KEY_IAQTCH_PREV_PAGE 0x20
#define KEY_IAQTCH_NEXT_PAGE 0x21
#define KEY_IAQTCH_OK 0x01 //HEX: 0x10|0x02|0x00|0x01|0x00|0x01|0x14|0x10|0x03|. OK BUTTON
#define KEY_IAQTCH_PREV_PAGE_ALTERNATE 0x1d // System setup prev
#define KEY_IAQTCH_NEXT_PAGE_ALTERNATE 0x1e // System setup next
@ -414,8 +415,9 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define IAQ_PAGE_VSP_SETUP 0x2d
#define IAQ_PAGE_FREEZE_PROTECT 0x11
#define IAQ_PAGE_LABEL_AUX 0x32
#define IAQ_PAGE_HELP 0x0c
//#define IAQ_PAGE_START_BOOST 0x3f
#define IAQ_PAGE_DEGREES 0xFF // Added this as never want to actually select the page, just go to it.
//#define IAQ_PAGE_DEGREES 0xFF // Added this as never want to actually select the page, just go to it.

View File

@ -180,6 +180,12 @@ bool checkAqualinkTime()
LOG(AQUA_LOG,LOG_DEBUG, "time not checked, will check in %d seconds\n", TIME_CHECK_INTERVAL - time_difference);
return true;
}
else if (strlen(_aqualink_data.date) <=0 ||
strlen(_aqualink_data.time) <=0)
{
LOG(AQUA_LOG,LOG_DEBUG, "time not checked, no time from panel\n");
return true;
}
else
{
last_checked = now;
@ -188,7 +194,7 @@ bool checkAqualinkTime()
char datestr[DATE_STRING_LEN];
#ifdef AQ_PDA
if (isPDA_PANEL) {
if (isPDA_PANEL && !isPDA_IAQT) {
LOG(AQUA_LOG,LOG_DEBUG, "PDA Time Check\n");
// date is simply a day or week for PDA.
localtime_r(&now, &aq_tm);
@ -1890,6 +1896,8 @@ void main_loop()
_aqualink_data.updated = process_iaqtouch_packet(packet_buffer, packet_length, &_aqualink_data);
_aqualink_data.updated = true; // FORCE UPDATE SINCE THIS IS NOT WORKING YET
caculate_ack_packet(rs_fd, packet_buffer, IAQTOUCH);
if (checkAqualinkTime() == false) // Need to do this better.
{aq_programmer(AQ_SET_TIME, NULL, &_aqualink_data);}
}
else /*if (_aqualink_data.simulator_active == SIM_NONE)*/ {
caculate_ack_packet(rs_fd, packet_buffer, AQUAPDA);

View File

@ -50,8 +50,8 @@ const char *_color_light_options[NUMBER_LIGHT_COLOR_TYPES][LIGHT_COLOR_OPTIONS]
},
{ // Color Logic
"Voodoo Lounge",
"Blue Sea",
"Royal Blue",
"Deep Blue Sea",
//"Royal Blue",
"Afternoon Skies",
//"Aqua Green",
"Emerald",

View File

@ -112,6 +112,11 @@ unsigned char iaqtCurrentPage()
{
return _currentPage;
}
unsigned char iaqtCurrentPageLoading()
{
return _currentPageLoading;
}
const char *iaqtGetMessageLine(int index) {
if (index < IAQ_STATUS_PAGE_LINES)
@ -137,10 +142,6 @@ struct iaqt_page_button *iaqtFindButtonByIndex(int index) {
buttons = _devicePageButtons[1];
else if (_currentPage == IAQ_PAGE_DEVICES3)
buttons = _devicePageButtons[2];
/*
else if (_currentPage == IAQ_PAGE_DEVICES2 )
buttons = _devicePage2Buttons;
*/
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP )
buttons = _deviceSystemSetupButtons[0];
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP2 )
@ -169,9 +170,6 @@ struct iaqt_page_button *iaqtFindButtonByLabel(char *label) {
buttons = _devicePageButtons[1];
else if (_currentPage == IAQ_PAGE_DEVICES3)
buttons = _devicePageButtons[2];
//else if (_currentPage == IAQ_PAGE_DEVICES2 )
// buttons = _devicePage2Buttons;
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP )
buttons = _deviceSystemSetupButtons[0];
else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP2 )
@ -308,7 +306,7 @@ void processPageButton(unsigned char *message, int length, struct aqualinkdata *
else {
button = &_pageButtons[index];
// if _currentPageLoading = 0x00 then we should use current page
LOG(IAQT_LOG,LOG_WARNING, "Not sure where to add Button %d %s - LoadingPage = %s\n",index,button->name,iaqt_page_name(_currentPageLoading));
LOG(IAQT_LOG,LOG_NOTICE, "Not sure where to add Button %d %s - LoadingPage = %s\n",index,button->name,iaqt_page_name(_currentPageLoading));
}
button->state = message[PKT_IAQT_BUTSTATE];
@ -391,16 +389,6 @@ void processPageButton(unsigned char *message, int length, struct aqualinkdata *
}
}
}
/*
_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);
*/
}
@ -535,21 +523,23 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data)
LOG(IAQT_LOG,LOG_INFO, "Set Cemlink ORP = %d PH = %f from message '%s'\n",orp,ph,_deviceStatus[i]);
}
}
#ifdef READ_SWG_FROM_EXTENDED_ID
else if (rsm_strcmp(_deviceStatus[i],"AQUAPURE") == 0) {
//#ifdef READ_SWG_FROM_EXTENDED_ID
else if (isPDA_PANEL) {
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) {
} else if (rsm_strcmp(_deviceStatus[i],"salt") == 0) {
aq_data->swg_ppm = rsm_atoi(&_deviceStatus[i][5]);
aq_data->updated = true;
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) {
} else if (rsm_strcmp(_deviceStatus[i],"Boost Pool") == 0) {
aq_data->boost = true;
aq_data->updated = true;
// Let RS pickup time remaing message.
}
#endif
}
}
//#endif
} // for
}
@ -563,6 +553,8 @@ void debugPrintButtons(struct iaqt_page_button buttons[])
}
}
//#define member_size(type, member) (sizeof( ((type*)0)->member ))
void processPage(struct aqualinkdata *aq_data)
{
//static int _home_cnt = 0;
@ -606,34 +598,13 @@ void processPage(struct aqualinkdata *aq_data)
// If Button 15 has type 0x02 then we have previous, if 0x00 nothing (previous send code KEY_IAQTCH_PREV_PAGE)
// If Button 16 has type 0x03 then we have next, if 0x00 nothing (next send code KEY_IAQTCH_NEXT_PAGE)
if ( (isPDA_PANEL || PANEL_SIZE() >= 16) && !in_iaqt_programming_mode(aq_data) ) {
printf("********* button 16 type = 0x%02hhx **********\n",_devicePageButtons[dp][16].type);
if (_devicePageButtons[dp][16].type == 0x03) {
printf("********* NEXT PAGE FROM DEVICES **********\n");
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
} else {
printf("********* STATUS FROM DEVICES **********\n");
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
}
}
break;
/*
case IAQ_PAGE_DEVICES2:
//LOG(IAQT_LOG,LOG_INFO, "Devices Page #2:-\n");
debugPrintButtons(_devicePage2Buttons);
// If Button 15 has type 0x02 then we have previous, if 0x00 nothing (previous send code KEY_IAQTCH_PREV_PAGE)
// If Button 16 has type 0x03 then we have next, if 0x00 nothing (next send code KEY_IAQTCH_NEXT_PAGE)
if (isPDA_PANEL && !in_iaqt_programming_mode(aq_data) ) {
printf("********* button 16 type = 0x%02hhx **********\n",_devicePage2Buttons[16].type);
if (_devicePage2Buttons[16].type == 0x03) {
printf("********* NEXT PAGE FROM DEVICES2 **********\n");
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
} else {
printf("********* STATUS FROM DEVICES2 **********\n");
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
}
}
break;*/
case IAQ_PAGE_COLOR_LIGHT:
//LOG(IAQT_LOG,LOG_INFO, "Color Light Page :-\n");
debugPrintButtons(_pageButtons);
@ -652,7 +623,7 @@ void processPage(struct aqualinkdata *aq_data)
//Info: iAQ Touch: Home Status page 01| 72
//Info: iAQ Touch: Home Status page 04| Spa Temp
//Info: iAQ Touch: Home Status page 05| Air Temp
if (isPDA_PANEL) {
if (isPDA_PANEL) { // Set temp if PDA panel
if (rsm_strcmp(_homeStatus[5],"Air Temp") == 0) {
aq_data->air_temp = atoi(_homeStatus[1]);
LOG(IAQT_LOG,LOG_DEBUG, "Air Temp set to %d\n",aq_data->air_temp);
@ -663,8 +634,8 @@ void processPage(struct aqualinkdata *aq_data)
LOG(IAQT_LOG,LOG_DEBUG, "Pool Temp set to %d\n",aq_data->air_temp);
aq_data->updated = true;
} else if (rsm_strcmp(_homeStatus[4],"Spa Temp") == 0) {
aq_data->pool_temp = atoi(_homeStatus[0]);
LOG(IAQT_LOG,LOG_DEBUG, "Spa Temp set to %d\n",aq_data->air_temp);
aq_data->spa_temp = atoi(_homeStatus[0]);
LOG(IAQT_LOG,LOG_DEBUG, "Spa Temp set to %d\n",aq_data->spa_temp);
aq_data->updated = true;
}
}
@ -687,6 +658,25 @@ void processPage(struct aqualinkdata *aq_data)
case IAQ_PAGE_SET_VSP:
debugPrintButtons(_pageButtons);
break;
case IAQ_PAGE_HELP:
/*
Info: iAQ Touch: Table Messages 01| Interface: AquaLink Touch
Info: iAQ Touch: Table Messages 02| Model: RS-8 Combo
Info: iAQ Touch: Table Messages 03| AquaLink: REV T.0.1
Info: iAQ Touch: Table Messages 04| CPU p/n: B0029221
Info: iAQ Touch: Table Messages 05| TL Rev:
*/
if (isPDA_PANEL && ((char *)_tableInformation[03]) > 0) {
if ( rsm_get_revision(aq_data->revision,(char *)_tableInformation[3], sizeof(aq_data->revision) ) == TRUE) {
int len = rsm_get_boardcpu(aq_data->version, sizeof(aq_data->version), (char *)_tableInformation[4], IAQT_TABLE_MSGLEN );
sprintf(aq_data->version+len, " REV %s",aq_data->revision);
LOG(IAQT_LOG,LOG_NOTICE, "Control Panel revision %s\n", aq_data->revision);
LOG(IAQT_LOG,LOG_NOTICE, "Control Panel version %s\n", aq_data->version);
aq_data->updated = true;
}
}
break;
default:
//LOG(IAQT_LOG,LOG_INFO, "** UNKNOWN PAGE 0x%02hhx **\n",_currentPage);
@ -711,10 +701,13 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
static bool gotInit = false;
static int cnt = 0;
static bool gotStatus = true;
static char message[AQ_MSGLONGLEN + 1];
bool fake_pageend = false;
//char buff[1024];
// NSF Take this out
if ( packet[3] != CMD_IAQ_POLL && getLogLevel(IAQT_LOG) >= LOG_DEBUG ) {
//if ( getLogLevel(IAQT_LOG) >= LOG_DEBUG ) {
char buff[1000];
beautifyPacket(buff, packet, length, false);
LOG(IAQT_LOG,LOG_DEBUG, "Received message : %s", buff);
@ -722,6 +715,9 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
if (packet[PKT_CMD] == CMD_IAQ_PAGE_START) {
// Reset and messages on new page
aq_data->last_display_message[0] = ' ';
aq_data->last_display_message[1] = '\0';
LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND off\n");
set_iaq_cansend(false);
_currentPageLoading = packet[PKT_IAQT_PAGTYPE];
@ -743,13 +739,19 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
} else {
LOG(IAQT_LOG,LOG_DEBUG, "Page end message without proceding page start, ignoring!\n");
}
// Time is in the page end command
// 1/18/2011 13:42
//Hex |0x10|0x02|0x33|0x28|0x01|0x12|0x0b|0x0d|0x2a|0xc2|0x10|0x03|
//Dec | 16| 2| 51| 40| 1| 18| 11| 13| 42| 194| 16| 3
//Ascii | | | 3| (| | | | | *| | |
snprintf(aq_data->date, sizeof(aq_data->date), "%d/%d/%d", packet[4],packet[5],packet[6]);
snprintf(aq_data->time, sizeof(aq_data->date), "%d:%d", packet[7],packet[8]);
if (isPDA_PANEL) {
// Time is in the page end command
// 1/18/2011 13:42
//Hex |0x10|0x02|0x33|0x28|0x01|0x12|0x0b|0x0d|0x2a|0xc2|0x10|0x03|
//Dec | 16| 2| 51| 40| 1| 18| 11| 13| 42| 194| 16| 3
//Ascii | | | 3| (| | | | | *| | |
snprintf(aq_data->date, sizeof(aq_data->date), "%02d/%02d/%02d", packet[4],packet[5],packet[6]);
if (packet[7] <= 12)
snprintf(aq_data->time, sizeof(aq_data->date), "%d:%02d am", packet[7],packet[8]);
else
snprintf(aq_data->time, sizeof(aq_data->date), "%d:%02d pm", (packet[7] - 12),packet[8]);
}
processPage(aq_data);
@ -773,18 +775,32 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
// 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) {
if (packet[7] == 0x00 && packet[4] == 0x0e) { // packet[4] is button number 0x0e is 14 (last button)
//printf("** MANUAL PAGE END\n");
LOG(IAQT_LOG,LOG_DEBUG, "MANUAL PAGE END\n");
_currentPage = _currentPageLoading;
//_currentPageLoading = NUL;
processPage(aq_data);
set_iaq_cansend(true);
// For programming mode
fake_pageend = 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
}
}
}
} else if (isPDA_PANEL && packet[PKT_CMD] == CMD_IAQ_MSG_LONG) {
// Set disply message if PDA panel
memset(message, 0, AQ_MSGLONGLEN + 1);
rsm_strncpy(message, packet + 6, AQ_MSGLONGLEN, length-9);
LOG(IAQT_LOG,LOG_NOTICE, "Popup message '%s'\n",message);
strcpy(aq_data->last_display_message, message); // Also display the message on web UI
/*
for(int i=0; i<length; i++) {
printf("0x%02hhx|",packet[i]);
}
printf("\n");
*/
}
if (packet[3] == 0x29) {
//printf("***** iAqualink Touch STARTUP Message ******* \n");
@ -800,18 +816,15 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd
/*
NEED TO ALTERNATE SEND KEY_IAQTCH_HOMEP_KEY08 KEY and KEY_IAQTCH_STATUS BELOW FOR PDA
*/
// Standard ack/poll not interested in printing or kicking threads
// Standard ack/poll
if (packet[3] == CMD_IAQ_POLL) {
//LOG(IAQT_LOG,LOG_DEBUG, "poll count %d\n",cnt);
// Load status page every 50 messages
if (cnt++ > REQUEST_STATUS_POLL_COUNT && in_programming_mode(aq_data) == false ) {
printf("********* START REQUEST LOOP **********\n");
if (isPDA_PANEL || PANEL_SIZE() >= 16) {
iaqt_queue_cmd(KEY_IAQTCH_HOMEP_KEY08);
printf("********* REQUEST OTHER DEVICES FROM HOME **********\n");
} else {
iaqt_queue_cmd(KEY_IAQTCH_STATUS);
printf("********* REQUEST OTHER SATUS FROM HOME **********\n");
}
gotStatus = false; // Reset if we got status page, for fix panel bug.
//aq_programmer(AQ_GET_IAQTOUCH_VSP_ASSIGNMENT, NULL, aq_data);
@ -834,14 +847,18 @@ printf("********* REQUEST OTHER SATUS FROM HOME **********\n");
// -5 seems to be too quick for VSP/GPM so using 10
cnt = REQUEST_STATUS_POLL_COUNT - 10;
}
// On poll no need to kick programming threads
return false;
}
//debuglogPacket(IAQT_LOG ,packet, length);
//_lastMsgType = packet[PKT_CMD];
set_iaqtouch_lastmsg(packet[PKT_CMD]);
if (fake_pageend){
set_iaqtouch_lastmsg(CMD_IAQ_PAGE_END);
} else {
set_iaqtouch_lastmsg(packet[PKT_CMD]);
}
//debuglogPacket(IAQT_LOG ,packet, length);
//beautifyPacket(buff, packet, length);
//LOG(IAQT_LOG,LOG_DEBUG, "%s", buff);
@ -926,6 +943,9 @@ const char *iaqt_page_name(const unsigned char page)
case IAQ_PAGE_LABEL_AUX:
return "Label Aux";
break;
case IAQ_PAGE_HELP:
return "Help Page";
break;
default:
sprintf (_namebuf,"** Unknown 0x%02hhx **",page);
return _namebuf;

View File

@ -15,6 +15,7 @@ struct iaqt_page_button {
bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data);
unsigned char iaqtThreadKickType();
unsigned char iaqtCurrentPage();
unsigned char iaqtCurrentPageLoading();
bool wasiaqtThreadKickTypePage();
struct iaqt_page_button *iaqtFindButtonByLabel(char *label);
struct iaqt_page_button *iaqtFindButtonByIndex(int index);

View File

@ -32,6 +32,7 @@
#include "config.h"
#include "devices_jandy.h"
#include "packetLogger.h"
#include "color_lights.h"
// System Page is obfiously fixed and not dynamic loaded, so set buttons to stop confustion.
@ -173,9 +174,64 @@ bool waitfor_iaqt_ctrl_queue2empty()
}
return true;
}
/*
unsigned const char _waitfor_iaqt_nextPage(struct aqualinkdata *aq_data, int numMessageReceived) {
waitfor_iaqt_queue2empty();
int i=0;
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
while( ++i <= numMessageReceived)
{
//LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_nextPage (%d of %d)\n",i,numMessageReceived);
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
if(wasiaqtThreadKickTypePage()) break;
}
LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_nextPage finished in (%d of %d)\n",i,numMessageReceived);
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if(wasiaqtThreadKickTypePage())
return iaqtCurrentPage();
else
return NUL;
}
unsigned const char shortwaitfor_iaqt_nextPage(struct aqualinkdata *aq_data) {
return _waitfor_iaqt_nextPage(aq_data, 3);
}
*/
unsigned const char waitfor_iaqt_messages(struct aqualinkdata *aq_data, int numMessageReceived) {
//return _waitfor_iaqt_nextPage(aq_data, 30);
waitfor_iaqt_queue2empty();
int i=0;
LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_messages (%d of %d)\n",i,numMessageReceived);
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
while( ++i <= numMessageReceived)
{
//LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_nextPage (%d of %d)\n",i,numMessageReceived);
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
}
LOG(IAQT_LOG,LOG_DEBUG, "waitfor_iaqt_messages finished in (%d of %d)\n",i,numMessageReceived);
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
return iaqtLastMsg();
}
unsigned const char waitfor_iaqt_nextPage(struct aqualinkdata *aq_data) {
//return _waitfor_iaqt_nextPage(aq_data, 30);
waitfor_iaqt_queue2empty();
@ -199,9 +255,10 @@ unsigned const char waitfor_iaqt_nextPage(struct aqualinkdata *aq_data) {
return iaqtCurrentPage();
else
return NUL;
}
unsigned const char waitfor_iaqt_nextMessage(struct aqualinkdata *aq_data, const unsigned char msg_type) {
waitfor_iaqt_queue2empty();
@ -324,7 +381,7 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
return true;
} else if (pageID == IAQ_PAGE_MENU || pageID == IAQ_PAGE_SET_TEMP || pageID == IAQ_PAGE_SET_TIME || pageID == IAQ_PAGE_SET_SWG ||
pageID == IAQ_PAGE_SYSTEM_SETUP || pageID == IAQ_PAGE_FREEZE_PROTECT || pageID == IAQ_PAGE_LABEL_AUX ||
pageID == IAQ_PAGE_VSP_SETUP || pageID == IAQ_PAGE_DEGREES) {
pageID == IAQ_PAGE_VSP_SETUP) {
// All other pages require us to go to Menu page
send_aqt_cmd(KEY_IAQTCH_MENU);
if (waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_MENU) {
@ -387,9 +444,6 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
case IAQ_PAGE_VSP_SETUP:
menuText = "VSP Setup";
break;
case IAQ_PAGE_DEGREES:
menuText = "Degrees";
break;
default:
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch unknown menu '0x%02hhx'\n", pageID);
return false;
@ -424,7 +478,7 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) {
void *set_aqualink_iaqtouch_device_on_off( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
char *buf = (char*)threadCtrl->thread_args;
@ -469,9 +523,150 @@ struct programmingThreadCtrl *threadCtrl;
}
send_aqt_cmd(button->keycode);
//LOG(IAQT_LOG, LOG_ERR, "******* CURRENT MENU '0x%02hhx' *****\n",iaqtCurrentPage());
// NSF NEED TO CHECK FOR POPUP MESSAGE, AND KILL IT.
//page IAQ_PAGE_SET_TEMP hit button 0
//page IAQ_PAGE_COLOR_LIGHT hit button ???????
// Heater popup can be cleared with a home button and still turn on.
// Color light can be cleared with a home button, but won;t turn on.
waitfor_iaqt_queue2empty();
//waitfor_iaqt_messages(aq_data,1);
// OR maybe use waitfor_iaqt_messages(aq_data,1)
// Turn spa on when pump off, ned to remove message "spa will turn on after safty delay", home doesn't clear.
send_aqt_cmd(KEY_IAQTCH_HOME);
// Turn spa off need to read message if heater is on AND hit ok......
f_end:
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *set_aqualink_iaqtouch_light_colormode( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
char *buf = (char*)threadCtrl->thread_args;
//char device_name[15];
struct iaqt_page_button *button;
const char *mode_name;
int val = atoi(&buf[0]);
int btn = atoi(&buf[5]);
int typ = atoi(&buf[10]);
bool use_current_mode = false;
bool turn_off = false;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE);
//char *buf = (char*)threadCtrl->thread_args;
if (btn < 0 || btn >= aq_data->total_buttons ) {
LOG(IAQT_LOG, LOG_ERR, "Can't program light mode on button %d\n", btn);
cleanAndTerminateThread(threadCtrl);
return ptr;
}
aqkey *key = &aq_data->aqbuttons[btn];
//unsigned char code = key->code;
// We also need to cater for light being ON AND changing the color mode. we have extra OK to hit.
if (val == 0) {
use_current_mode = true;
LOG(IAQT_LOG, LOG_INFO, "Light Programming #: %d, button: %s, color light type: %d, using current mode\n", val, key->label, typ);
// NOT SURE WHAT TO DO HERE..... No color mode and iaatouch doesn;t support last color in PDA mode.
} else if (val == -1) {
turn_off = true;
LOG(IAQT_LOG, LOG_INFO, "Light Programming #: %d, button: %s, color light type: %d, Turning off\n", val, key->label, typ);
} else {
mode_name = light_mode_name(typ, val-1);
use_current_mode = false;
if (mode_name == NULL) {
LOG(IAQT_LOG, LOG_ERR, "Light Programming #: %d, button: %s, color light type: %d, couldn't find mode name '%s'\n", val, key->label, typ, mode_name);
cleanAndTerminateThread(threadCtrl);
return ptr;
} else {
LOG(IAQT_LOG, LOG_INFO, "Light Programming #: %d, button: %s, color light type: %d, name '%s'\n", val, key->label, typ, mode_name);
}
}
// See if it's on the current page
button = iaqtFindButtonByLabel(key->label);
if (button == NULL) {
// No luck, go to the device page
if ( goto_iaqt_page(IAQ_PAGE_DEVICES, aq_data) == false )
goto f_end;
button = iaqtFindButtonByLabel(key->label);
// If not found see if page has next
if (button == NULL && iaqtFindButtonByIndex(16)->type == 0x03 ) {
iaqt_queue_cmd(KEY_IAQTCH_NEXT_PAGE);
waitfor_iaqt_nextPage(aq_data);
// This will fail, since not looking at device page 2 buttons
button = iaqtFindButtonByLabel(key->label);
}
}
if (button == NULL) {
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on device list\n", key->label);
goto f_end;
}
// WE have a iaqualink button, press it.
send_aqt_cmd(button->keycode);
// See if we want to use the last color, or turn it off
if (use_current_mode || turn_off) {
// After pressing the button, Just need to wait for 5 seconds and it will :-
// a) if off turn on and default to last color.
// b) if on, turn off. (pain that we need to wait 5 seconds.)
waitfor_iaqt_queue2empty();
waitfor_iaqt_nextPage(aq_data);
if (use_current_mode) {
// Their is no message for this, so give one.
sprintf(aq_data->last_display_message, "Light will turn on in 5 seconds");
aq_data->updated = true;
}
// Wait for next page maybe?
// Below needs a timeout.
while (waitfor_iaqt_nextPage(aq_data) == IAQ_PAGE_COLOR_LIGHT);
goto f_end;
}
// BELOW WE NEED TO CATER FOR OK POPUP IF LIGHT IS ALREADY ON
if (button->state == 0x01) { // Light is on, need to select the BUTTON
waitfor_iaqt_queue2empty();
// We Should wait for popup message, before sending code
send_aqt_cmd(KEY_IAQTCH_OK);
}
if (waitfor_iaqt_nextPage(aq_data) != IAQ_PAGE_COLOR_LIGHT) {
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not color light page\n");
goto f_end;
}
button = iaqtFindButtonByLabel(mode_name);
if (button == NULL) {
LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did find color '%s' in color light page\n",mode_name);
goto f_end;
}
//LOG(IAQT_LOG, LOG_ERR, "IAQ Touch WAIYING FOR 1 MESSAGES\n");
//waitfor_iaqt_messages(aq_data, 1);
// Finally found the color. select it
send_aqt_cmd(button->keycode);
waitfor_iaqt_nextPage(aq_data);
f_end:
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
cleanAndTerminateThread(threadCtrl);
@ -662,6 +857,10 @@ void *get_aqualink_iaqtouch_setpoints( void *ptr )
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_IAQTOUCH_SETPOINTS);
// Get product info.
send_aqt_cmd(KEY_IAQTCH_HELP);
unsigned char page = waitfor_iaqt_nextPage(aq_data);
if ( goto_iaqt_page(IAQ_PAGE_SET_TEMP, aq_data) == false )
goto f_end;

View File

@ -19,7 +19,7 @@ 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 );
void *set_aqualink_iaqtouch_light_colormode( void *ptr );
void *set_aqualink_iaqtouch_device_on_off( void *ptr ); // For PDA only
int ref_iaqt_control_cmd(unsigned char **cmd);

Binary file not shown.

View File

@ -50,8 +50,8 @@ debug_log_mask = 1024
#debug_log_mask = 4096
# Log any packets from this device. (less outpit that DEBUG_SERIAL)
# debug_log_mask = 512 - MUST be set for this to work.
#RSSD_LOG_filter = 0x33
#debug_log_mask = 512 - MUST be set for this to work.
RSSD_LOG_filter = 0x33
display_warnings_in_web = yes
rs485_frame_delay = 4

Binary file not shown.

View File

@ -20,6 +20,7 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <regex.h>
#include "utils.h"
#include "rs_msg_utils.h"
@ -83,6 +84,42 @@ bool rsm_get_revision(char *dest, const char *src, int src_len)
return true;
}
/*
pull board CPU from strings line
' CPU p/n: B0029221'
'B0029221 REV T.0.1'
'E0260801 REV. O.2'
*/
int rsm_get_boardcpu(char *dest, int dest_len, const char *src, int src_len)
{
//char *regexString="/\\w\\d{4,10}/gi";
//char *regexString="/[[:alpha:]][[:digit:]]{4,10}/gi";
char *regexString="[[:alpha:]][[:digit:]]{4,10}";
regex_t regexCompiled;
regmatch_t match;
int rc, begin, end, len;
if (0 != (rc = regcomp(&regexCompiled, regexString, REG_EXTENDED))) {
LOG(AQUA_LOG,LOG_ERR, "regcomp() failed, returning nonzero (%d)\n", rc);
return 0;
}
if ((regexec(&regexCompiled,src,1,&match,0)) != 0) {
regfree(&regexCompiled);
printf("********** ERROR didn;t line match \n");
return 0;
}
begin = (int)match.rm_so;
end = (int)match.rm_eo;
len = MIN((end-begin), dest_len);
strncpy(dest, src+match.rm_so, len );
regfree(&regexCompiled);
return len;
}
/*
Find first char after a space in haystack after searching needle.

View File

@ -1,8 +1,11 @@
#ifndef RS_MSG_UTILS_H_
#define RS_MSG_UTILS_H_
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
bool rsm_get_revision(char *dest, const char *src, int src_len);
int rsm_get_boardcpu(char *dest, int dest_len, const char *src, int src_len);
char *rsm_charafterstr(const char *haystack, const char *needle, int length);
char *rsm_strstr(const char *haystack, const char *needle);