pull/116/head
shaun feakes 2020-05-31 19:35:17 -05:00
parent 03a9b62ca1
commit fcd828c818
37 changed files with 3093 additions and 861 deletions

View File

@ -11,9 +11,10 @@ LIBS := -l pthread -l m
#LIBS := -lpthread -lwebsockets
# debug of not
#DBG = -g -O0 -fsanitize=address -static-libasan
#DBG = -g
DBG =
#DBG = -g -O0 -fsanitize=address
DBG = -g
#DBG = -D ONETOUCH
#DBG =
# USe below to remove unused functions and global variables.
#LFLAGS = -Wl,--gc-sections,--print-gc-sections
@ -32,7 +33,7 @@ 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 aquapure.c packetLogger.c pentair_messages.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 aquapure.c onetouch.c onetouch_aq_programmer.c packetLogger.c pentair_messages.c mongoose.c
DBG_SRC = timespec_subtract.c
# If run with `make DEBUG=true` add debug files and pass parameter for compile

View File

@ -65,11 +65,17 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
* http://aqualink.ip/ <- (Standard WEB UI
* 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)
* http://aqualink.ip/debug.html <- (Turn on/off debug/serial debug & download logs)
#<a name="release"></a>
# Update in Release 1.3.9b
* Small fixes for Jandy protocol.
* Fixed some debug messages.
# Update in Release 1.3.9
# Update in Release 2.0.0a
* Big update, lots of core changes, <b>please read wiki section https://github.com/sfeakes/AqualinkD/wiki/Version_2</b>
* Full Variable Speed Pump support.
* Please consider this ALPHA version, no need to upgrade unless you need VSP support. Use a previous version unless you want VSP.
* I've noticed there is an issues with colored lights if your light is configured as such in the control panel. For this release suggest you either :-
* A) use AqualinkD to control the colors and configure Jandy control panel as normal light
* B) Don't use AqualinkD to turn light on/off (or if you do, wait ~10 seconds)
# Update in Release 1.3.9a
* Improved Debugging for serial.
* Added panel Timeout mode support to UI and MQTT
* Fixed SWG bug while in Service & Timeout modes
* Cleanded up SWG code and MQTT status messages for SWG and SWG/enabled

BIN
a.out Executable file

Binary file not shown.

View File

