pull/66/head
shaun feakes 2019-05-31 18:08:45 -05:00
parent 4f3fc5927c
commit 9a68a8161d
25 changed files with 535 additions and 478 deletions

BIN
._.DS_Store Normal file

Binary file not shown.

View File

@ -15,40 +15,35 @@ DBG =
#GCCFLAGS = -Wall -ffunction-sections -fdata-sections
# define any compile-time flags
GCCFLAGS = -Wall
GCCFLAGS = -Wall -O3
#GCCFLAGS = -Wall
#CFLAGS = -Wall -g -lpthread -lwiringPi -lm -I.
#CFLAGS = -Wall -g $(LIBS) -I/usr/local/include/ -L/usr/local/lib/
#CFLAGS = -Wall -g $(LIBS) -std=gnu11 -I/nas/data/Development/Raspberry/aqualink/libwebsockets-2.0-stable/lib -L/nas/data/Development/Raspberry/aqualink/libwebsockets-2.0-stable/lib
#CFLAGS = -Wall -g $(LIBS)
#CFLAGS = -Wall -g $(LIBS) -std=gnu11
CFLAGS = $(GCCFLAGS) $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
#CFLAGS = -Wall $(DBG) $(LIBS) -D MG_DISABLE_MQTT -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
INCLUDES = -I/nas/data/Development/Raspberry/aqualink/aqualinkd
# 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 iAqualink_messages.c mongoose.c
SL_SRC = serial_logger.c aq_serial.c utils.c
PDA_SRC = pda_test.c pda_menu.c aq_serial.c utils.c
#AL_SRC = aquarite_logger.c aq_serial.c utils.c
#AR_SRC = aquarite/aquarited.c aquarite/ar_net_services.c aquarite/ar_config.c aq_serial.c utils.c mongoose.c json_messages.c config.c
LR_SRC = log_reader.c aq_serial.c utils.c
PL_EXSRC = aq_serial.c
PL_SRC := $(filter-out aq_serial.c, $(SRCS))
OBJS = $(SRCS:.c=.o)
SL_OBJS = $(SL_SRC:.c=.o)
PDA_OBJS = $(PDA_SRC:.c=.o)
#AL_OBJS = $(AL_SRC:.c=.o)
#AR_OBJS = $(AR_SRC:.c=.o)
LR_OBJS = $(LR_SRC:.c=.o)
PL_OBJS = $(PL_SRC:.c=.o)
# define the executable file
MAIN = ./release/aqualinkd
SLOG = ./release/serial_logger
PDA = ./release/pda_test
#AQUARITELOG = ./release/aquarite_logger
AQUARITED = ./release/aquarited
LOGR = ./release/log_reader
PLAY = ./release/aqualinkd-player
all: $(MAIN)
@echo: $(MAIN) have been compiled
@ -56,31 +51,26 @@ all: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
slog: $(SLOG)
@echo: $(SLOG) have been compiled
$(SLOG): $(SL_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(SLOG) $(SL_OBJS)
pda: $(PDA)
@echo: $(PDA) have been compiled
logr: $(LOGR)
@echo: $(LOGR) have been compiled
$(PDA): $(PDA_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(PDA) $(PDA_OBJS)
$(LOGR): $(LR_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(LOGR) $(LR_OBJS)
player: $(PLAY)
@echo: $(PLAY) have been compiled
#aquaritelog: $(AQUARITELOG)
# @echo: $(AQUARITELOG) 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
#$(AQUARITELOG): $(AL_OBJS)
# $(CC) $(CFLAGS) $(INCLUDES) -o $(AQUARITELOG) $(AL_OBJS)
aquarited: $(AQUARITED)
@echo: $(AQUARITED) have been compiled
$(AQUARITED): $(AR_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(AQUARITED) $(AR_OBJS)
$(PLAY): $(PL_OBJS) aq_serial_player.o
$(CC) $(CFLAGS) $(INCLUDES) -o $(PLAY) $(PL_OBJS) aq_serial_player.o
# this is a suffix replacement rule for building .o's from .c's
# it uses automatic variables $<: the name of the prerequisite of
@ -90,32 +80,11 @@ $(AQUARITED): $(AR_OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
$(RM) *.o *~ $(MAIN) $(MAIN_U)
$(RM) *.o *~ $(MAIN) $(MAIN_U) $(PLAY)
depend: $(SRCS)
makedepend $(INCLUDES) $^
install: $(MAIN)
./release/install.sh
# All Target
#all: aqualinkd
#
# Tool invocations
#aqualinkd: $(OBJS) $(USER_OBJS)
# @echo 'Building target: $@'
# @echo 'Invoking: GCC C Linker'
# gcc -L/home/perry/workspace/libwebsockets/Debug -pg -o"aqualinkd" $(OBJS) $(USER_OBJS) $(LIBS)
# @echo 'Finished building target: $@'
# @echo ' '
#
# Other Targets
#clean:
# -$(RM) $(OBJS)$(C_DEPS)$(EXECUTABLES) aqualinkd
# -@echo ' '
#
#.PHONY: all clean dependents
#.SECONDARY:
#
#-include ../makefile.targets

View File

@ -63,6 +63,10 @@ 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.1
* Changed the way PDA mode will sleep.
* Added preliminary support for Variable Speed Pumps. (Limited to only reading status and post to MQTT/WebSocket/API if iAqualink is active on the RS485 bus)
* Added int status to Web API
## Update in Release 1.3.0
* Large update for PDA only control panels (Majority of this is ballle98 work)
* Can distinguish between AquaPalm and PDA supported control panels.

View File

@ -29,6 +29,11 @@
#define POOL_THERMO_TEMP_TOPIC BTN_POOL_HTR "/Temperature"
#define SPA_THERMO_TEMP_TOPIC BTN_SPA_HTR "/Temperature"
#define PUMP_TOPIC "Pump_"
#define PUMP_RPM_TOPIC "/RPM"
#define PUMP_GPH_TOPIC "/GPH"
#define PUMP_WATTS_TOPIC "/Watts"
/*
#define AIR_TEMPERATURE "Air"
#define POOL_TEMPERATURE "Pool_Water"

View File

@ -1153,7 +1153,7 @@ bool waitForEitherMessage(struct aqualinkdata *aq_data, char* message1, char* me
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
char* msgS1;
char* msgS2;
char* ptr;
char* ptr = NULL;
if (message1 != NULL) {
@ -1221,7 +1221,7 @@ bool waitForMessage(struct aqualinkdata *aq_data, char* message, int numMessageR
pthread_mutex_init(&aq_data->active_thread.thread_mutex, NULL);
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
char* msgS;
char* ptr;
char* ptr = NULL;
if (message != NULL) {
if (message[0] == '^')

View File

@ -140,6 +140,12 @@ const char* get_packet_type(unsigned char* packet , int length)
case CMD_PDA_HIGHLIGHTCHARS:
return "PDA C_HlightChar";
break;
case CMD_IAQ_MSG:
return "iAq Message";
break;
case CMD_IAQ_MENU_MSG:
return "iAq Menu";
break;
default:
sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]);
return buf;
@ -148,6 +154,68 @@ const char* get_packet_type(unsigned char* packet , int length)
}
// Generate and return checksum of packet.
int generate_checksum(unsigned char* packet, int length)
{
int i, sum, n;
n = length - 3;
sum = 0;
for (i = 0; i < n; i++)
sum += (int) packet[i];
return(sum & 0x0ff);
}
// Send an ack packet to the Aqualink RS8 master device.
// fd: the file descriptor of the serial port connected to the device
// command: the command byte to send to the master device, NUL if no command
//
// NUL = '\x00'
// DLE = '\x10'
// STX = '\x02'
// ETX = '\x03'
//
// masterAddr = '\x00' # address of Aqualink controller
//
//msg = DLE+STX+dest+cmd+args
//msg = msg+self.checksum(msg)+DLE+ETX
// DLE+STX+DEST+CMD+ARGS+CHECKSUM+DLE+ETX
void print_hex(char *pk, int length)
{
int i=0;
for (i=0;i<length;i++)
{
printf("0x%02hhx|",pk[i]);
}
printf("\n");
}
void test_cmd()
{
const int length = 11;
unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
//send_cmd(fd, CMD_ACK, command);
print_hex((char *)ackPacket, length);
ackPacket[7] = generate_checksum(ackPacket, length-1);
print_hex((char *)ackPacket, length);
ackPacket[6] = 0x02;
ackPacket[7] = generate_checksum(ackPacket, length-1);
print_hex((char *)ackPacket, length);
}
#ifndef PLAYBACK_MODE
/*
Open and Initialize the serial communications port to the Aqualink RS8 device.
Arg is tty or port designation string
@ -231,64 +299,6 @@ void close_serial_port(int fd)
logMessage(LOG_DEBUG_SERIAL, "Closed serial port\n");
}
// Generate and return checksum of packet.
int generate_checksum(unsigned char* packet, int length)
{
int i, sum, n;
n = length - 3;
sum = 0;
for (i = 0; i < n; i++)
sum += (int) packet[i];
return(sum & 0x0ff);
}
// Send an ack packet to the Aqualink RS8 master device.
// fd: the file descriptor of the serial port connected to the device
// command: the command byte to send to the master device, NUL if no command
//
// NUL = '\x00'
// DLE = '\x10'
// STX = '\x02'
// ETX = '\x03'
//
// masterAddr = '\x00' # address of Aqualink controller
//
//msg = DLE+STX+dest+cmd+args
//msg = msg+self.checksum(msg)+DLE+ETX
// DLE+STX+DEST+CMD+ARGS+CHECKSUM+DLE+ETX
void print_hex(char *pk, int length)
{
int i=0;
for (i=0;i<length;i++)
{
printf("0x%02hhx|",pk[i]);
}
printf("\n");
}
void test_cmd()
{
const int length = 11;
unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
//send_cmd(fd, CMD_ACK, command);
print_hex((char *)ackPacket, length);
ackPacket[7] = generate_checksum(ackPacket, length-1);
print_hex((char *)ackPacket, length);
ackPacket[6] = 0x02;
ackPacket[7] = generate_checksum(ackPacket, length-1);
print_hex((char *)ackPacket, length);
}
void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3)
{
const int length = 11;
@ -548,6 +558,72 @@ int get_packet(int fd, unsigned char* packet)
return index;
}
#else // PLAYBACK_MODE
#include <stdlib.h>
FILE *_fp;
int init_serial_port(char* file)
{
_fp = fopen ( file, "r" );
if ( _fp == NULL )
{
perror ( file ); /* why didn't the file open? */
return -1;
}
return 0;
}
void close_serial_port(int fd)
{
fclose(_fp);
}
int get_packet(int fd, unsigned char* packet_buffer)
{
int packet_length = 0;
char line[256];
char hex[6];
int i;
if ( fgets ( line, sizeof line, _fp ) != NULL ) /* read a line */
{
packet_length=0;
for (i=0; i < strlen(line); i=i+5)
{
strncpy(hex, &line[i], 4);
hex[5] = '\0';
packet_buffer[packet_length] = (int)strtol(hex, NULL, 16);
//printf("%s = 0x%02hhx = %c\n", hex, packet_buffer[packet_length], packet_buffer[packet_length]);
packet_length++;
}
packet_length--;
logMessage(LOG_DEBUG_SERIAL, "PLAYBACK read %d bytes\n",packet_length);
//printf("To 0x%02hhx, type %15.15s, length %2.2d ", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),packet_length);
//fputs ( line, stdout );
return packet_length;
}
return 0;
}
void send_extended_ack(int fd, unsigned char ack_type, unsigned char command)
{}
void send_ack(int fd, unsigned char command)
{}
void send_messaged(int fd, unsigned char destination, char *message)
{}
void send_command(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3)
{}
#endif // PLAYBACK_MODE
// Reads the bytes of the next incoming packet, and
// returns when a good packet is available in packet
// fd: the file descriptor to read the bytes from

View File

@ -16,6 +16,7 @@
#define DEV_MASTER 0x00
#define SWG_DEV_ID 0x50
#define IAQ_DEV_ID 0x33
// PACKET DEFINES
#define NUL 0x00
@ -184,6 +185,12 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define CMD_PDA_SHIFTLINES 0x0F
#define CMD_PDA_HIGHLIGHTCHARS 0x10
/* iAqualink */
#define CMD_IAQ_MSG 0x25
#define CMD_IAQ_MENU_MSG 0x24
typedef enum {
ON,
OFF,

View File

@ -19,6 +19,8 @@
//#define UNKNOWN TEMP_UNKNOWN
#define DATE_STRING_LEN 30
#define MAX_PUMPS 2
enum {
FAHRENHEIT,
CELSIUS,
@ -63,6 +65,13 @@ struct action {
//char value[10];
};
typedef struct pumpd
{
int rpm;
int gph;
int watts;
} pump_detail;
struct aqualinkdata
{
//char crap[AQ_MSGLEN];
@ -98,6 +107,8 @@ struct aqualinkdata
aqledstate service_mode_state;
aqledstate frz_protect_state;
unsigned char last_packet_type;
pump_detail pumps[MAX_PUMPS];
int open_websockets;
//bool last_msg_was_status;
//bool ar_swg_connected;
};

View File

@ -38,6 +38,7 @@
#include "net_services.h"
#include "pda_menu.h"
#include "pda.h"
#include "iAqualink_messages.h"
#include "version.h"
#define DEFAULT_CONFIG_FILE "./aqualinkd.conf"
@ -727,6 +728,7 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
/*
void debugPacketPrint(unsigned char ID, unsigned char *packet_buffer, int packet_length)
{
char buff[1000];
@ -791,6 +793,26 @@ void logPacket(unsigned char *packet_buffer, int packet_length)
debugPacketPrint(last_packet_buffer[PKT_DEST], packet_buffer, packet_length);
}
}
*/
void logPacket(unsigned char *packet_buffer, int packet_length)
{
char buff[1000];
int i = 0;
int cnt = 0;
cnt = sprintf(buff, "To 0x%02hhx of type %8.8s", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
cnt += sprintf(buff + cnt, " | HEX: ");
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);
}
#define MAX_BLOCK_ACK 12
#define MAX_BUSY_ACK (50 + MAX_BLOCK_ACK)
@ -842,7 +864,8 @@ void main_loop()
int rs_fd;
int packet_length;
unsigned char packet_buffer[AQ_MAXPKTLEN];
bool interestedInNextAck;
bool interestedInNextAck = false;
int i;
//int delayAckCnt = 0;
// NSF need to find a better place to init this.
@ -866,6 +889,13 @@ void main_loop()
_aqualink_data.frz_protect_state = OFF;
_aqualink_data.service_mode_state = OFF;
_aqualink_data.battery = OK;
_aqualink_data.open_websockets = 0;
for (i=0; i < MAX_PUMPS; i++) {
_aqualink_data.pumps[i].rpm = TEMP_UNKNOWN;
_aqualink_data.pumps[i].gph = TEMP_UNKNOWN;
_aqualink_data.pumps[i].watts = TEMP_UNKNOWN;
}
if (_config_parameters.force_swg == true)
_aqualink_data.swg_percent = 0;
@ -926,7 +956,8 @@ void main_loop()
{
blank_read = 0;
if (_config_parameters.debug_RSProtocol_packets) logPacket(packet_buffer, packet_length);
if (_config_parameters.debug_RSProtocol_packets || getLogLevel() >= LOG_DEBUG_SERIAL)
logPacket(packet_buffer, packet_length);
if (packet_length > 0 && packet_buffer[PKT_DEST] == _config_parameters.device_id)
{
@ -991,12 +1022,17 @@ void main_loop()
{
interestedInNextAck = false;
}
if (packet_buffer[PKT_DEST] == IAQ_DEV_ID && packet_buffer[PKT_CMD] == CMD_IAQ_MSG) {
if (processiAqualinkMsg(packet_buffer, packet_length, &_aqualink_data) != false)
broadcast_aqualinkstate(mgr.active_connections);
}
//}
// logMessage(LOG_DEBUG_SERIAL, "Received Packet for ID 0x%02hhx of type %s %s\n",packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),
// (packet_buffer[PKT_DEST] == _config_parameters.device_id)?" <-- Aqualinkd ID":"");
}
/*
if (getLogLevel() >= LOG_DEBUG_SERIAL) {
logMessage(LOG_DEBUG_SERIAL, "Received Packet for ID 0x%02hhx of type %s %s\n",packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),
(packet_buffer[PKT_DEST] == _config_parameters.device_id)?" <-- Aqualinkd ID":"");
}*/
}
mg_mgr_poll(&mgr, 0);

65
iAqualink_messages.c Normal file
View File

@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aqualink.h"
#include "iAqualink_messages.h"
#include "utils.h"
bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
{
bool changedAnything = false;
static char lastmessage[AQ_MSGLONGLEN];
//static char message[AQ_MSGLONGLEN + 1];
static int pumpIndex = 1;
/*
Pump type are like // Not sure how to read this accuratly.
"Jandy ePUMP 1"
"Intelliflo VS 1"
RPM message always comes after the above, so maybe saving last string
then when see RPM go back to get pump number.
' RPM: 2950'
' Watts: 1028'
' GPM: 1028'
*/
if (packet_buffer[9] == 'R' && packet_buffer[10] == 'P' && packet_buffer[11] == 'M' && packet_buffer[12] == ':') {
pumpIndex = atoi((char *) &lastmessage[14]);
if ( pumpIndex < MAX_PUMPS && pumpIndex < 0) {
pumpIndex = 1;
logMessage(LOG_ERR, "Can't find pump index for messsage '%.*s' in string '%.*s' using %d\n",AQ_MSGLEN, packet_buffer+4, AQ_MSGLEN, lastmessage, pumpIndex);
}
aqdata->pumps[pumpIndex-1].rpm = atoi((char *) &packet_buffer[13]);
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
changedAnything = true;
}
else if (packet_buffer[9] == 'G' && packet_buffer[10] == 'P' && packet_buffer[11] == 'H' && packet_buffer[12] == ':') {
aqdata->pumps[pumpIndex-1].gph = atoi((char *) &packet_buffer[13]);
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
changedAnything = true;
}
else if (packet_buffer[7] == 'W' && packet_buffer[8] == 'a' && packet_buffer[9] == 't' && packet_buffer[10] == 't' && packet_buffer[11] == 's' && packet_buffer[12] == ':') {
//printf("Punp %d, Watts = %d\n", pumpIndex, atoi((char *) &packet_buffer[13]));
aqdata->pumps[pumpIndex-1].watts = atoi((char *) &packet_buffer[13]);
logMessage(LOG_DEBUG, "Read message '%.*s' from iAqualink device\n",AQ_MSGLEN, packet_buffer+4);
changedAnything = true;
}
//printf("Message : '");
//fwrite(packet_buffer + 4, 1, packet_length-7, stdout);
//printf("'\n");
strncpy(lastmessage, (char *)&packet_buffer[4], packet_length-7);
return changedAnything;
}

9
iAqualink_messages.h Normal file
View File

@ -0,0 +1,9 @@
#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

@ -117,6 +117,28 @@ char *LED2text(aqledstate state)
}
}
int LED2int(aqledstate state)
{
switch (state) {
case ON:
return 1;
break;
case OFF:
return 0;
break;
case FLASH:
return 2;
break;
case ENABLE:
return 3;
break;
case LED_S_UNKNOWN:
default:
return 4;
break;
}
}
int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char* buffer, int size, bool homekit)
{
memset(&buffer[0], 0, size);
@ -138,7 +160,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
for (i=0; i < TOTAL_BUTTONS; i++)
{
if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0 && aqdata->pool_htr_set_point != TEMP_UNKNOWN) {
length += sprintf(buffer+length, "{\"type\": \"setpoint_thermo\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\" },",
length += sprintf(buffer+length, "{\"type\": \"setpoint_thermo\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
aqdata->aqbuttons[i].name,
aqdata->aqbuttons[i].label,
aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
@ -146,9 +168,10 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->pool_htr_set_point):aqdata->pool_htr_set_point),
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->pool_temp):aqdata->pool_temp));
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->pool_temp):aqdata->pool_temp),
LED2int(aqdata->aqbuttons[i].led->state));
} else if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name)==0 && aqdata->spa_htr_set_point != TEMP_UNKNOWN) {
length += sprintf(buffer+length, "{\"type\": \"setpoint_thermo\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\" },",
length += sprintf(buffer+length, "{\"type\": \"setpoint_thermo\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
aqdata->aqbuttons[i].name,
aqdata->aqbuttons[i].label,
aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
@ -156,24 +179,27 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->spa_htr_set_point):aqdata->spa_htr_set_point),
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->spa_temp):aqdata->spa_temp));
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->spa_temp):aqdata->spa_temp),
LED2int(aqdata->aqbuttons[i].led->state));
} else if (programable_switch > 0 && programable_switch == i) {
length += sprintf(buffer+length, "{\"type\": \"switch_program\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\" },",
length += sprintf(buffer+length, "{\"type\": \"switch_program\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" },",
aqdata->aqbuttons[i].name,
aqdata->aqbuttons[i].label,
aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
LED2text(aqdata->aqbuttons[i].led->state));
LED2text(aqdata->aqbuttons[i].led->state),
LED2int(aqdata->aqbuttons[i].led->state));
} else {
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\" },",
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" },",
aqdata->aqbuttons[i].name,
aqdata->aqbuttons[i].label,
aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
LED2text(aqdata->aqbuttons[i].led->state));
LED2text(aqdata->aqbuttons[i].led->state),
LED2int(aqdata->aqbuttons[i].led->state));
}
}
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) {
length += sprintf(buffer+length, "{\"type\": \"setpoint_freeze\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\" },",
length += sprintf(buffer+length, "{\"type\": \"setpoint_freeze\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
FREEZE_PROTECT,
"Freeze Protection",
//JSON_OFF,
@ -183,11 +209,12 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->frz_protect_set_point):aqdata->frz_protect_set_point),
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->air_temp):aqdata->air_temp));
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->air_temp):aqdata->air_temp),
aqdata->frz_protect_state==ON?1:0);
}
if ( aqdata->swg_percent != TEMP_UNKNOWN ) {
length += sprintf(buffer+length, "{\"type\": \"setpoint_swg\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\" },",
length += sprintf(buffer+length, "{\"type\": \"setpoint_swg\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
SWG_TOPIC,
"Salt Water Generator",
aqdata->ar_swg_status == 0x00?JSON_ON:JSON_OFF,
@ -195,7 +222,8 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
((homekit)?2:0),
((homekit)?degFtoC(aqdata->swg_percent):aqdata->swg_percent),
((homekit)?2:0),
((homekit)?degFtoC(aqdata->swg_percent):aqdata->swg_percent));
((homekit)?degFtoC(aqdata->swg_percent):aqdata->swg_percent),
aqdata->ar_swg_status == 0x00?1:0);
//length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%d\" },",
length += sprintf(buffer+length, "{\"type\": \"value\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"value\": \"%.*f\" },",
@ -236,6 +264,11 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
((homekit)?2:0),
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->air_temp):aqdata->spa_temp));
/*
length += sprintf(buffer+length, "], \"aux_device_detail\": [");
for (i=0; i < MAX_PUMPS; i++) {
}
*/
length += sprintf(buffer+length, "]}");
logMessage(LOG_DEBUG, "WEB: homebridge used %d of %d", length, size);
@ -309,7 +342,7 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
length += sprintf(buffer+length, ",\"leds\":{" );
for (i=0; i < TOTAL_BUTTONS; i++)
{
char *state;
char *state = JSON_OFF;
switch (aqdata->aqbuttons[i].led->state)
{
case ON:
@ -340,6 +373,17 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, aqdata->frz_protect_state==ON?JSON_ON:JSON_ENABLED);
}
length += sprintf(buffer+length, "}, \"extra\":{" );
for (i=0; i < MAX_PUMPS; i++) {
if (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gph != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN) {
length += sprintf(buffer+length, "\"Pump_%d\":{\"RPM\":\"%d\",\"GPH\":\"%d\",\"WATTS\":\"%d\"},",i+1,aqdata->pumps[i].rpm,aqdata->pumps[i].gph,aqdata->pumps[i].watts);
}
}
if (buffer[length-1] == ',')
length--;
length += sprintf(buffer+length, "}}" );
buffer[length] = '\0';

