mirror of https://github.com/sfeakes/AqualinkD.git
Updates
parent
6f16015593
commit
a146f1d171
10
README.md
10
README.md
|
@ -23,9 +23,10 @@ https://github.com/sfeakes/AqualinkD/wiki
|
|||
|
||||
For information on Control panel versions and upgrading the chips.<br>
|
||||
https://github.com/sfeakes/AqualinkD/wiki/Upgrading-Jandy-Aqualink-PDA-to-RS-panel
|
||||
|
||||
<!--
|
||||
Here's where I started to document what I know about the Jandy RS485 protocol.<br>
|
||||
https://github.com/sfeakes/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
|
||||
-->
|
||||
|
||||
## AqualinkD built in WEB Interface(s).
|
||||
|
||||
|
@ -74,10 +75,9 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* http://aqualink.ip/debug.html <- (Turn on/off debug/serial debug & download logs)
|
||||
#<a name="release"></a>
|
||||
# ToDo (future release)
|
||||
* Allow selecting of pre-defined VSP programs
|
||||
* Update homekit-aqualinkd to use new API & features.
|
||||
* Add light programming to Aqualink Touch protocol.
|
||||
* Add set time to Aqualink OneTouch protocol
|
||||
* Allow selecting of pre-defined VSP programs (Aqualink Touch & OneTouch protocols.)
|
||||
* Add light programming to Aqualink Touch & OneTouch protocols.
|
||||
* Add set time to OneTouch protocol.
|
||||
|
||||
# Update in Release 2.3.0 (pre release)
|
||||
* This is pre-release, please treat it as such.
|
||||
|
|
|
@ -627,6 +627,10 @@ bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int dev
|
|||
case ON_OFF:
|
||||
//setDeviceState(&aqdata->aqbuttons[deviceIndex], value<=0?false:true, deviceIndex );
|
||||
setDeviceState(aqdata, deviceIndex, value<=0?false:true );
|
||||
// Clear timer if off request and timer is active
|
||||
if (value<=0 && (aqdata->aqbuttons[deviceIndex].special_mask & TIMER_ACTIVE) == TIMER_ACTIVE ) {
|
||||
clear_timer(aqdata, &aqdata->aqbuttons[deviceIndex]);
|
||||
}
|
||||
break;
|
||||
case TIMER:
|
||||
//setDeviceState(&aqdata->aqbuttons[deviceIndex], true);
|
||||
|
|
216
aq_programmer.c
216
aq_programmer.c
|
@ -84,6 +84,8 @@ bool push_aq_cmd(unsigned char cmd);
|
|||
void waitfor_queue2empty();
|
||||
void longwaitfor_queue2empty();
|
||||
|
||||
void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data, bool allowOveride);
|
||||
|
||||
#define MAX_STACK 20
|
||||
int _stack_place = 0;
|
||||
unsigned char _commands[MAX_STACK];
|
||||
|
@ -222,6 +224,50 @@ unsigned char pop_aq_cmd_OLD(struct aqualinkdata *aq_data)
|
|||
}
|
||||
*/
|
||||
|
||||
/* Maybe use in future, not needed for moment
|
||||
Idea here was to convert all button on/off commands to rs_serial_adapter commands to use if in all button probramming mode */
|
||||
/*
|
||||
unsigned char AllButton2RSsrialAdapter(unsigned char abcmd)
|
||||
{
|
||||
switch(abcmd) {
|
||||
case KEY_PUMP:
|
||||
return RS_SA_PUMP;
|
||||
break;
|
||||
case KEY_SPA:
|
||||
return RS_SA_SPA;
|
||||
break;
|
||||
case KEY_AUX1:
|
||||
return RS_SA_AUX1;
|
||||
break;
|
||||
case KEY_AUX2:
|
||||
return RS_SA_AUX2;
|
||||
break;
|
||||
case KEY_AUX3:
|
||||
return RS_SA_AUX3;
|
||||
break;
|
||||
case KEY_AUX4:
|
||||
return RS_SA_AUX4;
|
||||
break;
|
||||
case KEY_AUX5:
|
||||
return RS_SA_AUX5;
|
||||
break;
|
||||
case KEY_AUX6:
|
||||
return RS_SA_AUX6;
|
||||
break;
|
||||
case KEY_AUX7:
|
||||
return RS_SA_AUX7;
|
||||
break;
|
||||
case KEY_POOL_HTR:
|
||||
return RS_SA_POOLHT;
|
||||
break;
|
||||
case KEY_SPA_HTR:
|
||||
return RS_SA_SPAHT;
|
||||
break;
|
||||
}
|
||||
return NUL;
|
||||
}
|
||||
*/
|
||||
|
||||
int roundTo(int num, int denominator) {
|
||||
return ((num + (denominator/2) ) / denominator )* denominator;
|
||||
}
|
||||
|
@ -333,7 +379,78 @@ int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
|
|||
return rtn;
|
||||
}
|
||||
|
||||
/*
|
||||
Figure out the fastest way in get all needed startup data depending on what protocols
|
||||
are available and what's just called us
|
||||
*/
|
||||
void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_data)
|
||||
{
|
||||
LOG(PROG_LOG, LOG_INFO, "Initial setup call from %s with RSSA=%s ONETouch=%s IAQTouch=%s ExtendedProgramming=%s\n",
|
||||
(source_type == ALLBUTTON)?"AllButton":((source_type == RSSADAPTER)?"RSSA":((source_type == ONETOUCH)?"OneTouch":((source_type == IAQTOUCH)?"IAQTouch":"PDA"))),
|
||||
(isRSSA_ENABLED)?"enabled":"disabled",
|
||||
(isONET_ENABLED)?"enabled":"disabled",
|
||||
(isIAQT_ENABLED)?"enabled":"disabled",
|
||||
(isEXTP_ENABLED)?"enabled":"disabled"
|
||||
);
|
||||
|
||||
if (isRSSA_ENABLED && isEXTP_ENABLED == true) {
|
||||
// serial adapter enabled and extended programming
|
||||
if (source_type == RSSADAPTER) {
|
||||
_aq_programmer(AQ_GET_RSSADAPTER_SETPOINTS, NULL, aq_data, false);
|
||||
} else if (source_type == ONETOUCH && isEXTP_ENABLED) {
|
||||
//_aq_programmer(AQ_GET_ONETOUCH_FREEZEPROTECT, NULL, aq_data, false); // Add back and remove below once tested and working
|
||||
//_aq_programmer(AQ_GET_ONETOUCH_SETPOINTS, NULL, aq_data, false);
|
||||
} else if (source_type == IAQTOUCH && isEXTP_ENABLED) {
|
||||
//_aq_programmer(AQ_GET_IAQTOUCH_FREEZEPROTECT, NULL, aq_data, false); // Add back and remove below once tested and working
|
||||
//_aq_programmer(AQ_GET_IAQTOUCH_SETPOINTS, NULL, aq_data, false); // This get's freeze & heaters, we should just get freeze if isRSSA_ENABLED
|
||||
} else if (source_type == ALLBUTTON) {
|
||||
_aq_programmer(AQ_GET_FREEZE_PROTECT_TEMP, NULL, aq_data, false); // This is still quicker that IAQ or ONE Touch protocols at the moment.
|
||||
if (_aqconfig_.use_panel_aux_labels) {
|
||||
_aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data, false);
|
||||
}
|
||||
}
|
||||
} else if (isRSSA_ENABLED && isEXTP_ENABLED == false) {
|
||||
// serial adapter enabled with no extended programming
|
||||
if (source_type == RSSADAPTER) {
|
||||
_aq_programmer(AQ_GET_RSSADAPTER_SETPOINTS, NULL, aq_data, false);
|
||||
} else if (source_type == ALLBUTTON) {
|
||||
_aq_programmer(AQ_GET_FREEZE_PROTECT_TEMP, NULL, aq_data, false);
|
||||
if (_aqconfig_.use_panel_aux_labels) {
|
||||
_aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data, false);
|
||||
}
|
||||
}
|
||||
} else if (!isRSSA_ENABLED && isEXTP_ENABLED && isONET_ENABLED) {
|
||||
// One touch extended and no serial adapter
|
||||
if (source_type == ONETOUCH) {
|
||||
_aq_programmer(AQ_GET_ONETOUCH_SETPOINTS, NULL, aq_data, false);
|
||||
} else if (source_type == ALLBUTTON) {
|
||||
if (_aqconfig_.use_panel_aux_labels) {
|
||||
_aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data, false);
|
||||
}
|
||||
}
|
||||
} else if (!isRSSA_ENABLED && isEXTP_ENABLED && isIAQT_ENABLED) {
|
||||
// IAQ touch extended and no serial adapter
|
||||
if (source_type == IAQTOUCH) {
|
||||
_aq_programmer(AQ_GET_IAQTOUCH_SETPOINTS, NULL, aq_data, false);
|
||||
} else if (source_type == ALLBUTTON) {
|
||||
if (_aqconfig_.use_panel_aux_labels) {
|
||||
_aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data, false);
|
||||
}
|
||||
}
|
||||
#ifdef AQ_PDA
|
||||
} else if ( source_type == AQUAPDA) {
|
||||
aq_programmer(AQ_PDA_INIT, NULL, aq_data);
|
||||
#endif
|
||||
} else { // Must be all button only
|
||||
aq_programmer(AQ_GET_POOL_SPA_HEATER_TEMPS, NULL, aq_data);
|
||||
aq_programmer(AQ_GET_FREEZE_PROTECT_TEMP, NULL, aq_data);
|
||||
if (_aqconfig_.use_panel_aux_labels) {
|
||||
aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void queueGetProgramData_OLD(emulation_type source_type, struct aqualinkdata *aq_data)
|
||||
{
|
||||
// Wait for onetouch if enabeled.
|
||||
//if ( source_type == ALLBUTTON && ( onetouch_enabled() == false || extended_device_id_programming() == false ) ) {
|
||||
|
@ -341,15 +458,20 @@ void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_dat
|
|||
aq_programmer(AQ_GET_RSSADAPTER_SETPOINTS, NULL, aq_data);
|
||||
} else if ( source_type == ALLBUTTON && ( isEXTP_ENABLED == false || (isONET_ENABLED == false && isIAQT_ENABLED == false)) ) {
|
||||
aq_send_cmd(NUL);
|
||||
if (!isRSSA_ENABLED)
|
||||
if (!isRSSA_ENABLED) {
|
||||
aq_programmer(AQ_GET_POOL_SPA_HEATER_TEMPS, NULL, aq_data);
|
||||
}
|
||||
aq_programmer(AQ_GET_FREEZE_PROTECT_TEMP, NULL, aq_data);
|
||||
if (_aqconfig_.use_panel_aux_labels)
|
||||
if (_aqconfig_.use_panel_aux_labels) {
|
||||
aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data);
|
||||
}
|
||||
#ifdef AQ_ONETOUCH
|
||||
} else if ( source_type == ONETOUCH) {
|
||||
//if (!isRSSA_ENABLED)
|
||||
aq_programmer(AQ_GET_ONETOUCH_SETPOINTS, NULL, aq_data); // This get's freeze & heaters, we should just get freeze if isRSSA_ENABLED
|
||||
if (!isRSSA_ENABLED) {
|
||||
aq_programmer(AQ_GET_ONETOUCH_FREEZEPROTECT, NULL, aq_data);
|
||||
} else {
|
||||
aq_programmer(AQ_GET_ONETOUCH_SETPOINTS, NULL, aq_data); // This get's freeze & heaters, we should just get freeze if isRSSA_ENABLED
|
||||
}
|
||||
if (_aqconfig_.use_panel_aux_labels)
|
||||
aq_programmer(AQ_GET_AUX_LABELS, NULL, aq_data);
|
||||
#endif
|
||||
|
@ -454,6 +576,34 @@ bool in_iaqt_programming_mode(struct aqualinkdata *aq_data)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Don't need this at the moment, it's kind-a inverse of above two functions
|
||||
|
||||
bool in_allb_programming_mode(struct aqualinkdata *aq_data)
|
||||
{
|
||||
if ( ( aq_data->active_thread.thread_id != 0 ) &&
|
||||
( aq_data->active_thread.ptype == AQ_GET_POOL_SPA_HEATER_TEMPS ||
|
||||
aq_data->active_thread.ptype == AQ_GET_FREEZE_PROTECT_TEMP ||
|
||||
aq_data->active_thread.ptype == AQ_SET_TIME ||
|
||||
aq_data->active_thread.ptype == AQ_SET_POOL_HEATER_TEMP ||
|
||||
aq_data->active_thread.ptype == AQ_SET_SPA_HEATER_TEMP ||
|
||||
aq_data->active_thread.ptype == AQ_SET_FRZ_PROTECTION_TEMP ||
|
||||
aq_data->active_thread.ptype == AQ_GET_DIAGNOSTICS_MODEL ||
|
||||
aq_data->active_thread.ptype == AQ_GET_PROGRAMS ||
|
||||
aq_data->active_thread.ptype == AQ_SET_LIGHTPROGRAM_MODE ||
|
||||
aq_data->active_thread.ptype == AQ_SET_LIGHTCOLOR_MODE ||
|
||||
aq_data->active_thread.ptype == AQ_SET_SWG_PERCENT ||
|
||||
aq_data->active_thread.ptype == AQ_GET_AUX_LABELS ||
|
||||
aq_data->active_thread.ptype == AQ_SET_BOOST ||
|
||||
aq_data->active_thread.ptype == AQ_SET_PUMP_RPM ||
|
||||
aq_data->active_thread.ptype == AQ_SET_PUMP_VS_PROGRAM)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
bool in_programming_mode(struct aqualinkdata *aq_data)
|
||||
{
|
||||
if ( aq_data->active_thread.thread_id != 0 ) {
|
||||
|
@ -468,7 +618,7 @@ void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_
|
|||
if ( aq_data->active_thread.thread_id != 0 ) {
|
||||
if ( (source_type == ONETOUCH) && in_ot_programming_mode(aq_data))
|
||||
{
|
||||
LOG(PROG_LOG, LOG_DEBUG, "Kicking OneTouch thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
|
||||
LOG(ONET_LOG, 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 == ALLBUTTON && !in_ot_programming_mode(aq_data)) {
|
||||
|
@ -476,19 +626,23 @@ void kick_aq_program_thread(struct aqualinkdata *aq_data, emulation_type source_
|
|||
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
|
||||
}
|
||||
else if (source_type == IAQTOUCH && in_iaqt_programming_mode(aq_data)) {
|
||||
LOG(PROG_LOG, LOG_DEBUG, "Kicking IAQ Touch thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
|
||||
LOG(IAQT_LOG, LOG_DEBUG, "Kicking IAQ Touch thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
|
||||
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
|
||||
}
|
||||
#ifdef AQ_PDA
|
||||
else if (source_type == AQUAPDA && !in_ot_programming_mode(aq_data)) {
|
||||
LOG(PROG_LOG, LOG_DEBUG, "Kicking PDA thread %d,%p\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id);
|
||||
LOG(PDA_LOG, 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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data)
|
||||
|
||||
void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data){
|
||||
_aq_programmer(r_type, args, aq_data, true);
|
||||
}
|
||||
void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data, bool allowOveride)
|
||||
{
|
||||
struct programmingThreadCtrl *programmingthread = malloc(sizeof(struct programmingThreadCtrl));
|
||||
|
||||
|
@ -580,7 +734,7 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
|
|||
else if (isONET_ENABLED && isEXTP_ENABLED) {
|
||||
switch (r_type){
|
||||
case AQ_GET_POOL_SPA_HEATER_TEMPS:
|
||||
case AQ_GET_FREEZE_PROTECT_TEMP:
|
||||
//case AQ_GET_FREEZE_PROTECT_TEMP:
|
||||
type = AQ_GET_ONETOUCH_SETPOINTS;
|
||||
break;
|
||||
case AQ_SET_POOL_HEATER_TEMP:
|
||||
|
@ -610,7 +764,7 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
|
|||
// IAQ Touch programming modes that should overite standard ones.
|
||||
switch (r_type){
|
||||
case AQ_GET_POOL_SPA_HEATER_TEMPS:
|
||||
case AQ_GET_FREEZE_PROTECT_TEMP:
|
||||
//case AQ_GET_FREEZE_PROTECT_TEMP:
|
||||
type = AQ_GET_IAQTOUCH_SETPOINTS;
|
||||
break;
|
||||
case AQ_SET_SWG_PERCENT:
|
||||
|
@ -658,7 +812,12 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
|
|||
}
|
||||
#endif
|
||||
|
||||
LOG(PROG_LOG, LOG_INFO, "Starting programming thread '%s'\n",ptypeName(type));
|
||||
if (!allowOveride) {
|
||||
// Reset anything back from changes above.
|
||||
type = r_type;
|
||||
}
|
||||
|
||||
LOG(PROG_LOG, LOG_NOTICE, "Starting programming thread '%s'\n",ptypeName(type));
|
||||
|
||||
programmingthread->aq_data = aq_data;
|
||||
programmingthread->thread_id = 0;
|
||||
|
@ -794,6 +953,12 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
|
|||
return;
|
||||
}
|
||||
break;
|
||||
case AQ_GET_ONETOUCH_FREEZEPROTECT:
|
||||
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_onetouch_freezeprotect, (void*)programmingthread) < 0) {
|
||||
LOG(PROG_LOG, 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) {
|
||||
LOG(PROG_LOG, LOG_ERR, "could not create thread\n");
|
||||
|
@ -856,6 +1021,12 @@ void aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data
|
|||
return;
|
||||
}
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_FREEZEPROTECT:
|
||||
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_iaqtouch_freezeprotect, (void*)programmingthread) < 0) {
|
||||
LOG(PROG_LOG, LOG_ERR, "could not create thread\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_AUX_LABELS:
|
||||
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_iaqtouch_aux_labels, (void*)programmingthread) < 0) {
|
||||
LOG(PROG_LOG, LOG_ERR, "could not create thread\n");
|
||||
|
@ -967,8 +1138,8 @@ void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, pr
|
|||
|
||||
if (i >= tries) {
|
||||
//LOG(PROG_LOG, LOG_ERR, "Thread %d timeout waiting, ending\n",threadCtrl->thread_id);
|
||||
LOG(PROG_LOG, LOG_ERR, "Thread %d,%p timeout waiting for thread %d,%p to finish\n",
|
||||
type, &threadCtrl->thread_id, threadCtrl->aq_data->active_thread.ptype,
|
||||
LOG(PROG_LOG, LOG_ERR, "Thread (%s) %p timeout waiting for thread (%s) %p to finish\n",
|
||||
ptypeName(type), &threadCtrl->thread_id, ptypeName(threadCtrl->aq_data->active_thread.ptype),
|
||||
threadCtrl->aq_data->active_thread.thread_id);
|
||||
free(threadCtrl);
|
||||
pthread_exit(0);
|
||||
|
@ -983,7 +1154,7 @@ void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, pr
|
|||
clock_gettime(CLOCK_REALTIME, &threadCtrl->aq_data->start_active_time);
|
||||
#endif
|
||||
|
||||
LOG(PROG_LOG, LOG_NOTICE, "Programming: %s, %d\n", ptypeName(threadCtrl->aq_data->active_thread.ptype), threadCtrl->aq_data->active_thread.ptype);
|
||||
LOG(PROG_LOG, LOG_INFO, "Programming: %s, %d\n", ptypeName(threadCtrl->aq_data->active_thread.ptype), threadCtrl->aq_data->active_thread.ptype);
|
||||
|
||||
LOG(PROG_LOG, LOG_DEBUG, "Thread %d,%p is active (%s)\n",
|
||||
threadCtrl->aq_data->active_thread.ptype,
|
||||
|
@ -1073,6 +1244,8 @@ bool setAqualinkNumericField_new(struct aqualinkdata *aq_data, char *value_label
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool OLD_setAqualinkNumericField_OLD(struct aqualinkdata *aq_data, char *value_label, int value)
|
||||
{ // Works for everything but not SWG
|
||||
LOG(PROG_LOG, LOG_DEBUG,"Setting menu item '%s' to %d\n",value_label, value);
|
||||
|
@ -2277,12 +2450,15 @@ bool select_sub_menu_item(struct aqualinkdata *aq_data, char* item_string)
|
|||
int wait_messages = 28;
|
||||
int i=0;
|
||||
|
||||
waitfor_queue2empty();
|
||||
|
||||
while( (stristr(aq_data->last_message, item_string) == NULL) && ( i++ < wait_messages) )
|
||||
{
|
||||
LOG(PROG_LOG, LOG_DEBUG, "Find item in Menu: loop %d of %d looking for '%s' received message '%s'\n",i,wait_messages,item_string,aq_data->last_message);
|
||||
send_cmd(KEY_RIGHT);
|
||||
waitfor_queue2empty(); // ADDED BACK MAY 2023
|
||||
waitForMessage(aq_data, NULL, 1);
|
||||
waitfor_queue2empty(); // ADDED BACK MAY 2023 setting time warked better
|
||||
//waitForMessage(aq_data, NULL, 1);
|
||||
waitForMessage(aq_data, item_string, 1);
|
||||
}
|
||||
|
||||
if (stristr(aq_data->last_message, item_string) == NULL) {
|
||||
|
@ -2406,6 +2582,9 @@ const char *ptypeName(program_type type)
|
|||
break;
|
||||
case AQ_GET_ONETOUCH_SETPOINTS:
|
||||
return "Get OneTouch setpoints";
|
||||
break;
|
||||
case AQ_GET_ONETOUCH_FREEZEPROTECT:
|
||||
return "Get OneTouch freezeprotect";
|
||||
break;
|
||||
case AQ_SET_ONETOUCH_TIME:
|
||||
return "Set OneTouch time";
|
||||
|
@ -2439,6 +2618,9 @@ const char *ptypeName(program_type type)
|
|||
case AQ_GET_IAQTOUCH_SETPOINTS:
|
||||
return "Get iAqualink Touch Setpoints";
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_FREEZEPROTECT:
|
||||
return "Get iAqualink Touch Freezeprotect";
|
||||
break;
|
||||
case AQ_GET_IAQTOUCH_AUX_LABELS:
|
||||
return "Get iAqualink AUX Labels";
|
||||
break;
|
||||
|
@ -2488,6 +2670,8 @@ const char *programtypeDisplayName(program_type type)
|
|||
case AQ_GET_FREEZE_PROTECT_TEMP:
|
||||
case AQ_GET_IAQTOUCH_SETPOINTS:
|
||||
case AQ_GET_RSSADAPTER_SETPOINTS:
|
||||
case AQ_GET_ONETOUCH_FREEZEPROTECT:
|
||||
case AQ_GET_IAQTOUCH_FREEZEPROTECT:
|
||||
#ifdef AQ_PDA
|
||||
case AQ_PDA_INIT:
|
||||
#endif
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#include <pthread.h>
|
||||
//#include "aqualink.h"
|
||||
|
||||
//#define PROGRAMMING_POLL_DELAY_TIME 10
|
||||
#define PROGRAMMING_POLL_DELAY_TIME 10
|
||||
//#define PROGRAMMING_POLL_DELAY_TIME 2
|
||||
#define PROGRAMMING_POLL_DELAY_TIME 5
|
||||
//#define PROGRAMMING_POLL_DELAY_TIME 5
|
||||
#define PROGRAMMING_POLL_COUNTER 200
|
||||
|
||||
// need to get the C values from aqualink manual and add those just incase
|
||||
|
@ -64,6 +64,7 @@ typedef enum {
|
|||
AQ_GET_ONETOUCH_SETPOINTS,
|
||||
AQ_SET_ONETOUCH_POOL_HEATER_TEMP,
|
||||
AQ_SET_ONETOUCH_SPA_HEATER_TEMP,
|
||||
AQ_GET_ONETOUCH_FREEZEPROTECT,
|
||||
AQ_SET_ONETOUCH_FREEZEPROTECT,
|
||||
AQ_SET_ONETOUCH_TIME,
|
||||
AQ_SET_ONETOUCH_BOOST,
|
||||
|
@ -72,6 +73,8 @@ typedef enum {
|
|||
AQ_SET_IAQTOUCH_PUMP_VS_PROGRAM,
|
||||
AQ_GET_IAQTOUCH_VSP_ASSIGNMENT,
|
||||
AQ_GET_IAQTOUCH_SETPOINTS,
|
||||
AQ_GET_IAQTOUCH_FREEZEPROTECT,
|
||||
AQ_SET_IAQTOUCH_FREEZEPROTECT,
|
||||
AQ_GET_IAQTOUCH_AUX_LABELS,
|
||||
AQ_SET_IAQTOUCH_SWG_PERCENT,
|
||||
AQ_SET_IAQTOUCH_SWG_BOOST,
|
||||
|
@ -110,6 +113,7 @@ bool in_ot_programming_mode(struct aqualinkdata *aq_data);
|
|||
bool in_iaqt_programming_mode(struct aqualinkdata *aq_data);
|
||||
bool in_swg_programming_mode(struct aqualinkdata *aq_data);
|
||||
bool in_light_programming_mode(struct aqualinkdata *aq_data);
|
||||
bool in_allb_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);
|
||||
|
|
63
aq_timer.c
63
aq_timer.c
|
@ -19,6 +19,7 @@ struct timerthread {
|
|||
struct aqualinkdata *aq_data;
|
||||
int duration_min;
|
||||
struct timespec timeout;
|
||||
time_t started_at;
|
||||
struct timerthread *next;
|
||||
struct timerthread *prev;
|
||||
};
|
||||
|
@ -27,8 +28,56 @@ struct timerthread {
|
|||
|
||||
void *timer_worker( void *ptr );
|
||||
|
||||
struct timerthread *find_timerthread(aqkey *button)
|
||||
{
|
||||
struct timerthread *t_ptr;
|
||||
|
||||
if (_timerthread_ll != NULL) {
|
||||
for (t_ptr = _timerthread_ll; t_ptr != NULL; t_ptr = t_ptr->next) {
|
||||
if (t_ptr->button == button) {
|
||||
return t_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_timer_left(aqkey *button)
|
||||
{
|
||||
struct timerthread *t_ptr = find_timerthread(button);
|
||||
|
||||
if (t_ptr != NULL) {
|
||||
time_t now = time(0);
|
||||
double seconds = difftime(now, t_ptr->started_at);
|
||||
return (int) ((t_ptr->duration_min - (seconds / 60)) +0.5) ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear_timer(struct aqualinkdata *aq_data, aqkey *button)
|
||||
{
|
||||
struct timerthread *t_ptr = find_timerthread(button);
|
||||
|
||||
if (t_ptr != NULL) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Clearing timer for '%s'\n",t_ptr->button->name);
|
||||
t_ptr->duration_min = 0;
|
||||
pthread_cond_broadcast(&t_ptr->thread_cond);
|
||||
}
|
||||
}
|
||||
|
||||
void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration)
|
||||
{
|
||||
struct timerthread *t_ptr = find_timerthread(button);
|
||||
|
||||
if (t_ptr != NULL) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer already active for '%s', resetting\n",t_ptr->button->name);
|
||||
t_ptr->duration_min = duration;
|
||||
pthread_cond_broadcast(&t_ptr->thread_cond);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
struct timerthread *t_ptr;
|
||||
|
||||
if (_timerthread_ll != NULL) {
|
||||
|
@ -40,7 +89,7 @@ void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration)
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
struct timerthread *tmthread = calloc(1, sizeof(struct timerthread));
|
||||
tmthread->aq_data = aq_data;
|
||||
|
@ -81,7 +130,7 @@ void *timer_worker( void *ptr )
|
|||
tmthread = (struct timerthread *) ptr;
|
||||
int retval = 0;
|
||||
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "Started for button '%s'\n",tmthread->button->name);
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "Start timer for '%s'\n",tmthread->button->name);
|
||||
|
||||
// Add mask so we know timer is active
|
||||
tmthread->button->special_mask |= TIMER_ACTIVE;
|
||||
|
@ -108,17 +157,23 @@ void *timer_worker( void *ptr )
|
|||
if (retval != 0) {
|
||||
LOG(TIMR_LOG, LOG_ERR, "pthread_cond_timedwait failed for '%s', error %d %s\n",tmthread->button->name,retval,strerror(retval));
|
||||
break;
|
||||
} else if (tmthread->duration_min <= 0) {
|
||||
//LOG(TIMR_LOG, LOG_INFO, "Timer has been reset to 0 for '%s'\n",tmthread->button->name);
|
||||
break;
|
||||
}
|
||||
clock_gettime(CLOCK_REALTIME, &tmthread->timeout);
|
||||
tmthread->timeout.tv_sec += (tmthread->duration_min * 60);
|
||||
tmthread->started_at = time(0);
|
||||
LOG(TIMR_LOG, LOG_INFO, "Will turn off '%s' in %d minutes\n",tmthread->button->name, tmthread->duration_min);
|
||||
} while ((retval = pthread_cond_timedwait(&tmthread->thread_cond, &tmthread->thread_mutex, &tmthread->timeout)) != ETIMEDOUT);
|
||||
|
||||
|
||||
pthread_mutex_unlock(&tmthread->thread_mutex);
|
||||
|
||||
LOG(TIMR_LOG, LOG_NOTICE, "End timer for '%s'\n",tmthread->button->name);
|
||||
|
||||
if (tmthread->button->led->state != OFF) {
|
||||
LOG(TIMR_LOG, LOG_INFO, "waking, turning off '%s'\n",tmthread->button->name);
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking turning '%s' off\n",tmthread->button->name);
|
||||
#ifdef AQ_PDA
|
||||
if (isPDA_PANEL)
|
||||
create_PDA_on_off_request(tmthread->button, false);
|
||||
|
@ -126,7 +181,7 @@ void *timer_worker( void *ptr )
|
|||
#endif
|
||||
aq_send_cmd(tmthread->button->code);
|
||||
} else {
|
||||
LOG(TIMR_LOG, LOG_INFO, "waking '%s' is already off\n",tmthread->button->name);
|
||||
LOG(TIMR_LOG, LOG_INFO, "Timer waking '%s' is already off\n",tmthread->button->name);
|
||||
}
|
||||
|
||||
// remove mask so we know timer is dead
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#include "aqualink.h"
|
||||
|
||||
void start_timer(struct aqualinkdata *aq_data, aqkey *button, int duration);
|
||||
|
||||
int get_timer_left(aqkey *button);
|
||||
void clear_timer(struct aqualinkdata *aq_data, aqkey *button);
|
||||
// Not best place for this, but leave it here so all requests are in net services, this is forward decleration of function in net_services.c
|
||||
#ifdef AQ_PDA
|
||||
void create_PDA_on_off_request(aqkey *button, bool isON);
|
||||
|
|
|
@ -13,13 +13,14 @@
|
|||
#define DEFAULT_POLL_SPEED_NON_THREADDED 2
|
||||
|
||||
#define TIME_CHECK_INTERVAL 3600
|
||||
//#define TIME_CHECK_INTERVAL 100 // DEBUG ONLY
|
||||
#define ACCEPTABLE_TIME_DIFF 120
|
||||
|
||||
// Use these settings to test time
|
||||
//#define TIME_CHECK_INTERVAL 100
|
||||
//#define ACCEPTABLE_TIME_DIFF 10
|
||||
|
||||
#define MAX_ZERO_READ_BEFORE_RECONNECT 10000 // 2k normally
|
||||
#define MAX_ZERO_READ_BEFORE_RECONNECT 20000 // 2k normally
|
||||
|
||||
// The below will change state of devices before that are actually set on the control panel, this helps
|
||||
// with duplicate messages that come in quick succession that can catch the state before it happens.
|
||||
|
@ -77,7 +78,7 @@ typedef struct aqualinkkey
|
|||
// special_mask for above aqualinkkey structure.
|
||||
#define VS_PUMP (1 << 0)
|
||||
#define PROGRAM_LIGHT (1 << 1)
|
||||
#define TIMER_ACTIVE (1 << 2) // Not used yet, but will need to timer
|
||||
#define TIMER_ACTIVE (1 << 2)
|
||||
|
||||
//typedef struct ProgramThread ProgramThread; // Definition is later
|
||||
|
||||
|
|
52
aqualinkd.c
52
aqualinkd.c
|
@ -168,27 +168,54 @@ bool checkAqualinkTime()
|
|||
else
|
||||
#endif // AQ_PDA
|
||||
{
|
||||
|
||||
strcpy(&datestr[0], _aqualink_data.date);
|
||||
strcpy(&datestr[12], " ");
|
||||
strcpy(&datestr[13], _aqualink_data.time);
|
||||
|
||||
if (strptime(datestr, "%m/%d/%y %a %I:%M %p", &aq_tm) == NULL)
|
||||
datestr[8] = ' ';
|
||||
strcpy(&datestr[9], _aqualink_data.time);
|
||||
//datestr[16] = ' ';
|
||||
if (strlen(_aqualink_data.time) <= 7) {
|
||||
datestr[13] = ' ';
|
||||
datestr[16] ='\0';
|
||||
} else {
|
||||
datestr[14] = ' ';
|
||||
datestr[17] ='\0';
|
||||
}
|
||||
if (strptime(datestr, "%m/%d/%y %I:%M %p", &aq_tm) == NULL)
|
||||
|
||||
//sprintf(datestr, "%s %s", _aqualink_data.date, _aqualink_data.time);
|
||||
//if (strptime(datestr, "%m/%d/%y %a %I:%M %p", &aq_tm) == NULL)
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Could not convert RS time string '%s'", datestr);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Could not convert RS time string '%s'\n", datestr);
|
||||
last_checked = (time_t)NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
aq_tm.tm_isdst = -1; // Force mktime to use local timezone
|
||||
aq_tm.tm_isdst = localtime(&now)->tm_isdst; // ( Might need to use -1) set daylight savings to same as system time
|
||||
aq_tm.tm_sec = 0; // Set seconds to time. Really messes up when we don't do this.
|
||||
|
||||
char buff[20];
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Aqualinkd created time from : %s\n", datestr);
|
||||
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", &aq_tm);
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Aqualinkd created time : %s\n", buff);
|
||||
|
||||
aqualink_time = mktime(&aq_tm);
|
||||
|
||||
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&aqualink_time));
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Aqualinkd converted time : %s\n", buff);
|
||||
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "System time : %s\n", buff);
|
||||
|
||||
|
||||
time_difference = (int)difftime(now, aqualink_time);
|
||||
|
||||
LOG(AQUA_LOG,LOG_INFO, "Aqualink time is off by %d seconds...\n", time_difference);
|
||||
strftime(buff, 20, "%m/%d/%y %I:%M %p", localtime(&now));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Aqualink time '%s' is off system time '%s' by %d seconds...\n", datestr, buff, time_difference);
|
||||
|
||||
if (abs(time_difference) <= ACCEPTABLE_TIME_DIFF)
|
||||
if (abs(time_difference) < ACCEPTABLE_TIME_DIFF)
|
||||
{
|
||||
// Time difference is less than or equal to 90 seconds (1 1/2 minutes).
|
||||
// Time difference is less than or equal to ACCEPTABLE_TIME_DIFF seconds (1 1/2 minutes).
|
||||
// Set the return value to true.
|
||||
return true;
|
||||
}
|
||||
|
@ -595,6 +622,7 @@ void _processMessage(char *message, bool reset)
|
|||
LOG(AQRS_LOG,LOG_NOTICE, "Control Panel %s\n", msg);
|
||||
if (_initWithRS == false)
|
||||
{
|
||||
//LOG(ALLBUTTON,LOG_NOTICE, "Standard protocol initialization complete\n");
|
||||
queueGetProgramData(ALLBUTTON, &_aqualink_data);
|
||||
//queueGetExtendedProgramData(ALLBUTTON, &_aqualink_data, _aqconfig_.use_panel_aux_labels);
|
||||
_initWithRS = true;
|
||||
|
@ -1624,7 +1652,7 @@ void main_loop()
|
|||
blank_read = 0;
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE) {
|
||||
got_probe = true;
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Got probe on '0x%02hhx'\n",_aqconfig_.device_id);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Got probe on '0x%02hhx' Standard Protocol\n",_aqconfig_.device_id);
|
||||
} else {
|
||||
if(!print_once) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Got message but no probe on '0x%02hhx', did we start too soon? (waiting for probe)\n",_aqconfig_.device_id);
|
||||
|
@ -1637,7 +1665,7 @@ void main_loop()
|
|||
blank_read = 0;
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE) {
|
||||
got_probe_rssa = true;
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Got probe on '0x%02hhx'\n",_aqconfig_.rssa_device_id);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Got probe on '0x%02hhx' RS SerialAdapter Protocol\n",_aqconfig_.rssa_device_id);
|
||||
} else {
|
||||
if(!print_once) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Got message but no probe on '0x%02hhx', did we start too soon? (waiting for probe)\n",_aqconfig_.rssa_device_id);
|
||||
|
@ -1651,7 +1679,7 @@ void main_loop()
|
|||
blank_read = 0;
|
||||
if (packet_buffer[PKT_CMD] == CMD_PROBE) {
|
||||
got_probe_extended = true;
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Got probe on '0x%02hhx'\n",_aqconfig_.extended_device_id);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Got probe on '0x%02hhx' Extended Protocol\n",_aqconfig_.extended_device_id);
|
||||
} else {
|
||||
if(!print_once) {
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Got message but no probe on '0x%02hhx', did we start too soon? (waiting for probe)\n",_aqconfig_.extended_device_id);
|
||||
|
|
|
@ -545,7 +545,39 @@ void *set_aqualink_iaqtouch_vsp_assignments( void *ptr )
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void *get_aqualink_iaqtouch_freezeprotect( void *ptr )
|
||||
{
|
||||
LOG(IAQT_LOG,LOG_ERR, "IAQ Touch get_aqualink_iaqtouch_freezeprotect has not beed tested\n");
|
||||
LOG(IAQT_LOG,LOG_ERR, "**** We should not be here ****\n");
|
||||
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_IAQTOUCH_FREEZEPROTECT);
|
||||
|
||||
if ( goto_iaqt_page(IAQ_PAGE_FREEZE_PROTECT, aq_data) == false )
|
||||
goto f_end;
|
||||
|
||||
// The Message at index 0 is the deg that freeze protect is set to.
|
||||
int frz = rsm_atoi(iaqtGetMessageLine(0));
|
||||
if (frz >= 0) {
|
||||
aq_data->frz_protect_set_point = frz;
|
||||
LOG(IAQT_LOG,LOG_NOTICE, "IAQ Touch Freeze Protection setpoint %d\n",frz);
|
||||
}
|
||||
|
||||
// Need to run over table messages and check ens with X for on off.
|
||||
|
||||
// Go to status page on startup to read devices
|
||||
goto_iaqt_page(IAQ_PAGE_STATUS, aq_data);
|
||||
|
||||
f_end:
|
||||
goto_iaqt_page(IAQ_PAGE_HOME, aq_data);
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
// just stop compiler error, ptr is not valid as it's just been freed
|
||||
return ptr;
|
||||
}
|
||||
void *get_aqualink_iaqtouch_setpoints( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
|
|
|
@ -11,6 +11,7 @@ bool iaqt_queue_cmd(unsigned char cmd);
|
|||
void *set_aqualink_iaqtouch_pump_rpm( void *ptr );
|
||||
void *set_aqualink_iaqtouch_vsp_assignments( void *ptr );
|
||||
void *get_aqualink_iaqtouch_setpoints( void *ptr );
|
||||
void *get_aqualink_iaqtouch_freezeprotect( void *ptr );
|
||||
void *get_aqualink_iaqtouch_aux_labels( void *ptr );
|
||||
void *set_aqualink_iaqtouch_swg_percent( void *ptr );
|
||||
void *set_aqualink_iaqtouch_swg_boost( void *ptr );
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "aq_mqtt.h"
|
||||
#include "devices_jandy.h"
|
||||
#include "version.h"
|
||||
#include "aq_timer.h"
|
||||
|
||||
|
||||
//#define test_message "{\"type\": \"status\",\"version\": \"8157 REV MMM\",\"date\": \"09/01/16 THU\",\"time\": \"1:16 PM\",\"temp_units\": \"F\",\"air_temp\": \"96\",\"pool_temp\": \"86\",\"spa_temp\": \" \",\"battery\": \"ok\",\"pool_htr_set_pnt\": \"85\",\"spa_htr_set_pnt\": \"99\",\"freeze_protection\": \"off\",\"frz_protect_set_pnt\": \"0\",\"leds\": {\"pump\": \"on\",\"spa\": \"off\",\"aux1\": \"off\",\"aux2\": \"off\",\"aux3\": \"off\",\"aux4\": \"off\",\"aux5\": \"off\",\"aux6\": \"off\",\"aux7\": \"off\",\"pool_heater\": \"off\",\"spa_heater\": \"off\",\"solar_heater\": \"off\"}}"
|
||||
|
@ -207,6 +208,9 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
|
|||
|
||||
//printf("Button %s is Switch\n", button->name);
|
||||
length += sprintf(buffer, ",\"type_ext\": \"switch_timer\", \"timer_active\":\"%s\"", (((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE)?JSON_ON:JSON_OFF) );
|
||||
if ((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) {
|
||||
length += sprintf(buffer+length,",\"timer_duration\":\"%d\"", get_timer_left(button));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -545,13 +549,26 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
{
|
||||
if ((aqdata->aqbuttons[i].special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"on\",", aqdata->aqbuttons[i].name);
|
||||
//length += sprintf(buffer+length, "\"%s_duration\": \"%d\",", aqdata->aqbuttons[i].name, get_timer_left(&aqdata->aqbuttons[i]) );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
length += sprintf(buffer+length, ",\"timer_durations\":{" );
|
||||
for (i=0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if ((aqdata->aqbuttons[i].special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%d\",", aqdata->aqbuttons[i].name, get_timer_left(&aqdata->aqbuttons[i]) );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
length--;
|
||||
length += sprintf(buffer+length, "}");
|
||||
|
||||
|
||||
|
||||
|
||||
length += sprintf(buffer+length, "}" );
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ static void ws_send(struct mg_connection *nc, char *msg)
|
|||
|
||||
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, msg, size);
|
||||
|
||||
LOG(NET_LOG,LOG_DEBUG, "WS: Sent %d characters '%s'\n",size, msg);
|
||||
//LOG(NET_LOG,LOG_DEBUG, "WS: Sent %d characters '%s'\n",size, msg);
|
||||
}
|
||||
|
||||
void _broadcast_aqualinkstate_error(struct mg_connection *nc, char *msg)
|
||||
|
@ -243,6 +243,20 @@ void send_mqtt_state_msg(struct mg_connection *nc, char *dev_name, aqledstate st
|
|||
send_mqtt(nc, mqtt_pub_topic, (state==OFF?MQTT_OFF:MQTT_ON));
|
||||
}
|
||||
|
||||
|
||||
void send_mqtt_timer_duration_msg(struct mg_connection *nc, char *dev_name, aqkey *button)
|
||||
{
|
||||
static char mqtt_pub_topic[250];
|
||||
sprintf(mqtt_pub_topic, "%s/%s/timer/duration",_aqconfig_.mqtt_aq_topic, dev_name);
|
||||
if ((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) {
|
||||
char val[10];
|
||||
sprintf(val, "%d", get_timer_left(button));
|
||||
send_mqtt(nc, mqtt_pub_topic, val);
|
||||
} else {
|
||||
send_mqtt(nc, mqtt_pub_topic, "0");
|
||||
}
|
||||
}
|
||||
|
||||
void send_mqtt_timer_state_msg(struct mg_connection *nc, char *dev_name, aqkey *button)
|
||||
{
|
||||
static char mqtt_pub_topic[250];
|
||||
|
@ -250,6 +264,8 @@ void send_mqtt_timer_state_msg(struct mg_connection *nc, char *dev_name, aqkey *
|
|||
sprintf(mqtt_pub_topic, "%s/%s/timer",_aqconfig_.mqtt_aq_topic, dev_name);
|
||||
|
||||
send_mqtt(nc, mqtt_pub_topic, ( ((button->special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) && (button->led->state != OFF) )?MQTT_ON:MQTT_OFF );
|
||||
|
||||
send_mqtt_timer_duration_msg(nc, dev_name, button);
|
||||
}
|
||||
|
||||
//void send_mqtt_aux_msg(struct mg_connection *nc, char *root_topic, int dev_index, char *dev_topic, int value)
|
||||
|
@ -562,9 +578,16 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
}
|
||||
|
||||
send_mqtt_timer_state_msg(nc, _aqualink_data->aqbuttons[i].name, &_aqualink_data->aqbuttons[i]);
|
||||
|
||||
if (_aqualink_data->aqbuttons[i].dz_idx != DZ_NULL_IDX)
|
||||
|
||||
if (_aqualink_data->aqbuttons[i].dz_idx != DZ_NULL_IDX) {
|
||||
send_domoticz_mqtt_state_msg(nc, _aqualink_data->aqbuttons[i].dz_idx, (_aqualink_data->aqbuttons[i].led->state==OFF?DZ_OFF:DZ_ON));
|
||||
}
|
||||
} else if ((_aqualink_data->aqbuttons[i].special_mask & TIMER_ACTIVE) == TIMER_ACTIVE) {
|
||||
//send_mqtt_timer_duration_msg(nc, _aqualink_data->aqbuttons[i].name, &_aqualink_data->aqbuttons[i]);
|
||||
// send_mqtt_timer_state_msg will call send_mqtt_timer_duration_msg so no need to do it here.
|
||||
// Have to use send_mqtt_timer_state_msg due to a timer being set on a device that's already on, (ir no state change so above code does't get hit)
|
||||
send_mqtt_timer_state_msg(nc, _aqualink_data->aqbuttons[i].name, &_aqualink_data->aqbuttons[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -541,6 +541,20 @@ void *set_aqualink_onetouch_pump_rpm( void *ptr )
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void *set_aqualink_onetouch_freezeprotect( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_ONETOUCH_FREEZEPROTECT);
|
||||
|
||||
LOG(ONET_LOG,LOG_ERR, "***** OneTouch set freeze protect not implimented *****\n");
|
||||
|
||||
cleanAndTerminateThread(threadCtrl);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *set_aqualink_onetouch_macro( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
|
@ -565,6 +579,36 @@ void *set_aqualink_onetouch_macro( void *ptr )
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void *get_aqualink_onetouch_freezeprotect( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
threadCtrl = (struct programmingThreadCtrl *) ptr;
|
||||
struct aqualinkdata *aq_data = threadCtrl->aq_data;
|
||||
|
||||
waitForSingleThreadOrTerminate(threadCtrl, AQ_GET_ONETOUCH_FREEZEPROTECT);
|
||||
|
||||
LOG(ONET_LOG,LOG_DEBUG, "OneTouch get Freezeprotect\n");
|
||||
|
||||
if ( !goto_onetouch_menu(aq_data, OTM_SET_TEMP) ){
|
||||
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get heater temp menu\n");
|
||||
}
|
||||
|
||||
if ( !goto_onetouch_menu(aq_data, OTM_FREEZE_PROTECT) ){
|
||||
LOG(ONET_LOG,LOG_ERR, "OneTouch device programmer failed to get freeze protect menu\n");
|
||||
}
|
||||
|
||||
if (! goto_onetouch_menu(aq_data, OTM_SYSTEM) ){
|
||||
LOG(ONET_LOG,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;
|
||||
}
|
||||
/*
|
||||
This will get all setpoints, including freeze protect, above just gets freeze protect.
|
||||
*/
|
||||
void *get_aqualink_onetouch_setpoints( void *ptr )
|
||||
{
|
||||
struct programmingThreadCtrl *threadCtrl;
|
||||
|
@ -860,10 +904,7 @@ void *set_aqualink_onetouch_swg_percent( void *ptr )
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void *set_aqualink_onetouch_freezeprotect( void *ptr )
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
bool set_numeric_value(struct aqualinkdata *aq_data, int val) {
|
||||
int len;
|
||||
|
|
|
@ -15,6 +15,7 @@ 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 *get_aqualink_onetouch_freezeprotect( void *ptr );
|
||||
void *set_aqualink_onetouch_freezeprotect( void *ptr );
|
||||
|
||||
#endif // ONETOUCH_AQ_PROGRAMMER_H_
|
Binary file not shown.
Binary file not shown.
|
@ -38,7 +38,7 @@
|
|||
#define SLOG_MAX 80
|
||||
#define PACKET_MAX 600
|
||||
|
||||
#define VERSION "serial_logger V1.5"
|
||||
#define VERSION "serial_logger V1.6"
|
||||
|
||||
/*
|
||||
typedef enum used {
|
||||
|
@ -613,7 +613,7 @@ int main(int argc, char *argv[]) {
|
|||
//LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
|
||||
// (slog[i].inuse == false && canUse(slog[i].ID) == true)? " <-- can use for Aqualinkd" : "");
|
||||
if (logLevel >= LOG_DEBUG || slog[i].inuse == true || canUse(slog[i].ID) == true) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use" : "not used",
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", slog[i].ID, (slog[i].inuse == true) ? "in use " : "not used",
|
||||
(slog[i].inuse == false)?canUseExtended(slog[i].ID):getDevice(slog[i].ID));
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +623,7 @@ int main(int argc, char *argv[]) {
|
|||
LOG(RSSD_LOG, LOG_NOTICE, "Pentair ID's found\n");
|
||||
}
|
||||
for (i=0; i < pent_sindex; i++) {
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", pent_slog[i].ID, (pent_slog[i].inuse == true) ? "in use" : "not used",
|
||||
LOG(RSSD_LOG, LOG_NOTICE, "ID 0x%02hhx is %s %s\n", pent_slog[i].ID, (pent_slog[i].inuse == true) ? "in use " : "not used",
|
||||
(pent_slog[i].inuse == false)?canUseExtended(pent_slog[i].ID):getPentairDevice(pent_slog[i].ID));
|
||||
}
|
||||
|
||||
|
|
2
utils.c
2
utils.c
|
@ -429,7 +429,7 @@ void logMessage(int msg_level, const char *format, ...)
|
|||
_LOG(AQUA_LOG, msg_level, buffer);
|
||||
}
|
||||
*/
|
||||
#define LOGBUFFER 4096
|
||||
#define LOGBUFFER 5096
|
||||
|
||||
void LOG(int16_t from, int msg_level, const char * format, ...)
|
||||
{
|
||||
|
|
|
@ -1105,6 +1105,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
function toHoursAndMinutes(totalMinutes) {
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
return `${padToTwoDigits(hours)}:${padToTwoDigits(minutes)}`;
|
||||
}
|
||||
function padToTwoDigits(num) {
|
||||
return num.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
function createTile(object) {
|
||||
if (object.name == 'NONE') {
|
||||
return;
|
||||
|
@ -1132,7 +1141,11 @@
|
|||
if (typeof object.timer_active !== 'undefined' && object.timer_active) {
|
||||
//console.log("Timer for "+object.name+" = "+object.timer_active);
|
||||
if (object.timer_active == 'on') {
|
||||
setTileOnText(object.id, 'On (timer)');
|
||||
if (typeof object.timer_duration !== 'undefined') {
|
||||
setTileOnText(object.id, 'On (timer '+toHoursAndMinutes(object.timer_duration)+')');
|
||||
} else {
|
||||
setTileOnText(object.id, 'On (timer)');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (typeof object.type_ext !== 'undefined' && object.type_ext == 'switch_vsp') {
|
||||
|
@ -1998,6 +2011,10 @@
|
|||
for (var obj in data.timers) {
|
||||
setTileOnText(obj.toString(),"On (timer)");
|
||||
}
|
||||
for (var obj in data.timer_durations) {
|
||||
setTileOnText(obj.toString(),"Timer "+toHoursAndMinutes(data.timer_durations[obj]));
|
||||
}
|
||||
|
||||
|
||||
if (data.swg_boost_msg != null ) {
|
||||
var tile = document.getElementById('SWG');
|
||||
|
|
Loading…
Reference in New Issue