@ -33,7 +33,7 @@
//#define PUMP_TOPIC "Pump_"
#define PUMP_RPM_TOPIC "/RPM"
#define PUMP_GPH_TOPIC "/GPH"
#define PUMP_GPM_TOPIC "/GPM"
#define PUMP_WATTS_TOPIC "/Watts"
/*
#define AIR_TEMPERATURE "Air"

View File

@ -30,6 +30,7 @@
#include "pda_menu.h"
#include "init_buttons.h"
#include "pda_aq_programmer.h"
#include "onetouch_aq_programmer.h"
#ifdef AQ_DEBUG
#include <time.h>
@ -56,6 +57,9 @@ void *set_aqualink_light_colormode( void *ptr );
void *set_aqualink_PDA_init( void *ptr );
void *set_aqualink_SWG( void *ptr );
void *set_aqualink_boost( void *ptr );
void *set_aqualink_pump_rpm( void *ptr );
void *set_aqualink_onetouch_macro( void *ptr );
void *get_aqualink_onetouch_setpoints( void *ptr );
//void *get_aqualink_PDA_device_status( void *ptr );
//void *set_aqualink_PDA_device_on_off( void *ptr );
@ -67,12 +71,14 @@ bool waitForEitherMessage(struct aqualinkdata *aq_data, char* message1, char* me
bool push_aq_cmd(unsigned char cmd);
void waitfor_queue2empty();
void longwaitfor_queue2empty();
#define MAX_STACK 20
int _stack_place = 0;
unsigned char _commands[MAX_STACK];
//unsigned char pgm_commands[MAX_STACK];
unsigned char _pgm_command = NUL;
//unsigned char _ot_pgm_command = NUL;
bool _last_sent_was_cmd = false;
@ -81,6 +87,23 @@ void aq_send_cmd(unsigned char cmd) {
push_aq_cmd(cmd);
}
/*
void ot_send_cmd(unsigned char cmd) {
_ot_pgm_command = cmd;
}
unsigned char pop_ot_cmd(unsigned char receive_type)
{
unsigned char cmd = NUL;
if (receive_type == CMD_STATUS) {
cmd = _ot_pgm_command;
_ot_pgm_command = NUL;
}
return cmd;
}
*/
bool push_aq_cmd(unsigned char cmd) {
//logMessage(LOG_DEBUG, "push_aq_cmd '0x%02hhx'\n", cmd);
@ -102,17 +125,47 @@ int get_aq_cmd_length()
}
unsigned char pop_aq_cmd(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
// Only send commands on status messages
// Are we in programming mode and it's not ONETOUCH programming mode
if (aq_data->active_thread.thread_id != 0 && in_ot_programming_mode(aq_data) == false ) {
//if (aq_data->active_thread.thread_id != 0) {
if ( _pgm_command != NUL && aq_data->last_packet_type == CMD_STATUS) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG_SERIAL, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);
} else if (_pgm_command != NUL) {
logMessage(LOG_DEBUG_SERIAL, "RS Waiting to send cmd '0x%02hhx' (programming)\n", _pgm_command);
} else {
logMessage(LOG_DEBUG_SERIAL, "RS SEND cmd '0x%02hhx' empty queue (programming)\n", cmd);
}
} else if (_stack_place > 0 && aq_data->last_packet_type == CMD_STATUS ) {
cmd = _commands[0];
_stack_place--;
logMessage(LOG_DEBUG_SERIAL, "RS SEND cmd '0x%02hhx'\n", cmd);
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _stack_place ) ;
} else {
logMessage(LOG_DEBUG_SERIAL, "RS SEND cmd '0x%02hhx'\n", cmd);
}
//printf("RSM sending cmd '0x%02hhx' in reply to '0x%02hhx'\n",cmd,aq_data->last_packet_type);
return cmd;
}
/*
unsigned char pop_aq_cmd_OLD(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
// Only send commands on status messages
// Are we in programming mode
if (aq_data->active_thread.thread_id != 0) {
/*if ( (_pgm_command == KEY_MENU && aq_data->last_packet_type == CMD_STATUS) ||
if ( (_pgm_command == KEY_MENU && aq_data->last_packet_type == CMD_STATUS) ||
// Need to not the key_menu below
( _pgm_command != NUL && (aq_data->last_packet_type == CMD_STATUS || aq_data->last_packet_type == CMD_MSG_LONG) )) {*/
if ( (_pgm_command != NUL && (aq_data->last_packet_type == CMD_STATUS)) ||
// Boost pool has to send commands to msg long
(aq_data->active_thread.ptype == AQ_SET_BOOST && (aq_data->last_packet_type == CMD_STATUS || aq_data->last_packet_type == CMD_MSG_LONG)) ) {
( _pgm_command != NUL && (aq_data->last_packet_type == CMD_STATUS || aq_data->last_packet_type == CMD_MSG_LONG) )) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);
@ -134,95 +187,39 @@ unsigned char pop_aq_cmd(struct aqualinkdata *aq_data)
return cmd;
}
//unsigned char pop_aq_cmd_old(struct aqualinkdata *aq_data);
unsigned char pop_aq_cmd_XXXXXX(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
static bool last_sent_was_cmd = false;
// USE BELOW IF PDA HAS ISSUES WITH NEW COMMAND LOGIC
//if ( pda_mode() == true ) {
// return pop_aq_cmd_old(aq_data);
//}
// Only press menu to a status command
// Only send commands on status messages when programming date
// Otherwise send every other command.
// Are we in programming mode
if (aq_data->active_thread.thread_id != 0) {
if ( ((_pgm_command == KEY_MENU || aq_data->active_thread.ptype == AQ_SET_TIME) && aq_data->last_packet_type == CMD_STATUS) ||
(pda_mode() == false && aq_data->active_thread.ptype != AQ_SET_TIME && last_sent_was_cmd == false) ||
(pda_mode() == true && aq_data->last_packet_type == CMD_STATUS)
//(pda_mode() == true && last_sent_was_cmd == false)
) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);
/*} else if (aq_data->active_thread.ptype != AQ_SET_TIME && last_sent_was_cmd == false) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);*/
} else if (_pgm_command != NUL) {
logMessage(LOG_DEBUG, "RS Waiting to send cmd '0x%02hhx' (programming)\n", _pgm_command);
} else {
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' empty queue (programming)\n", cmd);
}
} else if (_stack_place > 0 && aq_data->last_packet_type == CMD_STATUS ) {
cmd = _commands[0];
_stack_place--;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx'\n", cmd);
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _stack_place ) ;
} else {
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx'\n", cmd);
}
if (cmd == NUL)
last_sent_was_cmd= false;
else
last_sent_was_cmd= true;
return cmd;
}
unsigned char pop_aq_cmd_old(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
//logMessage(LOG_DEBUG, "pop_aq_cmd\n");
// can only send a command every other ack.
if (_last_sent_was_cmd == true) {
_last_sent_was_cmd= false;
}
else if (aq_data->active_thread.thread_id != 0) {
cmd = _pgm_command;
_pgm_command = NUL;
//logMessage(LOG_DEBUG, "pop_aq_cmd '0x%02hhx' (programming)\n", cmd);
}
else if (_stack_place > 0) {
cmd = _commands[0];
_stack_place--;
//logMessage(LOG_DEBUG, "pop_aq_cmd '0x%02hhx'\n", cmd);
//memcpy(&_commands[0], &_commands[1], (sizeof(unsigned char) * MAX_STACK) - 1);
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _stack_place ) ;
}
if (cmd == NUL)
_last_sent_was_cmd= false;
else
_last_sent_was_cmd= true;
return cmd;
}
*/
int roundTo(int num, int denominator) {
return ((num + (denominator/2) ) / denominator )* denominator;
}
//(Intelliflo VF you set GPM, not RPM)
int RPM_check(pump_type type, int value, struct aqualinkdata *aqdata)
{
int rtn = value;
// RPM 3450 seems to be max
// RPM 600 min
// GPM 130 max
// GPM 15 min
if (type == VFPUMP) {
if (rtn > 130)
rtn = 130;
else if (rtn < 15)
rtn = 15;
else
rtn = roundTo(rtn, 5);
} else {
if (rtn > 3450)
rtn = 3450;
else if (rtn < 600)
rtn = 600;
else
rtn = roundTo(rtn, 5);
}
return rtn;
}
int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
{
int rtn = value;
@ -303,6 +300,28 @@ int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
return rtn;
}
void queueGetExtendedProgramData(emulation_type source_type, struct aqualinkdata *aq_data, bool labels)
{
// Wait for onetouch if enabeled.
if ( source_type == ALLBUTTON && ( onetouch_enabled() == false || extended_device_id_programming() == false ) ) {
aq_send_cmd(NUL);
aq_programmer(AQ_GET_POOL_SPA_HEATER_TEMPS, NULL, aq_data);
aq_programmer(AQ_GET_FREEZE_PROTECT_TEMP, NULL, aq_data);
if (labels)
aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data);
} else if ( source_type == ONETOUCH) {
aq_programmer(AQ_GET_ONETOUCH_SETPOINTS, NULL, aq_data);
} else if ( source_type == AQUAPDA) {
aq_programmer(AQ_PDA_INIT, NULL, aq_data);
}
}
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data)
{
queueGetExtendedProgramData(source_type, aq_data, false);
}
/*
void kick_aq_program_thread(struct aqualinkdata *aq_data)
{
if (aq_data->active_thread.thread_id != 0) {
@ -310,11 +329,78 @@ void kick_aq_program_thread(struct aqualinkdata *aq_data)
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
}
*/
bool in_ot_programming_mode(struct aqualinkdata *aq_data)
{
//( type != AQ_SET_PUMP_RPM || type != AQ_SET_OT_MACRO )) {
void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data)
if ( ( aq_data->active_thread.thread_id != 0 ) &&
( aq_data->active_thread.ptype == AQ_SET_ONETOUCH_PUMP_RPM ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_MACRO ||
aq_data->active_thread.ptype == AQ_GET_ONETOUCH_SETPOINTS ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_TIME ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_SWG_PERCENT ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_BOOST ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_POOL_HEATER_TEMP ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_SPA_HEATER_TEMP ||
aq_data->active_thread.ptype == AQ_SET_ONETOUCH_FREEZEPROTECT)
) {
return true;
}
return false;
}
void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_type)
{
if ( aq_data->active_thread.thread_id != 0 ) {
if ( (source_type == ONETOUCH) && in_ot_programming_mode(aq_data))
{
logMessage(LOG_DEBUG, "Kicking OneTouch thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
else if (source_type == AQUAPDA && !in_ot_programming_mode(aq_data)) {
logMessage(LOG_DEBUG, "Kicking PDA thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
else if (source_type == ALLBUTTON && !in_ot_programming_mode(aq_data)) {
logMessage(LOG_DEBUG, "Kicking RS thread %d,%p message '%s'\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id,aq_data->last_message);
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
}
}
void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data)
{
struct programmingThreadCtrl *programmingthread = malloc(sizeof(struct programmingThreadCtrl));
program_type type = r_type;
// reset any types if to onetouch if available and if one touch is quicker
// At moment. onetouch is quicker for boost, and slower for heaters
if (onetouch_enabled() && extended_device_id_programming()) {
switch (r_type){
case AQ_GET_POOL_SPA_HEATER_TEMPS:
case AQ_GET_FREEZE_PROTECT_TEMP:
type = AQ_GET_ONETOUCH_SETPOINTS;
break;
case AQ_SET_POOL_HEATER_TEMP:
type = AQ_SET_ONETOUCH_POOL_HEATER_TEMP;
break;
case AQ_SET_SPA_HEATER_TEMP:
type = AQ_SET_ONETOUCH_SPA_HEATER_TEMP;
break;
case AQ_SET_BOOST:
type = AQ_SET_ONETOUCH_BOOST;
break;
default:
type = r_type;
break;
}
}
// Check we are doing something valid request
if (pda_mode() == true) {
pda_reset_sleep();
if (type != AQ_PDA_INIT &&
@ -332,7 +418,11 @@ void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data)
type != AQ_SET_BOOST) {
logMessage(LOG_ERR, "Selected Programming mode '%d' not supported with PDA mode control panel\n",type);
return;
}
} /*else if (onetouch_enabled() == false &&
( type != AQ_SET_ONETOUCH_PUMP_RPM || type != AQ_SET_ONETOUCH_MACRO || type != AQ_GET_ONETOUCH_SETPOINTS)) {
logMessage(LOG_ERR, "Selected Programming mode '%d' not supported without OneTouch mode (extra_device_id) enabled\n",type);
return;
}*/
}
programmingthread->aq_data = aq_data;
@ -460,6 +550,54 @@ void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data)
return;
}
break;
case AQ_SET_ONETOUCH_PUMP_RPM:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_pump_rpm, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_ONETOUCH_SETPOINTS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_onetouch_setpoints, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_ONETOUCH_TIME:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_time, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_ONETOUCH_BOOST:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_boost, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_ONETOUCH_SWG_PERCENT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_swg_percent, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_ONETOUCH_POOL_HEATER_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_pool_heater_temp, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_ONETOUCH_SPA_HEATER_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_spa_heater_temp, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_ONETOUCH_FREEZEPROTECT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_onetouch_freezeprotect, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
default:
logMessage (LOG_ERR, "Don't understand thread type\n");
break;
@ -707,19 +845,17 @@ STOP BOOST POOL
if (val==true) {
waitForMessage(threadCtrl->aq_data, "TO START BOOST POOL", 5);
send_cmd(KEY_ENTER);
waitfor_queue2empty();
longwaitfor_queue2empty();
} else {
int wait_messages = 5;
int i=0;
//waitfor_queue2empty();
//waitForMessage(aq_data, NULL, 1);
while( i++ < wait_messages)
{
waitForMessage(aq_data, "STOP BOOST POOL", 1);
if (stristr(aq_data->last_message, "STOP BOOST POOL") != NULL) {
// This is a really bad hack, message sequence is out for boost for some reason, so as soon as we see stop message, force enter key.
_pgm_command = KEY_ENTER;
//send_cmd(KEY_ENTER);
//_pgm_command = KEY_ENTER;
send_cmd(KEY_ENTER);
logMessage(LOG_DEBUG, "**** FOUND STOP BOOST POOL ****\n");
//waitfor_queue2empty();
break;
@ -727,38 +863,29 @@ STOP BOOST POOL
logMessage(LOG_DEBUG, "Find item in Menu: loop %d of %d looking for 'STOP BOOST POOL' received message '%s'\n",i,wait_messages,aq_data->last_message);
delay(200);
if (stristr(aq_data->last_message, "STOP BOOST POOL") != NULL) {
_pgm_command = KEY_ENTER;
//_pgm_command = KEY_ENTER;
send_cmd(KEY_ENTER);
logMessage(LOG_DEBUG, "**** FOUND STOP BOOST POOL ****\n");
break;
}
send_cmd(KEY_RIGHT);
//printf("WAIT\n");
waitfor_queue2empty();
longwaitfor_queue2empty();
//printf("FINISHED WAIT\n");
}
//waitfor_queue2empty();
//waitForMessage(aq_data, NULL, 1);
}
waitForMessage(aq_data, "STOP BOOST POOL", 1);
if (stristr(aq_data->last_message, "STOP BOOST POOL") != NULL) {
//logMessage(LOG_DEBUG, "**** FOUND STOP BOOST POOL ****\n");
send_cmd(KEY_ENTER);
} else {
logMessage(LOG_DEBUG, "**** GIVING UP ****\n");
if (i < wait_messages) {
// Takes ages to see bost is off from menu, to set it here.
aq_data->boost = false;
aq_data->boost_msg[0] = '\0';
aq_data->swg_percent = 0;
}
/*
if (stristr(aq_data->last_message, "STOP BOOST POOL") == NULL) {
send_cmd(KEY_RIGHT);
logMessage(LOG_DEBUG, "**** FOUND STOP BOOST POOL ****\n");
} else {
logMessage(LOG_ERR, "**** NOT FOUND STOP BOOST POOL ****\n");
}
*/
// Extra message overcome.
//send_cmd(KEY_RIGHT);
//waitfor_queue2empty();
/*
// Extra message overcome.
send_cmd(KEY_RIGHT);
waitfor_queue2empty();
if ( select_sub_menu_item(aq_data, "STOP BOOST POOL") != true ) {
logMessage(LOG_WARNING, "Could not select STOP BOOST POOL menu\n");
cancel_menu();
@ -767,6 +894,7 @@ STOP BOOST POOL
}*/
//send_cmd(KEY_ENTER);
}
waitForMessage(aq_data,NULL, 1);
cleanAndTerminateThread(threadCtrl);
@ -1403,11 +1531,11 @@ void send_cmd(unsigned char cmd, struct aqualinkdata *aq_data)
}
*/
void waitfor_queue2empty()
void _waitfor_queue2empty(bool longwait)
{
int i=0;
while ( (_pgm_command != NUL) && ( i++ < 20) ) {
while ( (_pgm_command != NUL) && ( i++ < (30*(longwait?2:1) ) ) ) {
//sleep(1); // NSF Change to smaller time.
//logMessage(LOG_DEBUG, "******** QUEUE IS FULL ******** delay\n");
delay(50);
@ -1416,7 +1544,7 @@ void waitfor_queue2empty()
if (_pgm_command != NUL) {
if (pda_mode()) {
// Wait for longer in PDA mode since it's slower.
while ( (_pgm_command != NUL) && ( i++ < 100) ) {
while ( (_pgm_command != NUL) && ( i++ < (130*(longwait?2:1)) ) ) {
delay(100);
}
}
@ -1425,6 +1553,15 @@ void waitfor_queue2empty()
}
void waitfor_queue2empty()
{
_waitfor_queue2empty(false);
}
void longwaitfor_queue2empty()
{
_waitfor_queue2empty(true);
}
void send_cmd(unsigned char cmd)
{
waitfor_queue2empty();
@ -1753,6 +1890,33 @@ const char *ptypeName(program_type type)
case AQ_SET_BOOST:
return "SWG Boost";
break;
case AQ_SET_ONETOUCH_PUMP_RPM:
return "Set Pump RPM";
break;
case AQ_SET_ONETOUCH_MACRO:
return "Set OneTouch Macro";
break;
case AQ_GET_ONETOUCH_SETPOINTS:
return "Get OneTouch setpoints";
break;
case AQ_SET_ONETOUCH_TIME:
return "Set OneTouch time";
break;
case AQ_SET_ONETOUCH_BOOST:
return "Set OneTouch Boost";
break;
case AQ_SET_ONETOUCH_SWG_PERCENT:
return "Set OneTouch SWG Percent";
break;
case AQ_SET_ONETOUCH_FREEZEPROTECT:
return "Set OneTouch Freezeprotect";
break;
case AQ_SET_ONETOUCH_POOL_HEATER_TEMP:
return "Set OneTouch Pool Heater Temp";
break;
case AQ_SET_ONETOUCH_SPA_HEATER_TEMP:
return "Set OneTouch Spa Heater Temp";
break;
case AQP_NULL:
default:
return "Unknown";

View File

@ -2,6 +2,8 @@
#ifndef AQ_PROGRAMMER_H_
#define AQ_PROGRAMMER_H_
#include <pthread.h>
//#include "aqualink.h"
// need to get the C values from aqualink manual and add those just incase
// someone has the controller set to C.
@ -21,6 +23,12 @@
#define PTHREAD_ARG 25
#define LIGHT_MODE_BUFER PTHREAD_ARG
typedef enum emulation_type{
ALLBUTTON,
ONETOUCH,
AQUAPDA // AQUAPALM and PDA are taken as specific type.
} emulation_type;
typedef enum {
AQP_NULL = -1,
AQ_GET_POOL_SPA_HEATER_TEMPS,
@ -39,7 +47,16 @@ typedef enum {
AQ_PDA_DEVICE_ON_OFF,
AQ_GET_AUX_LABELS,
AQ_PDA_WAKE_INIT,
AQ_SET_BOOST
AQ_SET_BOOST,
AQ_SET_ONETOUCH_PUMP_RPM,
AQ_SET_ONETOUCH_MACRO,
AQ_GET_ONETOUCH_SETPOINTS,
AQ_SET_ONETOUCH_POOL_HEATER_TEMP,
AQ_SET_ONETOUCH_SPA_HEATER_TEMP,
AQ_SET_ONETOUCH_FREEZEPROTECT,
AQ_SET_ONETOUCH_TIME,
AQ_SET_ONETOUCH_BOOST,
AQ_SET_ONETOUCH_SWG_PERCENT
} program_type;
struct programmingThreadCtrl {
@ -49,14 +66,22 @@ struct programmingThreadCtrl {
struct aqualinkdata *aq_data;
};
typedef enum pump_type {
PT_UNKNOWN = -1,
EPUMP,
VSPUMP,
VFPUMP
} pump_type;
//void aq_programmer(program_type type, void *args, struct aqualinkdata *aq_data);
void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data);
void kick_aq_program_thread(struct aqualinkdata *aq_data);
//void kick_aq_program_thread(struct aqualinkdata *aq_data);
void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_type);
bool in_ot_programming_mode(struct aqualinkdata *aq_data);
void aq_send_cmd(unsigned char cmd);
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data);
void queueGetExtendedProgramData(emulation_type source_type, struct aqualinkdata *aq_data, bool labels);
unsigned char pop_aq_cmd(struct aqualinkdata *aq_data);
//bool push_aq_cmd(unsigned char cmd);
@ -68,6 +93,8 @@ unsigned char pop_aq_cmd(struct aqualinkdata *aq_data);
int get_aq_cmd_length();
int setpoint_check(int type, int value, struct aqualinkdata *aqdata);
int RPM_check(pump_type type, int value, struct aqualinkdata *aqdata);
//int RPM_check(int type, int value, struct aqualinkdata *aqdata);
const char *ptypeName(program_type type);
// These shouldn't be here, but just for the PDA AQ PROGRAMMER

View File

@ -40,7 +40,27 @@ static struct termios _oldtio;
void send_packet(int fd, unsigned char *packet, int length);
//unsigned char getProtocolType(unsigned char* packet);
/*
#ifdef ONETOUCH
bool _onetouch_mode = false;
void set_onetouch_mode(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using Onetouch mode\n");
_onetouch_mode = mode;
}
bool onetouch_mode()
{
return _onetouch_mode;
}
#endif
*/
bool _pda_mode = false;
bool _onetouch_enabled = false;
bool _extended_device_id_programming = false;
void set_pda_mode(bool mode)
{
if (mode)
@ -53,6 +73,30 @@ bool pda_mode()
return _pda_mode;
}
void set_onetouch_enabled(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using use ONETOUCH mode for VSP programming\n");
_onetouch_enabled = mode;
}
bool onetouch_enabled()
{
return _onetouch_enabled;
}
void set_extended_device_id_programming(bool mode)
{
if (mode)
logMessage(LOG_NOTICE, "AqualinkD is using use ONETOUCH mode for programming (where supported)\n");
_extended_device_id_programming = mode;
}
bool extended_device_id_programming()
{
return _extended_device_id_programming;
}
const char* get_packet_type(unsigned char* packet , int length)
{
static char buf[15];
@ -101,7 +145,7 @@ const char* get_packet_type(unsigned char* packet , int length)
return "PDA Shiftlines";
break;
case CMD_PDA_HIGHLIGHTCHARS:
return "PDA C_HlightChar";
return "PDA HlightChars";
break;
case CMD_IAQ_MSG:
return "iAq Message";
@ -438,10 +482,8 @@ void send_packet(int fd, unsigned char *packet, int length)
}
if ( getLogLevel() >= LOG_DEBUG_SERIAL) {
//char buf[30];
//sprintf(buf, "Sent %8.8s ", get_packet_type(packet+1, length));
//log_packet(buf, packet, length);
logMessage(LOG_DEBUG_SERIAL, "Serial send %d bytes\n",length-2);
// Packet is padded with 0x00, so discard for logging
logMessage(LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
logPacket(&packet[1], length-2);
}
}
@ -460,6 +502,8 @@ void _send_ack(int fd, unsigned char ack_type, unsigned char command)
ackPacket[7] = generate_checksum(ackPacket, length-1);
}
//printf("***Send ACK (%s) ***\n",(ack_type==ACK_NORMAL?"Normal":(ack_type==ACK_SCREEN_BUSY?"ScreenBusy":"ScreenBusyDisplay")) );
send_packet(fd, ackPacket, length);
}
@ -660,10 +704,8 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
return 0;
}
if ( getLogLevel() >= LOG_DEBUG_SERIAL) {
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
logPacket(packet, index);
}
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
logPacket(packet, index);
// Return the packet length.
return index;
}
@ -673,6 +715,63 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
#endif
#else //USE_AQ_SERIAL_OLD

View File

@ -65,9 +65,27 @@
/* ACK RETURN COMMANDS */
#define ACK_NORMAL 0x00
#define ACK_SCREEN_BUSY 0x01 // Seems to be busy but can cache a message,
#define ACK_SCREEN_BUSY_SCROLL 0x01 // Seems to be busy but can cache a message,
#define ACK_SCREEN_BUSY_BLOCK 0x03 // Seems to be don't send me shit.
// Remove this and fix all compile errors when get time.
#define ACK_SCREEN_BUSY ACK_SCREEN_BUSY_SCROLL
#define ACK_PDA 0x40
#define ACK_ONETOUCH 0x80
#define ACK_ALLB_SIM 0x80 // Jandy's Allbutton simulator uses this and not ACK_NORMAL
#define ACK_ALLB_SIM_BUSY 0x81 // Jandy's Allbutton simulator uses this and not ACK_SCREEN_BUSY_SCROLL
/* ONE TOUCH KEYCODES */
#define KEY_ONET_UP 0x06
#define KEY_ONET_DOWN 0x05
#define KEY_ONET_SELECT 0x04
#define KEY_ONET_PAGE_UP 0x03 // Top
#define KEY_ONET_BACK 0x02 // Middle
#define KEY_ONET_PAGE_DN 0x01 // Bottom
#define KEY_ONET_SELECT_1 KEY_ONET_PAGE_UP
#define KEY_ONET_SELECT_2 KEY_ONET_BACK
#define KEY_ONET_SELECT_3 KEY_ONET_PAGE_DN
/* AquaRite commands */
#define CMD_GETID 0x14 // May be remote control control
@ -187,7 +205,7 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define MSG_PMP_RPM "RPM:"
#define MSG_PMP_WAT "Watts:"
#define MSG_PMP_GPH "GPH:"
#define MSG_PMP_GPM "GPM:"
/* AQUAPURE SWG */
@ -221,11 +239,36 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define CMD_PDA_SHIFTLINES 0x0F
#define CMD_PDA_HIGHLIGHTCHARS 0x10
// One Touch commands
//#define CMD_PDA_0x04 0x04 // No idea, might be building menu
/* iAqualink */
#define CMD_IAQ_MSG 0x25
/* None of these are used, just here to gather data for the moment */
#define CMD_IAQ_MSG 0x25 // Equiptment status message??
#define CMD_IAQ_MENU_MSG 0x24
#define CMD_IAQ_MSG_LONG 0x2c // Long status message??
#define CMD_IAQ_MSG_3 0x2d // Equiptment status message??
#define CMD_IAQ_0x30 0x30
#define CMD_IAQ_0x23 0x23
#define CMD_IAQ_0x24 0x24 // Text for labels or maybe buttons (looks like next BIT is placment)
#define CMD_IAQ_0x25 0x25 // Status for labels
#define CMD_IAQ_0x31 0x31 // Some pump speed info
#define IAQ_KEY_PUMP 0x11
#define IAQ_KEY_SPA 0x12
#define IAQ_KEY_POOL_HEAT 0x13
#define IAQ_KEY_SPA_HEAT 0x14
#define IAQ_KEY_CUST_1 0x15
#define IAQ_KEY_CUST_2 0x16
#define IAQ_KEY_CUST_3 0x17
#define IAQ_KEY_AUX1 0x19 // Depending on page this is 0x15
#define IAQ_KEY_AUX2 0x1a
#define IAQ_KEY_AUX3 0x1b
#define IAQ_KEY_AUX4 0x1c
#define IAQ_KEY_AUX5 0x1d
#define IAQ_KEY_AUX6 0x1e
#define IAQ_KEY_AUX7 0x1f
typedef enum {
ON,
@ -275,11 +318,22 @@ int get_packet_lograw(int fd, unsigned char* packet);
void process_status(unsigned char* ptr);
const char* get_packet_type(unsigned char* packet , int length);
void set_onetouch_enabled(bool mode);
bool onetouch_enabled();
void set_extended_device_id_programming(bool mode);
bool extended_device_id_programming();
void send_jandy_command(int fd, unsigned char *packet_buffer, int size);
void send_pentair_command(int fd, unsigned char *packet_buffer, int size);
void send_command(int fd, unsigned char *packet_buffer, int size);
/*
#ifdef ONETOUCH
void set_onetouch_mode(bool mode);
bool onetouch_mode();
#endif
*/
//void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
//void send_command(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3);
//void send_messaged(int fd, unsigned char destination, char *message);

View File

@ -59,25 +59,40 @@ typedef enum action_type {
SPA_HTR_SETOINT,
FREEZE_SETPOINT,
SWG_SETPOINT,
SWG_BOOST
SWG_BOOST,
PUMP_RPM
} action_type;
struct action {
action_type type;
time_t requested;
int value;
int id; // Only used for Pumps at the moment.
//char value[10];
};
// Moved to aq_programmer to stop circular dependancy
/*
typedef enum pump_type {
PT_UNKNOWN = -1,
EPUMP,
VSPUMP,
VFPUMP
} pump_type;
*/
typedef struct pumpd
{
int rpm;
int gph;
int gpm;
int watts;
unsigned char pumpID;
int pumpIndex;
pump_type pumpType;
//int buttonID;
protocolType ptype;
aqkey *button;
//bool updated;
} pump_detail;
struct aqualinkdata
@ -115,6 +130,7 @@ struct aqualinkdata
aqledstate service_mode_state;
aqledstate frz_protect_state;
unsigned char last_packet_type;
int num_pumps;
pump_detail pumps[MAX_PUMPS];
int open_websockets;
bool boost;

File diff suppressed because it is too large Load Diff

View File

@ -17,19 +17,23 @@ bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualin
// Not really sure what to do with this, just ignore 0xff / 255 for the moment. (if statment above)
// SWG can get ~10 messages to set to 0 then go back again for some reason, so don't go to 0 until 10 messages are received
if (swg_zero_cnt <= swg_zero_ignore && packet[4] == 0x00 && packet[5] == 0x73) {
if (swg_zero_cnt <= swg_zero_ignore && packet[4] == 0x00) {
logMessage(LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet[4],
swg_zero_cnt, swg_zero_ignore, packet[4], packet[5]);
swg_zero_cnt++;
} else if (swg_zero_cnt > swg_zero_ignore && packet[4] == 0x00 && packet[5] == 0x73) {
aqdata->swg_percent = (int)packet[4];
changedAnything = true;
} else if (swg_zero_cnt > swg_zero_ignore && packet[4] == 0x00) {
if (aqdata->swg_percent != (int)packet[4]) {
aqdata->swg_percent = (int)packet[4];
changedAnything = true;
}
// logMessage(LOG_DEBUG, "SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n",
// (int)packet[4],swg_zero_cnt,SWG_ZERO_IGNORE_COUNT,packet[4],packet[5]); swg_zero_cnt++;
} else {
swg_zero_cnt = 0;
aqdata->swg_percent = (int)packet[4];
changedAnything = true;
if (aqdata->swg_percent != (int)packet[4]) {
aqdata->swg_percent = (int)packet[4];
changedAnything = true;
}
// logMessage(LOG_DEBUG, "SWG set to %d due to packet from control panel to SWG 0x%02hhx 0x%02hhx\n",
// aqdata.swg_percent,packet[4],packet[5]);
}
@ -66,7 +70,7 @@ bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqual
aqledstate get_swg_led_state(struct aqualinkdata *aqdata)
{
switch (aqdata->ar_swg_status) {
// Level = (0=gray, 1=green, 2=yellow, 3=orange, 4=red)
case SWG_STATUS_ON:
return (aqdata->swg_percent > 0?ON:ENABLE);
break;

324
config.c
View File

@ -33,19 +33,24 @@
#include <unistd.h>
#include <net/if.h>
#define CONFIG_C
#include "config.h"
#include "utils.h"
#include "aq_serial.h"
#define MAXCFGLINE 256
char *generate_mqtt_id(char *buf, int len);
pump_detail *getpump(struct aqualinkdata *aqdata, int button);
/*
* initialize data to default values
*/
void init_parameters (struct aqconfig * parms)
{
//int i;
//char *p;
parms->serial_port = DEFAULT_SERIALPORT;
parms->log_level = DEFAULT_LOG_LEVEL;
@ -53,6 +58,7 @@ void init_parameters (struct aqconfig * parms)
parms->web_directory = DEFAULT_WEBROOT;
//parms->device_id = strtoul(DEFAULT_DEVICE_ID, &p, 16);
parms->device_id = strtoul(DEFAULT_DEVICE_ID, NULL, 16);
parms->onetouch_device_id = 0x00;
//sscanf(DEFAULT_DEVICE_ID, "0x%x", &parms->device_id);
parms->override_freeze_protect = FALSE;
@ -76,6 +82,7 @@ void init_parameters (struct aqconfig * parms)
parms->deamonize = true;
parms->log_file = '\0';
parms->pda_mode = false;
parms->onetouch_mode = false;
parms->pda_sleep_mode = false;
parms->convert_mqtt_temp = true;
parms->convert_dz_temp = true;
@ -90,6 +97,7 @@ void init_parameters (struct aqconfig * parms)
parms->swg_zero_ignore = DEFAILT_SWG_ZERO_IGNORE_COUNT;
parms->display_warnings_web = false;
parms->log_raw_RS_bytes = false;
parms->extended_device_id_programming = false;
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
}
@ -219,69 +227,69 @@ void readCfg_OLD (struct aqconfig *config_parameters, struct aqualinkdata *aqdat
if ( indx != NULL)
{
if (strncasecmp (b_ptr, "socket_port", 11) == 0) {
//config_parameters->socket_port = cleanint(indx+1);
config_parameters->socket_port = cleanalloc(indx+1);
//_aqconfig_.socket_port = cleanint(indx+1);
_aqconfig_.socket_port = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "serial_port", 11) == 0) {
config_parameters->serial_port = cleanalloc(indx+1);
_aqconfig_.serial_port = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "log_level", 9) == 0) {
config_parameters->log_level = text2elevel(cleanalloc(indx+1));
_aqconfig_.log_level = text2elevel(cleanalloc(indx+1));
// should fee mem here
} else if (strncasecmp (b_ptr, "device_id", 9) == 0) {
config_parameters->device_id = strtoul(cleanalloc(indx+1), NULL, 16);
_aqconfig_.device_id = strtoul(cleanalloc(indx+1), NULL, 16);
// should fee mem here
} else if (strncasecmp (b_ptr, "web_directory", 13) == 0) {
config_parameters->web_directory = cleanalloc(indx+1);
_aqconfig_.web_directory = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "log_file", 8) == 0) {
config_parameters->log_file = cleanalloc(indx+1);
_aqconfig_.log_file = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "mqtt_address", 12) == 0) {
config_parameters->mqtt_server = cleanalloc(indx+1);
_aqconfig_.mqtt_server = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "mqtt_dz_sub_topic", 17) == 0) {
config_parameters->mqtt_dz_sub_topic = cleanalloc(indx+1);
_aqconfig_.mqtt_dz_sub_topic = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "mqtt_dz_pub_topic", 17) == 0) {
config_parameters->mqtt_dz_pub_topic = cleanalloc(indx+1);
_aqconfig_.mqtt_dz_pub_topic = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "mqtt_aq_topic", 13) == 0) {
config_parameters->mqtt_aq_topic = cleanalloc(indx+1);
_aqconfig_.mqtt_aq_topic = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "mqtt_user", 9) == 0) {
config_parameters->mqtt_user = cleanalloc(indx+1);
_aqconfig_.mqtt_user = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "mqtt_passwd", 11) == 0) {
config_parameters->mqtt_passwd = cleanalloc(indx+1);
_aqconfig_.mqtt_passwd = cleanalloc(indx+1);
} else if (strncasecmp (b_ptr, "air_temp_dzidx", 14) == 0) {
config_parameters->dzidx_air_temp = strtoul(indx+1, NULL, 10);
_aqconfig_.dzidx_air_temp = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "pool_water_temp_dzidx", 21) == 0) {
config_parameters->dzidx_pool_water_temp = strtoul(indx+1, NULL, 10);
_aqconfig_.dzidx_pool_water_temp = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "spa_water_temp_dzidx", 20) == 0) {
config_parameters->dzidx_spa_water_temp = strtoul(indx+1, NULL, 10);
_aqconfig_.dzidx_spa_water_temp = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "light_programming_mode", 21) == 0) {
config_parameters->light_programming_mode = atof(cleanalloc(indx+1)); // should free this
_aqconfig_.light_programming_mode = atof(cleanalloc(indx+1)); // should free this
} else if (strncasecmp (b_ptr, "light_programming_initial_on", 28) == 0) {
config_parameters->light_programming_initial_on = strtoul(indx+1, NULL, 10);
_aqconfig_.light_programming_initial_on = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "light_programming_initial_off", 29) == 0) {
config_parameters->light_programming_initial_off = strtoul(indx+1, NULL, 10);
_aqconfig_.light_programming_initial_off = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "light_programming_button", 21) == 0) {
config_parameters->light_programming_button = strtoul(indx+1, NULL, 10) - 1;
_aqconfig_.light_programming_button = strtoul(indx+1, NULL, 10) - 1;
} else if (strncasecmp (b_ptr, "SWG_percent_dzidx", 17) == 0) {
config_parameters->dzidx_swg_percent = strtoul(indx+1, NULL, 10);
_aqconfig_.dzidx_swg_percent = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "SWG_PPM_dzidx", 13) == 0) {
config_parameters->dzidx_swg_ppm = strtoul(indx+1, NULL, 10);
_aqconfig_.dzidx_swg_ppm = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "SWG_Status_dzidx", 14) == 0) {
config_parameters->dzidx_swg_status = strtoul(indx+1, NULL, 10);
_aqconfig_.dzidx_swg_status = strtoul(indx+1, NULL, 10);
} else if (strncasecmp (b_ptr, "override_freeze_protect", 23) == 0) {
config_parameters->override_freeze_protect = text2bool(indx+1);
_aqconfig_.override_freeze_protect = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "pda_mode", 8) == 0) {
config_parameters->pda_mode = text2bool(indx+1);
set_pda_mode(config_parameters->pda_mode);
_aqconfig_.pda_mode = text2bool(indx+1);
set_pda_mode(_aqconfig_.pda_mode);
} else if (strncasecmp (b_ptr, "convert_mqtt_temp_to_c", 22) == 0) {
config_parameters->convert_mqtt_temp = text2bool(indx+1);
_aqconfig_.convert_mqtt_temp = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "convert_dz_temp_to_c", 21) == 0) {
config_parameters->convert_dz_temp = text2bool(indx+1);
_aqconfig_.convert_dz_temp = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "flash_mqtt_buttons", 18) == 0) {
config_parameters->flash_mqtt_buttons = text2bool(indx+1);
_aqconfig_.flash_mqtt_buttons = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "report_zero_pool_temp", 21) == 0) {
config_parameters->report_zero_pool_temp = text2bool(indx+1);
_aqconfig_.report_zero_pool_temp = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "report_zero_spa_temp", 20) == 0) {
config_parameters->report_zero_spa_temp = text2bool(indx+1);
_aqconfig_.report_zero_spa_temp = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "report_zero_pool_temp", 21) == 0) {
config_parameters->report_zero_pool_temp = text2bool(indx+1);
_aqconfig_.report_zero_pool_temp = text2bool(indx+1);
} else if (strncasecmp (b_ptr, "button_", 7) == 0) {
int num = strtoul(b_ptr+7, NULL, 10) - 1;
//logMessage (LOG_DEBUG, "Button %d\n", strtoul(b_ptr+7, NULL, 10));
@ -310,146 +318,154 @@ void readCfg_OLD (struct aqconfig *config_parameters, struct aqualinkdata *aqdat
}
*/
bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *param, char *value) {
bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
bool rtn = false;
static int pi=0;
if (strncasecmp(param, "socket_port", 11) == 0) {
config_parameters->socket_port = cleanalloc(value);
_aqconfig_.socket_port = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "serial_port", 11) == 0) {
config_parameters->serial_port = cleanalloc(value);
_aqconfig_.serial_port = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "log_level", 9) == 0) {
config_parameters->log_level = text2elevel(cleanalloc(value));
_aqconfig_.log_level = text2elevel(cleanalloc(value));
rtn=true;
} else if (strncasecmp(param, "device_id", 9) == 0) {
config_parameters->device_id = strtoul(cleanalloc(value), NULL, 16);
_aqconfig_.device_id = strtoul(cleanalloc(value), NULL, 16);
} else if (strncasecmp (param, "extended_device_id_programming", 30) == 0) {
// Has to be before the below.
_aqconfig_.extended_device_id_programming = text2bool(value);
rtn=true;
} else if (strncasecmp(param, "extended_device_id", 9) == 0) {
_aqconfig_.onetouch_device_id = strtoul(cleanalloc(value), NULL, 16);
//_config_parameters.onetouch_device_id != 0x00
rtn=true;
} else if (strncasecmp(param, "web_directory", 13) == 0) {
config_parameters->web_directory = cleanalloc(value);
_aqconfig_.web_directory = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "log_file", 8) == 0) {
config_parameters->log_file = cleanalloc(value);
_aqconfig_.log_file = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "mqtt_address", 12) == 0) {
config_parameters->mqtt_server = cleanalloc(value);
_aqconfig_.mqtt_server = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "mqtt_dz_sub_topic", 17) == 0) {
config_parameters->mqtt_dz_sub_topic = cleanalloc(value);
_aqconfig_.mqtt_dz_sub_topic = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "mqtt_dz_pub_topic", 17) == 0) {
config_parameters->mqtt_dz_pub_topic = cleanalloc(value);
_aqconfig_.mqtt_dz_pub_topic = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "mqtt_aq_topic", 13) == 0) {
config_parameters->mqtt_aq_topic = cleanalloc(value);
_aqconfig_.mqtt_aq_topic = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "mqtt_user", 9) == 0) {
config_parameters->mqtt_user = cleanalloc(value);
_aqconfig_.mqtt_user = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "mqtt_passwd", 11) == 0) {
config_parameters->mqtt_passwd = cleanalloc(value);
_aqconfig_.mqtt_passwd = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param, "air_temp_dzidx", 14) == 0) {
config_parameters->dzidx_air_temp = strtoul(value, NULL, 10);
_aqconfig_.dzidx_air_temp = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "pool_water_temp_dzidx", 21) == 0) {
config_parameters->dzidx_pool_water_temp = strtoul(value, NULL, 10);
_aqconfig_.dzidx_pool_water_temp = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "spa_water_temp_dzidx", 20) == 0) {
config_parameters->dzidx_spa_water_temp = strtoul(value, NULL, 10);
_aqconfig_.dzidx_spa_water_temp = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "light_programming_mode", 21) == 0) {
config_parameters->light_programming_mode = atof(cleanalloc(value)); // should free this
_aqconfig_.light_programming_mode = atof(cleanalloc(value)); // should free this
rtn=true;
} else if (strncasecmp(param, "light_programming_initial_on", 28) == 0) {
config_parameters->light_programming_initial_on = strtoul(value, NULL, 10);
_aqconfig_.light_programming_initial_on = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "light_programming_initial_off", 29) == 0) {
config_parameters->light_programming_initial_off = strtoul(value, NULL, 10);
_aqconfig_.light_programming_initial_off = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "light_programming_button_spa", 28) == 0) {
config_parameters->light_programming_button_spa = strtoul(value, NULL, 10) - 1;
_aqconfig_.light_programming_button_spa = strtoul(value, NULL, 10) - 1;
rtn=true;
} else if (strncasecmp(param, "light_programming_button", 24) == 0 ||
strncasecmp(param, "light_programming_button_pool", 29) == 0) {
config_parameters->light_programming_button_pool = strtoul(value, NULL, 10) - 1;
_aqconfig_.light_programming_button_pool = strtoul(value, NULL, 10) - 1;
rtn=true;
} else if (strncasecmp(param, "SWG_percent_dzidx", 17) == 0) {
config_parameters->dzidx_swg_percent = strtoul(value, NULL, 10);
_aqconfig_.dzidx_swg_percent = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "SWG_PPM_dzidx", 13) == 0) {
config_parameters->dzidx_swg_ppm = strtoul(value, NULL, 10);
_aqconfig_.dzidx_swg_ppm = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "SWG_Status_dzidx", 14) == 0) {
config_parameters->dzidx_swg_status = strtoul(value, NULL, 10);
_aqconfig_.dzidx_swg_status = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp(param, "override_freeze_protect", 23) == 0) {
config_parameters->override_freeze_protect = text2bool(value);
_aqconfig_.override_freeze_protect = text2bool(value);
rtn=true;
} 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;
_aqconfig_.pda_mode = text2bool(value);
set_pda_mode(_aqconfig_.pda_mode);
//_aqconfig_.use_PDA_auxiliary = false;
rtn=true;
} else if (strncasecmp(param, "pda_sleep_mode", 8) == 0) {
config_parameters->pda_sleep_mode = text2bool(value);
//set_pda_mode(config_parameters->pda_mode);
_aqconfig_.pda_sleep_mode = text2bool(value);
//set_pda_mode(_aqconfig_.pda_mode);
rtn=true;
} else if (strncasecmp(param, "convert_mqtt_temp_to_c", 22) == 0) {
config_parameters->convert_mqtt_temp = text2bool(value);
_aqconfig_.convert_mqtt_temp = text2bool(value);
rtn=true;
} else if (strncasecmp(param, "convert_dz_temp_to_c", 20) == 0) {
config_parameters->convert_dz_temp = text2bool(value);
_aqconfig_.convert_dz_temp = text2bool(value);
rtn=true;
/*
} else if (strncasecmp(param, "flash_mqtt_buttons", 18) == 0) {
config_parameters->flash_mqtt_buttons = text2bool(value);
_aqconfig_.flash_mqtt_buttons = text2bool(value);
rtn=true;*/
} else if (strncasecmp(param, "report_zero_spa_temp", 20) == 0) {
config_parameters->report_zero_spa_temp = text2bool(value);
_aqconfig_.report_zero_spa_temp = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "report_zero_pool_temp", 21) == 0) {
config_parameters->report_zero_pool_temp = text2bool(value);
_aqconfig_.report_zero_pool_temp = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "read_all_devices", 16) == 0) {
config_parameters->read_all_devices = text2bool(value);
_aqconfig_.read_all_devices = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "use_panel_aux_labels", 20) == 0) {
config_parameters->use_panel_aux_labels = text2bool(value);
_aqconfig_.use_panel_aux_labels = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "force_SWG", 9) == 0) {
config_parameters->force_swg = text2bool(value);
_aqconfig_.force_swg = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "debug_RSProtocol_packets", 24) == 0) {
config_parameters->debug_RSProtocol_packets = text2bool(value);
_aqconfig_.debug_RSProtocol_packets = text2bool(value);
rtn=true;
} else if (strncasecmp (param, "read_pentair_packets", 17) == 0) {
config_parameters->read_pentair_packets = text2bool(value);
config_parameters->read_all_devices = true;
_aqconfig_.read_pentair_packets = text2bool(value);
if (_aqconfig_.read_pentair_packets)
_aqconfig_.read_all_devices = true;
rtn=true;
} else if (strncasecmp (param, "swg_zero_ignore_count", 21) == 0) {
config_parameters->swg_zero_ignore = strtoul(value, NULL, 10);
_aqconfig_.swg_zero_ignore = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp (param, "display_warnings_in_web", 23) == 0) {
config_parameters->display_warnings_web = text2bool(value);
_aqconfig_.display_warnings_web = text2bool(value);
rtn=true;
}
/*
else if (strncasecmp (param, "use_PDA_auxiliary", 17) == 0) {
config_parameters->use_PDA_auxiliary = text2bool(value);
_aqconfig_.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;
_aqconfig_.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);
_aqconfig_.dzidx_pool_thermostat = strtoul(value, NULL, 10);
rtn=true;
} else if (strncasecmp (param, "spa_thermostat_dzidx", 20) == 0) {
config_parameters->dzidx_spa_thermostat = strtoul(value, NULL, 10);
_aqconfig_.dzidx_spa_thermostat = strtoul(value, NULL, 10);
rtn=true;
} */
else if (strncasecmp(param, "button_", 7) == 0) {
@ -463,30 +479,92 @@ bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqd
} else if (strncasecmp(param + 9, "_PDA_label", 10) == 0) {
aqdata->aqbuttons[num].pda_label = cleanalloc(value);
rtn=true;
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
pump_detail *pump = getpump(aqdata, num);
if (pump != NULL) {
pump->pumpID = strtoul(cleanalloc(value), NULL, 16);
if (pump->pumpID < 119) {
pump->ptype = PENTAIR;
} else {
pump->ptype = JANDY;
//pump->pumpType = EPUMP; // For testing let the interface set this
}
} else {
logMessage(LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS-1,param);
}
rtn=true;
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
pump_detail *pump = getpump(aqdata, num);
if (pump != NULL) {
pump->pumpIndex = strtoul(value, NULL, 10);
} else {
logMessage(LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS-1,param);
}
rtn=true;
}
/*
} else if (strncasecmp(param + 9, "_pumpID", 7) == 0) {
//aqdata->aqbuttons[num].pda_label = cleanalloc(value);
//96 to 111 = Pentair, 120 to 123 = Jandy
if (pi < MAX_PUMPS) {
aqdata->pumps[pi].button = &aqdata->aqbuttons[num];
aqdata->pumps[pi].pumpID = strtoul(cleanalloc(value), NULL, 16);
aqdata->pumps[pi].pumpIndex = pi+1;
//aqdata->pumps[pi].buttonID = num;
if (aqdata->pumps[pi].pumpID < 119)
aqdata->pumps[pi].ptype = PENTAIR;
else
aqdata->pumps[pi].ptype = JANDY;
pi++;
} else {
logMessage(LOG_ERR, "Config error, VSP Pumps limited to %d, ignoring %s'\n",MAX_PUMPS,param);
}
rtn=true;
}
} else if (strncasecmp(param + 9, "_pumpIndex", 10) == 0) { //button_01_pumpIndex=1
}*/
}
return rtn;
}
pump_detail *getpump(struct aqualinkdata *aqdata, int button)
{
//static int _pumpindex = 0;
//aqdata->num_pumps
int pi;
void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *cfgFile)
// Does it exist
for (pi=0; pi < aqdata->num_pumps; pi++) {
if (aqdata->pumps[pi].button == &aqdata->aqbuttons[button]) {
//printf ("Found pump %d\n",button);
return &aqdata->pumps[pi];
}
}
// Create new entry
if (aqdata->num_pumps < MAX_PUMPS) {
//printf ("Creating pump %d\n",button);
aqdata->pumps[aqdata->num_pumps].button = &aqdata->aqbuttons[button];
aqdata->pumps[aqdata->num_pumps].pumpType = PT_UNKNOWN;
aqdata->pumps[aqdata->num_pumps].rpm = TEMP_UNKNOWN;
aqdata->pumps[aqdata->num_pumps].watts = TEMP_UNKNOWN;
aqdata->pumps[aqdata->num_pumps].gpm = TEMP_UNKNOWN;
aqdata->num_pumps++;
return &aqdata->pumps[aqdata->num_pumps-1];
}
return NULL;
}
void init_config()
{
init_parameters(&_aqconfig_);
}
//void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *cfgFile)
void read_config (struct aqualinkdata *aqdata, char *cfgFile)
{
FILE * fp ;
char bufr[MAXCFGLINE];
@ -496,7 +574,7 @@ void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, c
//int tokenindex = 0;
char *b_ptr;
config_parameters->config_file = cleanalloc(cfgFile);
_aqconfig_.config_file = cleanalloc(cfgFile);
if( (fp = fopen(cfgFile, "r")) != NULL){
while(! feof(fp)){
@ -511,7 +589,7 @@ void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata, c
indx = strchr(b_ptr, '=');
if ( indx != NULL)
{
if ( ! setConfigValue(config_parameters, aqdata, b_ptr, indx+1))
if ( ! setConfigValue(aqdata, b_ptr, indx+1))
logMessage(LOG_ERR, "Unknown config parameter '%.*s'\n",strlen(b_ptr)-1, b_ptr);
}
}
@ -596,67 +674,67 @@ void writeIntValue (FILE *fp, char *msg, int value)
fprintf(fp, "%s = %d\n", msg, value);
}
bool writeCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata)
bool writeCfg (struct aqualinkdata *aqdata)
{
FILE *fp;
int i;
bool fs = remount_root_ro(false);
fp = fopen(config_parameters->config_file, "w");
fp = fopen(_aqconfig_.config_file, "w");
if (fp == NULL) {
logMessage(LOG_ERR, "Open config file failed '%s'\n", config_parameters->config_file);
logMessage(LOG_ERR, "Open config file failed '%s'\n", _aqconfig_.config_file);
remount_root_ro(true);
//fprintf(stdout, "Open file failed 'sprinkler.cron'\n");
return false;
}
fprintf(fp, "#***** AqualinkD configuration *****\n");
fprintf(fp, "socket_port = %s\n", config_parameters->socket_port);
fprintf(fp, "serial_port = %s\n", config_parameters->serial_port);
fprintf(fp, "device_id = 0x%02hhx\n", config_parameters->device_id);
fprintf(fp, "read_all_devices = %s", bool2text(config_parameters->read_all_devices));
writeCharValue(fp, "log_level", errorlevel2text(config_parameters->log_level));
writeCharValue(fp, "web_directory", config_parameters->web_directory);
writeCharValue(fp, "log_file", config_parameters->log_file);
fprintf(fp, "pda_mode = %s\n", bool2text(config_parameters->pda_mode));
fprintf(fp, "socket_port = %s\n", _aqconfig_.socket_port);
fprintf(fp, "serial_port = %s\n", _aqconfig_.serial_port);
fprintf(fp, "device_id = 0x%02hhx\n", _aqconfig_.device_id);
fprintf(fp, "read_all_devices = %s", bool2text(_aqconfig_.read_all_devices));
writeCharValue(fp, "log_level", errorlevel2text(_aqconfig_.log_level));
writeCharValue(fp, "web_directory", _aqconfig_.web_directory);
writeCharValue(fp, "log_file", _aqconfig_.log_file);
fprintf(fp, "pda_mode = %s\n", bool2text(_aqconfig_.pda_mode));
fprintf(fp, "\n#** MQTT Configuration **\n");
writeCharValue(fp, "mqtt_address", config_parameters->mqtt_server);
writeCharValue(fp, "mqtt_dz_sub_topic", config_parameters->mqtt_dz_sub_topic);
writeCharValue(fp, "mqtt_dz_pub_topic", config_parameters->mqtt_dz_pub_topic);
writeCharValue(fp, "mqtt_aq_topic", config_parameters->mqtt_aq_topic);
writeCharValue(fp, "mqtt_user", config_parameters->mqtt_user);
writeCharValue(fp, "mqtt_passwd", config_parameters->mqtt_passwd);
writeCharValue(fp, "mqtt_address", _aqconfig_.mqtt_server);
writeCharValue(fp, "mqtt_dz_sub_topic", _aqconfig_.mqtt_dz_sub_topic);
writeCharValue(fp, "mqtt_dz_pub_topic", _aqconfig_.mqtt_dz_pub_topic);
writeCharValue(fp, "mqtt_aq_topic", _aqconfig_.mqtt_aq_topic);
writeCharValue(fp, "mqtt_user", _aqconfig_.mqtt_user);
writeCharValue(fp, "mqtt_passwd", _aqconfig_.mqtt_passwd);
fprintf(fp, "\n#** General **\n");
fprintf(fp, "convert_mqtt_temp_to_c = %s\n", bool2text(config_parameters->convert_mqtt_temp));
fprintf(fp, "override_freeze_protect = %s\n", bool2text(config_parameters->override_freeze_protect));
//fprintf(fp, "flash_mqtt_buttons = %s\n", bool2text(config_parameters->flash_mqtt_buttons));
fprintf(fp, "report_zero_spa_temp = %s\n", bool2text(config_parameters->report_zero_spa_temp));
fprintf(fp, "report_zero_pool_temp = %s\n", bool2text(config_parameters->report_zero_pool_temp));
fprintf(fp, "convert_mqtt_temp_to_c = %s\n", bool2text(_aqconfig_.convert_mqtt_temp));
fprintf(fp, "override_freeze_protect = %s\n", bool2text(_aqconfig_.override_freeze_protect));
//fprintf(fp, "flash_mqtt_buttons = %s\n", bool2text(_aqconfig_.flash_mqtt_buttons));
fprintf(fp, "report_zero_spa_temp = %s\n", bool2text(_aqconfig_.report_zero_spa_temp));
fprintf(fp, "report_zero_pool_temp = %s\n", bool2text(_aqconfig_.report_zero_pool_temp));
fprintf(fp, "\n#** Programmable light **\n");
//if (config_parameters->light_programming_button_pool <= 0) {
// fprintf(fp, "#light_programming_button_pool = %d\n", config_parameters->light_programming_button_pool);
// fprintf(fp, "#light_programming_mode = %f\n", config_parameters->light_programming_mode);
// fprintf(fp, "#light_programming_initial_on = %d\n", config_parameters->light_programming_initial_on);
// fprintf(fp, "#light_programming_initial_off = %d\n", config_parameters->light_programming_initial_off);
//if (_aqconfig_.light_programming_button_pool <= 0) {
// fprintf(fp, "#light_programming_button_pool = %d\n", _aqconfig_.light_programming_button_pool);
// fprintf(fp, "#light_programming_mode = %f\n", _aqconfig_.light_programming_mode);
// fprintf(fp, "#light_programming_initial_on = %d\n", _aqconfig_.light_programming_initial_on);
// fprintf(fp, "#light_programming_initial_off = %d\n", _aqconfig_.light_programming_initial_off);
//} else {
fprintf(fp, "light_programming_button_pool = %d\n", config_parameters->light_programming_button_pool);
fprintf(fp, "light_programming_button_spa = %d\n", config_parameters->light_programming_button_spa);
fprintf(fp, "light_programming_mode = %f\n", config_parameters->light_programming_mode);
fprintf(fp, "light_programming_initial_on = %d\n", config_parameters->light_programming_initial_on);
fprintf(fp, "light_programming_initial_off = %d\n", config_parameters->light_programming_initial_off);
fprintf(fp, "light_programming_button_pool = %d\n", _aqconfig_.light_programming_button_pool);
fprintf(fp, "light_programming_button_spa = %d\n", _aqconfig_.light_programming_button_spa);
fprintf(fp, "light_programming_mode = %f\n", _aqconfig_.light_programming_mode);
fprintf(fp, "light_programming_initial_on = %d\n", _aqconfig_.light_programming_initial_on);
fprintf(fp, "light_programming_initial_off = %d\n", _aqconfig_.light_programming_initial_off);
//}
fprintf(fp, "\n#** Domoticz **\n");
fprintf(fp, "convert_dz_temp_to_c = %s\n", bool2text(config_parameters->convert_dz_temp));
writeIntValue(fp, "air_temp_dzidx", config_parameters->dzidx_air_temp);
writeIntValue(fp, "pool_water_temp_dzidx", config_parameters->dzidx_pool_water_temp);
writeIntValue(fp, "spa_water_temp_dzidx", config_parameters->dzidx_spa_water_temp);
writeIntValue(fp, "SWG_percent_dzidx", config_parameters->dzidx_swg_percent);
writeIntValue(fp, "SWG_PPM_dzidx", config_parameters->dzidx_swg_ppm);
writeIntValue(fp, "SWG_Status_dzidx", config_parameters->dzidx_swg_status);
fprintf(fp, "convert_dz_temp_to_c = %s\n", bool2text(_aqconfig_.convert_dz_temp));
writeIntValue(fp, "air_temp_dzidx", _aqconfig_.dzidx_air_temp);
writeIntValue(fp, "pool_water_temp_dzidx", _aqconfig_.dzidx_pool_water_temp);
writeIntValue(fp, "spa_water_temp_dzidx", _aqconfig_.dzidx_spa_water_temp);
writeIntValue(fp, "SWG_percent_dzidx", _aqconfig_.dzidx_swg_percent);
writeIntValue(fp, "SWG_PPM_dzidx", _aqconfig_.dzidx_swg_ppm);
writeIntValue(fp, "SWG_Status_dzidx", _aqconfig_.dzidx_swg_status);
fprintf(fp, "\n#** Buttons **\n");
for (i=0; i < TOTAL_BUTTONS; i++)

View File

@ -7,7 +7,8 @@
#include "aqualink.h"
#define DEFAULT_LOG_LEVEL 5
//#define DEFAULT_LOG_LEVEL 10
#define DEFAULT_LOG_LEVEL LOG_NOTICE
#define DEFAULT_WEBPORT "6580"
#define DEFAULT_WEBROOT "./"
#define DEFAULT_SERIALPORT "/dev/ttyUSB0"
@ -18,7 +19,6 @@
#define DEFAULT_MQTT_SERVER NULL
#define DEFAULT_MQTT_USER NULL
#define DEFAULT_MQTT_PASSWD NULL
// Set this high, as people are confused about SWG bouncing to zero on some panels, just stop the questions
#define DEFAILT_SWG_ZERO_IGNORE_COUNT 20
#define MQTT_ID_LEN 18 // 20 seems to kill mosquitto 1.6
@ -31,6 +31,8 @@ struct aqconfig
char *socket_port;
char *web_directory;
unsigned char device_id;
unsigned char onetouch_device_id;
bool extended_device_id_programming;
bool deamonize;
char *log_file;
char *mqtt_dz_sub_topic;
@ -53,6 +55,7 @@ struct aqconfig
int light_programming_button_spa;
bool override_freeze_protect;
bool pda_mode;
bool onetouch_mode;
bool pda_sleep_mode;
bool convert_mqtt_temp;
bool convert_dz_temp;
@ -75,13 +78,31 @@ struct aqconfig
//char *mqtt_pub_tp_ptr = mqtt_pub_topic[];
};
#ifndef CONFIG_C
extern struct aqconfig _aqconfig_;
#else
struct aqconfig _aqconfig_;
#endif
/*
#ifndef CONFIG_C
#ifdef AQUALINKD_C
extern struct aqconfig _aqconfig_;
#else
extern const struct aqconfig _aqconfig_;
#endif
#endif
*/
void init_parameters (struct aqconfig * parms);
//bool parse_config (struct aqconfig * parms, char *cfgfile);
//void readCfg (struct aqconfig *config_parameters, char *cfgFile);
void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqualink_data, char *cfgFile);
bool writeCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata);
bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqdata, char *param, char *value);
//void readCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqualink_data, char *cfgFile);
void read_config(struct aqualinkdata *aqdata, char *cfgFile);
void init_config();
bool writeCfg (struct aqualinkdata *aqdata);
bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value);
char *cleanalloc(char*str);
#endif

