diff --git a/README.md b/README.md index 4ac3ce5..a04eff6 100644 --- a/README.md +++ b/README.md @@ -85,9 +85,12 @@ 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 * 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. - +* Fixed issue mqtt_timed_update (1~2 min rather than between 2 & 20 min) + # Update in Release 2.3.4 * Changes for Docker * Updated simulator code base and added new simulators for AllButton, OneTouch & PDA. diff --git a/aq_mqtt.h b/aq_mqtt.h index e701d9d..ba35570 100644 --- a/aq_mqtt.h +++ b/aq_mqtt.h @@ -24,12 +24,19 @@ #define SWG_EXTENDED_TOPIC SWG_TOPIC "/fullstatus" #define SWG_BOOST_TOPIC SWG_TOPIC "/Boost" +#define SWG_STATUS_MSG_TOPIC SWG_TOPIC "/Display_Message" + #define CHEM_TOPIC "CHEM" #define CHEM_PH_TOPIC CHEM_TOPIC "/pH" #define CHRM_PH_F_TOPIC CHEM_TOPIC "/pH_f" #define CHEM_ORP_TOPIC CHEM_TOPIC "/ORP" #define CHRM_ORP_F_TOPIC CHEM_TOPIC "/ORP_f" +#define LXI_TOPIC "LXi" +#define LXI_STATUS LXI_TOPIC "/Status" +#define LXI_ERROR_CODE LXI_TOPIC "/Error" +#define LXI_ERROR_MESSAGE LXI_TOPIC "/Error_Message" + #define FREEZE_PROTECT "Freeze_Protect" #define FREEZE_PROTECT_ENABELED FREEZE_PROTECT ENABELED_SUBT diff --git a/aq_programmer.c b/aq_programmer.c index 1969f80..eb73f0b 100644 --- a/aq_programmer.c +++ b/aq_programmer.c @@ -397,8 +397,15 @@ void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_dat } } #ifdef AQ_PDA - } else if ( source_type == AQUAPDA) { + } else if ( isPDA_PANEL && source_type == AQUAPDA) { aq_programmer(AQ_PDA_INIT, NULL, aq_data); + } else if ( isPDA_PANEL && source_type == IAQTOUCH) { + //aq_programmer(AQ_PDA_INIT, NULL, aq_data); + if (_aqconfig_.use_panel_aux_labels) { + aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data); + } + aq_programmer(AQ_GET_IAQTOUCH_SETPOINTS, NULL, aq_data); + #endif } else { // Must be all button only aq_programmer(AQ_GET_POOL_SPA_HEATER_TEMPS, NULL, aq_data); @@ -527,7 +534,8 @@ bool in_iaqt_programming_mode(struct aqualinkdata *aq_data) 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) + aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM || + aq_data->active_thread.ptype == AQ_SET_IAQTOUCH_DEVICE_ON_OFF) ) { return true; } @@ -719,7 +727,7 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat } #endif #ifdef AQ_IAQTOUCH - else if (isIAQT_ENABLED && isEXTP_ENABLED) { + else if ((isIAQT_ENABLED && isEXTP_ENABLED) || isPDA_IAQT) { // IAQ Touch programming modes that should overite standard ones. switch (r_type){ case AQ_GET_POOL_SPA_HEATER_TEMPS: @@ -741,6 +749,11 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat case AQ_SET_TIME: type = AQ_SET_IAQTOUCH_SET_TIME; break; + case AQ_PDA_DEVICE_ON_OFF: + if (isPDA_IAQT) { + type = AQ_SET_IAQTOUCH_DEVICE_ON_OFF; + } + break; default: type = r_type; break; @@ -752,11 +765,8 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat #ifdef AQ_PDA // Check we are doing something valid request - if (isPDA_PANEL -#ifdef AQ_IAQTOUCH - && _aqconfig_.extended_device_id_programming == false && _aqconfig_.extended_device_id == 0x00 -#endif - ) { + if (isPDA_PANEL && !isPDA_IAQT) + { pda_reset_sleep(); if (type != AQ_PDA_INIT && type != AQ_PDA_WAKE_INIT && @@ -1061,6 +1071,12 @@ void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_dat return; } break; + case AQ_SET_IAQTOUCH_DEVICE_ON_OFF: + if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_iaqtouch_device_on_off, (void*)programmingthread) < 0) { + LOG(PROG_LOG, LOG_ERR, "could not create thread\n"); + return; + } + break; #endif default: @@ -2622,6 +2638,9 @@ const char *ptypeName(program_type type) case AQ_SET_IAQTOUCH_SET_TIME: return "Set iAqualink Set Time"; break; + case AQ_SET_IAQTOUCH_DEVICE_ON_OFF: + return "Set iAqualink Device On/Off"; + break; #endif #ifdef AQ_PDA case AQ_PDA_INIT: @@ -2716,6 +2735,9 @@ const char *programtypeDisplayName(program_type type) case AQ_GET_IAQTOUCH_VSP_ASSIGNMENT: return "Get Pump Assignment"; break; + case AQ_SET_IAQTOUCH_DEVICE_ON_OFF: + return "Programming: setting device on/off"; + break; #ifdef AQ_PDA case AQ_PDA_DEVICE_STATUS: return "Programming: retrieving PDA Device status"; diff --git a/aq_programmer.h b/aq_programmer.h index b3e8a00..68527d9 100644 --- a/aq_programmer.h +++ b/aq_programmer.h @@ -83,6 +83,7 @@ typedef enum { AQ_SET_IAQTOUCH_POOL_HEATER_TEMP, AQ_SET_IAQTOUCH_SPA_HEATER_TEMP, AQ_SET_IAQTOUCH_SET_TIME, + AQ_SET_IAQTOUCH_DEVICE_ON_OFF, 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 cb720b1..1570160 100644 --- a/aq_serial.c +++ b/aq_serial.c @@ -168,6 +168,19 @@ const char* get_packet_type(unsigned char* packet , int length) case CMD_EPUMP_WATTS: return "ePump get Watts"; break; + case CMD_JXI_PING: + if (packet[4] == 0x19) + return "LXi heater on"; + else // 0x11 is normal off + return "LXi heater ping"; + break; + case CMD_JXI_STATUS: + if (packet[6] == 0x10) + return "LXi error"; + else + return "LXi status"; + break; + default: sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]); return buf; diff --git a/aq_serial.h b/aq_serial.h index dcc9e96..df58f16 100644 --- a/aq_serial.h +++ b/aq_serial.h @@ -40,10 +40,10 @@ #define PENTAIR_DEC_PUMP_MAX 111 // 0x6F #define JANDY_DEC_PUMP_MIN 120 // 0x80 #define JANDY_DEC_PUMP_MAX 123 // 0x83 -#define JANDY_DEC_LX_MIN 56 // 0x40 -#define JANDY_DEC_LX_MAX 59 // 0x43 -#define JANDY_DEC_LXI_MIN 104 // 0x60 -#define JANDY_DEC_LXI_MAX 107 // 0x6B +#define JANDY_DEC_JXI_MIN 104 // 0x68 +#define JANDY_DEC_JXI_MAX 107 // 0x6B +#define JANDY_DEC_LX_MIN 56 // 0x38 +#define JANDY_DEC_LX_MAX 59 // 0x3B // PACKET DEFINES Jandy @@ -125,6 +125,10 @@ #define CMD_PERCENT 0x11 // Set Percent #define CMD_PPM 0x16 // Received PPM +/* LXi Heater commands */ +#define CMD_JXI_PING 0x0c +#define CMD_JXI_STATUS 0x0d + /* PDA KEY CODES */ // Just plating at the moment #define KEY_PDA_UP 0x06 #define KEY_PDA_DOWN 0x05 @@ -390,6 +394,7 @@ SPILLOVER IS DISABLED WHILE SPA IS ON #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_DEVICES3 0x51 #define IAQ_PAGE_SET_TEMP 0x39 #define IAQ_PAGE_MENU 0x0f #define IAQ_PAGE_SET_VSP 0x1e @@ -426,7 +431,8 @@ typedef enum { DRS_NONE, DRS_SWG, DRS_EPUMP, - DRS_LXI + DRS_JXI, + DRS_LX } rsDeviceType; typedef enum { diff --git a/aqualink.h b/aqualink.h index d3dd383..ac6ec1d 100644 --- a/aqualink.h +++ b/aqualink.h @@ -220,6 +220,7 @@ struct aqualinkdata int swg_percent; int swg_ppm; unsigned char ar_swg_device_status; // Actual state + unsigned char heater_err_status; aqledstate swg_led_state; // Display state for UI's aqledstate service_mode_state; aqledstate frz_protect_state; diff --git a/aqualinkd.c b/aqualinkd.c index d2b5763..4414d4b 100644 --- a/aqualinkd.c +++ b/aqualinkd.c @@ -807,6 +807,9 @@ bool process_packet(unsigned char *packet, int length) #ifdef AQ_PDA if (isPDA_PANEL) { + if (isPDA_IAQT) { + return false; + } return process_pda_packet(packet, length); } #endif @@ -1168,7 +1171,7 @@ int startup(char *self, char *cfgFile) return EXIT_FAILURE; } } else if (isPDA_PANEL) { - if (_aqconfig_.device_id >= 0x60 && _aqconfig_.device_id <= 0x63) { + if ( (_aqconfig_.device_id >= 0x60 && _aqconfig_.device_id <= 0x63) || _aqconfig_.device_id == 0x33 ) { // We are good } else { LOG(AQUA_LOG,LOG_ERR, "Device ID 0x%02hhx does not match PDA panel, please check config!\n", _aqconfig_.device_id); @@ -1519,6 +1522,7 @@ void main_loop() _aqualink_data.swg_percent = TEMP_UNKNOWN; _aqualink_data.swg_ppm = TEMP_UNKNOWN; _aqualink_data.ar_swg_device_status = SWG_STATUS_UNKNOWN; + _aqualink_data.heater_err_status = NUL; // 0x00 is no error _aqualink_data.swg_led_state = LED_S_UNKNOWN; _aqualink_data.swg_delayed_percent = TEMP_UNKNOWN; _aqualink_data.temp_units = UNKNOWN; @@ -1578,7 +1582,7 @@ void main_loop() #ifdef AQ_PDA if (isPDA_PANEL) { init_pda(&_aqualink_data); - if (_aqconfig_.extended_device_id != 0x00 && _aqconfig_.extended_device_id != 0x33) + if (_aqconfig_.extended_device_id != 0x00) { LOG(AQUA_LOG,LOG_ERR, "Aqualink daemon can't use extended_device_id in PDA mode, ignoring value '0x%02hhx' from cfg\n",_aqconfig_.extended_device_id); _aqconfig_.extended_device_id = 0x00; @@ -1881,6 +1885,12 @@ void main_loop() #ifdef AQ_PDA if (isPDA_PANEL) { // If we are in simulator mode, the sim has already send the ack + if (isPDA_IAQT) { + //printf("****PDA IAQT Code\n"); + _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 (_aqualink_data.simulator_active == SIM_NONE) { caculate_ack_packet(rs_fd, packet_buffer, AQUAPDA); } diff --git a/config.c b/config.c index 54c6c9b..f54da56 100644 --- a/config.c +++ b/config.c @@ -552,11 +552,17 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) { else _aqconfig_.read_RS485_devmask &= ~READ_RS485_PEN_PUMP; rtn=true; - } else if (strncasecmp (param, "read_RS485_LXi", 14) == 0) { + } else if (strncasecmp (param, "read_RS485_JXi", 14) == 0) { if (text2bool(value)) - _aqconfig_.read_RS485_devmask |= READ_RS485_JAN_LXI; + _aqconfig_.read_RS485_devmask |= READ_RS485_JAN_JXI; else - _aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_LXI; + _aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_JXI; + rtn=true; + } else if (strncasecmp (param, "read_RS485_LX", 14) == 0) { + if (text2bool(value)) + _aqconfig_.read_RS485_devmask |= READ_RS485_JAN_LX; + else + _aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_LX; rtn=true; } else if (strncasecmp (param, "use_panel_aux_labels", 20) == 0) { _aqconfig_.use_panel_aux_labels = text2bool(value); diff --git a/config.h b/config.h index c28cb6e..da1312d 100644 --- a/config.h +++ b/config.h @@ -27,8 +27,8 @@ #define READ_RS485_SWG (1 << 0) // 1 SWG #define READ_RS485_JAN_PUMP (1 << 1) // 2 Jandy Pump #define READ_RS485_PEN_PUMP (1 << 2) // 4 Pentair Pump -#define READ_RS485_JAN_LXI (1 << 3) // Jandy LX & LXi heater -//#define READ_RS485_JAN_LXI (1 << 4) // Jandy LXi heater +#define READ_RS485_JAN_JXI (1 << 3) // Jandy JX & LXi heater +#define READ_RS485_JAN_LX (1 << 4) // Jandy LX heater struct aqconfig { @@ -112,8 +112,11 @@ struct aqconfig _aqconfig_; #define READ_RSDEV_SWG ((_aqconfig_.read_RS485_devmask & READ_RS485_SWG) == READ_RS485_SWG) #define READ_RSDEV_ePUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_PUMP) == READ_RS485_JAN_PUMP) #define READ_RSDEV_vsfPUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_PEN_PUMP) == READ_RS485_PEN_PUMP) -#define READ_RSDEV_LXI ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_LXI) == READ_RS485_JAN_LXI) +#define READ_RSDEV_JXI ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_JXI) == READ_RS485_JAN_JXI) +#define READ_RSDEV_LX ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_LX) == READ_RS485_JAN_LX) + +#define isPDA_IAQT (_aqconfig_.device_id == 0x33) //#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA) diff --git a/devices_jandy.c b/devices_jandy.c index 7bc5285..09cb4c2 100644 --- a/devices_jandy.c +++ b/devices_jandy.c @@ -50,9 +50,9 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct { rtn = processPacketFromJandyPump(packet_buffer, packet_length, aqdata, previous_packet_to); } - else if (interestedInNextAck == DRS_LXI) + else if (interestedInNextAck == DRS_JXI) { - rtn = processPacketFromJandyHeater(packet_buffer, packet_length, aqdata, previous_packet_to); + rtn = processPacketFromJandyJXiHeater(packet_buffer, packet_length, aqdata, previous_packet_to); } interestedInNextAck = DRS_NONE; previous_packet_to = NUL; @@ -83,11 +83,16 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct rtn = processPacketToJandyPump(packet_buffer, packet_length, aqdata); previous_packet_to = packet_buffer[PKT_DEST]; } - else if (READ_RSDEV_LXI && ( (packet_buffer[PKT_DEST] >= JANDY_DEC_LX_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LX_MAX) - || (packet_buffer[PKT_DEST] >= JANDY_DEC_LXI_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LXI_MAX))) + else if (READ_RSDEV_JXI && packet_buffer[PKT_DEST] >= JANDY_DEC_LX_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LX_MAX) { - interestedInNextAck = DRS_LXI; - rtn = processPacketToJandyHeater(packet_buffer, packet_length, aqdata); + interestedInNextAck = DRS_JXI; + rtn = processPacketToJandyJXiHeater(packet_buffer, packet_length, aqdata); + previous_packet_to = packet_buffer[PKT_DEST]; + } + else if (READ_RSDEV_LX && packet_buffer[PKT_DEST] >= JANDY_DEC_LX_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LX_MAX) + { + interestedInNextAck = DRS_LX; + rtn = processPacketToJandyLXHeater(packet_buffer, packet_length, aqdata); previous_packet_to = packet_buffer[PKT_DEST]; } else @@ -572,13 +577,158 @@ void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqua -bool processPacketToJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata) +bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata) { + if (packet_buffer[3] != CMD_JXI_PING) { + // Not sure what this message is, so ignore + // Maybe print a messsage. + return false; + } + /* + Below counfing first as bit 0 + 4th bit 0x00 no pump on (nothing) + 0x10 seems to be JXi came online. nothing more + 0x11 (pool mode) + 0x12 (spa mode) + 0x19 heat pool + 0x1a heat spa + 5th bit 0x55 = 85 deg. (current pool setpoint) + 6th bit 0x66 = 102 deg. (current spa setpoint) + 7th bit 0x4f = current water temp 79 (0xFF is off / 255) + */ + + if (packet_buffer[5] != aqdata->pool_htr_set_point) { + LOG(DJAN_LOG, LOG_DEBUG, "LXi pool setpoint %d, Pool heater sp %s (changing to LXi)\n", packet_buffer[5], aqdata->pool_htr_set_point); + aqdata->pool_htr_set_point = packet_buffer[5]; + } + + if (packet_buffer[6] != aqdata->spa_htr_set_point) { + LOG(DJAN_LOG, LOG_DEBUG, "LXi spa setpoint %d, Spa heater sp %s (changing to LXi)\n", packet_buffer[5], aqdata->spa_htr_set_point); + aqdata->spa_htr_set_point = packet_buffer[5]; + } + + if (packet_buffer[7] != 0xff && packet_buffer[4] != 0x00) { + if (packet_buffer[4] == 0x11 || packet_buffer[4] == 0x19) { + if (aqdata->pool_temp != packet_buffer[7]) { + LOG(DJAN_LOG, LOG_DEBUG, "LXi pool water temp %d, pool water temp %s (changing to LXi)\n", packet_buffer[7], aqdata->pool_temp); + aqdata->pool_temp = packet_buffer[7]; + } + } else if (packet_buffer[4] == 0x12 || packet_buffer[4] == 0x1a) { + if (aqdata->spa_temp != packet_buffer[7]) { + LOG(DJAN_LOG, LOG_DEBUG, "LXi spa water temp %d, spa water temp %s (changing to LXi)\n", packet_buffer[7], aqdata->spa_temp); + aqdata->spa_temp = packet_buffer[7]; + } + } + } + + switch (packet_buffer[4]) { + case 0x11: // Pool heat off or enabled + break; + case 0x12: // Pool Heat enabled or heating + break; + case 0x19: // Spa heat off or enabled + break; + case 0x1a: // Spa Hear Heat enabled or heating + break; + } + + /* char msg[1000]; int length = 0; beautifyPacket(msg, packet_buffer, packet_length, true); - LOG(DJAN_LOG, LOG_INFO, "To Heater: %s\n", msg); + LOG(DJAN_LOG, LOG_INFO, "To JXi Heater: %s\n", msg); + + length += sprintf(msg+length, "Last panel info "); + + for (int i=0; i < aqdata->total_buttons; i++) + { + if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0) { + length += sprintf(msg+length, ", Pool Heat LED=%d ",aqdata->aqbuttons[i].led->state); + } + if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name) == 0) { + length += sprintf(msg+length, ", Spa Heat LED=%d ",aqdata->aqbuttons[i].led->state); + } + } + + length += sprintf(msg+length, ", Pool SP=%d, Spa SP=%d",aqdata->pool_htr_set_point, aqdata->spa_htr_set_point); + length += sprintf(msg+length, ", Pool temp=%d, Spa temp=%d",aqdata->pool_temp, aqdata->spa_temp); + + LOG(DJAN_LOG, LOG_INFO, "%s\n", msg); + + return false; + */ + + return true; +} + +void getJandyHeaterError(struct aqualinkdata *aqdata, char *message) +{ + if (aqdata->heater_err_status == NUL) { + return; + } + + int size = sprintf(message, "JXi Heater "); + getJandyHeaterErrorMQTT(aqdata, message+size); +} + +void getJandyHeaterErrorMQTT(struct aqualinkdata *aqdata, char *message) +{ + switch (aqdata->heater_err_status) { + case 0x00: + //sprintf(message, ""); + break; + case 0x10: + sprintf(message, "FAULT HIGH LIMIT"); + break; + case 0x02: + sprintf(message, "FAULT H20 SENSOR"); + break; + case 0x08: + sprintf(message, "FAULT AUX MONITOR"); + break; + default: + // + /* Error we haven't decoded yet + ?x?? check flow + 0x10 Fault high limit + ?x?? Fault High Flu temp + ?x?? Fault Check Igntion Control + 0x02 Fault Short H20 sensor (or Fault open water sensor) + ?x?? Pump fault + 0x08 AUX Monitor + */ + sprintf(message, "FAULT"); + break; + } +} + +bool processPacketFromJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to) +{ + if (packet_buffer[3] != CMD_JXI_STATUS) { + // Not sure what this message is, so ignore + // Maybe print a messsage. + return false; + } + + // No error is 0x00, so blindly set it. + aqdata->heater_err_status = packet_buffer[6]; + // Check if error first + if (packet_buffer[6] != 0x00) { + + } else if (packet_buffer[4] == 0x00) { + // Not heating. + // Heater off or enabeled + } else if (packet_buffer[4] == 0x08) { + // Heating + // Heater on of enabled + } + /* + char msg[1000]; + int length = 0; + + beautifyPacket(msg, packet_buffer, packet_length, true); + LOG(DJAN_LOG, LOG_INFO, "From JXi Heater: %s\n", msg); length += sprintf(msg+length, "Last panel info "); @@ -598,15 +748,47 @@ bool processPacketToJandyHeater(unsigned char *packet_buffer, int packet_length, LOG(DJAN_LOG, LOG_INFO, "%s\n", msg); return false; + */ + return true; } -bool processPacketFromJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to) +bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata) +{ + + char msg[1000]; + int length = 0; + + beautifyPacket(msg, packet_buffer, packet_length, true); + LOG(DJAN_LOG, LOG_INFO, "To LX Heater: %s\n", msg); + + length += sprintf(msg+length, "Last panel info "); + + for (int i=0; i < aqdata->total_buttons; i++) + { + if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0) { + length += sprintf(msg+length, ", Pool Heat LED=%d ",aqdata->aqbuttons[i].led->state); + } + if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name) == 0) { + length += sprintf(msg+length, ", Spa Heat LED=%d ",aqdata->aqbuttons[i].led->state); + } + } + + length += sprintf(msg+length, ", Pool SP=%d, Spa SP=%d",aqdata->pool_htr_set_point, aqdata->spa_htr_set_point); + length += sprintf(msg+length, ", Pool temp=%d, Spa temp=%d",aqdata->pool_temp, aqdata->spa_temp); + + LOG(DJAN_LOG, LOG_INFO, "%s\n", msg); + + return false; + +} + +bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to) { char msg[1000]; int length = 0; beautifyPacket(msg, packet_buffer, packet_length, true); - LOG(DJAN_LOG, LOG_INFO, "From Heater: %s\n", msg); + LOG(DJAN_LOG, LOG_INFO, "From LX Heater: %s\n", msg); length += sprintf(msg+length, "Last panel info "); @@ -628,4 +810,55 @@ bool processPacketFromJandyHeater(unsigned char *packet_buffer, int packet_lengt return false; } +/* +// JXi Heater + +// Normal ping and return +5th bit 0x00 no pump on (nothing) + 0x10 seems to be JXi came online. nothing more + 0x11 (pool mode) + 0x12 (spa mode) + 0x19 heat pool + 0x1a heat spa +6th bit 0x55 = 85 deg. (current pool setpoint) +7th bit 0x66 = 102 deg. (current spa setpoint) +8th bit 0x4f = current water temp 79 (0xFF is off / 255) + +Jandy To 0x68 of type Unknown '0x0c' | HEX: 0x10|0x02|0x68|0x0c|0x11|0x55|0x66|0x4f|0xa1|0x10|0x03| +Jandy From 0x68 of type Unknown '0x0d' | HEX: 0x10|0x02|0x00|0x0d|0x00|0x00|0x00|0x1f|0x10|0x03| + +Request to turn on 85 +5th bit 0x19 looks like turn on +6th bit 0x55 = 85 deg. +7th bit 0x4f = current temp 79 +Jandy To 0x68 of type Unknown '0x0c' | HEX: 0x10|0x02|0x68|0x0c|0x19|0x55|0x66|0x4f|0xa9|0x10|0x03| +Jandy From 0x68 of type Unknown '0x0d' | HEX: 0x10|0x02|0x00|0x0d|0x08|0x00|0x00|0x27|0x10|0x03| + +Request to turn on 90 +5th bit 0x19 looks like turn on +6th bit 0x5a = 90 deg. +Jandy To 0x68 of type Unknown '0x0c' | HEX: 0x10|0x02|0x68|0x0c|0x19|0x5a|0x66|0x4f|0xae|0x10|0x03| +Jandy From 0x68 of type Unknown '0x0d' | HEX: 0x10|0x02|0x00|0x0d|0x08|0x00|0x00|0x27|0x10|0x03| + +Request to turn off (standard ping) // return had hi limit error in it +Jandy To 0x68 of type Unknown '0x0c' | HEX: 0x10|0x02|0x68|0x0c|0x11|0x55|0x66|0x4f|0xa1|0x10|0x03| +Jandy From 0x68 of type Unknown '0x0d' | HEX: 0x10|0x02|0x00|0x0d|0x00|0x00|0x10|0x2f|0x10|0x03| + +Returns + +5th bit is type 0x00 nothing (or enabeled) - 0x08 looks like heat +Hi limit error return +7th bit 0x10 looks like the error +Jandy To 0x68 of type Unknown '0x0c' | HEX: 0x10|0x02|0x68|0x0c|0x19|0x5a|0x66|0x4f|0xae|0x10|0x03| +Jandy From 0x68 of type Unknown '0x0d' | HEX: 0x10|0x02|0x00|0x0d|0x08|0x00|0x10|0x37|0x10|0x03| + +Errors are -> +check flow +Fault high limit -> 0x10 +Fault High Flu temp +Fault Check Igntion Control +Fault Short H20 sensor (or Fault open water sensor) -> 0x02 +Pump fault +AUX Monitor -> 0x08 +*/ \ No newline at end of file diff --git a/devices_jandy.h b/devices_jandy.h index 161cad0..16567cc 100644 --- a/devices_jandy.h +++ b/devices_jandy.h @@ -14,8 +14,10 @@ bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, void processMissingAckPacketFromSWG(unsigned char destination, struct aqualinkdata *aqdata); void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqualinkdata *aqdata); -bool processPacketFromJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to ); -bool processPacketToJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata); +bool processPacketFromJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to ); +bool processPacketToJandyJXiHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata); +bool processPacketFromJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to ); +bool processPacketToJandyLXHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata); void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert); aqledstate get_swg_led_state(struct aqualinkdata *aqdata); @@ -27,4 +29,7 @@ void setSWGenabled(struct aqualinkdata *aqdata); bool setSWGboost(struct aqualinkdata *aqdata, bool on); void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status); +void getJandyHeaterError(struct aqualinkdata *aqdata, char *message); +void getJandyHeaterErrorMQTT(struct aqualinkdata *aqdata, char *message); + #endif // AQUAPURE_H_ \ No newline at end of file diff --git a/iaqtouch.c b/iaqtouch.c index a3b4cc5..5ab38d5 100644 --- a/iaqtouch.c +++ b/iaqtouch.c @@ -16,6 +16,7 @@ #include #include +#include #include "aq_serial.h" #include "aqualink.h" @@ -69,13 +70,15 @@ unsigned char _lastMsgType = 0x00; //unsigned char _last_kick_type = -1; int _deviceStatusLines = 0; +char _homeStatus[IAQ_STATUS_PAGE_LINES][AQ_MSGLEN+1]; 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]; +struct iaqt_page_button _homeButtons[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 _devicePage2Buttons[IAQ_PAGE_BUTTONS]; struct iaqt_page_button _deviceSystemSetupButtons[IAQ_PAGE_BUTTONS]; unsigned char iaqtLastMsg() @@ -129,12 +132,18 @@ struct iaqt_page_button *iaqtFindButtonByIndex(int index) { struct iaqt_page_button *buttons; // NSF Need to merge this from iaqtFindButtonByLabel function - if (_currentPage == IAQ_PAGE_DEVICES ) + if (_currentPage == IAQ_PAGE_DEVICES || + _currentPage == IAQ_PAGE_DEVICES2 || + _currentPage == IAQ_PAGE_DEVICES3) buttons = _devicePageButtons; + /* else if (_currentPage == IAQ_PAGE_DEVICES2 ) buttons = _devicePage2Buttons; + */ else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP ) buttons = _deviceSystemSetupButtons; + else if (_currentPage == IAQ_PAGE_HOME ) + buttons = _homeButtons; else buttons = _pageButtons; @@ -149,12 +158,16 @@ struct iaqt_page_button *iaqtFindButtonByLabel(char *label) { int i; struct iaqt_page_button *buttons; - if (_currentPage == IAQ_PAGE_DEVICES ) + if (_currentPage == IAQ_PAGE_DEVICES || + _currentPage == IAQ_PAGE_DEVICES2 || + _currentPage == IAQ_PAGE_DEVICES3) buttons = _devicePageButtons; - else if (_currentPage == IAQ_PAGE_DEVICES2 ) - buttons = _devicePage2Buttons; + //else if (_currentPage == IAQ_PAGE_DEVICES2 ) + // buttons = _devicePage2Buttons; else if (_currentPage == IAQ_PAGE_SYSTEM_SETUP ) buttons = _deviceSystemSetupButtons; + else if (_currentPage == IAQ_PAGE_HOME ) + buttons = _homeButtons; else buttons = _pageButtons; @@ -237,8 +250,10 @@ void processPageMessage(unsigned char *message, int length) 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) { + + if (_currentPageLoading == IAQ_PAGE_HOME || _currentPage == IAQ_PAGE_HOME) { + rsm_strncpy(_homeStatus[(int)message[PKT_IAQT_MSGINDX]], &message[PKT_IAQT_MSGDATA], AQ_MSGLEN, length-PKT_IAQT_MSGDATA-3); + } else if (_currentPageLoading == IAQ_PAGE_STATUS || _currentPage == IAQ_PAGE_STATUS) { // 2nd page of device status doesn;t gine us new page message //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); @@ -259,19 +274,25 @@ void processTableMessage(unsigned char *message, int length) 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) +void processPageButton(unsigned char *message, int length, struct aqualinkdata *aq_data) { struct iaqt_page_button *button; int index = (int)message[PKT_IAQT_BUTINDX]; - if (_currentPageLoading == IAQ_PAGE_DEVICES ) + if (_currentPageLoading == IAQ_PAGE_DEVICES || + _currentPageLoading == IAQ_PAGE_DEVICES2 || + _currentPageLoading == IAQ_PAGE_DEVICES3 ) button = &_devicePageButtons[index]; - else if (_currentPageLoading == IAQ_PAGE_DEVICES2 ) - button = &_devicePage2Buttons[index]; + //else if (_currentPageLoading == IAQ_PAGE_DEVICES2 ) + // button = &_devicePage2Buttons[index]; else if (_currentPageLoading == IAQ_PAGE_SYSTEM_SETUP ) button = &_deviceSystemSetupButtons[index]; - else + else if (_currentPageLoading == IAQ_PAGE_HOME ) + button = &_homeButtons[index]; + else { button = &_pageButtons[index]; + LOG(IAQT_LOG,LOG_WARNING, "Not sure where to add Button %d %s - LoadingPage=%s\n",index,button->name,iaqt_page_name(_currentPageLoading)); + } button->state = message[PKT_IAQT_BUTSTATE]; button->type = message[PKT_IAQT_BUTTYPE]; @@ -285,9 +306,52 @@ void processPageButton(unsigned char *message, int length) // This doesn't work with return which is 0x00 //strncpy(&button->name, (char *)message + PKT_IAQT_BUTDATA, AQ_MSGLEN); + memset(button->name, 0, sizeof(button->name)); 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); + LOG(IAQT_LOG,LOG_DEBUG, "Added Button %d %s - LoadingPage=%s\n",index,button->name,iaqt_page_name(_currentPageLoading)); + + // This get's called or every device state change in PDA mode, since we page over all the devices. + // So capture and update the device state + + if (isPDA_PANEL) { + for (int i = 0; i < aq_data->total_buttons; i++) + { + if (rsm_strmatch(button->name, aq_data->aqbuttons[i].label) == 0) + { + LOG(IAQT_LOG,LOG_DEBUG, "*** Found Status for %s state 0x%02hhx\n", aq_data->aqbuttons[i].label, button->state); + switch(button->state) { + case 0x00: + if (aq_data->aqbuttons[i].led->state != OFF) { + aq_data->aqbuttons[i].led->state = OFF; + aq_data->updated = true; + } + break; + case 0x01: + if (aq_data->aqbuttons[i].led->state != ON) { + aq_data->aqbuttons[i].led->state = ON; + aq_data->updated = true; + } + break; + case 0x02: + if (aq_data->aqbuttons[i].led->state != FLASH) { + aq_data->aqbuttons[i].led->state = FLASH; + aq_data->updated = true; + } + break; + case 0x03: + if (aq_data->aqbuttons[i].led->state != ENABLE) { + aq_data->aqbuttons[i].led->state = ENABLE; + aq_data->updated = true; + } + break; + default: + LOG(IAQT_LOG,LOG_NOTICE, "Unknown state 0x%02hhx for button %s\n",button->state,button->name); + break; + } + } + } + } /* _pageButtons[index].state = (int)message[5]; @@ -367,39 +431,45 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) continue; } else if (rsm_strcmp(_deviceStatus[i],"RPM:") == 0) { - if (pump != NULL) + if (pump != NULL) { pump->rpm = rsm_atoi(&_deviceStatus[i][9]); - else + aq_data->updated = true; + } else LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"GPM:") == 0) { - if (pump != NULL) + if (pump != NULL) { pump->gpm = rsm_atoi(&_deviceStatus[i][9]); - else + aq_data->updated = true; + } else LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"Watts:") == 0) { - if (pump != NULL) + if (pump != NULL) { pump->watts = rsm_atoi(&_deviceStatus[i][9]); - else + aq_data->updated = true; + } else LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"*** Priming ***") == 0) { - if (pump != NULL) + if (pump != NULL) { pump->rpm = PUMP_PRIMING; - else + aq_data->updated = true; + } else LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; } else if (rsm_strcmp(_deviceStatus[i],"(Offline)") == 0) { - if (pump != NULL) + if (pump != NULL) { pump->rpm = PUMP_OFFLINE; - else + aq_data->updated = true; + } else LOG(IAQT_LOG,LOG_WARNING, "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) + if (pump != NULL) { pump->rpm = PUMP_ERROR; - else + aq_data->updated = true; + } else LOG(IAQT_LOG,LOG_WARNING, "Got pump message '%s' but can't find pump\n",_deviceStatus[i]); continue; // Need to catch messages like @@ -422,6 +492,7 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) aq_data->ph = ph; aq_data->orp = orp; } + aq_data->updated = true; LOG(IAQT_LOG,LOG_INFO, "Set Cemlink ORP = %d PH = %f from message '%s'\n",orp,ph,_deviceStatus[i]); } } @@ -432,9 +503,11 @@ void passDeviceStatusPage(struct aqualinkdata *aq_data) 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]); + 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) { aq_data->boost = true; + aq_data->updated = true; // Let RS pickup time remaing message. } #endif @@ -469,16 +542,21 @@ void processPage(struct aqualinkdata *aq_data) 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) + if (_pageButtons[1].type == 0x02) { iaqt_queue_cmd(KEY_IAQTCH_KEY02); - else + } else { iaqt_pump_update(aq_data, -1); // Reset pumps. + if (isPDA_PANEL && !in_iaqt_programming_mode(aq_data) ) { + iaqt_queue_cmd(KEY_IAQTCH_HOME); + } + } break; case IAQ_PAGE_DEVICES: + case IAQ_PAGE_DEVICES2: + case IAQ_PAGE_DEVICES3: //LOG(IAQT_LOG,LOG_INFO, "Devices Page #1:-\n"); debugPrintButtons(_devicePageButtons); - // 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) ) { @@ -492,6 +570,7 @@ void processPage(struct aqualinkdata *aq_data) } } break; + /* case IAQ_PAGE_DEVICES2: //LOG(IAQT_LOG,LOG_INFO, "Devices Page #2:-\n"); debugPrintButtons(_devicePage2Buttons); @@ -508,7 +587,7 @@ void processPage(struct aqualinkdata *aq_data) iaqt_queue_cmd(KEY_IAQTCH_STATUS); } } - break; + break;*/ case IAQ_PAGE_COLOR_LIGHT: //LOG(IAQT_LOG,LOG_INFO, "Color Light Page :-\n"); debugPrintButtons(_pageButtons); @@ -519,7 +598,33 @@ void processPage(struct aqualinkdata *aq_data) if (_deviceStatus[i][0] != 0) LOG(IAQT_LOG,LOG_INFO, "Status page %.2d| %s\n",i,_deviceStatus[i]); - debugPrintButtons(_pageButtons); + for (i=0; i air_temp = atoi(_homeStatus[1]); + LOG(IAQT_LOG,LOG_DEBUG, "Air Temp set to %d\n",aq_data->air_temp); + aq_data->updated = true; + } + if (rsm_strcmp(_homeStatus[4],"Pool Temp") == 0) { + aq_data->pool_temp = atoi(_homeStatus[0]); + 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->updated = true; + } + } + + //passHomePage(aq_data); + debugPrintButtons(_homeButtons); break; case IAQ_PAGE_SYSTEM_SETUP: //LOG(IAQT_LOG,LOG_INFO, "System Setup :-\n"); @@ -549,9 +654,16 @@ void processPage(struct aqualinkdata *aq_data) bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data) { + static bool gotInit = false; static int cnt = 0; static bool gotStatus = true; //char buff[1024]; + // NSF Take this out + if ( packet[3] != CMD_IAQ_POLL && getLogLevel(IAQT_LOG) >= LOG_DEBUG ) { + char buff[1000]; + beautifyPacket(buff, packet, length, false); + LOG(IAQT_LOG,LOG_DEBUG, "Received message : %s", buff); + } if (packet[PKT_CMD] == CMD_IAQ_PAGE_START) { LOG(IAQT_LOG,LOG_DEBUG, "Turning IAQ SEND off\n"); @@ -561,6 +673,7 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd 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 ); + memset(_devicePageButtons, 0, IAQ_PAGE_BUTTONS * sizeof(struct iaqt_page_button)); // Fix bug with control panel where after a few hours status page disapears and you need to hit menu. if (gotStatus == false) gotStatus = true; @@ -580,7 +693,7 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd } else if (packet[PKT_CMD] == CMD_IAQ_PAGE_MSG) { processPageMessage(packet, length); } else if (packet[PKT_CMD] == CMD_IAQ_PAGE_BUTTON) { - processPageButton(packet, length); + processPageButton(packet, length, aq_data); // 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 @@ -610,8 +723,11 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd if (packet[3] == 0x29) { //printf("***** iAqualink Touch STARTUP Message ******* \n"); - LOG(IAQT_LOG,LOG_DEBUG, "STARTUP Message\n"); - queueGetProgramData(IAQTOUCH, aq_data); + if (gotInit == false) { + LOG(IAQT_LOG,LOG_DEBUG, "STARTUP Message\n"); + //queueGetProgramData(IAQTOUCH, aq_data); + gotInit = true; + } //aq_programmer(AQ_SET_IAQTOUCH_SET_TIME, NULL, aq_data); } @@ -619,11 +735,11 @@ 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 - if (packet[3] == 0x30) { + 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 ) { - if (isPDA) { + if (isPDA_PANEL) { iaqt_queue_cmd(KEY_IAQTCH_HOMEP_KEY08); } else { iaqt_queue_cmd(KEY_IAQTCH_STATUS); @@ -635,12 +751,14 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd // Fix bug with control panel where after a few hours status page disapears and you need to hit menu. LOG(IAQT_LOG,LOG_INFO, "Overcomming Jandy control panel bug, (missing status, goto menu)\n",cnt); iaqt_queue_cmd(KEY_IAQTCH_HOME); - - if (isPDA) { + cnt = REQUEST_STATUS_POLL_COUNT - 5; + /* + if (isPDA_PANEL) { iaqt_queue_cmd(KEY_IAQTCH_HOMEP_KEY08); } else { iaqt_queue_cmd(KEY_IAQTCH_STATUS); } + */ } else if (in_programming_mode(aq_data) == true) { // Set count to something close to above, so we will pull latest info once programming has finished. // This is goot for VSP GPM programming as it takes number of seconds to register once finished programming. @@ -663,7 +781,7 @@ bool process_iaqtouch_packet(unsigned char *packet, int length, struct aqualinkd kick_aq_program_thread(aq_data, IAQTOUCH); - return false; + return true; } @@ -685,6 +803,9 @@ const char *iaqt_page_name(const unsigned char page) case IAQ_PAGE_DEVICES2: return "Devices #2"; break; + case IAQ_PAGE_DEVICES3: + return "Devices #2"; + break; case IAQ_PAGE_SET_TEMP: return "Set Temp"; break; @@ -961,4 +1082,4 @@ Notice: Jandy Packet | HEX: 0x10|0x02|0x31|0x24|0x01|0x00|0x00|0x02|0x00|0x00 Button | 1 | 0x02 | |-| |-| -off- -*/ \ No newline at end of file +*/ diff --git a/iaqtouch_aq_programmer.c b/iaqtouch_aq_programmer.c index 61597bd..54a028f 100644 --- a/iaqtouch_aq_programmer.c +++ b/iaqtouch_aq_programmer.c @@ -412,6 +412,65 @@ bool goto_iaqt_page(const unsigned char pageID, struct aqualinkdata *aq_data) { return false; } +void *set_aqualink_iaqtouch_device_on_off( 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; + + unsigned int device = atoi(&buf[0]); + unsigned int state = atoi(&buf[5]); + + waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_IAQTOUCH_DEVICE_ON_OFF); + + if (device > aq_data->total_buttons) { + LOG(IAQT_LOG,LOG_ERR, "(PDA mode) Device On/Off :- bad device number '%d'\n",device); + cleanAndTerminateThread(threadCtrl); + return ptr; + } + + LOG(IAQT_LOG,LOG_INFO, "PDA Device On/Off, device '%s', state %d\n",aq_data->aqbuttons[device].label,state); + + // See if it's on the current page + button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].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(aq_data->aqbuttons[device].label); + + // If not found see if page hax 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(aq_data->aqbuttons[device].label); + } + } + + if (button == NULL) { + LOG(IAQT_LOG, LOG_ERR, "IAQ Touch did not find '%s' button on device list\n", aq_data->aqbuttons[device].label); + goto f_end; + } + + send_aqt_cmd(button->keycode); + + // NSF NEED TO CHECK FOR POPUP MESSAGE, AND KILL IT. + + 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_pump_rpm( void *ptr ) { struct programmingThreadCtrl *threadCtrl; diff --git a/iaqtouch_aq_programmer.h b/iaqtouch_aq_programmer.h index db51aa8..0411d0b 100644 --- a/iaqtouch_aq_programmer.h +++ b/iaqtouch_aq_programmer.h @@ -20,6 +20,8 @@ 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_device_on_off( void *ptr ); // For PDA only + int ref_iaqt_control_cmd(unsigned char **cmd); void rem_iaqt_control_cmd(unsigned char *cmd); diff --git a/net_services.c b/net_services.c index 6e42890..5482e2a 100644 --- a/net_services.c +++ b/net_services.c @@ -685,7 +685,11 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc) const char *status; if (_aqconfig_.mqtt_timed_update) { +#ifdef AQ_NO_THREAD_NETSERVICE if (cnt > 300) { // 100 = about every 2 minutes. +#else + if (cnt > 30) { // 30 = about every 2 minutes. +#endif reset_last_mqtt_status(); cnt = 0; } else { @@ -831,9 +835,10 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc) int dzalert; get_swg_status_mqtt(_aqualink_data, message, &status, &dzalert); - send_domoticz_mqtt_status_message(nc, _aqconfig_.dzidx_swg_status, dzalert, &message[9]); + send_domoticz_mqtt_status_message(nc, _aqconfig_.dzidx_swg_status, dzalert, &message[9]); send_mqtt_int_msg(nc, SWG_EXTENDED_TOPIC, (int)_aqualink_data->ar_swg_device_status); + send_mqtt_string_msg(nc, SWG_STATUS_MSG_TOPIC, message); _last_mqtt_aqualinkdata.ar_swg_device_status = _aqualink_data->ar_swg_device_status; //LOG(NET_LOG,LOG_DEBUG, "SWG Extended sending cur=%d sent=%d\n",_aqualink_data->ar_swg_device_status,_last_mqtt_aqualinkdata.ar_swg_device_status); @@ -844,6 +849,22 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc) //LOG(NET_LOG,LOG_DEBUG, "SWG Extended unknown\n"); } + if (READ_RSDEV_JXI && _aqualink_data->heater_err_status != _last_mqtt_aqualinkdata.heater_err_status) { + char message[30]; + + if (_aqualink_data->heater_err_status == NUL) { + send_mqtt_int_msg(nc, LXI_ERROR_CODE, (int)_aqualink_data->heater_err_status); + send_mqtt_string_msg(nc, LXI_ERROR_MESSAGE, ""); + } else { + //send_mqtt_int_msg(nc, LXI_STATUS, (int)_aqualink_data->heater_err_status); + send_mqtt_int_msg(nc, LXI_ERROR_CODE, (int)_aqualink_data->heater_err_status); + getJandyHeaterErrorMQTT(_aqualink_data, message); + send_mqtt_string_msg(nc, LXI_ERROR_MESSAGE, status); + } + + _last_mqtt_aqualinkdata.heater_err_status = _aqualink_data->heater_err_status; + } + // LOG(NET_LOG,LOG_INFO, "mqtt_broadcast_aqualinkstate: START LEDs\n"); // if (time(NULL) % 2) {} <-- use to determin odd/even second in time to make state flash on enabled. @@ -1876,6 +1897,7 @@ void reset_last_mqtt_status() _last_mqtt_aqualinkdata.boost = -1; _last_mqtt_aqualinkdata.swg_percent = -1; _last_mqtt_aqualinkdata.swg_ppm = -1; + _last_mqtt_aqualinkdata.heater_err_status = NUL; // 0x00 } diff --git a/release/aqualinkd b/release/aqualinkd index df5d663..03bb81a 100755 Binary files a/release/aqualinkd and b/release/aqualinkd differ diff --git a/release/aqualinkd.conf b/release/aqualinkd.conf index cdedfd2..9b3541e 100755 --- a/release/aqualinkd.conf +++ b/release/aqualinkd.conf @@ -84,9 +84,13 @@ device_id=0x0a # swg = Salt Water Generator # ePump = Jandy ePump or ePump AC # vsfPump = Pentair VS,VF,VSF pump +# JXi = Jandy JXi heater (might also be LXi heaters) +# LX = Jandy LX & LT heaters #read_RS485_swg = yes #read_RS485_ePump = yes #read_RS485_vsfPump = yes +#read_RS485_JXi = yes +#read_RS485_LX = yes # Keep the panel time synced with systemtime. Make sure to set systemtime / NTP correctly. keep_paneltime_synced = yes diff --git a/release/aqualinkd.test.pda.conf b/release/aqualinkd.test.pda.conf index af39c36..5f64f84 100644 --- a/release/aqualinkd.test.pda.conf +++ b/release/aqualinkd.test.pda.conf @@ -39,13 +39,13 @@ log_level=NOTICE #debug_log_mask = 1 #debug_log_mask = 2 #debug_log_mask = 4 -debug_log_mask = 8 +#debug_log_mask = 8 debug_log_mask = 16 #debug_log_mask = 32 #debug_log_mask = 64 #debug_log_mask = 256 #debug_log_mask = 512 -#debug_log_mask = 1024 +debug_log_mask = 1024 #debug_log_mask = 2048 #debug_log_mask = 4096 @@ -80,7 +80,8 @@ mqtt_aq_topic = aqualinkd-test #device_id=0x0a #device_id=0xFF # For testing one touch, don't use kaypad #device_id=0x00 -device_id=0x60 +#device_id=0x60 +device_id=0x33 #rssa_device_id=0x48 @@ -89,12 +90,12 @@ device_id=0x60 # Valid ID's are 0x40, 0x41, 0x42 & 0x43. # If you have a one touch remote do not use Ox40 #extended_device_id=0x43 -extended_device_id=0x33 +#extended_device_id=0x33 # 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 +#extended_device_id_programming = yes #extended_device_id_programming = no # Not documented @@ -227,7 +228,7 @@ button_01_pumpID=0x78 #button_01_PDA_label=FILTER PUMP button_01_pumpIndex=1 -button_02_label=Spa Mode +button_02_label=Spa #button_02_dzidx=38 #button_02_pumpID= 0x78 #button_02_pumpIndex=3 diff --git a/release/serial_logger b/release/serial_logger index f8790c8..94d6c55 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 76ceed7..7392b08 100644 --- a/rs_msg_utils.c +++ b/rs_msg_utils.c @@ -193,9 +193,42 @@ int rsm_strcmp(const char *haystack, const char *needle) 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); + //printf("***** rsm_strcmp Compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2); return strncasecmp(sp1, sp2, strlen(sp2)); } +// Match two strings, used for button labels +// exact character length once white space removed is used for match +// use case insensative for match. +// so 'spa' !- 'spa mode' +int rsm_strmatch(const char *haystack, const char *needle) +{ + char *sp1 = (char *)haystack; + char *sp2 = (char *)needle; + + char *ep1 = (char *)sp1 + strlen(sp1) - 1; + char *ep2 = (char *)sp2 + strlen(sp2) - 1; + //int i=0; + // Get rid of all padding + while(isspace(*sp1)) sp1++; + while(isspace(*sp2)) sp2++; + while(isspace(*ep1) && (ep1 >= sp1)) ep1--; + while(isspace(*ep2) && (ep2 >= sp2)) ep2--; + + int l1 = ep1 - sp1 +1; + int l2 = ep2 - sp2 +1; + + //printf("***** rsm_strmatch Compare %d chars of '%s' to %d chars in '%s'\n",l2,sp2,l1,sp1); + + if ( l1 != l2 || (ep1 - sp1) <= 0 || (ep2 - 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, l2); +} + /* * Find last index of char in string. diff --git a/rs_msg_utils.h b/rs_msg_utils.h index befff8f..c44bc7a 100644 --- a/rs_msg_utils.h +++ b/rs_msg_utils.h @@ -11,6 +11,8 @@ char *rsm_strnstr(const char *haystack, const char *needle, size_t slen); char *rsm_strncasestr(const char *haystack, const char *needle, size_t length); char *rsm_lastindexof(const char *haystack, const char *needle, size_t length); +int rsm_strmatch(const char *haystack, const char *needle); + 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_strncmp(const char *haystack, const char *needle, int length); diff --git a/serial_logger.c b/serial_logger.c index ad08f66..af75431 100644 --- a/serial_logger.c +++ b/serial_logger.c @@ -117,7 +117,7 @@ int serial_logger (int rs_fd, char *port_name, int logLevel) { #define PDA " <-- PDA Remote" #define EPUMP " <-- Jandy VSP ePump" #define CHEM " <-- Chemlink" -#define LXI_LRZ_HEATER " <-- LXi / LRZ Heater" +#define JXI_HEATER " <-- LXi / LRZ Heater" #define UNKNOWN " <-- Unknown Device" @@ -151,7 +151,7 @@ const char *getDevice(unsigned char ID) { if (ID >= 0x60 && ID <= 0x63) return PDA; if (ID >= 0x68 && ID <= 0x6B) - return LXI_LRZ_HEATER; + return JXI_HEATER; //if (ID >= 0x70 && ID <= 0x73) if (ID >= 0x78 && ID <= 0x7B) return EPUMP; diff --git a/state b/state new file mode 100644 index 0000000..0a3bf64 --- /dev/null +++ b/state @@ -0,0 +1,178 @@ +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +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].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].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].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].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[index].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[i].led->state = OFF; +aq_panel.c: if ((button->led->state == OFF && isON == false) || +aq_panel.c: (isON > 0 && (button->led->state == ON || button->led->state == FLASH || +aq_panel.c: button->led->state == ENABLE))) { +aq_panel.c: if ((button->special_mask & PROGRAM_LIGHT) == PROGRAM_LIGHT && button->led->state == OFF) { +aq_panel.c: button->led->state = ENABLE; // if heater and set to on, set pre-status to enable. +aq_panel.c: button->led->state = (isON == false ? OFF : ON); // as long as it's not programmable light , pre-set to on/off +aq_panel.c: if ((_aqualink_data->aqbuttons[buttonIndex].led->state == OFF && value == 0) || +aq_panel.c: (value > 0 && (_aqualink_data->aqbuttons[buttonIndex].led->state == ON || _aqualink_data->aqbuttons[buttonIndex].led->state == FLASH || +aq_panel.c: _aqualink_data->aqbuttons[buttonIndex].led->state == ENABLE))) { +aq_panel.c: if ((_aqualink_data->aqbuttons[buttonIndex].special_mask & PROGRAM_LIGHT) == PROGRAM_LIGHT && _aqualink_data->aqbuttons[buttonIndex].led->state == OFF) { +aq_panel.c: _aqualink_data->aqbuttons[buttonIndex].led->state = ENABLE; // if heater and set to on, set pre-status to enable. +aq_panel.c: _aqualink_data->aqbuttons[buttonIndex].led->state = (value == 0 ? OFF : ON); // as long as it's not programmable light , pre-set to on/off +aq_panel.c: aqdata->aqbuttons[0].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[1].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[2].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[3].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[4].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[5].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[6].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[7].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[8].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[9].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[10].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[11].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[9].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[10].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[11].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[12].led->state = LED_S_UNKNOWN; +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[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[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[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[17].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[18].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[19].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[0].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[1].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[2].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[3].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[4].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[5].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[6].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[7].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[8].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[9].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[10].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[11].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[12].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[13].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[14].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[15].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[16].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[17].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[18].led->state = LED_S_UNKNOWN; +aq_panel.c: aqdata->aqbuttons[19].led->state = LED_S_UNKNOWN; +aq_programmer.c: if (aq_data->aqbuttons[SPA_INDEX].led->state != OFF) { +aq_programmer.c: if ( button->led->state == ON ) { +aq_programmer.c: if ( button->led->state == ON ) { +aq_programmer.c: if ( button->led->state == ON ) { +aq_programmer.c: if ( button->led->state != ON ) { +aq_programmer.c: LOG(PROG_LOG, LOG_DEBUG, "loop %d of %d looking for state change to '%d' for '%s' \n",i,numMessageReceived,button->led->state,button->name); +aq_programmer.c: if (button->led->state == state) { +aq_programmer.c: LOG(PROG_LOG, LOG_DEBUG, "did not find state '%d' for '%s'\n",button->led->state,button->name); +aq_programmer.c: LOG(PROG_LOG, LOG_DEBUG, "found state '%d' for '%s'\n",button->led->state,button->name); +aq_timer.c: if (!isPDA_PANEL && tmthread->button->led->state == OFF) { +aq_timer.c: if (tmthread->button->led->state != OFF) { +aqualinkd.c: _aqualink_data.aqbuttons[i].led->state = state; +aqualinkd.c: LOG(AQUA_LOG,LOG_INFO, "Set %s to %d\n", _aqualink_data.aqbuttons[i].label, _aqualink_data.aqbuttons[i].led->state); +aqualinkd.c: LOG(AQUA_LOG,LOG_ERR, "RS16 Button Set error %s to %d, %d is out of scope\n", _aqualink_data.aqbuttons[i].label, _aqualink_data.aqbuttons[i].led->state, i); +aqualinkd.c: if ((msg_loop & MSG_SWG) != MSG_SWG && _aqualink_data.aqbuttons[PUMP_INDEX].led->state == OFF ) +aqualinkd.c: if ( _aqualink_data.aqbuttons[PUMP_INDEX].led->state == OFF) { +aqualinkd.c: if ( _aqualink_data.aqbuttons[PUMP_INDEX].led->state == ON) { +aqualinkd.c: if ((msg_loop & MSG_SWG) != MSG_SWG && _aqualink_data.aqbuttons[PUMP_INDEX].led->state == OFF ) { +aqualinkd.c: _aqualink_data.aqbuttons[13].led->state = OFF; +aqualinkd.c: _aqualink_data.aqbuttons[14].led->state = OFF; +aqualinkd.c: _aqualink_data.aqbuttons[15].led->state = OFF; +aqualinkd.c: _aqualink_data.aqbuttons[16].led->state = OFF; +aqualinkd.c: if (_aqualink_data.aqbuttons[PUMP_INDEX].led->state == OFF) +aqualinkd.c: else if (_aqualink_data.aqbuttons[SPA_INDEX].led->state == OFF && isSINGLE_DEV_PANEL != true) +aqualinkd.c: else if (_aqualink_data.aqbuttons[SPA_INDEX].led->state == ON && isSINGLE_DEV_PANEL != true) +devices_jandy.c: length += sprintf(msg+length, ", Pool Heat LED=%d ",aqdata->aqbuttons[i].led->state); +devices_jandy.c: length += sprintf(msg+length, ", Spa Heat LED=%d ",aqdata->aqbuttons[i].led->state); +devices_jandy.c: length += sprintf(msg+length, ", Pool Heat LED=%d ",aqdata->aqbuttons[i].led->state); +devices_jandy.c: length += sprintf(msg+length, ", Spa Heat LED=%d ",aqdata->aqbuttons[i].led->state); +iaqtouch_aq_programmer.c: if (aq_data->aqbuttons[SPA_INDEX].led->state != OFF) { +iaqtouch.c: aq_data->aqbuttons[i].led->state = OFF; +iaqtouch.c: aq_data->aqbuttons[i].led->state = ON; +iaqtouch.c: aq_data->aqbuttons[i].led->state = FLASH; +iaqtouch.c: aq_data->aqbuttons[i].led->state = ENABLE; +iaqtouch.c: printf(" -Enabeled- "); +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].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].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].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].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].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: char *state = LED2text(aqdata->aqbuttons[i].led->state); +net_services.c: send_mqtt(nc, mqtt_pub_topic, ( ((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) && (button->led->state != OFF) )?MQTT_ON:MQTT_OFF ); +net_services.c: if (_last_mqtt_aqualinkdata.aqualinkleds[i].state != _aqualink_data->aqbuttons[i].led->state) { +net_services.c: _last_mqtt_aqualinkdata.aqualinkleds[i].state = _aqualink_data->aqbuttons[i].led->state; +net_services.c: send_mqtt_heater_state_msg(nc, _aqualink_data->aqbuttons[i].name, _aqualink_data->aqbuttons[i].led->state); +net_services.c: send_mqtt_state_msg(nc, _aqualink_data->aqbuttons[i].name, _aqualink_data->aqbuttons[i].led->state); +net_services.c: send_domoticz_mqtt_state_msg(nc, _aqualink_data->aqbuttons[i].dz_idx, (_aqualink_data->aqbuttons[i].led->state==OFF?DZ_OFF:DZ_ON)); +net_services.c: if ( (_aqualink_data->aqbuttons[i].led->state == OFF && nvalue==DZ_OFF) || +net_services.c: (nvalue == DZ_ON && (_aqualink_data->aqbuttons[i].led->state == ON || +net_services.c: _aqualink_data->aqbuttons[i].led->state == FLASH || +net_services.c: _aqualink_data->aqbuttons[i].led->state == ENABLE))) { +onetouch_aq_programmer.c: if (aq_data->aqbuttons[SPA_INDEX].led->state == OFF) { +onetouch.c: if (isCOMBO_PANEL && aq_data->aqbuttons[SPA_INDEX].led->state == ON) +onetouch.c: aq_data->aqbuttons[i].led->state = ON; +onetouch.c: aq_data->aqbuttons[i].led->state = OFF; +pda_aq_programmer.c: if (aq_data->aqbuttons[device].led->state != state) { +pda_aq_programmer.c: } else if (aq_data->aqbuttons[SPA_INDEX].led->state != OFF) { +pda.c: aqledstate old_state = led->state; +pda.c: led->state = ON; +pda.c: led->state = ENABLE; +pda.c: led->state = FLASH; +pda.c: led->state = OFF; +pda.c: if (old_state != led->state) +pda.c: LOG(PDA_LOG,LOG_DEBUG, "set_pda_led from %d to %d\n", old_state, led->state); +pda.c: if (_aqualink_data->aqbuttons[i].led->state != OFF) { +pda.c: _aqualink_data->aqbuttons[i].led->state = OFF; +pda.c: if ((i==0) && (_aqualink_data->aqbuttons[0].led->state == OFF )) { +pda.c: _aqualink_data->aqbuttons[PUMP_INDEX].led->state = ON; +pda.c: _aqualink_data->aqbuttons[PUMP_INDEX].led->state = FLASH; +pda.c: _aqualink_data->aqbuttons[PUMP_INDEX].led->state = ON; +pda.c: _aqualink_data->aqbuttons[SPA_INDEX].led->state = ON; +pda.c: _aqualink_data->aqbuttons[PUMP_INDEX].led->state = FLASH; +pda.c: _aqualink_data->aqbuttons[SPA_INDEX].led->state = ON; +pda.c: _aqualink_data->aqbuttons[SPA_INDEX].led->state = OFF; +pda.c: _aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE; +pda.c: _aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE; +pda.c: if (_aqualink_data->aqbuttons[SPA_INDEX].led->state != OFF) { +pda.c: if (_aqualink_data->aqbuttons[SPA_INDEX].led->state == OFF) { +pda.c: _aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE; +pda.c: _aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE; +pda.c: if (_aqualink_data->aqbuttons[i].led->state != FLASH) +pda.c: _aqualink_data->aqbuttons[i].led->state = ON; +serialadapter.c: if (led->state != OFF) { +serialadapter.c: led->state = OFF; +serialadapter.c: if (led->state != ON) { +serialadapter.c: led->state = ON; +serialadapter.c: //_aqualink_data.aqbuttons[13].led->state = OFF; +serialadapter.c: //_aqualink_data.aqbuttons[13].led->state = OFF; diff --git a/version.h b/version.h index 45826be..6f3a0cb 100644 --- a/version.h +++ b/version.h @@ -1,4 +1,4 @@ #define AQUALINKD_NAME "Aqualink Daemon" -#define AQUALINKD_VERSION "2.3.4" +#define AQUALINKD_VERSION "2.3.5"