97
log_reader.c Normal file
View File

@ -0,0 +1,97 @@
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "aq_serial.h"
#include "utils.h"
void logiAqualinkMsg(unsigned char *packet_buffer, int packet_length) {
static int pumpIndex = 0;
/*
Pump type are like // Not sure how to read this accuratly.
"Jandy ePUMP 1"
"Intelliflo VS 1"
RPM message always comes after the above, so maybe saving last string
then when see RPM go back to get pump number.
' RPM: 2950'
' Watts: 1028'
*/
if (packet_buffer[9] == 'R' && packet_buffer[10] == 'P' && packet_buffer[11] == 'M' && packet_buffer[12] == ':')
printf("RPM = %d\n", atoi((char *) &packet_buffer[13]));
else if (packet_buffer[7] == 'W' && packet_buffer[8] == 'a' && packet_buffer[9] == 't' && packet_buffer[10] == 't' && packet_buffer[11] == 's' && packet_buffer[12] == ':')
printf("Watts = %d\n", atoi((char *) &packet_buffer[13]));
}
int main(int argc, char *argv[]) {
//unsigned char packet_buffer[10];
unsigned char packet_buffer[AQ_MAXPKTLEN];
int packet_length = 0;
char hex[5];
int i;
//int num;
//int pi;
if (argc < 1 || access( argv[1], F_OK ) == -1 ) {
fprintf(stderr, "ERROR, first param must be valid log file\n");
return 1;
}
FILE *file = fopen ( argv[1], "r" );
if ( file == NULL )
{
perror ( argv[1] ); /* why didn't the file open? */
return 1;
}
char line [ 128 ]; /* or other suitable maximum line size */
while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
{
packet_length=0;
for (i=0; i < strlen(line); i=i+5)
{
strncpy(hex, &line[i], 4);
hex[5] = '\0';
packet_buffer[packet_length] = (int)strtol(hex, NULL, 16);
//printf("%s = 0x%02hhx = %c\n", hex, packet_buffer[packet_length], packet_buffer[packet_length]);
packet_length++;
}
packet_length--;
if (packet_buffer[PKT_DEST] == 0x33 && packet_buffer[PKT_CMD] == 0x25)
logiAqualinkMsg(packet_buffer, packet_length);
//if (packet_buffer[PKT_CMD] == 0x24 || packet_buffer[PKT_CMD] == 0x25) {
printf("To 0x%02hhx, type %15.15s, length %2.2d ", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),packet_length);
fputs ( line, stdout );
//printf("Message : '");
//fwrite(packet_buffer + 4, 1, packet_length-7, stdout);
//printf("'\n");
//}
}
fclose ( file );
return 0;
}
/*
*** NOTES ***
iAqualink is ID 0x33
Two TEXT Message Types 0x24 & 0x25
0x24 seems to be menu options
0x25 seems to be status messages
*/

