pull/66/head
shaun feakes 2019-06-07 16:31:06 -05:00
parent 1d5000355d
commit 26a98c159c
16 changed files with 365 additions and 44 deletions

View File

@ -27,11 +27,12 @@ CFLAGS = $(GCCFLAGS) $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_
# Add inputs and outputs from these tool invocations to the build variables
# define the C source files
SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c pda.c pda_menu.c pda_aq_programmer.c mongoose.c
SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c pda.c pda_menu.c pda_aq_programmer.c pentair_messages.c mongoose.c
SL_SRC = serial_logger.c aq_serial.c utils.c
LR_SRC = log_reader.c aq_serial.c utils.c
PL_EXSRC = aq_serial.c
PL_EXOBJ = aq_serial_player.o
PL_SRC := $(filter-out aq_serial.c, $(SRCS))
OBJS = $(SRCS:.c=.o)
@ -67,11 +68,11 @@ $(LOGR): $(LR_OBJS)
player: $(PLAY)
@echo: $(PLAY) have been compiled
aq_serial_player.o: aq_serial.c
$(CC) $(CFLAGS) -D PLAYBACK_MODE $(INCLUDES) -c aq_serial.c -o aq_serial_player.o
$(PL_EXOBJ): $(PL_EXSRC)
$(CC) $(CFLAGS) -D PLAYBACK_MODE $(INCLUDES) -c $(PL_EXSRC) -o $(PL_EXOBJ)
$(PLAY): $(PL_OBJS) aq_serial_player.o
$(CC) $(CFLAGS) $(INCLUDES) -o $(PLAY) $(PL_OBJS) aq_serial_player.o
$(PLAY): $(PL_OBJS) $(PL_EXOBJ)
$(CC) $(CFLAGS) $(INCLUDES) -o $(PLAY) $(PL_OBJS) $(PL_EXOBJ)
# this is a suffix replacement rule for building .o's from .c's
# it uses automatic variables $<: the name of the prerequisite of
@ -81,7 +82,7 @@ $(PLAY): $(PL_OBJS) aq_serial_player.o
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY)
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY) $(PL_EXOBJ)
depend: $(SRCS)
makedepend $(INCLUDES) $^

View File

@ -63,9 +63,9 @@ Designed to mimic AqualinkRS6 All Button keypad, and just like the keypad you ca
* http://aqualink.ip/simple.html <- (Simple opion if you don't like the above)
* http://aqualink.ip/simulator.html <- (RS8 All Button Control Panel simulator)
#<a name="release"></a>
## Update in Release 1.3.2
## Update in Release 1.3.2a
* Miscellaneous bug fixes and buffer overrun (could cause core dump).
* VSP update.
* VSP update & Pantair device support.
## Update in Release 1.3.1
* Changed the way PDA mode will sleep.
* Added preliminary support for Variable Speed Pumps. (many limitations on support)

View File