16
epump.h Normal file
View File

@ -0,0 +1,16 @@
/*
Nothing seems to change these in simulator, need real pump to test
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
0x10|0x02|0x7a|0x44|0x00|0x58|0x1b|0x43|0x10|0x03|
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
*/

View File

@ -171,12 +171,15 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
int length = 0;
buffer[0] = '\0';
for (i=0; i < MAX_PUMPS; i++) {
for (i=0; i < aqdata->num_pumps; i++) {
if (button == aqdata->pumps[i].button) {
if (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gph != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN) {
length += sprintf(buffer, ",\"Pump_RPM\":\"%d\",\"Pump_GPH\":\"%d\",\"Pump_Watts\":\"%d\"", aqdata->pumps[i].rpm,aqdata->pumps[i].gph,aqdata->pumps[i].watts);
//if (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gpm != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN) {
length += sprintf(buffer, ",\"Pump_RPM\":\"%d\",\"Pump_GPM\":\"%d\",\"Pump_Watts\":\"%d\",\"Pump_Type\":\"%s\"",
aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")));
break;
}
//}
}
}
@ -231,21 +234,38 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch1, int
LED2int(aqdata->aqbuttons[i].led->state));
} else if ( (programable_switch1 > 0 && programable_switch1 == i) ||
(programable_switch2 > 0 && programable_switch2 == i)) {
/*
length += sprintf(buffer+length, "{\"type\": \"switch_program\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" %s},",
aqdata->aqbuttons[i].name,
aqdata->aqbuttons[i].label,
aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
LED2text(aqdata->aqbuttons[i].led->state),
LED2int(aqdata->aqbuttons[i].led->state),
get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info));
get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info));*/
length += sprintf(buffer+length, "{\"type\": \"switch\", \"type_ext\": \"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),
LED2int(aqdata->aqbuttons[i].led->state));
} else {
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" %s},",
if ( get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info)[0] == '\0' ) {
length += sprintf(buffer+length, "{\"type\": \"switch\", \"type_ext\": \"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),
LED2int(aqdata->aqbuttons[i].led->state));
} else {
length += sprintf(buffer+length, "{\"type\": \"switch\", \"type_ext\": \"switch_vsp\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" %s},",
aqdata->aqbuttons[i].name,
aqdata->aqbuttons[i].label,
aqdata->aqbuttons[i].led->state==ON?JSON_ON:JSON_OFF,
LED2text(aqdata->aqbuttons[i].led->state),
LED2int(aqdata->aqbuttons[i].led->state),
get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info));
aux_info);
//get_aux_information(&aqdata->aqbuttons[i], aqdata, aux_info));
}
}
}
@ -455,10 +475,12 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
//length += sprintf(buffer+length, "}, \"extra\":{" );
length += sprintf(buffer+length, "},");
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\":{\"name\":\"%s\",\"id\":\"%s\",\"RPM\":\"%d\",\"GPH\":\"%d\",\"Watts\":\"%d\"},",
i+1,aqdata->pumps[i].button->label,aqdata->pumps[i].button->name,aqdata->pumps[i].rpm,aqdata->pumps[i].gph,aqdata->pumps[i].watts);
// NSF Check below needs to be for VSP Pump (any state), not just known state
for (i=0; i < aqdata->num_pumps; i++) {
if (aqdata->pumps[i].pumpType != PT_UNKNOWN && (aqdata->pumps[i].rpm != TEMP_UNKNOWN || aqdata->pumps[i].gpm != TEMP_UNKNOWN || aqdata->pumps[i].watts != TEMP_UNKNOWN)) {
length += sprintf(buffer+length, "\"Pump_%d\":{\"name\":\"%s\",\"id\":\"%s\",\"RPM\":\"%d\",\"GPM\":\"%d\",\"Watts\":\"%d\",\"Pump_Type\":\"%s\"},",
i+1,aqdata->pumps[i].button->label,aqdata->pumps[i].button->name,aqdata->pumps[i].rpm,aqdata->pumps[i].gpm,aqdata->pumps[i].watts,
(aqdata->pumps[i].pumpType==VFPUMP?"vfPump":(aqdata->pumps[i].pumpType==VSPUMP?"vsPump":"ePump")));
}
}

View File

@ -4,7 +4,7 @@
//FUNCTION PROTOTYPES
#define JSON_LABEL_SIZE 300
#define JSON_STATUS_SIZE 800
#define JSON_STATUS_SIZE 1024
#define JSON_MQTT_MSG_SIZE 100
#define JSON_ON "on"

View File