View File

@ -194,6 +194,17 @@ void send_mqtt_state_msg(struct mg_connection *nc, char *dev_name, aqledstate st
send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON));
}
void send_mqtt_aux_msg(struct mg_connection *nc, char *root_topic, int dev_index, char *dev_topic, int value)
{
static char mqtt_pub_topic[250];
static char msg[10];
sprintf(msg, "%d", value);
sprintf(mqtt_pub_topic, "%s/%s%d%s",_aqualink_config->mqtt_aq_topic, root_topic, dev_index, dev_topic);
send_mqtt(nc, mqtt_pub_topic, msg);
}
void send_mqtt_heater_state_msg(struct mg_connection *nc, char *dev_name, aqledstate state)
{
@ -513,6 +524,27 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
send_domoticz_mqtt_state_msg(nc, _aqualink_data->aqbuttons[i].dz_idx, (_aqualink_data->aqbuttons[i].led->state==OFF?DZ_OFF:DZ_ON));
}
}
// Loop over Pumps
for (i=0; i < MAX_PUMPS; i++) {
//_aqualink_data->pumps[i].rpm = TEMP_UNKNOWN;
//_aqualink_data->pumps[i].gph = TEMP_UNKNOWN;
//_aqualink_data->pumps[i].watts = TEMP_UNKNOWN;
if (_aqualink_data->pumps[i].rpm != TEMP_UNKNOWN && _aqualink_data->pumps[i].rpm != _last_mqtt_aqualinkdata.pumps[i].rpm) {
_last_mqtt_aqualinkdata.pumps[i].rpm = _aqualink_data->pumps[i].rpm;
send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_RPM_TOPIC, _aqualink_data->pumps[i].rpm);
}
if (_aqualink_data->pumps[i].gph != TEMP_UNKNOWN && _aqualink_data->pumps[i].gph != _last_mqtt_aqualinkdata.pumps[i].gph) {
_last_mqtt_aqualinkdata.pumps[i].gph = _aqualink_data->pumps[i].gph;
send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_GPH_TOPIC, _aqualink_data->pumps[i].gph);
}
if (_aqualink_data->pumps[i].watts != TEMP_UNKNOWN && _aqualink_data->pumps[i].watts != _last_mqtt_aqualinkdata.pumps[i].watts) {
_last_mqtt_aqualinkdata.pumps[i].watts = _aqualink_data->pumps[i].watts;
send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_WATTS_TOPIC, _aqualink_data->pumps[i].watts);
}
}
/*
// Loop over LED's and send any changes.
for (i=0; i < TOTAL_BUTTONS; i++) {
@ -1046,6 +1078,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
//nc->user_data = WS;
_aqualink_data->open_websockets++;
logMessage(LOG_DEBUG, "++ Websocket joined\n");
break;
@ -1056,6 +1089,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
case MG_EV_CLOSE:
if (is_websocket(nc)) {
_aqualink_data->open_websockets--;
logMessage(LOG_DEBUG, "-- Websocket left\n");
} else if (is_mqtt(nc)) {
logMessage(LOG_WARNING, "MQTT Connection closed\n");

57
pda.c
View File

@ -18,17 +18,43 @@ static unsigned long _pda_loop_cnt = 0;
static bool _initWithRS = false;
// Each RS message is around 0.5 seconds apart, so 2 mins = 120 seconds = 240 polls
#define PDA_LOOP_COUNT 240 // 2 mins in poll (sleep timer)
//#define PDA_LOOP_COUNT 240 // 2 mins in poll (sleep timer)
#define PDA_SLEEP_FOR 60 // 30 seconds
#define PDA_WAKE_FOR 6 // 3 seconds
void init_pda(struct aqualinkdata *aqdata)
{
_aqualink_data = aqdata;
set_pda_mode(true);
//clock_gettime(CLOCK_REALTIME, &_aqualink_data->last_active_time);
//aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data); // NEED TO MOVE THIS. Can't run this here incase serial connection fails / needs to be cleaned up.
}
bool pda_shouldSleep() {
//logMessage(LOG_DEBUG, "PDA loop count %d, will sleep at %d\n",_pda_loop_cnt,PDA_LOOP_COUNT);
if (_pda_loop_cnt++ < PDA_WAKE_FOR) {
return false;
} else if (_pda_loop_cnt > PDA_WAKE_FOR + PDA_SLEEP_FOR) {
_pda_loop_cnt = 0;
return false;
}
// NSF NEED TO CHECK ACTIVE THREADS.
if (_aqualink_data->active_thread.thread_id != 0) {
logMessage(LOG_DEBUG, "PDA can't sleep as thread is active");
_pda_loop_cnt = 0;
return false;
}
// Last see if there are any open websockets. (don't sleep if the web UI is open)
if ( _aqualink_data->open_websockets > 0 ) {
logMessage(LOG_DEBUG, "PDA can't sleep as websocket is active");
return false;
}
return true;
}
/*
bool pda_shouldSleep() {
//logMessage(LOG_DEBUG, "PDA loop count %d, will sleep at %d\n",_pda_loop_cnt,PDA_LOOP_COUNT);
if (_pda_loop_cnt++ < PDA_LOOP_COUNT) {
@ -40,6 +66,7 @@ bool pda_shouldSleep() {
return true;
}
*/
void pda_wake() {
pda_reset_sleep();
@ -396,12 +423,6 @@ bool process_pda_packet(unsigned char *packet, int length)
int i;
char *msg;
static bool init = false;
static time_t _lastStatus = 0;
if (_lastStatus == 0)
{
time(&_lastStatus);
}
process_pda_menu_packet(packet, length);
@ -454,21 +475,7 @@ bool process_pda_packet(unsigned char *packet, int length)
{
pass_pda_equiptment_status_item(pda_m_line(i));
}
time(&_lastStatus);
}
else
{
time_t now;
time(&now);
if (init && difftime(now, _lastStatus) > 60)
{
logMessage(LOG_DEBUG, "OVER 60 SECONDS SINCE LAST STATUS UPDATE, forcing refresh\n");
// Reset aquapure to nothing since it must be off at this point
_aqualink_data->pool_temp = TEMP_UNKNOWN;
_aqualink_data->spa_temp = TEMP_UNKNOWN;
time(&_lastStatus);
aq_programmer(AQ_PDA_DEVICE_STATUS, NULL, _aqualink_data);
}
}
if (pda_m_type() == PM_FREEZE_PROTECT_DEVICES)
{
@ -556,4 +563,4 @@ bool process_pda_packet(unsigned char *packet, int length)
kick_aq_program_thread(_aqualink_data);
}
return rtn;
}
}