@ -64,6 +64,7 @@ void log_packet(int level, char *init_str, unsigned char* packet, int length)
char buff[MAXLEN];
cnt = sprintf(buff, "%s", init_str);
cnt += sprintf(" | %8.8s",getProtocolType(packet)==JANDY?"Jandy":"Pentair");
cnt += sprintf(buff+cnt, " | HEX: ");
//printHex(packet_buffer, packet_length);
for (i=0;i<length;i++)
@ -214,6 +215,15 @@ void test_cmd()
print_hex((char *)ackPacket, length);
}
protocolType getProtocolType(unsigned char* packet) {
if (packet[0] == DLE)
return JANDY;
else if (packet[0] == PP1)
return PENTAIR;
return P_UNKNOWN;
}
#ifndef PLAYBACK_MODE
/*
@ -561,6 +571,200 @@ int get_packet(int fd, unsigned char* packet)
bool check_jandy_checksum(unsigned char* packet, int length)
{
if (generate_checksum(packet, length) == packet[length-3])
return true;
return false;
}
bool check_pentair_checksum(unsigned char* packet, int length)
{
int i, sum, n;
n = packet[8] + 9;
sum = 0;
for (i = 3; i < n; i++) {
sum += (int) packet[i];
}
if (sum == (packet[length-1] * 256 + packet[length]))
return true;
return false;
}
int get_packet_new(int fd, unsigned char* packet)
{
unsigned char byte;
int bytesRead;
int index = 0;
bool endOfPacket = false;
//bool packetStarted = FALSE;
bool lastByteDLE = false;
int retry = 0;
bool jandyPacketStarted = false;
bool pentairPacketStarted = false;
//bool lastByteDLE = false;
int PentairPreCnt = 0;
int PentairDataCnt = -1;
// Read packet in byte order below
// DLE STX ........ ETX DLE
// sometimes we get ETX DLE and no start, so for now just ignoring that. Seem to be more applicable when busy RS485 traffic
while (!endOfPacket) {
bytesRead = read(fd, &byte, 1);
//if (bytesRead < 0 && errno == EAGAIN && packetStarted == FALSE && lastByteDLE == FALSE) {
if (bytesRead < 0 && errno == EAGAIN &&
jandyPacketStarted == false &&
pentairPacketStarted == false &&
lastByteDLE == false) {
// We just have nothing to read
return 0;
} else if (bytesRead < 0 && errno == EAGAIN) {
// If we are in the middle of reading a packet, keep going
if (retry > 20) {
logMessage(LOG_WARNING, "Serial read timeout\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
retry++;
delay(10);
} else if (bytesRead == 1) {
if (lastByteDLE == true && byte == NUL)
{
// Check for DLE | NULL (that's escape DLE so delete the NULL)
//printf("IGNORE THIS PACKET\n");
lastByteDLE = false;
}
else if (lastByteDLE == true)
{
if (index == 0)
index++;
packet[index] = byte;
index++;
if (byte == STX && jandyPacketStarted == false)
{
jandyPacketStarted = true;
pentairPacketStarted = false;
}
else if (byte == ETX && jandyPacketStarted == true)
{
endOfPacket = true;
}
}
else if (jandyPacketStarted || pentairPacketStarted)
{
packet[index] = byte;
index++;
if (pentairPacketStarted == true && index == 9)
{
//printf("Read 0x%02hhx %d pentair\n", byte, byte);
PentairDataCnt = byte;
}
if (PentairDataCnt >= 0 && index - 11 >= PentairDataCnt && pentairPacketStarted == true)
{
endOfPacket = true;
PentairPreCnt = -1;
index--;
}
}
else if (byte == DLE && jandyPacketStarted == false)
{
packet[index] = byte;
}
// // reset index incase we have EOP before start
if (jandyPacketStarted == false && pentairPacketStarted == false)
{
index = 0;
}
if (byte == DLE && pentairPacketStarted == false)
{
lastByteDLE = true;
PentairPreCnt = -1;
}
else
{
lastByteDLE = false;
if (byte == PP1 && PentairPreCnt == 0)
PentairPreCnt = 1;
else if (byte == PP2 && PentairPreCnt == 1)
PentairPreCnt = 2;
else if (byte == PP3 && PentairPreCnt == 2)
PentairPreCnt = 3;
else if (byte == PP4 && PentairPreCnt == 3)
{
pentairPacketStarted = true;
jandyPacketStarted = false;
PentairDataCnt = -1;
packet[0] = PP1;
packet[1] = PP2;
packet[2] = PP3;
packet[3] = byte;
index = 4;
}
else if (byte != PP1) // Don't reset counter if multiple PP1's
PentairPreCnt = 0;
}
} else if(bytesRead < 0) {
// Got a read error. Wait one millisecond for the next byte to
// arrive.
logMessage(LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
if(errno == 9) {
// Bad file descriptor. Port has been disconnected for some reason.
// Return a -1.
return -1;
}
delay(100);
}
// Break out of the loop if we exceed maximum packet
// length.
if (index >= AQ_MAXPKTLEN) {
logMessage(LOG_WARNING, "Serial packet too large\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
break;
}
}
//logMessage(LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
if (jandyPacketStarted) {
if (generate_checksum(packet, index) != packet[index-3]){
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
} else if (pentairPacketStarted) {
if (check_pentair_checksum(packet, index) != true){
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
}
/*
if (generate_checksum(packet, index) != packet[index-3]){
logMessage(LOG_WARNING, "Serial read bad checksum, ignoring\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
} else*/ if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
logMessage(LOG_WARNING, "Serial read too small\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
// Return the packet length.
return index;
}
#else // PLAYBACK_MODE
#include <stdlib.h>
FILE *_fp;
@ -581,6 +785,10 @@ void close_serial_port(int fd)
fclose(_fp);
}
int get_packet_new(int fd, unsigned char* packet_buffer)
{
return get_packet(fd, packet_buffer);
}
int get_packet(int fd, unsigned char* packet_buffer)
{
int packet_length = 0;

View File

@ -18,12 +18,30 @@
#define SWG_DEV_ID 0x50
#define IAQ_DEV_ID 0x33
// PACKET DEFINES
// PACKET DEFINES Jandy
#define NUL 0x00
#define DLE 0x10
#define STX 0x02
#define ETX 0x03
// Pentair packet headder (first 4 bytes)
#define PP1 0xFF
#define PP2 0x00
#define PP3 0xFF
#define PP4 0xA5
#define PEN_CMD_STATUS 0x07
#define PEN_PKT_FROM 6
#define PEN_PKT_DEST 5
#define PEN_PKT_CMD 7
#define PEN_HI_B_RPM 14
#define PEN_LO_B_RPM 15
#define PEN_HI_B_WAT 12
#define PEN_LO_B_WAT 13
// END Pentair
#define AQ_MINPKTLEN 5
#define AQ_MAXPKTLEN 64
#define AQ_PSTLEN 5
@ -215,16 +233,26 @@ enum {
LOW
};
typedef enum {
JANDY,
PENTAIR,
P_UNKNOWN
} protocolType;
int init_serial_port(char* tty);
void close_serial_port(int file_descriptor);
void set_pda_mode(bool mode);
bool pda_mode();
int generate_checksum(unsigned char* packet, int length);
protocolType getProtocolType(unsigned char* packet);
bool check_jandy_checksum(unsigned char* packet, int length);
bool check_pentair_checksum(unsigned char* packet, int length);
void send_ack(int file_descriptor, unsigned char command);
void send_extended_ack(int fd, unsigned char ack_type, unsigned char command);
//void send_cmd(int file_descriptor, unsigned char cmd, unsigned char args);
int get_packet(int file_descriptor, unsigned char* packet);
int get_packet_new(int fd, unsigned char* packet);
//void close_serial_port(int file_descriptor, struct termios* oldtio);
//void process_status(void const * const ptr);
void process_status(unsigned char* ptr);

View File

@ -38,7 +38,7 @@
#include "net_services.h"
#include "pda_menu.h"
#include "pda.h"
#include "iAqualink_messages.h"
#include "pentair_messages.h"
#include "version.h"
//#define DEFAULT_CONFIG_FILE "./aqualinkd.conf"
@ -445,7 +445,7 @@ void processMessage(char *message)
// We processed the next message, kick any threads waiting on the message.
kick_aq_program_thread(&_aqualink_data);
}
/*
bool process_pda_monitor_packet(unsigned char *packet, int length)
{
bool rtn = false;
@ -495,7 +495,7 @@ bool process_pda_monitor_packet(unsigned char *packet, int length)
return rtn;
}
*/
bool process_packet(unsigned char *packet, int length)
{
bool rtn = false;
@ -764,7 +764,8 @@ int main(int argc, char *argv[])
logMessage(LOG_NOTICE, "Config log_file = %s\n", _config_parameters.log_file);
logMessage(LOG_NOTICE, "Config light_pgm_mode = %.2f\n", _config_parameters.light_programming_mode);
logMessage(LOG_NOTICE, "Debug RS485 protocol = %s\n", bool2text(_config_parameters.debug_RSProtocol_packets));
logMessage(LOG_NOTICE, "Use PDA 4 auxiliary info = %s\n", bool2text(_config_parameters.use_PDA_auxiliary));
//logMessage(LOG_NOTICE, "Use PDA 4 auxiliary info = %s\n", bool2text(_config_parameters.use_PDA_auxiliary));
logMessage(LOG_NOTICE, "Read Pentair Packets = %s\n", bool2text(_config_parameters.read_pentair_packets));
// logMessage (LOG_NOTICE, "Config serial_port = %s\n", config_parameters->serial_port);
for (i = 0; i < TOTAL_BUTONS; i++)
@ -855,8 +856,30 @@ void logPacket(unsigned char *packet_buffer, int packet_length)
}
*/
void logPacket_new(unsigned char* packet_buffer, int packet_length)
{
char buff[1000];
int i = 0;
int cnt = 0;
cnt = sprintf(buff, "%8.8s Packet | HEX: ",getProtocolType(packet_buffer)==JANDY?"Jandy":"Pentair");
for (i=0;i<packet_length;i++)
cnt += sprintf(buff + cnt, "0x%02hhx|", packet_buffer[i]);
if (_config_parameters.debug_RSProtocol_packets)
writePacketLog(buff);
else
logMessage(LOG_DEBUG_SERIAL, "%s", buff);
}
void logPacket(unsigned char *packet_buffer, int packet_length)
{
if (_config_parameters.read_pentair_packets) {
logPacket_new(packet_buffer, packet_length);
return;
}
char buff[1000];
int i = 0;
int cnt = 0;
@ -1000,7 +1023,11 @@ void main_loop()
blank_read = 0;
}
packet_length = get_packet(rs_fd, packet_buffer);
if (_config_parameters.read_pentair_packets)
packet_length = get_packet_new(rs_fd, packet_buffer);
else
packet_length = get_packet(rs_fd, packet_buffer);
if (packet_length == -1)
{
// Unrecoverable read error. Force an attempt to reconnect.
@ -1041,7 +1068,7 @@ void main_loop()
send_ack(rs_fd, pop_aq_cmd(&_aqualink_data));
else
caculate_ack_packet(rs_fd, packet_buffer);
}
}/*
else if (_config_parameters.use_PDA_auxiliary && packet_length > 0 && packet_buffer[PKT_DEST] == 0x60 && _aqualink_data.aqbuttons[PUMP_INDEX].led->state != OFF)
{
if (process_pda_monitor_packet(packet_buffer, packet_length))
@ -1049,7 +1076,7 @@ void main_loop()
//send_ack(rs_fd, NUL);
send_extended_ack(rs_fd, ACK_PDA, NUL);
}
}*/
else if (packet_length > 0 && _config_parameters.read_all_devices == true)
{
@ -1090,6 +1117,11 @@ void main_loop()
{
interestedInNextAck = false;
}
if (_config_parameters.read_pentair_packets && getProtocolType(packet_buffer) == PENTAIR) {
if (processPentairPacket(packet_buffer, packet_length, &_aqualink_data))
broadcast_aqualinkstate(mgr.active_connections);
}
/* Removed, iAqualink has sleep mode, so no use
if (packet_buffer[PKT_DEST] == IAQ_DEV_ID && packet_buffer[PKT_CMD] == CMD_IAQ_MSG) {
if (processiAqualinkMsg(packet_buffer, packet_length, &_aqualink_data) != false)

View File

@ -84,7 +84,7 @@ void init_parameters (struct aqconfig * parms)
parms->use_panel_aux_labels = false;
parms->debug_RSProtocol_packets = false;
parms->force_swg = false;
parms->use_PDA_auxiliary = false;
parms->read_pentair_packets = false;
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
}
@ -381,7 +381,7 @@ bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqd
} else if (strncasecmp(param, "pda_mode", 8) == 0) {
config_parameters->pda_mode = text2bool(value);
set_pda_mode(config_parameters->pda_mode);
config_parameters->use_PDA_auxiliary = false;
//config_parameters->use_PDA_auxiliary = false;
rtn=true;
} else if (strncasecmp(param, "pda_sleep_mode", 8) == 0) {
config_parameters->pda_sleep_mode = text2bool(value);
@ -415,14 +415,18 @@ bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqd
} else if (strncasecmp (param, "debug_RSProtocol_packets", 24) == 0) {
config_parameters->debug_RSProtocol_packets = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "use_PDA_auxiliary", 17) == 0) {
} else if (strncasecmp (param, "read_pentair_packets", 17) == 0) {
config_parameters->read_pentair_packets = text2bool(value);
config_parameters->read_all_devices = true;
} /*
else if (strncasecmp (param, "use_PDA_auxiliary", 17) == 0) {
config_parameters->use_PDA_auxiliary = text2bool(value);
if ( pda_mode() ) {
logMessage(LOG_ERR, "ERROR Can't use `use_PDA_auxiliary` in PDA mode, ignoring'\n");
config_parameters->use_PDA_auxiliary = false;
}
rtn=true;
}
} */
// removed until domoticz has a better virtual thermostat
/*else if (strncasecmp (param, "pool_thermostat_dzidx", 21) == 0) {
config_parameters->dzidx_pool_thermostat = strtoul(value, NULL, 10);

View File

@ -59,7 +59,8 @@ struct aqconfig
bool read_all_devices;
bool use_panel_aux_labels;
bool force_swg;
bool use_PDA_auxiliary;
//bool use_PDA_auxiliary;
bool read_pentair_packets;
bool debug_RSProtocol_packets;
//int dzidx_pool_thermostat; // Domoticz virtual thermostats are crap removed until better
//int dzidx_spa_thermostat; // Domoticz virtual thermostats are crap removed until better

View File

@ -1,9 +0,0 @@
#ifndef IAQ_MESSAGES_H_
#define IAQ_MESSAGES_H_
#include <stdbool.h>
bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
#endif // IAQ_MESSAGES_H_

View File

@ -794,4 +794,17 @@ PDA Line 6 =
PDA Line 7 =
PDA Line 8 =
PDA Line 9 =
VSP Motes.
four types of variable speed pumps,
Jandy ePumpTM DC,
Jandy ePumpTM AC,
IntelliFlo® 1 VF,
IntelliFlo® VS.
The SCALE setting is fixed to RPM for the Jandy ePumpTM DC, Jandy ePumpTM AC, and IntelliFlo® VS.
The SCALE setting is fixed to GPM for the IntelliFlo® VF
There are eight (8) default speed presets for each variable speed pump.
*/

View File

@ -1,19 +1,47 @@
/*
Removed as iAqualink has a sleep mode, Keeping code to use as stub for other devices.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aqualink.h"
#include "iAqualink_messages.h"
#include "aq_serial.h"
#include "pentair_messages.h"
#include "utils.h"
bool processPentairPacket(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata)
{
bool changedAnything = false;
// Need to find a better way to support pump index
static int pumpIndex = 1;
if ( packet[PEN_PKT_FROM] == 0x60 && packet[PEN_PKT_CMD] == PEN_CMD_STATUS ){
//printf("PUMP\n");
logMessage(LOG_INFO, "Pentair Pump Status message = RPM %d | WATTS %d\n",
(packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM],
(packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT]);
aqdata->pumps[pumpIndex-1].rpm = (packet[PEN_HI_B_RPM] * 256) + packet[PEN_LO_B_RPM];
aqdata->pumps[pumpIndex-1].watts = (packet[PEN_HI_B_WAT] * 256) + packet[PEN_LO_B_WAT];
changedAnything = true;
}
return changedAnything;
}
/*
Removed as iAqualink has a sleep mode, Keeping code to use as stub for other devices.
*/
#ifdef DO_NOT_COMPILE
bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
{
bool changedAnything = false;
@ -74,4 +102,6 @@ bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct
strncpy(lastmessage, (char *)&packet_buffer[4], packet_length-7);
return changedAnything;
}
}
#endif