@ -37,7 +37,7 @@
#include "aquapure.h"
static struct aqconfig *_aqualink_config;
//static struct aqconfig *_aqconfig_;
static struct aqualinkdata *_aqualink_data;
static char *_web_root;
@ -70,7 +70,13 @@ static void signal_handler(int sig_num) {
static int is_websocket(const struct mg_connection *nc) {
return nc->flags & MG_F_IS_WEBSOCKET;
return nc->flags & MG_F_IS_WEBSOCKET && !(nc->flags & MG_F_USER_2);
}
static void set_websocket_RSraw(struct mg_connection *nc) {
nc->flags |= MG_F_USER_2;
}
static int is_websocket_RSraw(const struct mg_connection *nc) {
return nc->flags & MG_F_USER_2;
}
static int is_mqtt(const struct mg_connection *nc) {
return nc->flags & MG_F_USER_1;
@ -153,7 +159,7 @@ void send_domoticz_mqtt_state_msg(struct mg_connection *nc, int idx, int value)
char mqtt_msg[JSON_MQTT_MSG_SIZE];
build_mqtt_status_JSON(mqtt_msg ,JSON_MQTT_MSG_SIZE, idx, value, TEMP_UNKNOWN);
send_mqtt(nc, _aqualink_config->mqtt_dz_pub_topic, mqtt_msg);
send_mqtt(nc, _aqconfig_.mqtt_dz_pub_topic, mqtt_msg);
}
void send_domoticz_mqtt_temp_msg(struct mg_connection *nc, int idx, int value)
@ -162,8 +168,8 @@ void send_domoticz_mqtt_temp_msg(struct mg_connection *nc, int idx, int value)
return;
char mqtt_msg[JSON_MQTT_MSG_SIZE];
build_mqtt_status_JSON(mqtt_msg ,JSON_MQTT_MSG_SIZE, idx, 0, (_aqualink_data->temp_units==FAHRENHEIT && _aqualink_config->convert_dz_temp)?roundf(degFtoC(value)):value);
send_mqtt(nc, _aqualink_config->mqtt_dz_pub_topic, mqtt_msg);
build_mqtt_status_JSON(mqtt_msg ,JSON_MQTT_MSG_SIZE, idx, 0, (_aqualink_data->temp_units==FAHRENHEIT && _aqconfig_.convert_dz_temp)?roundf(degFtoC(value)):value);
send_mqtt(nc, _aqconfig_.mqtt_dz_pub_topic, mqtt_msg);
}
void send_domoticz_mqtt_numeric_msg(struct mg_connection *nc, int idx, int value)
{
@ -172,7 +178,7 @@ void send_domoticz_mqtt_numeric_msg(struct mg_connection *nc, int idx, int value
char mqtt_msg[JSON_MQTT_MSG_SIZE];
build_mqtt_status_JSON(mqtt_msg ,JSON_MQTT_MSG_SIZE, idx, 0, value);
send_mqtt(nc, _aqualink_config->mqtt_dz_pub_topic, mqtt_msg);
send_mqtt(nc, _aqconfig_.mqtt_dz_pub_topic, mqtt_msg);
}
void send_domoticz_mqtt_status_message(struct mg_connection *nc, int idx, int value, char *svalue) {
if (idx <= 0)
@ -181,17 +187,17 @@ void send_domoticz_mqtt_status_message(struct mg_connection *nc, int idx, int va
char mqtt_msg[JSON_MQTT_MSG_SIZE];
build_mqtt_status_message_JSON(mqtt_msg, JSON_MQTT_MSG_SIZE, idx, value, svalue);
send_mqtt(nc, _aqualink_config->mqtt_dz_pub_topic, mqtt_msg);
send_mqtt(nc, _aqconfig_.mqtt_dz_pub_topic, mqtt_msg);
}
void send_mqtt_state_msg(struct mg_connection *nc, char *dev_name, aqledstate state)
{
static char mqtt_pub_topic[250];
sprintf(mqtt_pub_topic, "%s/%s/delay",_aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s/delay",_aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, (state==FLASH?MQTT_ON:MQTT_OFF));
sprintf(mqtt_pub_topic, "%s/%s",_aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s",_aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON));
}
@ -203,8 +209,8 @@ void send_mqtt_aux_msg(struct mg_connection *nc, char *dev_name, char *dev_topic
sprintf(msg, "%d", value);
//sprintf(mqtt_pub_topic, "%s/%s%d%s",_aqualink_config->mqtt_aq_topic, root_topic, dev_index, dev_topic);
sprintf(mqtt_pub_topic, "%s/%s%s",_aqualink_config->mqtt_aq_topic, dev_name, dev_topic);
//sprintf(mqtt_pub_topic, "%s/%s%d%s",_aqconfig_.mqtt_aq_topic, root_topic, dev_index, dev_topic);
sprintf(mqtt_pub_topic, "%s/%s%s",_aqconfig_.mqtt_aq_topic, dev_name, dev_topic);
send_mqtt(nc, mqtt_pub_topic, msg);
}
@ -213,15 +219,15 @@ void send_mqtt_heater_state_msg(struct mg_connection *nc, char *dev_name, aqleds
static char mqtt_pub_topic[250];
sprintf(mqtt_pub_topic, "%s/%s",_aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s",_aqconfig_.mqtt_aq_topic, dev_name);
if (state == ENABLE) {
send_mqtt(nc, mqtt_pub_topic, MQTT_OFF);
sprintf(mqtt_pub_topic, "%s/%s%s",_aqualink_config->mqtt_aq_topic, dev_name, ENABELED_SUBT);
sprintf(mqtt_pub_topic, "%s/%s%s",_aqconfig_.mqtt_aq_topic, dev_name, ENABELED_SUBT);
send_mqtt(nc, mqtt_pub_topic, MQTT_ON);
} else {
send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON));
sprintf(mqtt_pub_topic, "%s/%s%s",_aqualink_config->mqtt_aq_topic, dev_name, ENABELED_SUBT);
sprintf(mqtt_pub_topic, "%s/%s%s",_aqconfig_.mqtt_aq_topic, dev_name, ENABELED_SUBT);
send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON));
}
}
@ -231,8 +237,8 @@ void send_mqtt_temp_msg(struct mg_connection *nc, char *dev_name, long value)
{
static char mqtt_pub_topic[250];
static char degC[10];
sprintf(degC, "%.2f", (_aqualink_data->temp_units==FAHRENHEIT && _aqualink_config->convert_mqtt_temp)?degFtoC(value):value );
sprintf(mqtt_pub_topic, "%s/%s", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(degC, "%.2f", (_aqualink_data->temp_units==FAHRENHEIT && _aqconfig_.convert_mqtt_temp)?degFtoC(value):value );
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, degC);
}
/*
@ -241,9 +247,9 @@ void send_mqtt_temp_msg_new(struct mg_connection *nc, char *dev_name, long value
static char mqtt_pub_topic[250];
static char degC[5];
// NSF remove false below once we have finished.
sprintf(degC, "%.2f", (false && _aqualink_data->temp_units==FAHRENHEIT && _aqualink_config->convert_mqtt_temp)?degFtoC(value):value );
sprintf(degC, "%.2f", (false && _aqualink_data->temp_units==FAHRENHEIT && _aqconfig_.convert_mqtt_temp)?degFtoC(value):value );
//sprintf(degC, "%d", value );
sprintf(mqtt_pub_topic, "%s/%s", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, degC);
}
*/
@ -252,8 +258,8 @@ void send_mqtt_setpoint_msg(struct mg_connection *nc, char *dev_name, long value
static char mqtt_pub_topic[250];
static char degC[10];
sprintf(degC, "%.2f", (_aqualink_data->temp_units==FAHRENHEIT && _aqualink_config->convert_mqtt_temp)?degFtoC(value):value );
sprintf(mqtt_pub_topic, "%s/%s/setpoint", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(degC, "%.2f", (_aqualink_data->temp_units==FAHRENHEIT && _aqconfig_.convert_mqtt_temp)?degFtoC(value):value );
sprintf(mqtt_pub_topic, "%s/%s/setpoint", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, degC);
}
void send_mqtt_numeric_msg(struct mg_connection *nc, char *dev_name, int value)
@ -262,7 +268,7 @@ void send_mqtt_numeric_msg(struct mg_connection *nc, char *dev_name, int value)
static char msg[10];
sprintf(msg, "%d", value);
sprintf(mqtt_pub_topic, "%s/%s", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, msg);
}
void send_mqtt_float_msg(struct mg_connection *nc, char *dev_name, float value) {
@ -270,7 +276,7 @@ void send_mqtt_float_msg(struct mg_connection *nc, char *dev_name, float value)
static char msg[10];
sprintf(msg, "%.2f", value);
sprintf(mqtt_pub_topic, "%s/%s", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, msg);
}
@ -281,7 +287,7 @@ void send_mqtt_int_msg(struct mg_connection *nc, char *dev_name, int value) {
static char msg[10];
sprintf(msg, "%d", value);
sprintf(mqtt_pub_topic, "%s/%s", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, msg);
*/
}
@ -289,7 +295,7 @@ void send_mqtt_int_msg(struct mg_connection *nc, char *dev_name, int value) {
void send_mqtt_string_msg(struct mg_connection *nc, char *dev_name, char *msg) {
static char mqtt_pub_topic[250];
sprintf(mqtt_pub_topic, "%s/%s", _aqualink_config->mqtt_aq_topic, dev_name);
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
send_mqtt(nc, mqtt_pub_topic, msg);
}
@ -321,41 +327,41 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
_last_mqtt_aqualinkdata.air_temp = _aqualink_data->air_temp;
send_mqtt_temp_msg(nc, AIR_TEMP_TOPIC, _aqualink_data->air_temp);
//send_mqtt_temp_msg_new(nc, AIR_TEMPERATURE_TOPIC, _aqualink_data->air_temp);
send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_air_temp, _aqualink_data->air_temp);
send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_air_temp, _aqualink_data->air_temp);
}
/*
if (_aqualink_data->pool_temp != TEMP_UNKNOWN && _aqualink_data->pool_temp != _last_mqtt_aqualinkdata.pool_temp) {
_last_mqtt_aqualinkdata.pool_temp = _aqualink_data->pool_temp;
send_mqtt_temp_msg(nc, POOL_TEMP_TOPIC, _aqualink_data->pool_temp);
send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_pool_water_temp, _aqualink_data->pool_temp);
send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_pool_water_temp, _aqualink_data->pool_temp);
// IF spa is off, report pool water temp to Domoticz.
if (_aqualink_data->spa_temp == TEMP_UNKNOWN)
send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_spa_water_temp, _aqualink_data->pool_temp);
send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_spa_water_temp, _aqualink_data->pool_temp);
}
*/
if (_aqualink_data->pool_temp != _last_mqtt_aqualinkdata.pool_temp) {
if (_aqualink_data->pool_temp == TEMP_UNKNOWN && _aqualink_config->report_zero_pool_temp) {
if (_aqualink_data->pool_temp == TEMP_UNKNOWN && _aqconfig_.report_zero_pool_temp) {
_last_mqtt_aqualinkdata.pool_temp = TEMP_UNKNOWN;
send_mqtt_temp_msg(nc, POOL_TEMP_TOPIC, (_aqualink_config->convert_mqtt_temp?-18:0));
send_mqtt_temp_msg(nc, POOL_TEMP_TOPIC, (_aqconfig_.convert_mqtt_temp?-18:0));
} else if (_aqualink_data->pool_temp != TEMP_UNKNOWN) {
_last_mqtt_aqualinkdata.pool_temp = _aqualink_data->pool_temp;
send_mqtt_temp_msg(nc, POOL_TEMP_TOPIC, _aqualink_data->pool_temp);
send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_pool_water_temp, _aqualink_data->pool_temp);
send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_pool_water_temp, _aqualink_data->pool_temp);
// IF spa is off, report pool water temp to Domoticz.
if (_aqualink_data->spa_temp == TEMP_UNKNOWN)
send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_spa_water_temp, _aqualink_data->pool_temp);
send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_spa_water_temp, _aqualink_data->pool_temp);
}
}
if (_aqualink_data->spa_temp != _last_mqtt_aqualinkdata.spa_temp) {
if (_aqualink_data->spa_temp == TEMP_UNKNOWN && _aqualink_config->report_zero_spa_temp) {
if (_aqualink_data->spa_temp == TEMP_UNKNOWN && _aqconfig_.report_zero_spa_temp) {
_last_mqtt_aqualinkdata.spa_temp = TEMP_UNKNOWN;
send_mqtt_temp_msg(nc, SPA_TEMP_TOPIC, (_aqualink_config->convert_mqtt_temp?-18:0));
send_mqtt_temp_msg(nc, SPA_TEMP_TOPIC, (_aqconfig_.convert_mqtt_temp?-18:0));
} else if (_aqualink_data->spa_temp != TEMP_UNKNOWN) {
_last_mqtt_aqualinkdata.spa_temp = _aqualink_data->spa_temp;
send_mqtt_temp_msg(nc, SPA_TEMP_TOPIC, _aqualink_data->spa_temp);
send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_spa_water_temp, _aqualink_data->spa_temp);
send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_spa_water_temp, _aqualink_data->spa_temp);
}
}
@ -363,7 +369,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
_last_mqtt_aqualinkdata.pool_htr_set_point = _aqualink_data->pool_htr_set_point;
send_mqtt_setpoint_msg(nc, BTN_POOL_HTR, _aqualink_data->pool_htr_set_point);
// removed until domoticz has a better virtuel thermostat
//send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_pool_thermostat, _aqualink_data->pool_htr_set_point);
//send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_pool_thermostat, _aqualink_data->pool_htr_set_point);
}
if (_aqualink_data->spa_htr_set_point != TEMP_UNKNOWN && _aqualink_data->spa_htr_set_point != _last_mqtt_aqualinkdata.spa_htr_set_point) {
@ -384,7 +390,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
send_mqtt_string_msg(nc, FREEZE_PROTECT_ENABELED, MQTT_ON);
/*
send_mqtt_string_msg(nc, FREEZE_PROTECT_ENABELED, MQTT_ON);
//send_domoticz_mqtt_temp_msg(nc, _aqualink_config->dzidx_rfz_protect, _aqualink_data->frz_protect_set_point);
//send_domoticz_mqtt_temp_msg(nc, _aqconfig_.dzidx_rfz_protect, _aqualink_data->frz_protect_set_point);
} else if (_aqualink_data->frz_protect_set_point != _last_mqtt_aqualinkdata.frz_protect_set_point) {
_last_mqtt_aqualinkdata.frz_protect_set_point = _aqualink_data->frz_protect_set_point;
send_mqtt_string_msg(nc, FREEZE_PROTECT_ENABELED, MQTT_OFF);*/
@ -411,7 +417,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
if (!_aqualink_data->simulate_panel)
sprintf(_aqualink_data->last_display_message, message);
send_domoticz_mqtt_status_message(nc, _aqualink_config->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_TOPIC, status);
if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF)
@ -436,13 +442,13 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
send_mqtt_numeric_msg(nc, SWG_PERCENT_TOPIC, _aqualink_data->swg_percent);
send_mqtt_float_msg(nc, SWG_PERCENT_F_TOPIC, roundf(degFtoC(_aqualink_data->swg_percent)));
send_mqtt_float_msg(nc, SWG_SETPOINT_TOPIC, roundf(degFtoC(_aqualink_data->swg_percent)));
send_domoticz_mqtt_numeric_msg(nc, _aqualink_config->dzidx_swg_percent, _aqualink_data->swg_percent);
send_domoticz_mqtt_numeric_msg(nc, _aqconfig_.dzidx_swg_percent, _aqualink_data->swg_percent);
}
if (_aqualink_data->swg_ppm != TEMP_UNKNOWN && ( force_update || _aqualink_data->swg_ppm != _last_mqtt_aqualinkdata.swg_ppm)) {
_last_mqtt_aqualinkdata.swg_ppm = _aqualink_data->swg_ppm;
send_mqtt_numeric_msg(nc, SWG_PPM_TOPIC, _aqualink_data->swg_ppm);
send_mqtt_float_msg(nc, SWG_PPM_F_TOPIC, roundf(degFtoC(_aqualink_data->swg_ppm)));
send_domoticz_mqtt_numeric_msg(nc, _aqualink_config->dzidx_swg_ppm, _aqualink_data->swg_ppm);
send_domoticz_mqtt_numeric_msg(nc, _aqconfig_.dzidx_swg_ppm, _aqualink_data->swg_ppm);
}
}
@ -453,7 +459,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
// Loop over LED's and send any changes.
for (i=0; i < TOTAL_BUTTONS; i++) {
/*
if ( _aqualink_data->aqbuttons[i].led->state == FLASH && _aqualink_config->flash_mqtt_buttons == true ) {
if ( _aqualink_data->aqbuttons[i].led->state == FLASH && _aqconfig_.flash_mqtt_buttons == true ) {
// Simply send on or off depending on if current second is odd or even.
// will send too many off and on messages as we get hit multiple times a second, but most effecient way to handle this
// considering flash is not very often and not for long.
@ -475,7 +481,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
}
// Loop over Pumps
for (i=0; i < MAX_PUMPS; i++) {
for (i=0; i < _aqualink_data->num_pumps; i++) {
//_aqualink_data->pumps[i].rpm = TEMP_UNKNOWN;
//_aqualink_data->pumps[i].gph = TEMP_UNKNOWN;
//_aqualink_data->pumps[i].watts = TEMP_UNKNOWN;
@ -485,10 +491,10 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
//send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_RPM_TOPIC, _aqualink_data->pumps[i].rpm);
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, 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;
if (_aqualink_data->pumps[i].gpm != TEMP_UNKNOWN && _aqualink_data->pumps[i].gpm != _last_mqtt_aqualinkdata.pumps[i].gpm) {
_last_mqtt_aqualinkdata.pumps[i].gpm = _aqualink_data->pumps[i].gpm;
//send_mqtt_aux_msg(nc, PUMP_TOPIC, i+1, PUMP_GPH_TOPIC, _aqualink_data->pumps[i].gph);
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_GPH_TOPIC, _aqualink_data->pumps[i].gph);
send_mqtt_aux_msg(nc, _aqualink_data->pumps[i].button->name, PUMP_GPM_TOPIC, _aqualink_data->pumps[i].gpm);
}
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;
@ -507,7 +513,7 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
//if (_aqualink_data->aqbuttons[i].dz_idx != DZ_NULL_IDX) {
if (_aqualink_data->aqbuttons[i].code == KEY_POOL_HTR || _aqualink_data->aqbuttons[i].code == KEY_SPA_HTR) {
send_mqtt_heater_state_msg(nc, _aqualink_data->aqbuttons[i].name, _aqualink_data->aqbuttons[i].led->state);
} else if (_aqualink_data->aqbuttons[i].led->state == FLASH && _aqualink_config->flash_mqtt_buttons == true) {
} else if (_aqualink_data->aqbuttons[i].led->state == FLASH && _aqconfig_.flash_mqtt_buttons == true) {
// This messed up the origional LED state, which means we send the flash to WEB UI as well.
time_t now;
now = time(NULL);
@ -553,12 +559,12 @@ int getTempforMeteohub(char *buffer)
void set_light_mode(char *value, int button)
{
if (_aqualink_config->pda_mode == true) {
if (_aqconfig_.pda_mode == true) {
logMessage(LOG_ERR, "Light mode control not supported in PDA mode\n");
return;
}
if (_aqualink_config->light_programming_button_pool != button &&
_aqualink_config->light_programming_button_spa != button) {
if (_aqconfig_.light_programming_button_pool != button &&
_aqconfig_.light_programming_button_spa != button) {
logMessage(LOG_ERR, "Light mode control not configured for button %d\n",button);
return;
}
@ -567,9 +573,9 @@ void set_light_mode(char *value, int button)
// 5 below is light index, need to look this up so it's not hard coded.
sprintf(buf, "%-5s%-5d%-5d%-5d%.2f",value,
button,
_aqualink_config->light_programming_initial_on,
_aqualink_config->light_programming_initial_off,
_aqualink_config->light_programming_mode );
_aqconfig_.light_programming_initial_on,
_aqconfig_.light_programming_initial_off,
_aqconfig_.light_programming_mode );
//logMessage(LOG_NOTICE, "WEB: requset light mode %s\n", buf);
aq_programmer(AQ_SET_COLORMODE, buf, _aqualink_data);
}
@ -611,24 +617,20 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
char value[20];
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
//aq_programmer(AQ_SET_COLORMODE, value, _aqualink_data);
set_light_mode(value, _aqualink_config->light_programming_button_pool);
set_light_mode(value, _aqconfig_.light_programming_button_pool);
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
} else if (strcmp(command, "spalightmode") == 0) {
char value[20];
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
//aq_programmer(AQ_SET_COLORMODE, value, _aqualink_data);
set_light_mode(value, _aqualink_config->light_programming_button_spa);
set_light_mode(value, _aqconfig_.light_programming_button_spa);
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
} else if (strcmp(command, "diag") == 0) {
aq_programmer(AQ_GET_DIAGNOSTICS_MODEL, NULL, _aqualink_data);
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
} else if (strcmp(command, "settime") == 0) {
aq_programmer(AQ_SET_TIME, NULL, _aqualink_data);
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
} else if (strcmp(command, "swg_percent") == 0) {
char value[20];
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
@ -659,12 +661,12 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
} else if (strcmp(command, "devices") == 0) {
char message[JSON_LABEL_SIZE*10];
int size = build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button_pool, _aqualink_config->light_programming_button_spa, message, JSON_LABEL_SIZE*10, false);
int size = build_device_JSON(_aqualink_data, _aqconfig_.light_programming_button_pool, _aqconfig_.light_programming_button_spa, message, JSON_LABEL_SIZE*10, false);
mg_send_head(nc, 200, size, "Content-Type: application/json");
mg_send(nc, message, size);
} else if (strcmp(command, "homebridge") == 0) {
char message[JSON_LABEL_SIZE*10];
int size = build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button_pool, _aqualink_config->light_programming_button_spa, message, JSON_LABEL_SIZE*10, true);
int size = build_device_JSON(_aqualink_data, _aqconfig_.light_programming_button_pool, _aqconfig_.light_programming_button_spa, message, JSON_LABEL_SIZE*10, true);
mg_send_head(nc, 200, size, "Content-Type: application/json");
mg_send(nc, message, size);
} else if (strcmp(command, "setconfigprm") == 0) {
@ -674,7 +676,7 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
mg_get_http_var(&http_msg->query_string, "param", param, sizeof(param));
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
if (setConfigValue(_aqualink_config, _aqualink_data, param, value)) {
if (setConfigValue(_aqualink_data, param, value)) {
webrtn = GET_RTN_OK;
logMessage(LOG_INFO, "Web: request to config %s to %s\n", param, value);
} else {
@ -684,7 +686,7 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
mg_send_head(nc, 200, strlen(webrtn), "Content-Type: text/plain");
mg_send(nc, webrtn, strlen(webrtn));
} else if (strcmp(command, "writeconfig") == 0) {
if (writeCfg (_aqualink_config, _aqualink_data)) {
if (writeCfg (_aqualink_data)) {
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
} else {
@ -704,8 +706,12 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
stopInlineDebug();
rtn = GET_RTN_OK;
} else if (strcmp(value, "serialstart") == 0) {
startInlineSerialDebug();
logMessage(LOG_DEBUG, "WEB: Started inline debug mode\n");
rtn = GET_RTN_OK;
} else if (strcmp(value, "serialstop") == 0) {
logMessage(LOG_DEBUG, "WEB: Stoped inline debug mode\n");
stopInlineDebug();
rtn = GET_RTN_OK;
} else if (strcmp(value, "status") == 0) {
snprintf(value,80,"{\"sLevel\":\"%s\", \"iLevel\":%d, \"logReady\":\"%s\"}\n",elevel2text(getLogLevel()),getLogLevel(),islogFileReady()?"true":"false" );
@ -724,6 +730,28 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
}
mg_send_head(nc, 200, strlen(rtn), "Content-Type: text/plain");
mg_send(nc, rtn, strlen(rtn));
} else if (strncmp(command, "Pump_", 5) == 0) {
// Set Pump RPM
bool found = false;
int pumpIndex = atoi(command+5); // Check for 0
char value[10];
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
int rpm = atoi(value);
// Check for pumpIndex = 0 (BAD) and check RPM Value
//printf("******** ADD CHECK FOR PUMP & RPM HERE ********\n");
int pi;
for (pi=0; pi < _aqualink_data->num_pumps; pi++) {
if (_aqualink_data->pumps[pi].pumpIndex == pumpIndex) {
logMessage(LOG_NOTICE, "WEB: request to change pump %d to %d\n",pumpIndex, round(rpm));
_aqualink_data->unactioned.type = PUMP_RPM;
_aqualink_data->unactioned.value = round(rpm);
_aqualink_data->unactioned.id = pumpIndex;
found=true;
break;
}
}
if(!found)
logMessage(LOG_ERR, "WEB: Didn't find pump %d from command %s\n",pumpIndex,command);
} else {
int i;
for (i = 0; i < TOTAL_BUTTONS; i++) {
@ -736,7 +764,7 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
// *)&_aqualink_data->aqbuttons[i].code, _aqualink_data);
logMessage(LOG_DEBUG, "WEB: Message request '%s' change state to '%s'\n", command, value);
if (_aqualink_config->pda_mode == true) {
if (_aqconfig_.pda_mode == true) {
char msg[PTHREAD_ARG];
sprintf(msg, "%-5d%-5d",i, (strcmp(value, "on") == 0)?ON:OFF);
//printf("******* '%s' ********\n",msg);
@ -825,8 +853,12 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
//aq_programmer(AQ_SEND_CMD, (char *)&n, NULL);
aq_send_cmd((unsigned char)n);
//char message[JSON_LABEL_SIZE*10];
//build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button, message, JSON_LABEL_SIZE*10);
//build_device_JSON(_aqualink_data, _aqconfig_.light_programming_button, message, JSON_LABEL_SIZE*10);
//ws_send(nc, message);
} else if (strcmp(request.first.key, "mode") == 0) {
if (strcmp(request.first.value, "onetouchraw") == 0) {
set_websocket_RSraw(nc);
}
} else if (strcmp(request.first.key, "command") == 0) {
_aqualink_data->simulate_panel = false;
if (strcmp(request.first.value, "GET_AUX_LABELS") == 0) {
@ -835,7 +867,7 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
ws_send(nc, labels);
} else if (strcmp(request.first.value, "GET_DEVICES") == 0) {
char message[JSON_LABEL_SIZE*10];
build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button_pool, _aqualink_config->light_programming_button_spa, message, JSON_LABEL_SIZE*10, false);
build_device_JSON(_aqualink_data, _aqconfig_.light_programming_button_pool, _aqconfig_.light_programming_button_spa, message, JSON_LABEL_SIZE*10, false);
ws_send(nc, message);
} else if ( strcmp(request.first.value, "simulator") == 0) {
_aqualink_data->simulate_panel = true;
@ -857,7 +889,7 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
if (strcmp(request.first.value, _aqualink_data->aqbuttons[i].name) == 0) {
logMessage (LOG_INFO, "WS: button '%s' pressed\n",_aqualink_data->aqbuttons[i].name);
// send_command( (unsigned char)_aqualink_data->aqbuttons[i].code);
if (_aqualink_config->pda_mode == false) {
if (_aqconfig_.pda_mode == false) {
//aq_programmer(AQ_SEND_CMD, (char *)&_aqualink_data->aqbuttons[i].code, _aqualink_data);
aq_send_cmd(_aqualink_data->aqbuttons[i].code);
} else {
@ -889,7 +921,7 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
_aqualink_data->swg_percent = value; // Set the value as if it's already been set, just incase it's 0 as we won't get that message, or will update next time
}
} else if (strcmp(request.first.value, "POOL_LIGHT_MODE") == 0) {
set_light_mode(request.second.value, _aqualink_config->light_programming_button_pool);
set_light_mode(request.second.value, _aqconfig_.light_programming_button_pool);
} else if (strcmp(request.first.value, "LIGHT_MODE") == 0) {
int i;
for (i = 0; i < TOTAL_BUTTONS; i++) {
@ -900,7 +932,26 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
}
//set_light_mode(request.second.value, 0);
} else {
logMessage(LOG_DEBUG, "WS: Unknown parameter %s\n", request.first.value);
int i;
bool found = false;
for (i = 0; i < TOTAL_BUTTONS; i++) {
if (strcmp(request.first.value, _aqualink_data->aqbuttons[i].name) == 0) {
int pi;
logMessage (LOG_INFO, "WS: button parameter request '%s' '%s'\n",_aqualink_data->aqbuttons[i].name, request.second.value);
for (pi=0; pi < _aqualink_data->num_pumps; pi++) {
if (_aqualink_data->pumps[pi].button == &_aqualink_data->aqbuttons[i]) {
logMessage(LOG_NOTICE, "WS: request to change pump %d %s to %s\n",pi, _aqualink_data->aqbuttons[i].name, request.second.value);
_aqualink_data->unactioned.type = PUMP_RPM;
_aqualink_data->unactioned.value = atoi(request.second.value);
_aqualink_data->unactioned.id = _aqualink_data->pumps[pi].pumpIndex;
found=true;
break;
}
}
}
}
if (!found)
logMessage(LOG_DEBUG, "WS: Unknown parameter %s\n", request.first.value);
}
}
}
@ -925,12 +976,12 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
//printf("Topic %.*s\n",msg->topic.len, msg->topic.p);
// get the parts from the topic
char *pt1 = (char *)&msg->topic.p[strlen(_aqualink_config->mqtt_aq_topic)+1];
char *pt1 = (char *)&msg->topic.p[strlen(_aqconfig_.mqtt_aq_topic)+1];
char *pt2 = NULL;
char *pt3 = NULL;
//for (i=10; i < msg->topic.len; i++) {
for (i=strlen(_aqualink_config->mqtt_aq_topic)+1; i < msg->topic.len; i++) {
for (i=strlen(_aqconfig_.mqtt_aq_topic)+1; i < msg->topic.len; i++) {
if ( msg->topic.p[i] == '/' ) {
if (pt2 == NULL) {
pt2 = (char *)&msg->topic.p[++i];
@ -949,8 +1000,11 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
//aqualinkd/Pool_Heater/set
//aqualinkd/SWG/Percent_f/set
//aqualinkd/Filter_Pump/RPM/set // Should add this at some point
//aqualinkd/Pump_1/RPM/set
if (pt3 != NULL && (strncmp(pt2, "setpoint", 8) == 0) && (strncmp(pt3, "set", 3) == 0)) {
int val = _aqualink_data->unactioned.value = (_aqualink_data->temp_units != CELSIUS && _aqualink_config->convert_mqtt_temp) ? round(degCtoF(value)) : round(value);
int val = _aqualink_data->unactioned.value = (_aqualink_data->temp_units != CELSIUS && _aqconfig_.convert_mqtt_temp) ? round(degCtoF(value)) : round(value);
if (strncmp(pt1, BTN_POOL_HTR, strlen(BTN_POOL_HTR)) == 0) {
_aqualink_data->unactioned.value = setpoint_check(POOL_HTR_SETOINT, val, _aqualink_data);
_aqualink_data->unactioned.type = POOL_HTR_SETOINT;
@ -984,6 +1038,28 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
} else if ((pt3 != NULL && (strncmp(pt1, "SWG", 3) == 0) && (strncmp(pt2, "Boost", 5) == 0) && (strncmp(pt3, "set", 3) == 0))) {
_aqualink_data->unactioned.value = round(value);
_aqualink_data->unactioned.type = SWG_BOOST;
} else if ((pt3 != NULL && (strncmp(pt1, "Pump_", 5) == 0) && ((strncmp(pt2, "RPM", 3) == 0) || (strncmp(pt2, "GPM", 3) == 0)) && (strncmp(pt3, "set", 3) == 0))) {
// Set Pump RPM
bool found = false;
int pumpIndex = atoi(pt1+5); // Check for 0
// Check for pumpIndex = 0 (BAD) and check RPM Value
//printf("******** ADD CHECK FOR PUMP & RPM HERE ********\n");
int pi;
for (pi=0; pi < _aqualink_data->num_pumps; pi++) {
if (_aqualink_data->pumps[pi].pumpIndex == pumpIndex) {
//printf("******** Set pump %d RPM to %d ******\n",pumpIndex, round(value));
//int val = RPM_check(_aqualink_data->pumps[pi].pumpType, val, _aqualink_data);
//RPM_check( val)
logMessage(LOG_NOTICE, "MQTT: request to change pump %d %s to %d\n",pumpIndex, (strncmp(pt2, "RPM", 3) == 0)?"RPM":"GPM", round(value));
_aqualink_data->unactioned.type = PUMP_RPM;
_aqualink_data->unactioned.value = round(value);
_aqualink_data->unactioned.id = pumpIndex;
found=true;
break;
}
}
if(!found)
logMessage(LOG_ERR, "MQTT: Didn't find pump %d from message %.*s\n",pumpIndex,msg->topic.len, msg->topic.p);
} else if (pt2 != NULL && (strncmp(pt2, "set", 3) == 0) && (strncmp(pt2, "setpoint", 8) != 0)) {
// Must be a switch on / off
for (i=0; i < TOTAL_BUTTONS; i++) {
@ -1003,7 +1079,7 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
} else {
logMessage(LOG_INFO, "MQTT: received '%s' for '%s', turning '%s'\n", (value==0?"OFF":"ON"), _aqualink_data->aqbuttons[i].name,(value==0?"OFF":"ON"));
//aq_programmer(AQ_SEND_CMD, (char *)&_aqualink_data->aqbuttons[i].code, _aqualink_data);
if (_aqualink_config->pda_mode == false) {
if (_aqconfig_.pda_mode == false) {
//aq_programmer(AQ_SEND_CMD, (char *)&_aqualink_data->aqbuttons[i].code, _aqualink_data);
aq_send_cmd(_aqualink_data->aqbuttons[i].code);
} else {
@ -1048,7 +1124,7 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
} else {
logMessage(LOG_INFO, "MQTT: DZ: received '%s' for '%s', turning '%s'\n", (nvalue==DZ_OFF?"OFF":"ON"), _aqualink_data->aqbuttons[i].name,(nvalue==DZ_OFF?"OFF":"ON"));
//aq_programmer(AQ_SEND_CMD, (char *)&_aqualink_data->aqbuttons[i].code, _aqualink_data);
if (_aqualink_config->pda_mode == false) {
if (_aqconfig_.pda_mode == false) {
//aq_programmer(AQ_SEND_CMD, (char *)&_aqualink_data->aqbuttons[i].code, _aqualink_data);
aq_send_cmd(_aqualink_data->aqbuttons[i].code);
} else {
@ -1062,7 +1138,7 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
}
}
/* removed until domoticz has a better virtual thermostat
if (idx == _aqualink_config->dzidx_pool_thermostat) {
if (idx == _aqconfig_.dzidx_pool_thermostat) {
float degC = atof(svalue);
int degF = (int)degCtoF(degC);
if (degC > 0.0 && 1 < (degF - _aqualink_data->pool_htr_set_point)) {
@ -1071,7 +1147,7 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
} else {
logMessage(LOG_INFO, "MQTT: DZ: received temp setting '%s' for 'pool heater setpoint' matched current setting (or was zero), ignoring!\n", svalue);
}
} else if (idx == _aqualink_config->dzidx_spa_thermostat) {
} else if (idx == _aqconfig_.dzidx_spa_thermostat) {
float degC = atof(svalue);
int degF = (int)degCtoF(degC);
if (degC > 0.0 && 1 < (degF - _aqualink_data->spa_htr_set_point)) {
@ -1132,18 +1208,18 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
//char *MQTT_id = "AQUALINK_MQTT_TEST_ID";
struct mg_send_mqtt_handshake_opts opts;
memset(&opts, 0, sizeof(opts));
opts.user_name = _aqualink_config->mqtt_user;
opts.password = _aqualink_config->mqtt_passwd;
opts.user_name = _aqconfig_.mqtt_user;
opts.password = _aqconfig_.mqtt_passwd;
opts.keep_alive = 5;
opts.flags |= MG_MQTT_CLEAN_SESSION; // NFS Need to readup on this
snprintf(aq_topic, 24, "%s/%s", _aqualink_config->mqtt_aq_topic,MQTT_LWM_TOPIC);
snprintf(aq_topic, 24, "%s/%s", _aqconfig_.mqtt_aq_topic,MQTT_LWM_TOPIC);
opts.will_topic = aq_topic;
opts.will_message = MQTT_OFF;
mg_set_protocol_mqtt(nc);
mg_send_mqtt_handshake_opt(nc, _aqualink_config->mqtt_ID, opts);
logMessage(LOG_INFO, "MQTT: Subscribing mqtt with id of: %s\n", _aqualink_config->mqtt_ID);
mg_send_mqtt_handshake_opt(nc, _aqconfig_.mqtt_ID, opts);
logMessage(LOG_INFO, "MQTT: Subscribing mqtt with id of: %s\n", _aqconfig_.mqtt_ID);
//last_control_time = mg_time();
} break;
@ -1160,27 +1236,27 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
_mqtt_exit_flag = true;
}
snprintf(aq_topic, 29, "%s/#", _aqualink_config->mqtt_aq_topic);
if (_aqualink_config->mqtt_aq_topic != NULL && _aqualink_config->mqtt_dz_sub_topic != NULL) {
snprintf(aq_topic, 29, "%s/#", _aqconfig_.mqtt_aq_topic);
if (_aqconfig_.mqtt_aq_topic != NULL && _aqconfig_.mqtt_dz_sub_topic != NULL) {
topics[0].topic = aq_topic;
topics[0].qos = qos;
topics[1].topic = _aqualink_config->mqtt_dz_sub_topic;
topics[1].topic = _aqconfig_.mqtt_dz_sub_topic;
topics[1].qos = qos;
mg_mqtt_subscribe(nc, topics, 2, 42);
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", aq_topic);
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", _aqualink_config->mqtt_dz_sub_topic);
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", _aqconfig_.mqtt_dz_sub_topic);
}
else if (_aqualink_config->mqtt_aq_topic != NULL) {
else if (_aqconfig_.mqtt_aq_topic != NULL) {
topics[0].topic = aq_topic;
topics[0].qos = qos;
mg_mqtt_subscribe(nc, topics, 1, 42);
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", aq_topic);
}
else if (_aqualink_config->mqtt_dz_sub_topic != NULL) {
topics[0].topic = _aqualink_config->mqtt_dz_sub_topic;;
else if (_aqconfig_.mqtt_dz_sub_topic != NULL) {
topics[0].topic = _aqconfig_.mqtt_dz_sub_topic;;
topics[0].qos = qos;
mg_mqtt_subscribe(nc, topics, 1, 42);
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", _aqualink_config->mqtt_dz_sub_topic);
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", _aqconfig_.mqtt_dz_sub_topic);
}
}
break;
@ -1190,20 +1266,21 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
break;
case MG_EV_MQTT_SUBACK:
logMessage(LOG_INFO, "MQTT: Subscription(s) acknowledged\n");
snprintf(aq_topic, 24, "%s/%s", _aqualink_config->mqtt_aq_topic,MQTT_LWM_TOPIC);
snprintf(aq_topic, 24, "%s/%s", _aqconfig_.mqtt_aq_topic,MQTT_LWM_TOPIC);
send_mqtt(nc, aq_topic ,MQTT_ON);
break;
case MG_EV_MQTT_PUBLISH:
mqtt_msg = (struct mg_mqtt_message *)ev_data;
if (mqtt_msg->message_id != 0) {
logMessage(LOG_INFO, "MQTT: received (msg_id: %d), looks like my own message, ignoring\n", mqtt_msg->message_id);
logMessage(LOG_DEBUG, "MQTT: received (msg_id: %d), looks like my own message, ignoring\n", mqtt_msg->message_id);
}
// NSF Need to change strlen to a global so it's not executed every time we check a topic
if (_aqualink_config->mqtt_aq_topic != NULL && strncmp(mqtt_msg->topic.p, _aqualink_config->mqtt_aq_topic, strlen(_aqualink_config->mqtt_aq_topic)) == 0) {
if (_aqconfig_.mqtt_aq_topic != NULL && strncmp(mqtt_msg->topic.p, _aqconfig_.mqtt_aq_topic, strlen(_aqconfig_.mqtt_aq_topic)) == 0)
{
action_mqtt_message(nc, mqtt_msg);
}
if (_aqualink_config->mqtt_dz_sub_topic != NULL && strncmp(mqtt_msg->topic.p, _aqualink_config->mqtt_dz_sub_topic, strlen(_aqualink_config->mqtt_dz_sub_topic)) == 0) {
if (_aqconfig_.mqtt_dz_sub_topic != NULL && strncmp(mqtt_msg->topic.p, _aqconfig_.mqtt_dz_sub_topic, strlen(_aqconfig_.mqtt_dz_sub_topic)) == 0) {
action_domoticz_mqtt_message(nc, mqtt_msg);
}
break;
@ -1224,13 +1301,13 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
}
void start_mqtt(struct mg_mgr *mgr) {
logMessage (LOG_NOTICE, "Starting MQTT client to %s\n", _aqualink_config->mqtt_server);
if ( _aqualink_config->mqtt_server == NULL ||
( _aqualink_config->mqtt_aq_topic == NULL && _aqualink_config->mqtt_dz_pub_topic == NULL && _aqualink_config->mqtt_dz_sub_topic == NULL) )
logMessage (LOG_NOTICE, "Starting MQTT client to %s\n", _aqconfig_.mqtt_server);
if ( _aqconfig_.mqtt_server == NULL ||
( _aqconfig_.mqtt_aq_topic == NULL && _aqconfig_.mqtt_dz_pub_topic == NULL && _aqconfig_.mqtt_dz_sub_topic == NULL) )
return;
if (mg_connect(mgr, _aqualink_config->mqtt_server, ev_handler) == NULL) {
logMessage (LOG_ERR, "Failed to create MQTT listener to %s\n", _aqualink_config->mqtt_server);
if (mg_connect(mgr, _aqconfig_.mqtt_server, ev_handler) == NULL) {
logMessage (LOG_ERR, "Failed to create MQTT listener to %s\n", _aqconfig_.mqtt_server);
} else {
int i;
for (i=0; i < TOTAL_BUTTONS; i++) {
@ -1246,10 +1323,11 @@ void start_mqtt(struct mg_mgr *mgr) {
}
//bool start_web_server(struct mg_mgr *mgr, struct aqualinkdata *aqdata, char *port, char* web_root) {
bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct aqconfig *aqconfig) {
//bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct aqconfig *aqconfig) {
bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata) {
struct mg_connection *nc;
_aqualink_data = aqdata;
_aqualink_config = aqconfig;
//_aqconfig_ = aqconfig;
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
@ -1257,8 +1335,8 @@ bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct
setvbuf(stderr, NULL, _IOLBF, 0);
mg_mgr_init(mgr, NULL);
logMessage (LOG_NOTICE, "Starting web server on port %s\n", _aqualink_config->socket_port);
nc = mg_bind(mgr, _aqualink_config->socket_port, ev_handler);
logMessage (LOG_NOTICE, "Starting web server on port %s\n", _aqconfig_.socket_port);
nc = mg_bind(mgr, _aqconfig_.socket_port, ev_handler);
if (nc == NULL) {
logMessage (LOG_ERR, "Failed to create listener\n");
return false;
@ -1266,7 +1344,7 @@ bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = _aqualink_config->web_directory; // Serve current directory
s_http_server_opts.document_root = _aqconfig_.web_directory; // Serve current directory
s_http_server_opts.enable_directory_listing = "yes";
#ifndef MG_DISABLE_MQTT

View File

@ -9,7 +9,8 @@
//void main_server();
//void main_server_TEST(struct aqualinkdata *aqdata, char *s_http_port);
//bool start_web_server(struct mg_mgr *mgr, struct aqualinkdata *aqdata, char *port, char* web_root);
bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct aqconfig *aqconfig);
//bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct aqconfig *aqconfig);
bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata);
void broadcast_aqualinkstate(struct mg_connection *nc);
void broadcast_aqualinkstate_error(struct mg_connection *nc, char *msg);

689
onetouch.c Normal file
View File

@ -0,0 +1,689 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include "onetouch.h"
#include "onetouch_aq_programmer.h"
#include "aq_serial.h"
#include "utils.h"
#include "aq_serial.h"
#include "packetLogger.h"
#include "aq_programmer.h"
#include "aqualink.h"
//#include "pda_menu.h"
int _ot_hlightindex = -1;
int _ot_hlightcharindexstart = -1;
int _ot_hlightcharindexstop = -1;
char _menu[ONETOUCH_LINES][AQ_MSGLEN+1];
struct ot_macro _macros[3];
void set_macro_status();
void pump_update(struct aqualinkdata *aq_data, int updated);
void print_onetouch_menu()
{
int i;
for (i=0; i < ONETOUCH_LINES; i++) {
//printf("PDA Line %d = %s\n",i,_menu[i]);
logMessage(LOG_INFO, "OneTouch Menu Line %d = %s\n",i,_menu[i]);
}
if (_ot_hlightcharindexstart > -1) {
logMessage(LOG_INFO, "OneTouch Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
_ot_hlightindex,_menu[_ot_hlightindex],
(_ot_hlightcharindexstart - _ot_hlightcharindexstop + 1), &_menu[_ot_hlightindex][_ot_hlightcharindexstart]);
} else if (_ot_hlightindex > -1) {
logMessage(LOG_INFO, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
}
}
int onetouch_menu_hlightindex()
{
return _ot_hlightindex;
}
char *onetouch_menu_hlight()
{
return onetouch_menu_line(_ot_hlightindex);
}
char *onetouch_menu_hlightchars(int *len)
{
*len = _ot_hlightcharindexstart - _ot_hlightcharindexstop + 1;
return &_menu[_ot_hlightindex][_ot_hlightcharindexstart];
}
char *onetouch_menu_line(int index)
{
if (index >= 0 && index < ONETOUCH_LINES)
return _menu[index];
else
return "-"; // Just return something bad so I can use string comparison with no null check
// return NULL;
}
// Find exact menu item.
int onetouch_menu_find_index(char *text)
{
int i;
for (i = 0; i < ONETOUCH_LINES; i++) {
if (ot_strcmp(onetouch_menu_line(i), text) == 0)
//if (ot_strcmp(onetouch_menu_line(i), text, limit) == 0)
return i;
}
return -1;
}
bool process_onetouch_menu_packet(unsigned char* packet, int length)
{
bool rtn = true;
signed char first_line;
signed char last_line;
signed char line_shift;
signed char i;
switch (packet[PKT_CMD]) {
case CMD_PDA_CLEAR:
_ot_hlightindex = -1;
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
memset(_menu, 0, ONETOUCH_LINES * (AQ_MSGLEN+1));
break;
case CMD_MSG_LONG:
if (packet[PKT_DATA] < ONETOUCH_LINES) {
memset(_menu[(int)packet[PKT_DATA]], 0, AQ_MSGLEN);
strncpy(_menu[(int)packet[PKT_DATA]], (char*)packet+PKT_DATA+1, AQ_MSGLEN);
_menu[packet[PKT_DATA]][AQ_MSGLEN] = '\0';
}
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
break;
case CMD_PDA_HIGHLIGHT:
// when switching from hlight to hlightchars index 255 is sent to turn off hlight
if (packet[4] <= ONETOUCH_LINES) {
_ot_hlightindex = packet[4];
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
} else {
_ot_hlightindex = -1;
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
}
logMessage(LOG_DEBUG, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
break;
case CMD_PDA_HIGHLIGHTCHARS:
if (packet[4] <= ONETOUCH_LINES) {
_ot_hlightindex = packet[4];
_ot_hlightcharindexstart = packet[5];
_ot_hlightcharindexstop = packet[6];
} else {
_ot_hlightindex = -1;
_ot_hlightcharindexstart = -1;
_ot_hlightcharindexstart = -1;
}
logMessage(LOG_DEBUG, "OneTouch Menu highlighted line = %d, '%s' chars '%.*s'\n",
_ot_hlightindex,_menu[_ot_hlightindex],
(_ot_hlightcharindexstart - _ot_hlightcharindexstop + 1), &_menu[_ot_hlightindex][_ot_hlightcharindexstart]);
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
break;
case CMD_PDA_SHIFTLINES:
/// press up from top - shift menu down by 1
// PDA Shif | HEX: 0x10|0x02|0x62|0x0f|0x01|0x08|0x01|0x8d|0x10|0x03|
// press down from bottom - shift menu up by 1
// PDA Shif | HEX: 0x10|0x02|0x62|0x0f|0x01|0x08|0xff|0x8b|0x10|0x03|
first_line = (signed char)(packet[4]);
last_line = (signed char)(packet[5]);
line_shift = (signed char)(packet[6]);
logMessage(LOG_DEBUG, "\n");
if (line_shift < 0) {
for (i = first_line-line_shift; i <= last_line; i++) {
memcpy(_menu[i+line_shift], _menu[i], AQ_MSGLEN+1);
}
} else {
for (i = last_line; i >= first_line+line_shift; i--) {
memcpy(_menu[i], _menu[i-line_shift], AQ_MSGLEN+1);
}
}
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
break;
}
return rtn;
}
void setUnits_ot(char *str, struct aqualinkdata *aq_data)
{
// NSF This needs to use setUnits from aqualinkd.c
if (aq_data->temp_units == UNKNOWN) {
if (str[15] == 'F')
aq_data->temp_units = FAHRENHEIT;
else if (str[15] == 'C')
aq_data->temp_units = CELSIUS;
else
aq_data->temp_units = UNKNOWN;
logMessage(LOG_INFO, "Temp Units set to %d (F=0, C=1, Unknown=2)\n", aq_data->temp_units);
}
}
bool log_heater_setpoints(struct aqualinkdata *aq_data)
{
bool rtn = false;
if (ot_strcmp(_menu[2], "Pool Heat") == 0)
aq_data->pool_htr_set_point = ot_atoi(&_menu[2][10]);
if (ot_strcmp(_menu[3], "Spa Heat") == 0 )
aq_data->spa_htr_set_point = ot_atoi(&_menu[3][9]);
setUnits_ot(_menu[2], aq_data);
logMessage(LOG_DEBUG, "POOL HEATER SETPOINT %d\n",aq_data->pool_htr_set_point);
logMessage(LOG_DEBUG, "SPA HEATER SETPOINT %d\n",aq_data->spa_htr_set_point);
return rtn;
}
bool log_panelversion(struct aqualinkdata *aq_data)
{
char *end;
// It's already been set
if (strlen(aq_data->version) > 0) {
return false;
}
strcpy(aq_data->version, trimwhitespace(_menu[4]));
// Trim trailing space
end = aq_data->version + strlen(aq_data->version) - 1;
while(end > aq_data->version && isspace(*end)) end--;
strcpy(end+2, trimwhitespace(_menu[7]));
// Trim trailing space
end = aq_data->version + strlen(aq_data->version) - 1;
while(end > aq_data->version && isspace(*end)) end--;
// Write new null terminator
*(end+1) = 0;
logMessage(LOG_DEBUG, "**** '%s' ****\n",aq_data->version);
return true;
}
//Info: OneTouch Menu Line 3 = Temp 38`F
bool log_freeze_setpoints(struct aqualinkdata *aq_data)
{
bool rtn = false;
if (ot_strcmp(_menu[3], "Temp") == 0)
aq_data->frz_protect_set_point = ot_atoi(&_menu[3][11]);
setUnits_ot(_menu[3], aq_data);
logMessage(LOG_DEBUG, "FREEZE PROTECT SETPOINT %d\n",aq_data->frz_protect_set_point);
return rtn;
}
bool log_qeuiptment_status(struct aqualinkdata *aq_data)
{
bool rtn = false;
if (ot_strcmp(_menu[2],"Intelliflo VS") == 0 ||
ot_strcmp(_menu[2],"Intelliflo VF") == 0 ||
ot_strcmp(_menu[2],"Jandy ePUMP") == 0) {
rtn = true;
int rpm = 0;
int watts = 0;
int gpm = 0;
int pump_index = ot_atoi(&_menu[2][14]);
// RPM displays differently depending on 3 or 4 digit rpm.
if (ot_strcmp(_menu[3],"RPM:") == 0){
rpm = ot_atoi(&_menu[3][10]);
if (ot_strcmp(_menu[4],"Watts:") == 0) {
watts = ot_atoi(&_menu[4][11]);
}
if (ot_strcmp(_menu[5],"GPM:") == 0) {
gpm = ot_atoi(&_menu[5][11]);
}
} else if (ot_strcmp(_menu[3],"*** Priming ***") == 0){
rpm = PUMP_PRIMING;
} else if (ot_strcmp(_menu[3],"(Offline)") == 0){
rpm = PUMP_OFFLINE;
}
logMessage(LOG_DEBUG, "OneTouch Pump %s, Index %d, RPM %d, Watts %d, GPM %d\n",_menu[2],pump_index,rpm,watts,gpm);
int i;
for (i=0; i < aq_data->num_pumps; i++) {
if (aq_data->pumps[i].pumpIndex == pump_index) {
//printf("**** FOUND PUMP %d at index %d *****\n",pump_index,i);
//aq_data->pumps[i].updated = true;
pump_update(aq_data, i);
aq_data->pumps[i].rpm = rpm;
aq_data->pumps[i].watts = watts;
aq_data->pumps[i].gpm = gpm;
if (aq_data->pumps[i].pumpType == PT_UNKNOWN){
if (ot_strcmp(_menu[2],"Intelliflo VS") == 0)
aq_data->pumps[i].pumpType = VSPUMP;
else if (ot_strcmp(_menu[2],"Intelliflo VF") == 0)
aq_data->pumps[i].pumpType = VFPUMP;
else if (ot_strcmp(_menu[2],"Jandy ePUMP") == 0)
aq_data->pumps[i].pumpType = EPUMP;
}
//printf ("Set Pump Type to %d\n",aq_data->pumps[i].pumpType);
}
}
//aqdata->pumps[pumpIndex-1].rpm = atoi((char *) &packet_buffer[13]);
} else if (true == false) {
/*
Debug: OneTouch Menu Line 0 = Equipment Status
Debug: OneTouch Menu Line 1 =
Debug: OneTouch Menu Line 2 = AQUAPURE 30%
Debug: OneTouch Menu Line 3 = Salt 3800 PPM
Debug: OneTouch Menu Line 4 = Add 2 lbs Salt
*/
}
return rtn;
}
ot_menu_type get_onetouch_memu_type()
{
if (ot_strcmp(_menu[11],"SYSTEM") == 0)
return OTM_ONETOUCH;
else if (ot_strcmp(_menu[0],"Jandy AquaLinkRS") == 0)
return OTM_SYSTEM;
else if (ot_strcmp(_menu[0],"EQUIPMENT STATUS") == 0)
return OTM_EQUIPTMENT_STATUS;
else if (ot_strcmp(_menu[0],"Select Speed") == 0)
return OTM_SELECT_SPEED;
else if (ot_strcmp(_menu[0],"Menu") == 0)
return OTM_MENUHELP;
else if (ot_strcmp(_menu[0],"Set Temp") == 0)
return OTM_SET_TEMP;
else if (ot_strcmp(_menu[0],"Set Time") == 0)
return OTM_SET_TIME;
else if (ot_strcmp(_menu[0],"System Setup") == 0)
return OTM_SYSTEM_SETUP;
else if (ot_strcmp(_menu[0],"Freeze Protect") == 0)
return OTM_FREEZE_PROTECT;
else if (ot_strcmp(_menu[0],"Boost Pool") == 0)
return OTM_BOOST;
else if (ot_strcmp(_menu[7],"REV ") == 0) // NSF Need a better check.
return OTM_VERSION;
return OTM_UNKNOWN;
}
void pump_update(struct aqualinkdata *aq_data, int updated) {
const int bitmask[MAX_PUMPS] = {1,2,4,8};
static unsigned char updates = '\0';
int i;
if (updated == -1) {
for(i=0; i < MAX_PUMPS; i++) {
if ((updates & bitmask[i]) != bitmask[i]) {
aq_data->pumps[i].rpm = TEMP_UNKNOWN;
aq_data->pumps[i].gpm = TEMP_UNKNOWN;
aq_data->pumps[i].watts = TEMP_UNKNOWN;
}
}
updates = '\0';
} else if (updated >=0 && updated < MAX_PUMPS) {
updates |= bitmask[updated];
}
}
bool new_menu(struct aqualinkdata *aq_data)
{
static bool initRS = false;
bool rtn = false;
static ot_menu_type last_menu_type = OTM_UNKNOWN;
ot_menu_type menu_type = get_onetouch_memu_type();
print_onetouch_menu();
switch (menu_type) {
case OTM_ONETOUCH:
set_macro_status();
break;
case OTM_EQUIPTMENT_STATUS:
if (initRS == false) {
queueGetProgramData(ONETOUCH, aq_data);
initRS = true;
}
rtn = log_qeuiptment_status(aq_data);
// Hit select to get to next menu ASAP.
if ( in_ot_programming_mode(aq_data) == false )
ot_queue_cmd(KEY_ONET_SELECT);
break;
case OTM_SET_TEMP:
rtn = log_heater_setpoints(aq_data);
break;
case OTM_FREEZE_PROTECT:
rtn = log_freeze_setpoints(aq_data);
break;
case OTM_VERSION:
rtn = log_panelversion(aq_data);
logMessage(LOG_DEBUG, "**** ONETOUCH INIT ****");
queueGetProgramData(ONETOUCH, aq_data);
//set_aqualink_onetouch_pool_heater_temp()
//aq_programmer(AQ_SET_ONETOUCH_POOL_HEATER_TEMP, "95", aq_data);
//aq_programmer(AQ_SET_ONETOUCH_SPA_HEATER_TEMP, "94", aq_data);
initRS = true;
break;
default:
break;
}
if (last_menu_type == OTM_EQUIPTMENT_STATUS && menu_type != OTM_EQUIPTMENT_STATUS ) {
// End of equiptment status chain of menus, reset any pump that wasn't listed in menus
pump_update(aq_data, -1);
}
last_menu_type = menu_type;
return rtn;
}
void set_macro_status()
{
// OneTouch Menu Line 2 = SPA MODE OFF
// OneTouch Menu Line 5 = CLEAN MODE ON
// OneTouch Menu Line 8 = ONETOUCH 3 OFF
if (get_onetouch_memu_type() == OTM_ONETOUCH) {
strncpy(_macros[0].name, _menu[2], 13);
chopwhitespace(_macros[0].name);
_macros[0].ison = (_menu[2][15] == 'N'?true:false);
strncpy(_macros[1].name, _menu[5], 13);
chopwhitespace(_macros[1].name);
_macros[1].ison = (_menu[5][15] == 'N'?true:false);
strncpy(_macros[2].name, _menu[8], 13);
chopwhitespace(_macros[2].name);
_macros[2].ison = (_menu[8][15] == 'N'?true:false);
logMessage(LOG_DEBUG, "Macro #1 '%s' is %s\n",_macros[0].name,_macros[0].ison?"On":"Off");
logMessage(LOG_DEBUG, "Macro #2 '%s' is %s\n",_macros[1].name,_macros[1].ison?"On":"Off");
logMessage(LOG_DEBUG, "Macro #3 '%s' is %s\n",_macros[2].name,_macros[2].ison?"On":"Off");
}
}
unsigned char _last_msg_type = 0x00;
unsigned char _last_kick_type = -1;
int thread_kick_type()
{
return _last_kick_type;
}
unsigned char *last_onetouch_packet()
{
return &_last_msg_type;
}
bool process_onetouch_packet(unsigned char *packet, int length, struct aqualinkdata *aq_data)
{
static bool filling_menu = false;
bool rtn = false;
//int i;
//char *msg;
//static unsigned char last_msg_type = 0x00;
//static bool init = false;
//process_pda_packet(packet, length);
//logMessage(LOG_DEBUG, "RS Received ONETOUCH 0x%02hhx\n", packet[PKT_CMD]);
//debuglogPacket(packet, length);
process_onetouch_menu_packet(packet, length);
// Check for new menu.
// Usually PDA_CLEAR bunch of CMD_MSG_LONG then a CMD_PDA_HIGHLIGHT or CMD_PDA_HIGHLIGHTCHARS
// When we hit page down, just CMD_MSG_LONG then a CMD_PDA_HIGHLIGHT. (not seen CMD_PDA_HIGHLIGHTCHARS yet)
if ( (filling_menu == true &&
(//packet[PKT_CMD] == CMD_PDA_HIGHLIGHTCHARS ||
packet[PKT_CMD] == CMD_PDA_HIGHLIGHT ||
packet[PKT_CMD] == CMD_STATUS) )
||
( _last_msg_type == CMD_MSG_LONG && packet[PKT_CMD] == CMD_PDA_HIGHLIGHT )
)
{
filling_menu = false;
rtn = new_menu(aq_data);
_last_kick_type = KICKT_MENU;
} else {
_last_kick_type = KICKT_CMD;
}
if (packet[PKT_CMD] == CMD_PDA_CLEAR)
filling_menu = true;
/*
//if (_last_msg_type == CMD_MSG_LONG && packet[PKT_CMD] != CMD_MSG_LONG) {
if (_last_msg_type == CMD_MSG_LONG && ( packet[PKT_CMD] != CMD_MSG_LONG && packet[PKT_CMD] != CMD_PDA_HIGHLIGHTCHARS) ) { // CMD_PDA_SHIFTLINES
rtn = new_menu(aq_data);
_last_kick_type = KICKT_MENU;
} else {
_last_kick_type = KICKT_CMD;
}
*/
_last_msg_type = packet[PKT_CMD];
// Receive 0x04 for System menu (before 0x02)
// Receive 0x04 for startup menu (before 0x02)
// Receive 0x08 for Equiptment menu (before 0x02)
// Receive 0x04 while building menu
if ( packet[PKT_CMD] == CMD_MSG_LONG)
logMessage(LOG_DEBUG, "RS received ONETOUCH packet of type %s length %d '%.*s'\n", get_packet_type(packet, length), length, AQ_MSGLEN, (char*)packet+PKT_DATA+1);
else
logMessage(LOG_DEBUG, "RS received ONETOUCH packet of type %s length %d\n", get_packet_type(packet, length), length);
//debuglogPacket(packet, length);
//if ( in_ot_programming_mode(aq_data) == true )
kick_aq_program_thread(aq_data, ONETOUCH);
/*
switch (packet[PKT_CMD])
{
case CMD_ACK:
//logMessage(LOG_DEBUG, "RS Received ACK length %d.\n", length);
break;
//case CMD_PDA_HIGHLIGHT: // This doesn't work for end of menu, if menu is complete then get a change line, highlight isn't sent.
//set_macro_status();
// break;
case 0x04:
case 0x08:
logMessage(LOG_DEBUG, "RS Received MENU complete\n");
set_macro_status();
break;
case CMD_MSG_LONG:
msg = (char *)packet + PKT_DATA + 1;
logMessage(LOG_DEBUG, "RS Received message data 0x%02hhx string '%s'\n",packet[PKT_DATA],msg);
break;
default:
//logMessage(LOG_DEBUG, "RS Received 0x%02hhx\n", packet[PKT_CMD]);
break;
}
*/
return rtn;
}
// Check s2 exists in s1
int ot_strcmp(const char *s1, const char *s2)
{
char *sp1 = (char *)s1;
char *sp2 = (char *)s2;
//int i=0;
// Get rid of all padding
while(isspace(*sp1)) sp1++;
while(isspace(*sp2)) sp2++;
// Need to write this myself for speed
//logMessage(LOG_DEBUG, "OneTouch compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2);
return strncasecmp(sp1, sp2, strlen(sp2));
}
#define INT_MAX +2147483647
#define INT_MIN -2147483647
// atoi that can have blank start
int ot_atoi(const char* str)
{
int sign = 1, base = 0, i = 0;
// if whitespaces then ignore.
while (str[i] == ' ') {
i++;
}
// checking for valid input
while (str[i] >= '0' && str[i] <= '9') {
// handling overflow test case
if (base > INT_MAX / 10 || (base == INT_MAX / 10 && str[i] - '0' > 7)) {
if (sign == 1)
return INT_MAX;
else
return INT_MIN;
}
base = 10 * base + (str[i++] - '0');
}
return base * sign;
}
/*
Version something like
Info: OneTouch Menu Line 0 =
Info: OneTouch Menu Line 1 =
Info: OneTouch Menu Line 2 =
Info: OneTouch Menu Line 3 =
Info: OneTouch Menu Line 4 = B0029221
Info: OneTouch Menu Line 5 = RS-8 Combo
Info: OneTouch Menu Line 6 =
Info: OneTouch Menu Line 7 = REV T.0.1
Info: OneTouch Menu Line 8 =
Info: OneTouch Menu Line 9 =
Info: OneTouch Menu Line 10 =
Info: OneTouch Menu Line 11 =
*/
/*
Info: OneTouch Menu Line 0 = Set Temp
Info: OneTouch Menu Line 1 =
Info: OneTouch Menu Line 2 = Pool Heat 90`F
Info: OneTouch Menu Line 3 = Spa Heat 102`F
Info: OneTouch Menu Line 4 =
Info: OneTouch Menu Line 5 = Maintain OFF
Info: OneTouch Menu Line 6 = Hours 12AM-12AM
Info: OneTouch Menu Line 7 =
Info: OneTouch Menu Line 8 = Highlight an
Info: OneTouch Menu Line 9 = item and press
Info: OneTouch Menu Line 10 = Select
Info: OneTouch Menu Line 11 =
*/
/*
nfo: OneTouch Menu Line 0 = Freeze Protect
Info: OneTouch Menu Line 1 =
Info: OneTouch Menu Line 2 =
Info: OneTouch Menu Line 3 = Temp 38`F
Info: OneTouch Menu Line 4 =
Info: OneTouch Menu Line 5 =
Info: OneTouch Menu Line 6 = Use Arrow Keys
Info: OneTouch Menu Line 7 = to set value.
Info: OneTouch Menu Line 8 = Press SELECT
Info: OneTouch Menu Line 9 = to continue.
Info: OneTouch Menu Line 10 =
Info: OneTouch Menu Line 11 =
*/
/*
Pump Stuff Use Intelliflo|Jandy & last number of line.
(Intelliflo VF you set GPM, not RPM)
Debug: OneTouch Menu Line 0 = Equipment Status
Debug: OneTouch Menu Line 1 =
Debug: OneTouch Menu Line 2 = Intelliflo VS 3
Debug: OneTouch Menu Line 3 = *** Priming ***
Debug: OneTouch Menu Line 4 = Watts: 100
Debug: OneTouch Menu Line 5 =
Debug: OneTouch Menu Line 6 =
Debug: OneTouch Menu Line 7 =
Debug: OneTouch Menu Line 8 =
Debug: OneTouch Menu Line 9 =
Debug: OneTouch Menu Line 10 =
Debug: OneTouch Menu Line 11 =
Debug: OneTouch Menu Line 0 = Equipment Status
Debug: OneTouch Menu Line 1 =
Debug: OneTouch Menu Line 2 = Intelliflo VS 3
Debug: OneTouch Menu Line 3 = RPM: 2750
Debug: OneTouch Menu Line 3 = RPM: 600 // Option for 3 digit RPM
Debug: OneTouch Menu Line 4 = Watts: 55
Debug: OneTouch Menu Line 5 =
Debug: OneTouch Menu Line 6 =
Debug: OneTouch Menu Line 7 =
Debug: OneTouch Menu Line 8 =
Debug: OneTouch Menu Line 9 =
Debug: OneTouch Menu Line 10 =
Debug: OneTouch Menu Line 11 =
Debug: OneTouch Menu Line 0 = Equipment Status
Debug: OneTouch Menu Line 1 =
Debug: OneTouch Menu Line 2 = Intelliflo VF 2
Debug: OneTouch Menu Line 3 = (Offline)
Debug: OneTouch Menu Line 4 =
Debug: OneTouch Menu Line 5 =
Debug: OneTouch Menu Line 6 =
Debug: OneTouch Menu Line 7 =
Debug: OneTouch Menu Line 8 =
Debug: OneTouch Menu Line 9 =
Debug: OneTouch Menu Line 10 =
Debug: OneTouch Menu Line 11 =
Debug: OneTouch Menu Line 0 = Equipment Status
Debug: OneTouch Menu Line 1 =
Debug: OneTouch Menu Line 2 = Intelliflo VF 2
Debug: OneTouch Menu Line 3 = RPM: 2250
Debug: OneTouch Menu Line 4 = Watts: 55
Debug: OneTouch Menu Line 5 = GPM: 80
Debug: OneTouch Menu Line 6 =
Debug: OneTouch Menu Line 7 =
Debug: OneTouch Menu Line 8 =
Debug: OneTouch Menu Line 9 =
Debug: OneTouch Menu Line 10 =
Debug: OneTouch Menu Line 11 =
Debug: OneTouch Menu Line 0 = Equipment Status
Debug: OneTouch Menu Line 1 =
Debug: OneTouch Menu Line 2 = Jandy ePUMP 1
Debug: OneTouch Menu Line 3 = RPM: 1750
Debug: OneTouch Menu Line 4 = Watts: 43
Debug: OneTouch Menu Line 5 =
Debug: OneTouch Menu Line 6 =
Debug: OneTouch Menu Line 7 =
Debug: OneTouch Menu Line 8 =
Debug: OneTouch Menu Line 9 =
Debug: OneTouch Menu Line 10 =
Debug: OneTouch Menu Line 11 =
*/