View File

@ -1,313 +0,0 @@
#define _GNU_SOURCE // for strcasestr
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pda_menu.h"
#include "aq_serial.h"
#include "utils.h"
#define SLOG_MAX 80
#define PACKET_MAX 600
/*
typedef enum used {
yes,
no,
unknown
} used;
*/
#define PDA_ID 0x60
//#define PDA_ID 0x58
#define PDA_LINES 10 // There is only 9 lines, but add buffer to make shifting easier
/*
typedef struct serial_id_log {
unsigned char ID;
bool inuse;
} serial_id_log;
*/
bool _keepRunning = true;
//int _lineindex = -1;
//char _menu[PDA_LINES][AQ_MSGLEN+1];
//bool _readMenu = false;
//unsigned char _goodID[] = {0x0a, 0x0b, 0x08, 0x09};
unsigned char _filter = PDA_ID;
void intHandler(int dummy) {
_keepRunning = false;
logMessage(LOG_NOTICE, "Stopping!");
}
/*
bool canUse(unsigned char ID) {
int i;
for (i = 0; i < strlen((char *)_goodID); i++) {
if (ID == _goodID[i])
return true;
}
return false;
}
*/
void printHex(char *pk, int length)
{
int i=0;
for (i=0;i<length;i++)
{
printf("0x%02hhx|",pk[i]);
}
}
void printPacket(unsigned char ID, unsigned char *packet_buffer, int packet_length)
{
//if (_filter != 0x00 && ID != _filter && packet_buffer[PKT_DEST] != _filter )
// return;
if (_filter != 0x00) {
if ( packet_buffer[PKT_DEST]==0x00 && ID != _filter )
return;
if ( packet_buffer[PKT_DEST]!=0x00 && packet_buffer[PKT_DEST] != _filter )
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));
printf(" | HEX: ");
printHex((char *)packet_buffer, packet_length);
if (packet_buffer[PKT_CMD] == CMD_MSG || packet_buffer[PKT_CMD] == CMD_MSG_LONG) {
printf(" Message : ");
//fwrite(packet_buffer + 4, 1, AQ_MSGLEN+1, stdout);
fwrite(packet_buffer + 4, 1, packet_length-7, stdout);
}
//if (packet_buffer[PKT_DEST]==0x00)
// printf("\n\n");
//else
printf("\n");
}
/*
int addLine(unsigned char *packet_buffer)
{
//strcpy (_menu[20], ;
if (packet_buffer[PKT_DATA] < 10) {
memset(_menu[packet_buffer[PKT_DATA]], 0, AQ_MSGLEN);
strncpy(_menu[packet_buffer[PKT_DATA]], (char*)packet_buffer+PKT_DATA+1, AQ_MSGLEN);
_menu[packet_buffer[PKT_DATA]][AQ_MSGLEN+1] = '\0';
//printf ("Added line\n");
} else if (packet_buffer[PKT_DATA] == 0x82) {
printf("AIR TEMP = %s\n",(char*)packet_buffer+PKT_DATA+1);
} else if (packet_buffer[PKT_DATA] == 0x40) {
printf("TIME = %s\n",(char*)packet_buffer+PKT_DATA+1);
}
{
int i;
for (i=0; i < PDA_LINES; i++)
printf("Line %d = %s\n",i,_menu[i]);
printf("Highlight = %d = %s\n",_lineindex,_menu[_lineindex]);
}
return 0;
}
*/
/*
Line 2 = AquaPure 60%
Line 3 = SALT 3200 PPM
Line 4 = FILTER PUMP
Line 5 = SPA HEAT ENA
Line 4 = POOL MODE ON
Line 5 = POOL HEATER OFF
Line 6 = SPA MODE OFF
Line 7 = SPA HEATER OFF
Line 1 = FILTER PUMP ON
Line 2 = SPA OFF
Line 3 = POOL HEAT OFF
Line 4 = SPA HEAT OFF
Line 5 = CLEANER ON
Line 6 = AUX2 OFF
Line 7 = AUX3 OFF
Line 8 = AUX4 OFF
*/
bool process_pda_packet(unsigned char* packet, int length)
{
bool rtn = true;
process_pda_menu_packet(packet, length);
switch (packet[PKT_CMD]) {
case CMD_MSG_LONG: {
char *msg = (char*)packet+PKT_DATA+1;
if (packet[PKT_DATA] == 0x82) { // Air & Water temp is always this ID
// message = "73` 66`"
//_aqualink_data.temp_units = FAHRENHEIT; // Force FAHRENHEIT
//_aqualink_data.air_temp = atoi(msg);
//_aqualink_data.pool_temp = atoi(msg+7);
printf("Air Temp = %d | Water Temp = %d\n",atoi(msg),atoi(msg+7));
} else if (packet[PKT_DATA] == 0x40) {
// message " SAT 8:46AM"
//NSF strcpy(_aqualink_data.time, msg);
if (msg[8] == ' ')
printf("TIME = %.*s\n",6,msg+9);
else
printf("TIME = %.*s\n",7,msg+8);
// NSF strcpy(_aqualink_data.date, msg);
if (msg[4] == ' ')
printf("DAY = %.*s\n",3,msg+5);
else
printf("DAY = %.*s\n",3,msg+4);
// NSF Come back and change the above to correctly check date and time in future
} else if (pda_m_hlightindex() == -1) { // There is a chance this is a message we are interested in.
char *index;
if( (index = strcasestr(msg, MSG_SWG_PCT)) != NULL) {
int aq = atoi(index + strlen(MSG_SWG_PCT));
printf("Aquapure PERCENT message %d\n", aq);
}
if( (index = strcasestr(msg, MSG_SWG_PPM)) != NULL) {
int aq = atoi(index + strlen(MSG_SWG_PPM));
printf("Aquapure SALT message %d\n", aq);
}
} else if (strcmp(pda_m_line(0), " EQUIPMENT ") != 0) {
// Check message for status of device
}
}
break;
}
return rtn;
}
int main(int argc, char *argv[]) {
int rs_fd;
int packet_length;
unsigned char packet_buffer[AQ_MAXPKTLEN];
unsigned char lastID;
int i = 0;
//bool found;
//serial_id_log slog[SLOG_MAX];
//int sindex = 0;
int received_packets = 0;
int logPackets = PACKET_MAX;
int logLevel = LOG_NOTICE;
unsigned char NextMsg = NUL;
//int logLevel;
//char buffer[256];
//bool idMode = true;
if (getuid() != 0) {
fprintf(stderr, "ERROR %s Can only be run as root\n", argv[0]);
return EXIT_FAILURE;
}
if (argc < 2 || access( argv[1], F_OK ) == -1 ) {
fprintf(stderr, "ERROR, first param must be valid serial port, ie:-\n\t%s /dev/ttyUSB0\n\n", argv[0]);
fprintf(stderr, "Optional parameters are -d (debug) & -p <number> (log # packets) & -i <ID> ie:=\n\t%s /dev/ttyUSB0 -d -p 1000 -i 0x08\n\n", argv[0]);
return 1;
}
for (i = 2; i < argc; i++) {
if (strcmp(argv[i], "-d") == 0) {
logLevel = LOG_DEBUG;
} else if (strcmp(argv[i], "-p") == 0 && i+1 < argc) {
logPackets = atoi(argv[i+1]);
} else if (strcmp(argv[i], "-i") == 0 && i+1 < argc) {
unsigned int n;
sscanf(argv[i+1], "0x%2x", &n);
_filter = n;
logLevel = LOG_DEBUG; // no point in filtering on ID if we're not going to print it.
}
}
setLoggingPrms(logLevel, false, false);
rs_fd = init_serial_port(argv[1]);
signal(SIGINT, intHandler);
signal(SIGTERM, intHandler);
logMessage(LOG_NOTICE, "Logging serial information!\n");
if (logLevel < LOG_DEBUG)
printf("Please wait.");
while (_keepRunning == true) {
if (rs_fd < 0) {
logMessage(LOG_ERR, "ERROR, serial port disconnect\n");
}
packet_length = get_packet(rs_fd, packet_buffer);
if (packet_length == -1) {
// Unrecoverable read error. Force an attempt to reconnect.
logMessage(LOG_ERR, "ERROR, on serial port\n");
_keepRunning = false;
} else if (packet_length == 0) {
// Nothing read
} else if (packet_length > 0) {
//logMessage(LOG_DEBUG_SERIAL, "Received Packet for ID 0x%02hhx of type %s\n", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
if (logLevel > LOG_NOTICE)
printPacket(lastID, packet_buffer, packet_length);
if (packet_buffer[PKT_DEST] == PDA_ID) {
if (packet_buffer[PKT_CMD] == CMD_STATUS) {
send_extended_ack(rs_fd, 0x40, NextMsg);
NextMsg = NUL;
} else {
//printf("****** Send ACK *******\n");
send_extended_ack(rs_fd, ACK_PDA, NUL);
}
process_pda_packet(packet_buffer, packet_length);
switch (packet_buffer[PKT_CMD]) {
case CMD_MSG_LONG:
if (strcasestr(pda_m_line(0), "EQUIPMENT STATUS") != NULL) {
//NextMsg = KEY_PDA_BACK;
//printf("****** queue BACK *******\n");
}
//if (_readMenu)
// addLine(packet_buffer);
break;
}
}
char *selection = pda_m_hlight();
if (selection != NULL && strcmp(selection, "EQUIPMENT ON/OFF") != 0) {
NextMsg = KEY_PDA_DOWN;
} else if (selection != NULL && strcmp(selection, "EQUIPMENT ON/OFF") == 0) {
NextMsg = KEY_PDA_SELECT;
}
lastID = packet_buffer[PKT_DEST];
received_packets++;
}
if (logPackets != 0 && received_packets >= logPackets) {
_keepRunning = false;
}
//sleep(1);
}
return 0;
}