9
pentair_messages.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef PEN_MESSAGES_H_
#define PEN_MESSAGES_H_
#include <stdbool.h>
bool processPentairPacket(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
#endif // PEN_MESSAGES_H_

Binary file not shown.

BIN
release/aqualinkd-player Executable file

Binary file not shown.

Binary file not shown.

View File

@ -120,10 +120,13 @@ void printPacket(unsigned char ID, unsigned char *packet_buffer, int packet_leng
return;
}
*/
if (packet_buffer[PKT_DEST] != 0x00)
printf("\n");
printf("%4.4s 0x%02hhx of type %8.8s", (packet_buffer[PKT_DEST]==0x00?"From":"To"), (packet_buffer[PKT_DEST]==0x00?ID:packet_buffer[PKT_DEST]), get_packet_type(packet_buffer, packet_length));
if (getProtocolType(packet_buffer)==JANDY) {
if (packet_buffer[PKT_DEST] != 0x00)
printf("\n");
printf("Jandy %4.4s 0x%02hhx of type %8.8s", (packet_buffer[PKT_DEST]==0x00?"From":"To"), (packet_buffer[PKT_DEST]==0x00?ID:packet_buffer[PKT_DEST]), get_packet_type(packet_buffer, packet_length));
} else {
printf("Pentair From 0x%02hhx To 0x%02hhx ",packet_buffer[PEN_PKT_FROM],packet_buffer[PEN_PKT_DEST] );
}
printf(" | HEX: ");
printHex((char *)packet_buffer, packet_length);
@ -215,7 +218,8 @@ int main(int argc, char *argv[]) {
logMessage(LOG_ERR, "ERROR, serial port disconnect\n");
}
packet_length = get_packet(rs_fd, packet_buffer);
//packet_length = get_packet(rs_fd, packet_buffer);
packet_length = get_packet_new(rs_fd, packet_buffer);
if (packet_length == -1) {
// Unrecoverable read error. Force an attempt to reconnect.

View File

@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
#define AQUALINKD_VERSION "1.3.2"
#define AQUALINKD_VERSION "1.3.2a"