80
onetouch.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef ONETOUCH_H_
#define ONETOUCH_H_
#include "aq_serial.h"
#include "aqualink.h"
#define ONETOUCH_LINES 12
#define PUMP_PRIMING -1
#define PUMP_OFFLINE -2
#define KICKT_CMD 0
#define KICKT_MENU 1
typedef enum ot_menu_type {
OTM_ONETOUCH,
OTM_EQUIPTMENT_STATUS,
OTM_SYSTEM, // Default screen with date,time & temperature
OTM_MAIN,
OTM_EQUIPTMENT,
OTM_EQUIPTMENT_ONOFF,
OTM_SELECT_SPEED,
OTM_MENUHELP,
OTM_VERSION,
OTM_SET_TEMP,
OTM_SET_TIME,
OTM_SYSTEM_SETUP,
OTM_FREEZE_PROTECT,
OTM_SET_AQUAPURE,
OTM_BOOST,
OTM_UNKNOWN
} ot_menu_type;
struct ot_macro {
char name[AQ_MSGLEN];
bool ison;
};
/*
Left Top Button
Ack | HEX: 0x10|0x02|0x00|0x01|0x80|0x03|0x96|0x10|0x03|
Left Middle Button (Back)
Ack | HEX: 0x10|0x02|0x00|0x01|0x80|0x02|0x95|0x10|0x03|
Left Botom Button
Ack | HEX: 0x10|0x02|0x00|0x01|0x80|0x01|0x94|0x10|0x03|
Select Button
Ack | HEX: 0x10|0x02|0x00|0x01|0x80|0x04|0x97|0x10|0x03|
Up Button
Ack | HEX: 0x10|0x02|0x00|0x01|0x80|0x06|0x99|0x10|0x03|
Down Button
Ack | HEX: 0x10|0x02|0x00|0x01|0x80|0x05|0x98|0x10|0x03|
*/
bool process_onetouch_packet(unsigned char *packet, int length,struct aqualinkdata *aq_data);
ot_menu_type get_onetouch_memu_type();
unsigned char *last_onetouch_packet();
int thread_kick_type();
int onetouch_menu_hlightindex();
char *onetouch_menu_hlight();
char *onetouch_menu_line(int index);
char *onetouch_menu_hlightchars(int *len);
int onetouch_menu_find_index(char *text);
int ot_atoi(const char* str);
int ot_strcmp(const char *s1, const char *s2);
#endif // ONETOUCH_H_