Binary file not shown.

BIN
release/aqualinkd-player Executable file

Binary file not shown.

View File

@ -19,13 +19,13 @@ web_directory=/nas/data/Development/Raspberry/AqualinkD/web
# DEBUG would print everything possible
#log_level=DEBUG_SERIAL
#log_level=DEBUG
log_level=INFO
log_level=DEBUG
#log_level=INFO
#log_level=NOTICE
# The socket port that the daemon listens to
# If you change this from 80, remember to update aqualink.service.avahi
socket_port=80
socket_port=88
# The serial port the daemon access to read the Aqualink RS8
serial_port=/dev/ttyUSB0
@ -54,8 +54,6 @@ pda_sleep_mode = yes
convert_mqtt_temp_to_c = yes
convert_dz_temp_to_c = yes
# Bug, leave at no for the moment
flash_mqtt_buttons = yes
# by default use pool temp as spa temp when spa is off, enable below to report 0 as spa temp when off.
report_zero_spa_temp = yes

BIN
release/log_reader Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -137,7 +137,7 @@ int main(int argc, char *argv[]) {
int rs_fd;
int packet_length;
unsigned char packet_buffer[AQ_MAXPKTLEN];
unsigned char lastID;
unsigned char lastID = 0x00;
int i = 0;
bool found;
serial_id_log slog[SLOG_MAX];

View File

@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
#define AQUALINKD_VERSION "1.3.0"
#define AQUALINKD_VERSION "1.3.1"

View File

@ -1106,6 +1106,14 @@
for (var obj in data.leds) {
setTileOn(obj.toString(), data.leds[obj])
}
// NSF Really quick hack to show RPM on filter pump. Need to come back and do this correctly.
if (typeof data.extra["Pump_1"].RPM !== 'undefined') {
console.log(data.extra["Pump_1"].RPM);
if (document.getElementById('Filter_Pump').getAttribute('status') == 'on') {
document.getElementById('Filter_Pump_status').innerHTML = 'RPM:'+data.extra["Pump_1"].RPM;
}
}
}
function deviceSort(a, b) {