2024-09-13 22:44:48 +00:00
/*
* Copyright ( c ) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and / or modify this code under the terms of
2024-09-17 22:48:06 +00:00
* the GNU General Public License version 2 as published by the
* Free Software Foundation . For the terms of this license ,
2024-09-13 22:44:48 +00:00
* see < http : //www.gnu.org/licenses/>.
*
* You are free to use this software under the terms of the GNU General
* Public License , but WITHOUT ANY WARRANTY ; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details .
*
* https : //github.com/sfeakes/aqualinkd
*/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include "aq_serial.h"
# include "aqualink.h"
2024-09-30 00:47:04 +00:00
# include "iaqualink.h"
2024-09-13 22:44:48 +00:00
# include "packetLogger.h"
2024-09-17 22:48:06 +00:00
# include "aq_serial.h"
# include "serialadapter.h"
2024-09-30 00:47:04 +00:00
# include "rs_msg_utils.h"
2024-09-13 22:44:48 +00:00
2024-09-30 00:47:04 +00:00
# define IAQUA_QLEN 20
typedef struct iaqulnkcmd
2024-09-13 22:44:48 +00:00
{
2024-09-30 00:47:04 +00:00
unsigned char command [ 20 ] ;
int length ;
} iaqualink_cmd ;
iaqualink_cmd _iqaua_queue [ IAQUA_QLEN ] ;
unsigned char _std_cmd [ 2 ] ;
int _iaqua_q_length = 0 ;
bool _aqua_last_cmdfrom_queue = false ;
2024-10-12 22:37:26 +00:00
unsigned char _cmd_readyCommand [ ] = { 0x3f , 0x20 } ;
unsigned char _fullcmd [ ] = { 0x00 , 0x24 , 0x73 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2024-09-30 00:47:04 +00:00
bool push_iaqualink_cmd ( unsigned char * cmd , int length ) {
if ( _iaqua_q_length > = IAQUA_QLEN ) {
LOG ( IAQL_LOG , LOG_ERR , " Queue overflow, last command ignored! \n " ) ;
return false ;
}
2024-09-13 22:44:48 +00:00
2024-09-30 00:47:04 +00:00
memcpy ( _iqaua_queue [ _iaqua_q_length ] . command , cmd , length ) ;
_iqaua_queue [ _iaqua_q_length ] . length = length ;
_iaqua_q_length + + ;
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Queue cmd, size %d, queu length=%d \n " , length , _iaqua_q_length ) ;
2024-09-30 00:47:04 +00:00
//LOG(IAQL_LOG,LOG_DEBUG, "Added to message queue, position %d 0x%02hhx|0x%02hhx|0x%02hhx|0x%02hhx\n",_rssa_q_length-1,_rssa_queue[_rssa_q_length-1][0],_rssa_queue[_rssa_q_length-1][1],_rssa_queue[_rssa_q_length-1][2],_rssa_queue[_rssa_q_length-1][3]);
return true ;
}
//unsigned char *get_iaqualink_cmd(unsigned char source_message_type, unsigned char *dest_message, int *len) {
int get_iaqualink_cmd ( unsigned char source_message_type , unsigned char * * dest_message ) {
//LOG(IAQL_LOG, LOG_INFO, "Caculating cmd\n");
_aqua_last_cmdfrom_queue = false ;
_std_cmd [ 0 ] = source_message_type ;
_std_cmd [ 1 ] = 0x00 ;
* dest_message = _std_cmd ;
int len = 2 ;
if ( source_message_type = = 0x73 & & _iaqua_q_length > 0 )
{ // Send big/long message
if ( _iqaua_queue [ 0 ] . length > = 19 ) {
* dest_message = _iqaua_queue [ 0 ] . command ;
len = _iqaua_queue [ 0 ] . length ;
_aqua_last_cmdfrom_queue = true ;
} else {
LOG ( IAQL_LOG , LOG_WARNING , " Next command in queue is not full command, ignoring \n " ) ;
}
}
else if ( source_message_type = = 0x53 & & _iaqua_q_length > 0 )
{ // Send small command
if ( _iqaua_queue [ 0 ] . length < = 2 ) {
* dest_message = _iqaua_queue [ 0 ] . command ;
len = _iqaua_queue [ 0 ] . length ;
_aqua_last_cmdfrom_queue = true ;
} else {
LOG ( IAQL_LOG , LOG_WARNING , " Next command in queue is too large, ignoring \n " ) ;
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_ERR , " Re sending get prepare frame \n " ) ;
* dest_message = _cmd_readyCommand ;
2024-09-30 00:47:04 +00:00
}
}
//LOG(IAQL_LOG, LOG_INFO, "Return cmd size %d\n",len);
return len ;
}
void remove_iaqualink_cmd ( ) {
if ( _iaqua_q_length > 0 & & _aqua_last_cmdfrom_queue = = true ) {
LOG ( IAQL_LOG , LOG_DEBUG , " Remove from message queue, length %d \n " , _iaqua_q_length - 1 ) ;
memmove ( & _iqaua_queue [ 0 ] , & _iqaua_queue [ 1 ] , ( sizeof ( iaqualink_cmd ) ) * _iaqua_q_length ) ;
_iaqua_q_length - - ;
}
}
unsigned char iAqalnkDevID ( aqkey * button ) {
// For the 3 actual vbuttons that exist, we have already set their codes so just return it with no conversion
if ( ( ( button - > special_mask & VIRTUAL_BUTTON ) = = VIRTUAL_BUTTON ) & & button - > rssd_code ! = NUL ) {
return button - > rssd_code ;
2024-09-20 21:49:41 +00:00
}
2024-09-30 00:47:04 +00:00
switch ( button - > rssd_code ) {
case RS_SA_PUMP :
return IAQ_PUMP ;
break ;
case RS_SA_SPA :
return IAQ_SPA ;
break ;
case RS_SA_POOLHT :
return IAQ_POOL_HTR ;
break ;
case RS_SA_SPAHT :
return IAQ_SPA_HTR ;
break ;
case RS_SA_AUX1 :
return IAQ_AUX1 ;
break ;
case RS_SA_AUX2 :
return IAQ_AUX2 ;
break ;
case RS_SA_AUX3 :
return IAQ_AUX3 ;
break ;
case RS_SA_AUX4 :
return IAQ_AUX4 ;
break ;
case RS_SA_AUX5 :
return IAQ_AUX5 ;
break ;
case RS_SA_AUX6 :
return IAQ_AUX6 ;
break ;
case RS_SA_AUX7 :
return IAQ_AUX7 ;
break ;
case RS_SA_AUX8 :
return IAQ_AUXB1 ;
break ;
case RS_SA_AUX9 :
return IAQ_AUXB2 ;
break ;
case RS_SA_AUX10 :
return IAQ_AUXB3 ;
break ;
case RS_SA_AUX11 :
return IAQ_AUXB4 ;
break ;
case RS_SA_AUX12 :
return IAQ_AUXB5 ;
break ;
case RS_SA_AUX13 :
return IAQ_AUXB6 ;
break ;
case RS_SA_AUX14 :
return IAQ_AUXB7 ;
break ;
case RS_SA_AUX15 :
return IAQ_AUXB8 ;
break ;
}
return 0xFF ;
}
2024-10-20 21:34:15 +00:00
void lastchecksum ( unsigned char * packet , int length )
{
if ( getLogLevel ( IAQL_LOG ) > = LOG_DEBUG )
{
static unsigned char last70checksum = 0x00 ;
static unsigned char last71checksum = 0x00 ;
static unsigned char last72checksum = 0x00 ;
2024-09-30 00:47:04 +00:00
2024-10-20 21:34:15 +00:00
switch ( packet [ PKT_CMD ] )
{
2024-09-30 00:47:04 +00:00
case 0x70 :
2024-10-20 21:34:15 +00:00
if ( last70checksum ! = packet [ length - 3 ] & & last70checksum ! = 0x00 )
{
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ******* CHECKSUM CHANGED for 0x70 ******* \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
2024-09-30 00:47:04 +00:00
}
2024-10-20 21:34:15 +00:00
last70checksum = packet [ length - 3 ] ;
break ;
2024-09-30 00:47:04 +00:00
case 0x71 :
2024-10-20 21:34:15 +00:00
if ( last71checksum ! = packet [ length - 3 ] & & last71checksum ! = 0x00 )
{
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ******* CHECKSUM CHANGED for 0x71 ******* \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
2024-09-30 00:47:04 +00:00
}
2024-10-20 21:34:15 +00:00
last71checksum = packet [ length - 3 ] ;
break ;
2024-09-30 00:47:04 +00:00
case 0x72 :
2024-10-20 21:34:15 +00:00
if ( last72checksum ! = packet [ length - 3 ] & & last72checksum ! = 0x00 )
{
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ******* CHECKSUM CHANGED for 0x72 ******* \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
2024-09-30 00:47:04 +00:00
}
2024-10-20 21:34:15 +00:00
last72checksum = packet [ length - 3 ] ;
break ;
}
}
2024-09-30 00:47:04 +00:00
}
/*
All taken from panel Yg , but only heater setpoints seem to work .
Only setpoints seem to work ,
2024-10-12 22:37:26 +00:00
Can ' t get to work on T2 panel
2024-09-30 00:47:04 +00:00
RPM to 2750
Bit 6 = 0x5e
Bit 10 * 256 + Bit 11
Bit 7 or 9 probably pump index .
HEX : 0x10 | 0x02 | 0x00 | 0x24 | 0x73 | 0x01 | 0x5e | 0x04 | 0x00 | 0x01 | 0x0a | 0xbe | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0xd5 | 0x10 | 0x03 |
RPM to 2995
HEX : 0x10 | 0x02 | 0x00 | 0x24 | 0x73 | 0x01 | 0x5e | 0x04 | 0x00 | 0x01 | 0x0b | 0xb3 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0xcb | 0x10 | 0x03 |
2024-10-12 22:37:26 +00:00
Can ' t get to work on T2 panel
2024-09-30 00:47:04 +00:00
SWG 50 %
Byte 6 = 0x19
Byte 7 = 50 %
Byte 9 & 10 ? ? ? ?
HEX : 0x10 | 0x02 | 0x00 | 0x24 | 0x73 | 0x01 | 0x19 | 0x32 | 0x00 | 0x18 | 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x0e | 0x10 | 0x03 |
SWG 51 %
Byte 7 = 51 %
HEX : 0x10 | 0x02 | 0x00 | 0x24 | 0x73 | 0x01 | 0x19 | 0x33 | 0x00 | 0x18 | 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x0f | 0x10 | 0x03 |
2024-10-12 22:37:26 +00:00
Works on T2
2024-09-30 00:47:04 +00:00
Spa Setpoint 102
Byte 6 = 0x06
Byte 8 = 0x66 = 102
HEX : 0x10 | 0x02 | 0x00 | 0x24 | 0x73 | 0x01 | 0x06 | 0x00 | 0x66 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x16 | 0x10 | 0x03 |
2024-10-12 22:37:26 +00:00
Works on T2
2024-09-30 00:47:04 +00:00
Pool Setpoint 72
Byte 6 = 0x05
Byte 8 = 0x48 = 72
HEX : 0x10 | 0x02 | 0x00 | 0x24 | 0x73 | 0x01 | 0x05 | 0x00 | 0x48 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0xf7 | 0x10 | 0x03 |
2024-09-20 21:49:41 +00:00
*/
2024-09-30 00:47:04 +00:00
void set_iaqualink_aux_state ( aqkey * button , bool isON ) {
_fullcmd [ 4 ] = iAqalnkDevID ( button ) ;
if ( _fullcmd [ 4 ] ! = 0xFF ) {
push_iaqualink_cmd ( _cmd_readyCommand , 2 ) ;
push_iaqualink_cmd ( _fullcmd , 19 ) ;
} else {
LOG ( IAQL_LOG , LOG_ERR , " Couldn't find iaqualink keycode for button %s \n " , button - > label ) ;
2024-09-20 21:49:41 +00:00
}
2024-09-30 00:47:04 +00:00
2024-10-12 22:37:26 +00:00
// reset
_fullcmd [ 4 ] = 0x00 ;
2024-09-30 00:47:04 +00:00
}
void set_iaqualink_heater_setpoint ( int value , bool isPool ) {
if ( isPool ) {
_fullcmd [ 4 ] = 0x05 ;
} else {
_fullcmd [ 4 ] = 0x06 ;
}
// Should check value is valid here.
_fullcmd [ 6 ] = value ;
push_iaqualink_cmd ( _cmd_readyCommand , 2 ) ;
push_iaqualink_cmd ( _fullcmd , 19 ) ;
2024-10-12 22:37:26 +00:00
// reset
_fullcmd [ 4 ] = 0x00 ;
_fullcmd [ 6 ] = 0x00 ;
}
void iAqSetButtonState ( struct aqualinkdata * aq_data , int index , const unsigned char byte )
{
if ( aq_data - > aqbuttons [ index ] . led - > state ! = OFF & & byte = = 0x00 ) {
aq_data - > aqbuttons [ index ] . led - > state = OFF ;
LOG ( IAQL_LOG , LOG_INFO , " Set %s off \n " , aq_data - > aqbuttons [ index ] . label ) ;
} else if ( aq_data - > aqbuttons [ index ] . led - > state ! = ON & & byte = = 0x01 ) {
aq_data - > aqbuttons [ index ] . led - > state = ON ;
LOG ( IAQL_LOG , LOG_INFO , " Set %s on \n " , aq_data - > aqbuttons [ index ] . label ) ;
} else if ( aq_data - > aqbuttons [ index ] . led - > state ! = ENABLE & & byte = = 0x03 ) {
aq_data - > aqbuttons [ index ] . led - > state = ENABLE ;
LOG ( IAQL_LOG , LOG_INFO , " Set %s enabled \n " , aq_data - > aqbuttons [ index ] . label ) ;
}
2024-09-30 00:47:04 +00:00
}
/*
Status packets are requested on iAqualink ID 0xA ? but received on AqualinkTouch ID 0x3 ?
They are also sent when iAqualink is connected and a device changes .
So good to catch in PDA mode when a physical iAqualink device is connected to PDA panel .
packet has cmd of 0x70 , 0x71 , 0x72
*/
bool process_iAqualinkStatusPacket ( unsigned char * packet , int length , struct aqualinkdata * aq_data )
{
if ( packet [ PKT_CMD ] = = CMD_IAQ_MAIN_STATUS )
2024-09-20 21:49:41 +00:00
{
2024-10-12 22:37:26 +00:00
logPacket ( IAQL_LOG , LOG_INFO , packet , length , true ) ;
2024-09-30 00:47:04 +00:00
int startIndex = 4 + 1 ;
int numberBytes = packet [ 4 ] ;
int offsetIndex = startIndex + numberBytes ;
bool foundSpaSP = false ;
bool foundWaterTemp = false ;
bool foundAirTemp = false ;
for ( int i = 0 ; i < = numberBytes ; i + + )
2024-09-20 21:49:41 +00:00
{
2024-09-30 00:47:04 +00:00
int byteType = packet [ 5 + i ] ;
int byte = packet [ offsetIndex + i ] ;
char * label ;
2024-09-20 21:49:41 +00:00
2024-09-30 00:47:04 +00:00
// Some panels have blanks for the last 3 buys, the first of which is "water temp" (not sure on others 0x20, 0x21)
// So if we saw 0x1d break loop if not force next as water temp.
if ( foundWaterTemp & & i = = numberBytes )
{
break ;
}
else if ( i = = numberBytes )
{
byteType = 0x1d ;
2024-09-20 21:49:41 +00:00
}
2024-09-30 00:47:04 +00:00
if ( byteType = = 0 ) {
label = " Filter Pump " ;
2024-10-12 22:37:26 +00:00
if ( isPDA_PANEL ) { iAqSetButtonState ( aq_data , 0 , byte ) ; }
2024-09-30 00:47:04 +00:00
} else if ( byteType = = 1 ) {
2024-10-12 22:37:26 +00:00
label = " Pool Heater " ; // 0x00 off 0x01=on&heating, 0x03=enabled
if ( isPDA_PANEL ) { iAqSetButtonState ( aq_data , aq_data - > pool_heater_index , byte ) ; }
2024-09-30 00:47:04 +00:00
} else if ( byteType = = 2 ) {
label = " Spa " ;
} else if ( byteType = = 3 ) {
label = " Spa Heater " ; // 0x01=on&heating, 0x03=ena
2024-10-12 22:37:26 +00:00
if ( isPDA_PANEL ) { iAqSetButtonState ( aq_data , aq_data - > spa_heater_index , byte ) ; }
2024-09-30 00:47:04 +00:00
} else if ( byteType = = 6 ) {
label = " Pool Htr setpoint " ;
} else if ( byteType = = 8 | | byteType = = 9 ) { // 8 usually, also get 9 & 14 (different spa/heater modes not sorted out yet. 14 sometimes blank as well)
label = " Spa Htr setpoint " ;
foundSpaSP = true ;
} else if ( ( /*byteType == 14 ||*/ byteType = = 12 ) & & foundSpaSP = = false & & byte ! = 0 ) {
label = " Spa Htr setpoint " ;
} else if ( ( byteType = = 14 | | byteType = = 15 | | byteType = = 26 ) & & byte ! = 0 & & byte ! = 255 & & foundAirTemp = = false ) { // 0x0f
label = " Air Temp " ; // we also see this as 14 (RS16) ONLY
foundAirTemp = true ;
} else if ( ( byteType = = 27 | | byteType = = 28 | | byteType = = 29 ) & & byte ! = 0 & & byte ! = 255 & & foundWaterTemp = = false ) {
// Last 3 bytes don't have type on some panels
label = " Water Temp " ;
foundWaterTemp = true ;
2024-09-20 21:49:41 +00:00
}
2024-09-30 00:47:04 +00:00
else
label = " " ;
2024-09-20 21:49:41 +00:00
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " %-17s = %3d | index=%d type=(%0.2d 0x%02hhx) value=0x%02hhx offset=%d \n " , label , byte , i , byteType , byteType , byte , ( offsetIndex + i ) ) ;
2024-09-30 00:47:04 +00:00
}
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Status from other protocols Pump %s, Spa %s, SWG %d, PumpRPM %d, PoolSP=%d, SpaSP=%d, WaterTemp=%d, AirTemp=%d \n " ,
2024-09-30 00:47:04 +00:00
aq_data - > aqbuttons [ 0 ] . led - > state = = OFF ? " Off " : " On " ,
aq_data - > aqbuttons [ 1 ] . led - > state = = OFF ? " Off " : " On " ,
aq_data - > swg_percent ,
aq_data - > pumps [ 0 ] . rpm ,
aq_data - > pool_htr_set_point ,
aq_data - > spa_htr_set_point ,
( aq_data - > aqbuttons [ 1 ] . led - > state = = OFF ? aq_data - > pool_temp : aq_data - > spa_temp ) ,
aq_data - > air_temp ) ;
}
else if ( packet [ PKT_CMD ] = = CMD_IAQ_1TOUCH_STATUS )
{
2024-10-12 22:37:26 +00:00
logPacket ( IAQL_LOG , LOG_INFO , packet , length , true ) ;
2024-09-30 00:47:04 +00:00
int numLabels = packet [ 4 ] ;
int start = numLabels + 4 + 1 ;
if ( numLabels = = 1 )
{
2024-10-12 22:37:26 +00:00
// This just seem to list a ton of pump (names)
LOG ( IAQL_LOG , LOG_INFO , " **** !!! haven't decoded above packet yet !!! ***** \n " ) ;
2024-09-30 00:47:04 +00:00
return false ;
}
for ( int i = 0 ; i < numLabels ; i + + )
{
int status = packet [ start ] ;
int length = packet [ start + 1 ] ;
int byteType = packet [ 5 + i ] ;
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " %-15.*s = %s | index %d type=(%0.2d 0x%02hhx) status=0x%02hhx start=%d length=%d \n " , length , & packet [ start + 2 ] , ( status = = 0x00 ? " Off " : " On " ) , i , byteType , byteType , status , start , length ) ;
2024-09-30 00:47:04 +00:00
// Check against virtual onetouch buttons.
for ( int bi = aq_data - > virtual_button_start ; bi < aq_data - > total_buttons ; bi + + ) {
if ( rsm_strcmp ( ( char * ) & packet [ start + 2 ] , aq_data - > aqbuttons [ bi ] . label ) = = 0 ) {
2024-10-12 22:37:26 +00:00
//LOG(IAQL_LOG, LOG_INFO, "Status for %s is %s\n",aq_data->aqbuttons[bi].label,(status == 0x00 ? "Off" : "On "));
2024-09-30 00:47:04 +00:00
// == means doesn;t match, RS 1=on 0=off / LED enum 1=off 0=on
if ( aq_data - > aqbuttons [ bi ] . led - > state = = status ) {
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Updated Status for %s is %s \n " , aq_data - > aqbuttons [ bi ] . label , ( status = = 0x00 ? " Off " : " On " ) ) ;
2024-09-30 00:47:04 +00:00
aq_data - > aqbuttons [ bi ] . led - > state = ( status = = 0x00 ? OFF : ON ) ;
aq_data - > updated = true ;
}
}
2024-09-20 21:49:41 +00:00
}
2024-09-30 00:47:04 +00:00
start = start + packet [ start + 1 ] + 2 ;
}
}
else if ( packet [ PKT_CMD ] = = CMD_IAQ_AUX_STATUS )
{
2024-10-12 22:37:26 +00:00
logPacket ( IAQL_LOG , LOG_INFO , packet , length , true ) ;
2024-09-30 00:47:04 +00:00
// Look at notes in iaqualink.c for how this packet is made up
// Since this is so similar to above CMD_IAQ_1TOUCH_STATUS, we should look at using same logic for both.
int start = packet [ 4 ] ;
start = start + 5 ;
for ( int i = start ; i < length - 3 ; i = i )
2024-09-20 21:49:41 +00:00
{
2024-09-30 00:47:04 +00:00
int status = i ;
int labelstart = status + 5 ;
int labellen = packet [ status + 4 ] ;
if ( labelstart + labellen < length )
2024-09-20 21:49:41 +00:00
{
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " %-15.*s = %s | bit1=0x%02hhx bit2=0x%02hhx bit3=0x%02hhx bit4=0x%02hhx \n " , labellen , & packet [ labelstart ] , ( packet [ status ] = = 0x00 ? " Off " : " On " ) , packet [ status ] , packet [ status + 1 ] , packet [ status + 2 ] , packet [ status + 3 ] ) ;
2024-09-30 00:47:04 +00:00
}
if ( isPDA_PANEL ) {
for ( int bi = 2 ; bi < aq_data - > total_buttons ; bi + + ) {
if ( rsm_strcmp ( ( char * ) & packet [ labelstart ] , aq_data - > aqbuttons [ bi ] . label ) = = 0 ) {
if ( aq_data - > aqbuttons [ bi ] . led - > state = = packet [ status ] ) {
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Updated Status for %s is %s \n " , aq_data - > aqbuttons [ bi ] . label , ( packet [ status ] = = 0x00 ? " Off " : " On " ) ) ;
2024-09-30 00:47:04 +00:00
aq_data - > aqbuttons [ bi ] . led - > state = ( packet [ status ] = = 0x00 ? OFF : ON ) ;
aq_data - > updated = true ;
}
2024-10-12 22:37:26 +00:00
//LOG(IAQL_LOG, LOG_INFO, "Match %s to %.*s state(aqd=%d pnl=%d)\n",aq_data->aqbuttons[bi].label, labellen, (char *)&packet[labelstart], aq_data->aqbuttons[bi].led->state, packet[status]);
2024-09-30 00:47:04 +00:00
}
2024-09-20 21:49:41 +00:00
}
}
2024-09-30 00:47:04 +00:00
i = labelstart + labellen ;
2024-09-20 21:49:41 +00:00
}
}
2024-09-13 22:44:48 +00:00
return true ;
2024-09-17 22:48:06 +00:00
}
2024-09-30 00:47:04 +00:00
bool process_iaqualink_packet ( unsigned char * packet , int length , struct aqualinkdata * aq_data )
{
lastchecksum ( packet , length ) ;
unsigned char cmd_getMainstatus [ ] = { 0x3f , 0x08 } ;
unsigned char cmd_getTouchstatus [ ] = { 0x3f , 0x10 } ;
unsigned char cmd_getAuxstatus [ ] = { 0x3f , 0x18 } ;
//unsigned char cmd_readyCommand[] = {0x3f, 0x20};
//unsigned char fullcmd[] = {0x00, 0x24, 0x73, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// byte 4 is ID. 0x00 pump, 0x02 spa etc
if ( packet [ PKT_DEST ] = = _aqconfig_ . extended_device_id2 )
{
static int cnt = 0 ;
//static unsigned char ID = 0;
//static cur_swg = 0;
2024-10-20 21:34:15 +00:00
//static unsigned char sendid = 0x00;
2024-09-30 00:47:04 +00:00
if ( packet [ PKT_CMD ] = = 0x53 )
{
cnt + + ;
if ( cnt = = 20 ) {
cnt = 0 ;
2024-10-12 22:37:26 +00:00
/*
sendid = sendid = = 0x18 ? 0x60 : 0x18 ;
_fullcmd [ 4 ] = sendid ;
push_iaqualink_cmd ( _cmd_readyCommand , 2 ) ;
push_iaqualink_cmd ( _fullcmd , 19 ) ;
_fullcmd [ 4 ] = 0x00 ;
*/
2024-09-30 00:47:04 +00:00
push_iaqualink_cmd ( cmd_getMainstatus , 2 ) ;
push_iaqualink_cmd ( cmd_getTouchstatus , 2 ) ;
push_iaqualink_cmd ( cmd_getAuxstatus , 2 ) ;
/*
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ********** Send %d 0x%02hhx ************ \n " , ID , ID ) ;
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
2024-09-30 00:47:04 +00:00
_fullcmd [ 4 ] = ID + + ;
push_iaqualink_cmd ( _cmd_readyCommand , 2 ) ;
push_iaqualink_cmd ( _fullcmd , 19 ) ;
push_iaqualink_cmd ( cmd_getMainstatus , 2 ) ;
push_iaqualink_cmd ( cmd_getTouchstatus , 2 ) ;
push_iaqualink_cmd ( cmd_getAuxstatus , 2 ) ;
push_iaqualink_cmd ( _cmd_readyCommand , 2 ) ;
push_iaqualink_cmd ( _fullcmd , 19 ) ;
*/
//fullcmd[4] = ID;
//fullcmd[4] = ID;
//fullcmd[5] = 0x32;
//fullcmd[7] = ID;
//fullcmd[8] = 0x01;
//set_iaqualink_heater_setpoint(50, true);
//push_iaqualink_cmd(cmd_getMainstatus, 2);
//push_iaqualink_cmd(cmd_getTouchstatus, 2);
//push_iaqualink_cmd(cmd_getAuxstatus, 2);
/*
if ( aq_data - > swg_percent ! = cur_swg & & cur_swg ! = 0 ) {
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
LOG ( IAQL_LOG , LOG_INFO , " ********** SWG Changed to %d ************ \n " , aq_data - > swg_percent ) ;
LOG ( IAQL_LOG , LOG_INFO , " ***************************************** \n " ) ;
2024-09-30 00:47:04 +00:00
exit ( 0 ) ;
}
cur_swg = aq_data - > swg_percent ;
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " ******* QUEUE SWG Comand of %d | 0x%02hhx ************* \n " , ID , ID ) ;
2024-09-30 00:47:04 +00:00
ID + + ; */
}
}
// Packets sent to iAqualink protocol
// debuglogPacket(IAQL_LOG, packet, length, true, true);
}
else if ( packet [ PKT_DEST ] = = _aqconfig_ . extended_device_id | | ( isPDA_PANEL & & packet [ PKT_DEST ] = = _aqconfig_ . device_id ) )
{
process_iAqualinkStatusPacket ( packet , length , aq_data ) ;
}
return true ;
}
# ifdef DONOTCOMPILE
2024-09-17 22:48:06 +00:00
// This is onle here temporarly until we figure out the protocol.
void send_iaqualink_ack ( int rs_fd , unsigned char * packet_buffer )
{
/*
Probe | HEX : 0x10 | 0x02 | 0xa3 | 0x00 | 0xb5 | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x00 | 0x00 | 0x13 | 0x10 | 0x03 |
Unknown ' 0x61 ' | HEX : 0x10 | 0x02 | 0xa3 | 0x61 | 0x00 | 0x00 | 0x00 | 0x04 | 0x00 | 0x27 | 0x41 | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x61 | 0x00 | 0x74 | 0x10 | 0x03 |
Unknown ' 0x50 ' | HEX : 0x10 | 0x02 | 0xa3 | 0x50 | 0x20 | 0x20 | 0x20 | 0x20 | 0x20 | 0x20 | 0x20 | 0x20 | 0x20 | 0x00 | 0x25 | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x50 | 0x00 | 0x63 | 0x10 | 0x03 |
Unknown ' 0x51 ' | HEX : 0x10 | 0x02 | 0xa3 | 0x51 | 0x00 | 0x06 | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x51 | 0x00 | 0x64 | 0x10 | 0x03 |
Unknown ' 0x59 ' | HEX : 0x10 | 0x02 | 0xa3 | 0x59 | 0x00 | 0x0e | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x59 | 0x00 | 0x6c | 0x10 | 0x03 |
Unknown ' 0x52 ' | HEX : 0x10 | 0x02 | 0xa3 | 0x52 | 0x00 | 0x07 | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x52 | 0x00 | 0x65 | 0x10 | 0x03 |
Unknown ' 0x53 ' | HEX : 0x10 | 0x02 | 0xa3 | 0x53 | 0x08 | 0x10 | 0x03 |
Ack | HEX : 0x10 | 0x02 | 0x00 | 0x01 | 0x3f | 0x00 | 0x52 | 0x10 | 0x03 |
Use byte 3 as return ack , except for 0x53 = 0x3f
*/
2024-09-20 21:49:41 +00:00
if ( packet_buffer [ PKT_CMD ] = = CMD_PROBE )
{
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Got probe on '0x%02hhx' 2nd iAqualink Protocol \n " , packet_buffer [ PKT_DEST ] ) ;
2024-09-17 22:48:06 +00:00
send_extended_ack ( rs_fd , packet_buffer [ PKT_CMD ] , 0x00 ) ;
2024-09-20 21:49:41 +00:00
}
2024-09-17 22:48:06 +00:00
else if ( packet_buffer [ PKT_CMD ] = = 0x53 )
{
static int cnt = 0 ;
2024-09-30 00:47:04 +00:00
cnt + + ;
2024-09-17 22:48:06 +00:00
if ( cnt = = 10 )
{
2024-09-30 00:47:04 +00:00
//cnt = 5;
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Sent accept next packet Comand \n " ) ;
2024-09-17 22:48:06 +00:00
send_extended_ack ( rs_fd , 0x3f , 0x20 ) ;
2024-09-30 00:47:04 +00:00
}
2024-09-20 21:49:41 +00:00
if ( cnt = = 20 )
2024-09-17 22:48:06 +00:00
{
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Sending get status \n " ) ;
2024-09-20 21:49:41 +00:00
send_extended_ack ( rs_fd , 0x3f , 0x08 ) ;
}
else if ( cnt = = 22 )
{
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Sending get other status \n " ) ;
2024-09-20 21:49:41 +00:00
send_extended_ack ( rs_fd , 0x3f , 0x10 ) ;
}
else if ( cnt = = 24 )
{
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " Sending get aux button status \n " ) ;
2024-09-17 22:48:06 +00:00
send_extended_ack ( rs_fd , 0x3f , 0x18 ) ;
}
else
{
// Use 0x3f
2024-09-20 21:49:41 +00:00
if ( cnt > 24 )
{
cnt = 0 ;
}
2024-09-17 22:48:06 +00:00
send_extended_ack ( rs_fd , 0x3f , 0x00 ) ;
}
2024-09-20 21:49:41 +00:00
// send_jandy_command(rs_fd, get_rssa_cmd(packet_buffer[PKT_CMD]), 4);
2024-09-17 22:48:06 +00:00
}
else if ( packet_buffer [ PKT_CMD ] = = 0x73 )
{
2024-09-30 00:47:04 +00:00
static int id = 10 ;
2024-09-17 22:48:06 +00:00
// unsigned char pb1[] = {PCOL_JANDY,0x10,0x02,0x00,0x24,0x73,0x01,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x10,0x03,0x00};
// unsigned char pb2[] = {PCOL_JANDY,0x10,0x02,0x00,0x24,0x73,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcb,0x10,0x03,0x00};
// 0x21 turns on filter_pump and aux 1
2024-09-30 00:47:04 +00:00
//unsigned char pb3[] = {0x00, 0x24, 0x73, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char swg [ ] = { 0x00 , 0x24 , 0x73 , 0x01 , 0x19 , 0x32 , 0x00 , 0x18 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
//unsigned char swg[] = {0x00, 0x24, 0x73, 0x01, 0x19, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char rpm [ ] = { 0x00 , 0x24 , 0x73 , 0x01 , 0x5e , 0x04 , 0x00 , 0x01 , 0x0a , 0xbe , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xd5 , 0x10 , 0x03 } ;
//pb3[4] = id++;
//swg[5] = ++id;
2024-10-12 22:37:26 +00:00
LOG ( IAQL_LOG , LOG_INFO , " *** Sending SWG dec=%d hex=0x%02hhx \n " , swg [ 5 ] , swg [ 5 ] ) ;
2024-09-17 22:48:06 +00:00
// send_packet(rs_fd, pb2, 25);
2024-09-30 00:47:04 +00:00
send_jandy_command ( rs_fd , swg , 19 ) ;
2024-09-17 22:48:06 +00:00
}
else
{
// Use packet_buffer[PKT_CMD]
send_extended_ack ( rs_fd , packet_buffer [ PKT_CMD ] , 0x00 ) ;
}
}
2024-09-30 00:47:04 +00:00
# endif
2024-09-17 22:48:06 +00:00