803
onetouch_aq_programmer.c Normal file
View File

@ -0,0 +1,803 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utils.h"
#include "aq_programmer.h"
#include "onetouch.h"
#include "aqualink.h"
unsigned char _ot_pgm_command = NUL;
// External command
bool ot_queue_cmd(unsigned char cmd) {
if (_ot_pgm_command == NUL) {
_ot_pgm_command = cmd;
return true;
}
return false;
}
unsigned char pop_ot_cmd(unsigned char receive_type)
{
unsigned char cmd = NUL;
if (receive_type == CMD_STATUS) {
cmd = _ot_pgm_command;
_ot_pgm_command = NUL;
}
logMessage(LOG_DEBUG, "OneTouch Sending '0x%02hhx' to controller\n", cmd);
return cmd;
}
void waitfor_ot_queue2empty()
{
int i=0;
while ( (_ot_pgm_command != NUL) && ( i++ < 20) ) {
delay(50);
}
if (_ot_pgm_command != NUL) {
// Wait for longer interval
while ( (_ot_pgm_command != NUL) && ( i++ < 100) ) {
delay(100);
}
}
if (_ot_pgm_command != NUL) {
logMessage(LOG_WARNING, "OneTouch Send command Queue did not empty, timeout\n");
}
}
// This is for internal use only.
// Will only work in programming mode
void send_ot_cmd(unsigned char cmd)
{
waitfor_ot_queue2empty();
ot_queue_cmd(cmd);
logMessage(LOG_INFO, "OneTouch Queue send '0x%02hhx' to controller (programming)\n", _ot_pgm_command);
}
bool waitForOT_MessageTypes(struct aqualinkdata *aq_data, unsigned char mtype1, unsigned char mtype2, int numMessageReceived)
{
//logMessage(LOG_DEBUG, "waitForOT_MessageType 0x%02hhx || 0x%02hhx\n",mtype1,mtype2);
int i=0;
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
while( ++i <= numMessageReceived)
{
logMessage(LOG_DEBUG, "waitForOT_MessageType 0x%02hhx||0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype1,mtype2,*last_onetouch_packet(),i,numMessageReceived);
if (*last_onetouch_packet() == mtype1 || *last_onetouch_packet() == mtype2) break;
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
}
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if (*last_onetouch_packet() != mtype1 && *last_onetouch_packet() != mtype2) {
//logMessage(LOG_ERR, "Could not select MENU of Aqualink control panel\n");
logMessage(LOG_DEBUG, "waitForOT_MessageType: did not receive 0x%02hhx||0x%02hhx\n",mtype1,mtype2);
return false;
} else
logMessage(LOG_DEBUG, "waitForOT_MessageType: received 0x%02hhx\n",*last_onetouch_packet());
return true;
}
bool waitForNextOT_Menu(struct aqualinkdata *aq_data) {
//waitForOT_MessageTypes(aq_data,CMD_PDA_CLEAR,CMD_PDA_0x04,10);
//return waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
int i=0;
const int numMessageReceived = 20;
pthread_mutex_lock(&aq_data->active_thread.thread_mutex);
while( ++i <= 20)
{
logMessage(LOG_DEBUG, "waitForNextOT_Menu (%d of %d)\n",i,numMessageReceived);
//if(thread_kick_type() == KICKT_MENU) break;
pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex);
if(thread_kick_type() == KICKT_MENU) break;
}
pthread_mutex_unlock(&aq_data->active_thread.thread_mutex);
if(thread_kick_type() == KICKT_MENU)
return true;
else
return false;
}
bool highlight_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
{
int i;
int index;
int cnt;
// Should probably to an UP as well as DOWN here.
// Also need page up and down " ^^ More vv"
if ( (index = onetouch_menu_find_index(item)) != -1) {
cnt = index - onetouch_menu_hlightindex();
logMessage(LOG_DEBUG, "*** OneTouch menu caculator selected=%d, wanted=%d, move=%d times ***\n",onetouch_menu_hlightindex(),index,cnt);
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_DOWN);
waitfor_ot_queue2empty();
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,3);
if (ot_strcmp(onetouch_menu_hlight(), item) == 0) {
// We got here early, probably because blank menu item
break;
}
}
// check if it's quicker to go up rather than down, if second page can't go up.
// This doesn;t work yet, not all versions of control panels have the same amount of items.
/*
if (cnt <= 5 || ot_strcmp(onetouch_menu_line(10), " ^^ More", 10) == 0 ) {
logMessage(LOG_DEBUG, "OneTouch device programmer pressing down %d times\n",cnt);
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_DOWN);
//waitfor_ot_queue2empty();
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
}
} else {
cnt = 11 - cnt;
logMessage(LOG_DEBUG, "OneTouch device programmer pressing up %d times\n",cnt);
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_UP);
//waitfor_ot_queue2empty();
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
}
}*/
// Not much quicker doing it this way that in the for loops above, may have to change back.
//waitfor_ot_queue2empty();
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
} else {
// Is their another page to search
if (ot_strcmp(onetouch_menu_line(10), "^^ More") == 0) {
char first_item[AQ_MSGLEN+1];
do {
send_ot_cmd(KEY_ONET_PAGE_DN);
waitForNextOT_Menu(aq_data);
if (onetouch_menu_find_index(item) != -1) {
return highlight_onetouch_menu_item(aq_data, item);
}
} while (strncpy(first_item, onetouch_menu_line(1), AQ_MSGLEN));
// Need to get menu item 1.
// Hit page down until menu item matches 1.
} else
logMessage(LOG_ERR, "OneTouch device programmer menu item '%s' does not exist\n",item);
//print_onetouch_menu();
}
if ( ot_strcmp(onetouch_menu_hlight(), item) != 0) {
logMessage(LOG_ERR, "OneTouch device programmer menu item '%s' not selected\n",item);
//print_onetouch_menu();
return false;
} else {
return true;
}
}
bool select_onetouch_menu_item(struct aqualinkdata *aq_data, char *item)
{
if (highlight_onetouch_menu_item(aq_data, item)) {
send_ot_cmd(KEY_ONET_SELECT);
waitForNextOT_Menu(aq_data);
return true;
}
return false;
}
bool goto_onetouch_system_menu(struct aqualinkdata *aq_data)
{
int i=0;
if (get_onetouch_memu_type() == OTM_SYSTEM)
return true;
// Get back to a known point, the system menu
while (get_onetouch_memu_type() != OTM_SYSTEM && get_onetouch_memu_type() != OTM_ONETOUCH && i < 5 ) {
send_ot_cmd(KEY_ONET_BACK);
waitForNextOT_Menu(aq_data);
i++;
}
if (get_onetouch_memu_type() == OTM_SYSTEM) {
//printf("*** SYSTEM MENU ***\n");
//return false;
} else if (get_onetouch_memu_type() == OTM_ONETOUCH) {
//printf("*** ONE TOUCH MENU ***\n");
// Can only be one of 2 options in this menu, so if it's not the one we want, hit down first
if ( ot_strcmp(onetouch_menu_hlight(), "System") != 0) {
send_ot_cmd(KEY_ONET_DOWN);
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
}
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForNextOT_Menu(aq_data);
//return false;
} else {
logMessage(LOG_ERR, "OneTouch device programmer couldn't get to System menu\n");
return false;
}
if (get_onetouch_memu_type() != OTM_SYSTEM) {
logMessage(LOG_ERR, "OneTouch device programmer couldn't get to System menu\n");
return false;
}
return true;
}
bool goto_onetouch_menu(struct aqualinkdata *aq_data, ot_menu_type menu)
{
char *second_menu = false;
char *third_menu = false;
logMessage(LOG_DEBUG, "OneTouch device programmer request for menu %d\n",menu);
if ( ! goto_onetouch_system_menu(aq_data) ) {
logMessage(LOG_ERR, "OneTouch device programmer failed to get system menu\n");
return false;
}
// Now we are at main menu, we should have 3 options
/* Debug: OneTouch Menu Line 9 = Equipment ON/OFF
Debug: OneTouch Menu Line 10 = OneTouch ON/OFF
Debug: OneTouch Menu Line 11 = Menu / Help
*/
// First setup any secondary menu's to hit.
switch(menu){
case OTM_SET_TEMP:
second_menu = "Set Temp";
break;
case OTM_SET_TIME:
second_menu = "Set Time";
break;
case OTM_SET_AQUAPURE:
second_menu = "Set AQUAPURE";
break;
case OTM_FREEZE_PROTECT:
second_menu = "System Setup";
third_menu = "Freeze Protect";
break;
case OTM_SYSTEM_SETUP:
second_menu = "System Setup";
break;
case OTM_BOOST:
second_menu = "Boost";
break;
default:
break;
}
// Now actually get the menu
switch(menu){
case OTM_SYSTEM:
// We are already here
return true;
break;
case OTM_EQUIPTMENT_ONOFF:
//if ( select_onetouch_menu_item(aq_data, "Equipment ON/OFF") == false ) { // NSF Should use this
if ( ot_strcmp(onetouch_menu_hlight(), "Equipment ON/OFF") == 0) {
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForNextOT_Menu(aq_data);
return true;
}
return false;
break;
case OTM_MENUHELP:
case OTM_SET_TEMP:
case OTM_SET_TIME:
case OTM_SET_AQUAPURE:
case OTM_FREEZE_PROTECT:
case OTM_BOOST:
case OTM_SYSTEM_SETUP:
if ( select_onetouch_menu_item(aq_data, " Menu / Help") == false ) {
logMessage(LOG_ERR, "OneTouch device programmer couldn't select menu %d\n",menu);
}
if (second_menu)
select_onetouch_menu_item(aq_data, second_menu);
if (third_menu)
select_onetouch_menu_item(aq_data, third_menu);
/*
if (menu == OTM_SET_HEATER) {
select_onetouch_menu_item(aq_data, "Set Temp");
} else if (menu == OTM_SET_TIME) {
select_onetouch_menu_item(aq_data, "Set Time");
} else if (menu == OTM_SET_AQUAPURE) {
select_onetouch_menu_item(aq_data, "Set AQUAPURE");
}
*/
break;
default:
logMessage(LOG_ERR, "OneTouch device programmer doesn't know how to access menu %d\n",menu);
break;
}
if (get_onetouch_memu_type() != menu)
return false;
return true;
}
/*
bool in_ot_programming_mode(struct aqualinkdata *aq_data)
{
//( type != AQ_SET_PUMP_RPM || type != AQ_SET_OT_MACRO )) {
if ( ( aq_data->active_thread.thread_id != 0 ) &&
( aq_data->active_thread.ptype == AQ_SET_PUMP_RPM ||
aq_data->active_thread.ptype == AQ_SET_OT_MACRO ||
aq_data->active_thread.ptype == AQ_GET_OT_POOL_SPA_HEATER_TEMPS)
) {
return true;
}
return false;
}
*/
// Return the digit at factor
// num=12 factor=10 would return 2
// num=12 factor=100 would return 1
int digit(int num, int factor)
{
return ( (num % factor) - (num % (factor/10)) ) / (factor/10) ;
}
// REturn the differance at a particular digit.
// new=120, old=130, factor=100 return 2-3 = -1
int digitDiff(int new, int old, int factor)
{
return ( digit(old, factor) - digit(new, factor) );
}
bool intPress(int diff) {
int i;
unsigned char key = KEY_ONET_UP;
if (diff < 0) {
diff = 0 - diff;
key = KEY_ONET_DOWN;
//printf ("**** Pressing down %d times\n",diff);
} else {
//printf ("**** Pressing UP %d times\n",diff);
}
for (i=0; i < diff; i++) {
send_ot_cmd(key);
waitfor_ot_queue2empty();
}
return true;
}
/*
PROGRAMMING FUNCTIONS
*/
void *set_aqualink_pump_rpm( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
char *buf = (char*)threadCtrl->thread_args;
char VSPstr[20];
int i, structIndex;
//printf("**** program string '%s'\n",buf);
int pumpIndex = atoi(&buf[0]);
int pumpRPM = -1;
//int pumpRPM = atoi(&buf[2]);
for (structIndex=0; structIndex < aq_data->num_pumps; structIndex++) {
if (aq_data->pumps[structIndex].pumpIndex == pumpIndex) {
if (aq_data->pumps[structIndex].pumpType == PT_UNKNOWN) {
logMessage(LOG_ERR, "Can't set Pump RPM/GPM until type is known\n");
cleanAndTerminateThread(threadCtrl);
return ptr;
}
pumpRPM = RPM_check(aq_data->pumps[structIndex].pumpType, atoi(&buf[2]), aq_data);
break;
}
}
// NSF Should probably check pumpRPM is not -1 here
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_PUMP_RPM);
logMessage(LOG_NOTICE, "OneTouch Set Pump %d to RPM %d, from '%s'\n",pumpIndex,pumpRPM,buf);
if (! goto_onetouch_menu(aq_data, OTM_EQUIPTMENT_ONOFF) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get Equiptment on/off menu\n");
}
sprintf(VSPstr, "VSP%1d Spd Adj",pumpIndex);
/*
if ( (index = onetouch_menu_find_index(VSPstr)) != -1) {
int cnt = index - onetouch_menu_hlightindex();
for (i=0; i < cnt; i ++) {
send_ot_cmd(KEY_ONET_DOWN);
waitfor_ot_queue2empty();
}
send_ot_cmd(KEY_ONET_SELECT);
waitForNextOT_Menu(aq_data);
*/
if ( select_onetouch_menu_item(aq_data, VSPstr) ) {
if ( get_onetouch_memu_type() == OTM_SELECT_SPEED) {
// Now fine menu item with X as last digit, and select that menu.
//Pool X
for (i=0; i < 12; i++) {
if ( onetouch_menu_hlight()[15] != 'X' ) {
send_ot_cmd(KEY_ONET_DOWN);
waitfor_ot_queue2empty();
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15);
} else {
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForNextOT_Menu(aq_data);
break;
}
}
//OneTouch Menu Line 3 = set to 50 GPM
//OneTouch Menu Line 3 = set to 1750 RPM
if ( strstr(onetouch_menu_hlight(), "set to") != NULL ) {
//printf("FOUND MENU")
if (strstr(onetouch_menu_hlight(), "RPM") != NULL ) {
// RPM 3450 & 600 max & min
int RPM = ot_atoi(&onetouch_menu_hlight()[7]);
intPress(digitDiff(RPM, pumpRPM, 10000));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
intPress(digitDiff(RPM, pumpRPM, 1000));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
intPress(digitDiff(RPM, pumpRPM, 100));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
intPress(digitDiff(RPM, pumpRPM, 10));
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
// Reset the pump RPM
aq_data->pumps[structIndex].rpm = RPM;
} else if (strstr(onetouch_menu_hlight(), "GPM") != NULL ) {
// GPM 130 max, GPM 15 min
for (i=0; i < 24 ; i++) { // Max of 23 key presses to get from max to min
int GPM = ot_atoi(&onetouch_menu_hlight()[8]);
//printf ("*** GPM = %d | Setting to %d\n",GPM,pumpRPM);
if ( GPM > pumpRPM ) {
send_ot_cmd(KEY_ONET_DOWN);
} else if (GPM < pumpRPM) {
send_ot_cmd(KEY_ONET_UP);
} else {
send_ot_cmd(KEY_ONET_SELECT);
aq_data->pumps[structIndex].gpm = GPM;
waitfor_ot_queue2empty();
break;
}
waitfor_ot_queue2empty();
// This really does slow it down, but we hit up.down once too ofter without it, need to fix.
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,5);
// Reset the pump GPM
aq_data->pumps[structIndex].rpm = GPM;
//waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_MSG_LONG,5);
//waitForNextOT_Menu(aq_data);
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer Not sure how to set '%s'\n",onetouch_menu_hlight());
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer didn't select VSP\n");
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer Couldn't find Select Speed menu\n");
}
} else {
logMessage(LOG_ERR, "OneTouch device programmer Couldn't find VSP in Equiptment on/off menu\n");
}
//printf( "Menu Index %d\n", onetouch_menu_find_index(VSPstr));
//printf("**** GOT THIS FAR, NOW LET'S GO BACK ****\n");
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
//printf("**** CLEAN EXIT ****\n");
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *set_aqualink_onetouch_macro( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
//sprintf(msg, "%-5d%-5d",index, (strcmp(value, "on") == 0)?ON:OFF);
// Use above to set
char *buf = (char*)threadCtrl->thread_args;
unsigned int device = atoi(&buf[0]);
unsigned int state = atoi(&buf[5]);
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_MACRO);
logMessage(LOG_DEBUG, "OneTouch Marco\n");
logMessage(LOG_ERR, "OneTouch Macro not implimented (device=%d|state=%d)\n",device,state);
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *get_aqualink_onetouch_setpoints( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_ONETOUCH_SETPOINTS);
logMessage(LOG_DEBUG, "OneTouch get heater temps\n");
if ( !goto_onetouch_menu(aq_data, OTM_SET_TEMP) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
}
if ( !goto_onetouch_menu(aq_data, OTM_FREEZE_PROTECT) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get freeze protect menu\n");
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
/*
logMessage(LOG_DEBUG, "*** OneTouch device programmer TEST page down ***\n");
goto_onetouch_menu(aq_data, OTM_SYSTEM_SETUP);
highlight_onetouch_menu_item(aq_data, "About");
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForNextOT_Menu(aq_data);
logMessage(LOG_DEBUG, "*** OneTouch device programmer END TEST page down ***\n");
*/
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void set_aqualink_onetouch_heater_setpoint( struct aqualinkdata *aq_data, bool ispool, int val )
{
int cval;
int diff;
int i;
int len;
//char *st;
unsigned char direction;
if ( !goto_onetouch_menu(aq_data, OTM_SET_TEMP) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
}
if(ispool){
if (!highlight_onetouch_menu_item(aq_data, "Pool Heat")) {
logMessage(LOG_ERR, "OneTouch device programmer failed to get pool heater temp menu\n");
return;
}
} else {
if (!highlight_onetouch_menu_item(aq_data, "Spa Heat")) {
logMessage(LOG_ERR, "OneTouch device programmer failed to get spa heater temp menu\n");
return;
}
}
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
waitForOT_MessageTypes(aq_data,CMD_PDA_HIGHLIGHTCHARS,0x00,15); // CMD_PDA_0x04 is just a packer.
{
char *st = onetouch_menu_hlightchars(&len);
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlighted='%.*s'\n", len, st);
}
cval = atoi(onetouch_menu_hlightchars(&len));
diff = val - cval;
if (diff > 0) {
direction = KEY_ONET_UP;
} else if (diff < 0) {
direction = KEY_ONET_DOWN;
diff=-diff;
}
logMessage(LOG_DEBUG, "** OneTouch set heater temp diff='%d'\n", diff);
for (i=0; i < diff; i++) {
send_ot_cmd(direction);
waitfor_ot_queue2empty();
}
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
send_ot_cmd(KEY_ONET_BACK);
waitfor_ot_queue2empty();
/*
logMessage(LOG_DEBUG, "** OneTouch set heater temp line='%s'\n", onetouch_menu_line(line));
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlight='%d'\n", onetouch_menu_hlightindex());
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlightline='%s'\n", onetouch_menu_line(onetouch_menu_hlightindex()));
logMessage(LOG_DEBUG, "** OneTouch set heater temp highlightchars='%s'\n", onetouch_menu_hlight());
*/
//onetouch_menu_line(line)
//onetouch_menu_hlightindex
//onetouch_menu_hlight
}
void *set_aqualink_onetouch_pool_heater_temp( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_POOL_HEATER_TEMP);
int val = atoi((char*)threadCtrl->thread_args);
val = setpoint_check(POOL_HTR_SETOINT, val, aq_data);
logMessage(LOG_DEBUG, "OneTouch set pool heater temp to %d\n", val);
set_aqualink_onetouch_heater_setpoint(aq_data, true, val);
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *set_aqualink_onetouch_spa_heater_temp( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_SPA_HEATER_TEMP);
int val = atoi((char*)threadCtrl->thread_args);
val = setpoint_check(SPA_HTR_SETOINT, val, aq_data);
logMessage(LOG_DEBUG, "OneTouch set spa heater temp to %d\n", val);
set_aqualink_onetouch_heater_setpoint(aq_data, false, val);
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *set_aqualink_onetouch_boost( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_BOOST);
int val = atoi((char*)threadCtrl->thread_args);
logMessage(LOG_DEBUG, "OneTouch request set Boost to '%d'\n",val==true?"On":"Off");
if ( !goto_onetouch_menu(aq_data, OTM_BOOST) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get BOOST menu\n");
} else {
if ( ot_strcmp(onetouch_menu_hlight(), "Start") == 0 ) {
if (val) {
logMessage(LOG_DEBUG, "OneTouch Boost is Off, turning On\n");
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
} else {
logMessage(LOG_INFO, "OneTouch Boost is Off, ignore request\n");
}
} else if ( ot_strcmp(onetouch_menu_hlight(), "Pause") == 0 ) {
if (! val) {
logMessage(LOG_DEBUG, "OneTouch set Boost is ON, turning Off\n");
highlight_onetouch_menu_item(aq_data, "Stop");
send_ot_cmd(KEY_ONET_SELECT);
waitfor_ot_queue2empty();
// Takes ages to see bost is off from menu, to set it here.
aq_data->boost = false;
aq_data->boost_msg[0] = '\0';
aq_data->swg_percent = 0;
} else {
logMessage(LOG_INFO, "OneTouch Boost is On, ignore request\n");
}
} else {
logMessage(LOG_ERR, "OneTouch Boost unknown menu\n");
}
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *set_aqualink_onetouch_swg_percent( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_SWG_PERCENT);
logMessage(LOG_DEBUG, "OneTouch set SWG Percent\n");
if ( !goto_onetouch_menu(aq_data, OTM_SET_AQUAPURE) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get Aquapure menu\n");
} else {
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}
void *set_aqualink_onetouch_freezeprotect( void *ptr )
{
return ptr;
}
void *set_aqualink_onetouch_time( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_TIME);
logMessage(LOG_DEBUG, "OneTouch set time\n");
if ( !goto_onetouch_menu(aq_data, OTM_SET_TIME) ){
logMessage(LOG_ERR, "OneTouch device programmer failed to get time menu\n");
} else {
}
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
logMessage(LOG_ERR, "OneTouch device programmer didn't get back to System menu\n");
}
cleanAndTerminateThread(threadCtrl);
// just stop compiler error, ptr is not valid as it's just been freed
return ptr;
}

20
onetouch_aq_programmer.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef ONETOUCH_AQ_PROGRAMMER_H_
#define ONETOUCH_AQ_PROGRAMMER_H_
unsigned char pop_ot_cmd(unsigned char receive_type);
bool ot_queue_cmd(unsigned char cmd);
//bool in_ot_programming_mode(struct aqualinkdata *aq_data);
void *set_aqualink_pump_rpm( void *ptr );
void *set_aqualink_onetouch_macro( void *ptr );
void *get_aqualink_onetouch_setpoints( void *ptr );
void *set_aqualink_onetouch_spa_heater_temp( void *ptr );
void *set_aqualink_onetouch_pool_heater_temp( void *ptr );
void *set_aqualink_onetouch_swg_percent( void *ptr );
void *set_aqualink_onetouch_boost( void *ptr );
void *set_aqualink_onetouch_time( void *ptr );
void *set_aqualink_onetouch_freezeprotect( void *ptr );
#endif // ONETOUCH_AQ_PROGRAMMER_H_

View File

@ -11,7 +11,7 @@ static FILE *_byteLogFile = NULL;
static bool _log2file = false;
static bool _includePentair = false;
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error);
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error, bool force);
void startPacketLogger(bool debug_RSProtocol_packets, bool read_pentair_packets) {
_log2file = debug_RSProtocol_packets;
@ -37,17 +37,21 @@ void writePacketLog(char *buffer) {
}
void logPacket(unsigned char *packet_buffer, int packet_length) {
_logPacket(packet_buffer, packet_length, false);
_logPacket(packet_buffer, packet_length, false, false);
}
void logPacketError(unsigned char *packet_buffer, int packet_length) {
_logPacket(packet_buffer, packet_length, true);
_logPacket(packet_buffer, packet_length, true, false);
}
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error)
void debuglogPacket(unsigned char *packet_buffer, int packet_length) {
_logPacket(packet_buffer, packet_length, false, true);
}
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error, bool force)
{
// No point in continuing if loglevel is < debug_serial and not writing to file
if ( error == false && getLogLevel() < LOG_DEBUG_SERIAL && _log2file == false)
if ( force == false && error == false && getLogLevel() < LOG_DEBUG_SERIAL && _log2file == false)
return;
char buff[1000];
@ -70,8 +74,12 @@ void _logPacket(unsigned char *packet_buffer, int packet_length, bool error)
if (error == true)
logMessage(LOG_WARNING, "%s", buff);
else
logMessage(LOG_DEBUG_SERIAL, "%s", buff);
else {
if (force)
logMessage(LOG_DEBUG, "%s", buff);
else
logMessage(LOG_DEBUG_SERIAL, "%s", buff);
}
}
//#define RAW_BUFFER_SIZE 100

