diff --git a/README.md b/README.md index a04eff6..c215372 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/aq_panel.c b/aq_panel.c index 520dad3..633911f 100644 --- a/aq_panel.c +++ b/aq_panel.c @@ -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 ); diff --git a/aq_programmer.c b/aq_programmer.c index eb73f0b..80135e8 100644 --- a/aq_programmer.c +++ b/aq_programmer.c @@ -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: diff --git a/aq_programmer.h b/aq_programmer.h index 68527d9..65ebb54 100644 --- a/aq_programmer.h +++ b/aq_programmer.h @@ -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, diff --git a/aq_serial.c b/aq_serial.c index 1570160..503757b 100644 --- a/aq_serial.c +++ b/aq_serial.c @@ -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. diff --git a/aq_serial.h b/aq_serial.h index 7abb6f1..ef2a0d5 100644 --- a/aq_serial.h +++ b/aq_serial.h @@ -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. diff --git a/aqualinkd.c b/aqualinkd.c index 08361c2..cdcace6 100644 --- a/aqualinkd.c +++ b/aqualinkd.c @@ -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); diff --git a/color_lights.c b/color_lights.c index 262d788..e43245f 100644 --- a/color_lights.c +++ b/color_lights.c @@ -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", diff --git a/iaqtouch.c b/iaqtouch.c index 7cdf6b0..4af519f 100644 --- a/iaqtouch.c +++ b/iaqtouch.c @@ -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 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; diff --git a/iaqtouch.h b/iaqtouch.h index 74b3a4b..91bae5d 100644 --- a/iaqtouch.h +++ b/iaqtouch.h @@ -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); diff --git a/iaqtouch_aq_programmer.c b/iaqtouch_aq_programmer.c index 743775e..dcbe166 100644 --- a/iaqtouch_aq_programmer.c +++ b/iaqtouch_aq_programmer.c @@ -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; diff --git a/iaqtouch_aq_programmer.h b/iaqtouch_aq_programmer.h index 0411d0b..94d943f 100644 --- a/iaqtouch_aq_programmer.h +++ b/iaqtouch_aq_programmer.h @@ -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); diff --git a/release/aqualinkd b/release/aqualinkd index aa3e118..f6f840c 100755 Binary files a/release/aqualinkd and b/release/aqualinkd differ diff --git a/release/aqualinkd.test.pda.conf b/release/aqualinkd.test.pda.conf index 470bd62..5ac3c9f 100644 --- a/release/aqualinkd.test.pda.conf +++ b/release/aqualinkd.test.pda.conf @@ -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 diff --git a/release/serial_logger b/release/serial_logger index b082f8d..c0b4b1d 100755 Binary files a/release/serial_logger and b/release/serial_logger differ diff --git a/rs_msg_utils.c b/rs_msg_utils.c index 3d3a122..8263bf5 100644 --- a/rs_msg_utils.c +++ b/rs_msg_utils.c @@ -20,6 +20,7 @@ #include #include #include +#include #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(®exCompiled, regexString, REG_EXTENDED))) { + LOG(AQUA_LOG,LOG_ERR, "regcomp() failed, returning nonzero (%d)\n", rc); + return 0; + } + + if ((regexec(®exCompiled,src,1,&match,0)) != 0) { + regfree(®exCompiled); + 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(®exCompiled); + + return len; +} /* Find first char after a space in haystack after searching needle. diff --git a/rs_msg_utils.h b/rs_msg_utils.h index 669f121..34284b4 100644 --- a/rs_msg_utils.h +++ b/rs_msg_utils.h @@ -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);