View File

@ -13,5 +13,8 @@ void logPacket(unsigned char *packet_buffer, int packet_length);
void logPacketError(unsigned char *packet_buffer, int packet_length);
void logPacketByte(unsigned char *byte);
// Only use for manual debugging
void debuglogPacket(unsigned char *packet_buffer, int packet_length);
#endif //PACKETLOGGER_H_

15
pda.c
View File

@ -43,11 +43,11 @@ static bool _initWithRS = false;
#ifdef BETA_PDA_AUTOLABEL
static struct aqconfig *_aqualink_config;
void init_pda(struct aqualinkdata *aqdata, struct aqconfig *aqconfig)
//static struct aqconfig *_aqconfig_;
void init_pda(struct aqualinkdata *aqdata)
{
_aqualink_data = aqdata;
_aqualink_config = aqconfig;
//_aqconfig_ = aqconfig;
set_pda_mode(true);
}
#else
@ -491,7 +491,7 @@ void process_pda_packet_msg_long_level_aux_device(const char *msg)
int li=-1;
char *str, *label;
if (! _aqualink_config->use_panel_aux_labels)
if (! _aqconfig_->use_panel_aux_labels)
return;
// NSF Need to check config for use_panel_aux_labels value and ignore if not set
@ -686,10 +686,11 @@ bool process_pda_packet(unsigned char *packet, int length)
{
_initWithRS = true;
logMessage(LOG_DEBUG, "**** PDA INIT ****");
aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data);
//aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data);
queueGetProgramData(AQUAPDA, _aqualink_data);
delay(50); // Make sure this one runs first.
#ifdef BETA_PDA_AUTOLABEL
if (_aqualink_config->use_panel_aux_labels)
if (_aqconfig_->use_panel_aux_labels)
aq_programmer(AQ_GET_AUX_LABELS, NULL, _aqualink_data);
#endif
aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data);
@ -707,7 +708,7 @@ bool process_pda_packet(unsigned char *packet, int length)
packet[PKT_CMD] == CMD_PDA_HIGHLIGHTCHARS)
{
// We processed the next message, kick any threads waiting on the message.
kick_aq_program_thread(_aqualink_data);
kick_aq_program_thread(_aqualink_data, AQUAPDA);
}
return rtn;
}

View File

@ -105,7 +105,7 @@ bool processiAqualinkMsg(unsigned char *packet_buffer, int packet_length, struct
pumpIndex = atoi((char *) &lastmessage[14]);
if ( pumpIndex < MAX_PUMPS && pumpIndex < 0) {
if ( pumpIndex < aqdata->num_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);
}

Binary file not shown.

View File

@ -64,6 +64,17 @@ report_zero_pool_temp = no
# You can use 0x00 and AqualinkD will find an ID for you, but this makes a slow startup
device_id=0x0a
# The ID for extended settings, These are ONE TOUCH MACROS & VARIABLE SPEED PUMP RPM
# Do not enable this if you don't use either, you'll just waste memory and cpu cycles
# Valid ID's are 0x40, 0x41, 0x42 & 0x43.
# If you have a one touch remote do not use Ox40
#extended_device_id=0x41
# 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
# Please see forum for this, only set to yes when logging information to support
# new devices. Inflrmation will be written to /tmp/RS485.log
#debug_RSProtocol_packets = no
@ -127,18 +138,23 @@ use_panel_aux_labels=no
# Simply change these to your setup, comment out ones that ent in _dzidx if you don't use Domoticz.
# If using PDA mode, PDA Labels below are of the utmost importance, the PDA labels MUST match the labels in the "EQUIPTMENT ON/OFF" menu of the PDA device.
#
# Optional, If you have a Variable Speed Pump, then assign the RS485 ID to the button below so RPM/GPH/WATTS are displayed
# Optional, ( button_01_pumpID & button_01_pumpIndex )
# If you have a Variable Speed Pump, then assign the RS485 ID to the button below so RPM/GPH/WATTS are displayed
# Format is button_01_pumpID=0x60. Leave blank if you don't have a VSP.
# Pentair pump ID's
# 0x60 to 0x6F (0x60, 0x61 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F)
# Jandy pump ID's
# 0x78, 0x79, 0x7A, 0x7B
#
# button_01_pumpIndex=1
# If you have assigned this pump an index number in your Aqualink control panel, (Between 1 & 4), put it here for VSP, RPM, Primp information to be captured.
# Labels for standard butons (shown in web UI), and domoticz idx's
button_01_label=Filter Pump
#button_01_dzidx=37
#button_01_PDA_label=FILTER PUMP
#button_01_pumpID=0x60
#button_01_pumpIndex=1
button_02_label=Spa Mode
#button_02_dzidx=38
@ -151,7 +167,8 @@ button_03_label=Cleaner
button_04_label=Waterfall
#button_04_dzidx=40
#button_04_PDA_label=AUX2
#button_01_pumpID=0x61
#button_04_pumpID=0x61
#button_04_pumpIndex=2
button_05_label=Spa Blower
#button_05_dzidx=41

View File

@ -38,42 +38,19 @@ command -v systemctl >/dev/null 2>&1 || { echo "This script needs systemd's syst
systemctl stop $SERVICE > /dev/null 2>&1
SERVICE_EXISTS=$(echo $?)
# Clean everything if requested.
if [ "$1" == "clean" ]; then
echo "Deleting install"
systemctl disable $SERVICE > /dev/null 2>&1
if [ -f $BINLocation/$BIN ]; then
rm -f $BINLocation/$BIN
fi
if [ -f $SRVLocation/$SRV ]; then
rm -f $SRVLocation/$SRV
fi
if [ -f $CFGLocation/$CFG ]; then
rm -f $CFGLocation/$CFG
fi
if [ -f $DEFLocation/$DEF ]; then
rm -f $DEFLocation/$DEF
fi
if [ -d $WEBLocation ]; then
rm -rf $WEBLocation
fi
systemctl daemon-reload
exit
fi
# copy files to locations, but only copy cfg if it doesn;t already exist
cp $BUILD/$BIN $BINLocation/$BIN
cp $BUILD/$SRV $SRVLocation/$SRV
if [ -f $CFGLocation/$CFG ]; then
echo "AqualinkD config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
echo "Config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
else
cp $BUILD/$CFG $CFGLocation/$CFG
fi
if [ -f $DEFLocation/$DEF ]; then
echo "AqualinkD defaults exists, did not copy new defaults to $DEFLocation/$DEF"
echo "Defaults exists, did not copy new defaults to $DEFLocation/$DEF"
else
cp $BUILD/$DEF.defaults $DEFLocation/$DEF
fi
@ -93,7 +70,7 @@ if [ ! -d "$WEBLocation" ]; then
fi
if [ -f "$WEBLocation/config.js" ]; then
echo "AqualinkD web config exists, did not copy new config, you may need to edit existing $WEBLocation/config.js "
echo "$WEBLocation/config.js exists, did not copy overight, please make sure to update manually"
rsync -avq --exclude='config.js' $BUILD/../web/* $WEBLocation
else
cp -r $BUILD/../web/* $WEBLocation
@ -106,7 +83,5 @@ systemctl daemon-reload
if [ $SERVICE_EXISTS -eq 0 ]; then
echo "Starting daemon $SERVICE"
systemctl start $SERVICE
else
echo "Please edit $CFGLocation/$CFG, then start AqualinkD service"
fi

Binary file not shown.

View File

@ -28,11 +28,12 @@
#include "aq_serial.h"
#include "utils.h"
#include "packetLogger.h"
#define SLOG_MAX 80
#define PACKET_MAX 600
#define VERSION "serial_logger V1.1"
#define VERSION "serial_logger V1.2"
/*
typedef enum used {
@ -51,6 +52,7 @@ bool _keepRunning = true;
unsigned char _goodID[] = {0x0a, 0x0b, 0x08, 0x09};
unsigned char _goodPDAID[] = {0x60, 0x61, 0x62, 0x63};
unsigned char _goodONETID[] = {0x40, 0x41, 0x42, 0x43};
unsigned char _filter[10];
int _filters=0;
bool _rawlog=false;
@ -67,7 +69,7 @@ void intHandler(int dummy) {
#define SWG " <-- Salt Water Generator (Aquarite mode)"
#define KEYPAD " <-- RS Keypad"
#define SPA_R " <-- Spa remote"
#define AQUA " <-- Aqualink (iAqualink?)"
#define AQUA " <-- Aqualink (iAqualink / Touch)"
#define HEATER " <-- LX Heater"
#define ONE_T " <-- Onetouch device"
#define PC_DOCK " <-- PC Interface (RS485 to RS232)"
@ -152,6 +154,10 @@ bool canUse(unsigned char ID) {
if (ID == _goodPDAID[i])
return true;
}
for (i = 0; i < 4; i++) {
if (ID == _goodONETID[i])
return true;
}
return false;
}
char* canUseExtended(unsigned char ID) {
@ -164,6 +170,10 @@ char* canUseExtended(unsigned char ID) {
if (ID == _goodPDAID[i])
return " <-- can use for Aqualinkd (PDA mode only)";
}
for (i = 0; i < 4; i++) {
if (ID == _goodONETID[i])
return " <-- can use for Aqualinkd (Extended Device ID)";
}
return "";
}
@ -249,6 +259,7 @@ int main(int argc, char *argv[]) {
int received_packets = 0;
int logPackets = PACKET_MAX;
int logLevel = LOG_NOTICE;
bool rsRawDebug = false;
//bool playback_file = false;
//int logLevel;
@ -264,7 +275,14 @@ int main(int argc, char *argv[]) {
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> & -r (raw) ie:=\n\t%s /dev/ttyUSB0 -d -p 1000 -i 0x08\n\n", argv[0]);
//fprintf(stderr, "Optional parameters are -d (debug) & -p <number> (log # packets) & -i <ID> & -r (raw) ie:=\n\t%s /dev/ttyUSB0 -d -p 1000 -i 0x08\n\n", argv[0]);
fprintf(stderr, "Optional parameters are :-\n");
fprintf(stderr, "\t-d (debug)\n");
fprintf(stderr, "\t-p <number> (log # packets)\n");
fprintf(stderr, "\t-i <ID> (just log these ID's, can use multiple -i)\n");
fprintf(stderr, "\t-r (raw)\n");
fprintf(stderr, "\t-rsrd (log raw RS bytes to %s)\n",RS485BYTELOGFILE);
fprintf(stderr, "\nie:\t%s /dev/ttyUSB0 -d -p 1000 -i 0x08 -i 0x0a\n\n", argv[0]);
return 1;
}
@ -286,6 +304,8 @@ int main(int argc, char *argv[]) {
logLevel = LOG_DEBUG;
} else if (strcmp(argv[i], "-f") == 0) {
_playback_file = true;
} else if (strcmp(argv[i], "-rsrd") == 0) {
rsRawDebug = true;
}
}
@ -315,7 +335,10 @@ int main(int argc, char *argv[]) {
}
//packet_length = get_packet(rs_fd, packet_buffer);
packet_length = get_packet(rs_fd, packet_buffer);
if (rsRawDebug)
packet_length = get_packet_lograw(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.
@ -401,6 +424,7 @@ int main(int argc, char *argv[]) {
if (sindex >= SLOG_MAX)
logMessage(LOG_ERR, "Ran out of storage, some ID's were not captured, please increase SLOG_MAX and recompile\n");
logMessage(LOG_NOTICE, "Jandy ID's found\n");
for (i = 0; i < sindex; i++) {
//logMessage(LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",

10
utils.c
View File

@ -87,6 +87,14 @@ void startInlineDebug()
_log_filename = DEFAULT_LOG_FILE;
}
void startInlineSerialDebug()
{
_log_level = LOG_DEBUG_SERIAL;
_log2file = true;
if (_log_filename == NULL)
_log_filename = DEFAULT_LOG_FILE;
}
void stopInlineDebug()
{
_log_level = _cfg_log_level;
@ -343,7 +351,7 @@ void logMessage(int msg_level, char *format, ...)
strncpy(buffer, " ", 8);
vsprintf (&buffer[8], format, args);
va_end(args);
//test(msg_level, buffer);
//fprintf (stderr, buffer);

View File

@ -56,6 +56,7 @@ char *prittyString(char *str);
//void writePacketLog(char *buff);
//void closePacketLog();
void startInlineDebug();
void startInlineSerialDebug();
void stopInlineDebug();
void cleanInlineDebug();
char *getInlineLogFName();

View File

@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
#define AQUALINKD_VERSION "1.3.9c"
#define AQUALINKD_VERSION "2.0.0a"

View File

@ -62,6 +62,10 @@
// 0 means only load once when page loads.
//var background_reload = 10;
// By default all Variable Speed Pumps will show RPM.
// this will show GPM on VSP's that you can only set GPM (ie Jandy VF pumps)
//var show_vsp_gpm=false;
var body_background = "#EBEBEA";
var body_text = "#000000";

View File

@ -469,6 +469,12 @@
var _aqualink_data;
var _landscape = false;
var _displayNames = [];
if (typeof show_vsp_gpm !== 'undefined' && show_vsp_gpm == false)
var _show_vsp_gpm=false;
else
var _show_vsp_gpm=true;
//init();
function init() {
setSizeSpecifics();
@ -476,6 +482,7 @@
document.getElementById('thermostat_options').classList.remove("hide");
document.getElementById('swg_options').classList.remove("hide");
document.getElementById('pswitch_options').classList.remove("hide");
document.getElementById('vspswitch_options').classList.remove("hide");
setColors();
load_background();
showTileOptions(false);
@ -714,10 +721,13 @@
subdiv.setAttribute('id', id + '_status');
subdiv.textContent = formatSatus(status);
div.appendChild(subdiv);
if (type == "switch" && subtype != "switch_program") {
if (type == "switch" && (subtype != "switch_program" && subtype != "switch_vsp") ) {
//if (type == "switch" && subtype != "switch_program" ) {
div.setAttribute('onclick', "switchTileState('" + id + "')");
//console.log("add onclick switchtilestate to "+id);
} else /*if (id != "SWG/Percent")*/ {
add_clickEvent(div, id);
//console.log("add click Event to "+id);
}
}
document.getElementById('wrapper').appendChild(div);
@ -735,9 +745,9 @@
try {
if (state == (document.getElementById(id).getAttribute('status') == 'off')) {
send_command(id);
console.log("Switch state "+id+" to "+(state)?"on":"off");
//console.log("Switch state "+id+" to "+(state)?"on":"off");
} else {
console.log("state "+id+" to "+(state)?"on":"off")
//console.log("state "+id+" to "+(state)?"on":"off")
}
setTileOn(id, ((state) ? "on" : "off"));
} catch(exception) {}
@ -866,10 +876,10 @@
text = 'Generating';
}
else if (type == 'setpoint_thermo')
if (status == 'enabled')
//if (status == 'enabled')
text = 'Heat to ' + tile.getAttribute('setpoint');
else
text = 'Heating to ' + tile.getAttribute('setpoint');
//else
// text = 'Heating to ' + tile.getAttribute('setpoint'); // too large for phone
else if (type == 'setpoint_freeze')
text = 'Turn on ' + tile.getAttribute('setpoint') + "&deg;";
//else
@ -921,12 +931,42 @@
if (typeof devices !== 'undefined' && devices.indexOf(object.id) < 0) {
return;
}
if (object.type == 'switch' || object.type == 'switch_program') {
//if (object.type == 'switch' || object.type == 'switch_program') {
if (object.type == 'switch') {
var img = object.id.replace('/', '_');
add_tile(object.id, object.name, object.state, 'switch', object.type, 'hk/' + img + '-off.png', 'hk/' + img + '-on.png');
var ext_type;
if (typeof object.type_ext !== 'undefined')
ext_type = object.type_ext;
else
ext_type = object.type;
add_tile(object.id, object.name, object.state, 'switch', ext_type, 'hk/' + img + '-off.png', 'hk/' + img + '-on.png');
setTileOn(object.id, object.status, null);
if (typeof object.Pump_RPM !== 'undefined' && object.Pump_RPM) {
setTileOnText(object.id, 'RPM:'+object.Pump_RPM);
if (typeof object.type_ext !== 'undefined' && object.type_ext == 'switch_vsp') {
if (typeof object.Pump_RPM !== 'undefined' && object.Pump_RPM) {
if (object.Pump_RPM == -2) {
setTileOnText(object.id, 'Pump Offline'); // Small txt
document.getElementById(object.id).setAttribute('setpoint', 0);
} else if (object.Pump_RPM == -1) {
setTileOnText(object.id, 'Pump Priming'); // Small text
document.getElementById(object.id).setAttribute('setpoint', 0);
} else {
if (object.Pump_Type == "vfPump") {
if (_show_vsp_gpm == true)
setTileOnText(object.id, 'GPM:'+object.Pump_GPM);
else
setTileOnText(object.id, 'RPM:'+object.Pump_RPM);
document.getElementById(object.id).setAttribute('setpoint', object.Pump_GPM);
} else {
setTileOnText(object.id, 'RPM:'+object.Pump_RPM);
document.getElementById(object.id).setAttribute('setpoint', object.Pump_RPM);
}
}
}
if (typeof object.Pump_Type !== 'undefined') {
document.getElementById(object.id).setAttribute('pumptype', object.Pump_Type);
}
}
} else if (object.type == 'value' || object.type == 'temperature') {
add_tile(object.id, object.name, object.state, 'value', object.type);
@ -942,6 +982,7 @@
}
function showTileOptions(show, id, contex) {
console.log("showTileOptions " + show + " "+id+" "+contex);
var active_option;
if (show == true) {
var wrapH = document.getElementById('wrapper').clientHeight + 'px';
@ -949,14 +990,22 @@
active_option = document.getElementById('thermostat_options');
document.getElementById('swg_options').style.display = 'none';
document.getElementById('pswitch_options').style.display = 'none';
document.getElementById('vspswitch_options').style.display = 'none';
} else if (id != null && document.getElementById(id).getAttribute('type') == 'switch_program') {
active_option = document.getElementById('pswitch_options');
document.getElementById('thermostat_options').style.display = 'none';
document.getElementById('swg_options').style.display = 'none';
} else /*if (id != null && document.getElementById(id).getAttribute('type') == 'setpoint_swg')*/ {
document.getElementById('vspswitch_options').style.display = 'none';
} else if (id != null && document.getElementById(id).getAttribute('type') == 'setpoint_swg') {
active_option = document.getElementById('swg_options');
document.getElementById('thermostat_options').style.display = 'none';
document.getElementById('pswitch_options').style.display = 'none';
document.getElementById('vspswitch_options').style.display = 'none';
} else if (id != null && document.getElementById(id).getAttribute('type') == 'switch_vsp') {
active_option = document.getElementById('vspswitch_options');
document.getElementById('thermostat_options').style.display = 'none';
document.getElementById('pswitch_options').style.display = 'none';
document.getElementById('swg_options').style.display = 'none';
}
active_option.style.display = 'flex';
var optionH = window.getComputedStyle(active_option, null).getPropertyValue("height");
@ -974,10 +1023,13 @@
document.getElementById("swg_options_close").click();
else if (document.getElementById('pswitch_options').style.display == 'flex')
document.getElementById("pswitch_options_close").click();
else if (document.getElementById('vspswitch_options').style.display == 'flex')
document.getElementById("vspswitch_options").click();
}
document.getElementById('thermostat_options').style.display = 'none';
document.getElementById('swg_options').style.display = 'none';
document.getElementById('pswitch_options').style.display = 'none';
document.getElementById('vspswitch_options').style.display = 'none';
document.getElementById('wrapper').classList.remove("opaque");
return;
}
@ -1011,6 +1063,12 @@
title = document.getElementById("pswitch_option_title");
close_button = document.getElementById("pswitch_options_close");
//ext = '&deg;' + _temperature_units;
} else if (type == 'switch_vsp') {
slider = document.getElementById("vspoption_slider_range");
slider_output = document.getElementById("vspoption_slider_text_value");
title = document.getElementById("vspswitch_option_title");
close_button = document.getElementById("vspswitch_option_close");
//ext = '&deg;' + _temperature_units;
} else {
slider = document.getElementById("option_slider_range");
slider_output = document.getElementById("option_slider_text_value");
@ -1042,6 +1100,18 @@
slider.max = 40;
slider.step = 1;
}
} else if (type == 'switch_vsp') {
if ( tile.getAttribute('pumptype') == "vfPump" ) { // RPM vs GPM
slider.min = 15;
slider.max = 130;
slider.step = 5;
ext = ' GPM';
} else {
slider.min = 600;
slider.max = 3450;
slider.step = 5;
ext = ' RPM';
}
}
title.innerHTML = document.getElementById(id + '_name').innerHTML;
if (type == 'switch_program') {
@ -1070,6 +1140,21 @@
oswitch_output.innerHTML = ((oswitch.checked) ? "Boost On" : "Boost Off");
//setTileOn(id, ((oswitch.checked)?"on":"off"), null);
}
} else if (type == 'switch_vsp') {
slider.value = sp_value;
oswitch = document.getElementById("vspoption_switch");
oswitch.checked = tile_state;
var oswitch_output = document.getElementById("vspoption_switch_text_value");
slider_output.innerHTML = slider.value + ext;
oswitch_output.innerHTML = ((oswitch.checked) ? "On" : "Off");
slider.oninput = function() {
slider_output.innerHTML = this.value + ext;
//sp_value = this.value
}
oswitch.onclick = function() {
oswitch_output.innerHTML = ((oswitch.checked) ? "On" : "Off");
//setTileOn(id, ((oswitch.checked)?"on":"off"), null);
}
} else {
slider.value = sp_value;
oswitch = document.getElementById("option_switch");
@ -1133,6 +1218,12 @@
if (sp_value != slider.value && slider.value != 101) // Don't change setpoint if slider is on boost
setThermostatSetpoint(id, slider.value);
}
} else if (type == 'switch_program') {
var value = slider.value;
if (state == (tile.getAttribute('status') == 'off'))
setTileState(id, state);
if (sp_value != slider.value)
setThermostatSetpoint(id, slider.value)
} else {
var value = slider.value;
if (state == (tile.getAttribute('status') == 'off'))
@ -1215,7 +1306,24 @@
while (i < 5) {
//console.log(data["Pump_"+i].RPM);
if ((typeof data["Pump_"+i] !== 'undefined') && (typeof data["Pump_"+i].RPM !== 'undefined')) {
setTileOnText(data["Pump_"+i].id, 'RPM:'+data["Pump_"+i].RPM);
if (data["Pump_"+i].RPM == -2) {
setTileOnText(data["Pump_"+i].id, 'Pump Offline');
} else if (data["Pump_"+i].RPM == -1) {
setTileOnText(data["Pump_"+i].id, 'Pump Priming');
} else {
//setTileOnText(object.id, 'RPM:'+object.Pump_RPM);
if (data["Pump_"+i].Pump_Type == "vfPump") {
if (_show_vsp_gpm == true)
setTileOnText(data["Pump_"+i].id, 'GPM:'+data["Pump_"+i].GPM);
else
setTileOnText(data["Pump_"+i].id, 'RPM:'+data["Pump_"+i].RPM);
document.getElementById(data["Pump_"+i].id).setAttribute('setpoint', data["Pump_"+i].GPM);
} else {
document.getElementById(data["Pump_"+i].id).setAttribute('setpoint', data["Pump_"+i].RPM);
setTileOnText(data["Pump_"+i].id, 'RPM:'+data["Pump_"+i].RPM);
}
}
/*
if (document.getElementById(data["Pump_"+i].id).getAttribute('status') == 'on')
document.getElementById(data["Pump_"+i].id + '_status').innerHTML = 'RPM:'+data["Pump_"+i].RPM;
@ -1247,8 +1355,12 @@
createTile(data['devices'][obj]);
} else {
//console.log("old type "+document.getElementById(data['devices'][obj].id).getAttribute('type')+" | new "+data['devices'][obj].type);
if (document.getElementById(data['devices'][obj].id).getAttribute('type') != data['devices'][obj].type) {
//console.log("Remove and create "+data['devices'][obj].id);
var element_type = document.getElementById(data['devices'][obj].id).getAttribute('type');
if ( (element_type != data['devices'][obj].type) &&
(typeof data['devices'][obj].type_ext !== 'undefined' && element_type != data['devices'][obj].type_ext ) ) {
console.log("Remove and create "+data['devices'][obj].id);
console.log("Old type "+element_type+" | new type "+data['devices'][obj].type+" sub "+data['devices'][obj].type_ext);
var element = document.getElementById(data['devices'][obj].id);
element.parentNode.removeChild(element);
createTile(data['devices'][obj]);
@ -1335,8 +1447,10 @@
if ((tile = document.getElementById(id)) == null) {
return;
}
if (tile.getAttribute('setpoint'))
temperature.parameter = tile.getAttribute('id');
temperature.value = tile.getAttribute('setpoint');
//console.log("Send value back "+temperature.parameter+" "+temperature.value);
socket_di.send(JSON.stringify(temperature));
}
@ -1516,6 +1630,42 @@
</table>
</div>
</div>
<div id='vspswitch_options' class='options hide'>
<div id='vspswitch_options_pane' class='options_pane' onclick='event.stopPropagation();'>
<table border='0' cellpadding='10px'>
<tr class='options_title'>
<th colspan='2'><span id="vspswitch_option_title"></span>
</th>
</tr>
<tr>
<td align='right' width='50%'><span class="option_text" id='vspoption_switch_text_value'></span>
</td>
<td align='left' width='50%'>
<label class="option_switch">
<input type="checkbox" id='vspoption_switch'>
<span class="option_switch_slide"></span>
</label>
</td>
</tr>
<tr>
<td colspan='2' align='center'><span class="option_text" id="vspoption_slider_text_value"></span>
</td>
</tr>
<tr>
<td colspan='2'>
<div class="slidecontainer">
<input type="range" class="option_slider" id='vspoption_slider_range'>
</div>
</td>
</tr>
<tr>
<td colspan='2' align='center'>
<input type="button" value="close" id='vspswitch_option_close' class='options_button'>
</td>
</tr>
</table>
</div>
</div>
</div>
</body>

View File

@ -56,6 +56,8 @@ Button style taken from https://github.com/ubuwaits/css3-buttons */
if (element.id == "start") {
document.getElementById('messages').innerHTML = "Debug Starting!"
} else if (element.id == "serialstart") {
document.getElementById('messages').innerHTML = "Serial Debug Starting!"
} else if (element.id == "stop") {
document.getElementById('messages').innerHTML = "Debug Stopping!"
} else if (element.id == "clean") {
@ -90,10 +92,15 @@ Button style taken from https://github.com/ubuwaits/css3-buttons */
//console.log(data.iLevel + " : " + data.sLevel);
if ( data.iLevel >= 7 ) {
document.getElementById('start').disabled = true;
document.getElementById('stop').disabled = false;
document.getElementById('messages').innerHTML = "Debug Running!"
document.getElementById('serialstart').disabled = true;
document.getElementById('stop').disabled = false;
if ( data.iLevel >= 8 )
document.getElementById('messages').innerHTML = "Serial debug Running!"
else
document.getElementById('messages').innerHTML = "Debug Running!"
} else if ( data.iLevel < 7 ) {
document.getElementById('start').disabled = false;
document.getElementById('serialstart').disabled = false;
document.getElementById('stop').disabled = true;
document.getElementById('messages').innerHTML = "Not debugging, Log level = "+data.sLevel;
}
@ -125,20 +132,25 @@ Button style taken from https://github.com/ubuwaits/css3-buttons */
<body onload="update();">
<table cellpadding="10" border="0" align="center">
<tr><td colspan="2" align="center">
<tr><td colspan="3" align="center">
<div id="messages">&nbsp</div>
</td></tr>
<tr><td align="center">
<button class="blue-pill" id="start" type="button" onclick='action(this);'>Start Debug</button>
</td><td align="center">
<button class="blue-pill" id="serialstart" type="button" onclick='action(this);'>Start Serial Debug</button>
</td><td align="center">
<button class="blue-pill" id="stop" type="button" onclick='action(this);'>Stop Debug</button>
</td></tr>
<tr><td colspan="2" align="center">
<button class="blue-pill" id="download" type="button" onclick='action(this);'>Download Debug File</button>
<tr><td colspan="3" align="center">
<table cellpadding="10" border="0" align="center">
<tr><td>
<button class="blue-pill" id="download" type="button" onclick='action(this);'>Download Debug File</button>
</td><td>
<button class="blue-pill" id="clean" type="button" onclick='action(this);'>Clean Debug File</button>
</td></tr>
</table>
</td></tr>
<tr><td colspan="2" align="center">
<button class="blue-pill" id="clean" type="button" onclick='action(this);'>Clean Debug File</button>
</td></tr>
</table>
</body>