Version 2.3.0e

pull/94/head
sfeakes 2023-05-21 10:03:27 -05:00
parent 4070750173
commit 557ad9f5fb
22 changed files with 554 additions and 154 deletions

View File

@ -107,6 +107,25 @@ setPanel("RS-6 Combo");
setPanel("RS-8 Combo");
}
*/
char _panelString[36];
void setPanelString()
{
sprintf(_panelString, "%s%s-%d %s%s%s",
isRS_PANEL?"RS":"",
isPDA_PANEL?"PDA":"", // No need for both of these, but for error validation leave it in.
PANEL_SIZE(),
isCOMBO_PANEL?"Combo Pool/Spa":"",
isSINGLE_DEV_PANEL?"Pool/Spa Only":"",
isDUAL_EQPT_PANEL?" Dual Equipment":"");
}
const char* getPanelString()
{
return _panelString;
}
//bool setPanelByName(const char *str) {
int setSizeMask(int size)
@ -181,16 +200,10 @@ void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool d
_aqconfig_.paneltype_mask |= RSP_COMBO;
_aqconfig_.paneltype_mask &= ~RSP_SINGLE;
}
/*
LOG(AQUA_LOG,LOG_ERR, "Panel set to %s%s size=%d type=%s%s %s\n",
(_aqconfig_.paneltype_mask & RSP_RS) == RSP_RS?"RS":"",
(_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA?"PDA":"",
nsize,
(_aqconfig_.paneltype_mask & RSP_COMBO) == RSP_COMBO?"Combo Pool/Spa":"",
(_aqconfig_.paneltype_mask & RSP_SINGLE) == RSP_SINGLE?"Pool/Spa Only":"",
(_aqconfig_.paneltype_mask & RSP_DUAL_EQPT) == RSP_DUAL_EQPT?"Dual Equiptment":"");
*/
initPanelButtons(aqdata, rs, nsize, combo, dual);
setPanelString();
}
void setPanelByName(struct aqualinkdata *aqdata, const char *str)
@ -481,6 +494,12 @@ void initPanelButtons(struct aqualinkdata *aqdata, bool rs, int size, bool combo
aqdata->pool_heater_index = index-3;
aqdata->spa_heater_index = index-2;
aqdata->solar_heater_index = index-1;
// Reset all LED's to off since their is no off state in PDA.
for(int i=0; i < aqdata->total_buttons; i++) {
aqdata->aqbuttons[i].led->state = OFF;
}
#endif
}

View File

@ -33,6 +33,7 @@
//void initButtons(struct aqualinkdata *aqdata);
void setPanelByName(struct aqualinkdata *aqdata, const char *str);
void setPanel(struct aqualinkdata *aqdata, bool rs, int size, bool combo, bool dual);
const char* getPanelString();
bool panel_device_request(struct aqualinkdata *aqdata, action_type type, int deviceIndex, int value, request_source source);

View File

@ -224,49 +224,7 @@ 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;
@ -2200,7 +2158,12 @@ void _waitfor_queue2empty(bool longwait)
{
int i=0;
LOG(PROG_LOG, LOG_DEBUG, "Waiting for queue to empty\n");
if (_pgm_command != NUL) {
LOG(PROG_LOG, LOG_DEBUG, "Waiting for queue to empty\n");
} else {
LOG(PROG_LOG, LOG_DEBUG, "Queue empty!\n");
return;
}
while ( (_pgm_command != NUL) && ( i++ < (PROGRAMMING_POLL_COUNTER*(longwait?2:1) ) ) ) {
delay(PROGRAMMING_POLL_DELAY_TIME);
@ -2248,6 +2211,13 @@ void send_cmd(unsigned char cmd)
LOG(PROG_LOG, LOG_INFO, "Queue send '0x%02hhx' to controller (programming)\n", _pgm_command);
}
void force_queue_delete()
{
if (_pgm_command != NUL)
LOG(PROG_LOG, LOG_INFO, "Reall bad coding, don't use this in release\n");
_pgm_command = NUL;
}
/*
void send_cmd(unsigned char cmd, struct aqualinkdata *aq_data)

View File

@ -119,6 +119,8 @@ void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_dat
//void queueGetExtendedProgramData(emulation_type source_type, struct aqualinkdata *aq_data, bool labels);
unsigned char pop_aq_cmd(struct aqualinkdata *aq_data);
//void force_queue_delete() // Yes I want compiler warning if this is used.
//bool push_aq_cmd(unsigned char cmd);

View File

@ -56,18 +56,18 @@ bool remount_root_ro(bool readonly) {
}
}
bool passJson_scObj(char* line, int length, aqs_cron *values)
{
int keystart=0;
int keyend=0;
//int keyend=0;
int valuestart=0;
int captured=0;
bool readingvalue=false;
bool invalue=false;
//char value;
values->enabled = true;
LOG(SCHD_LOG,LOG_DEBUG, "Obj body:'%.*s'\n", length, line);
//LOG(SCHD_LOG,LOG_DEBUG, "Obj body:'%.*s'\n", length, line);
for (int i=0; i < length; i++) {
if (line[i] == '}') {
@ -75,7 +75,7 @@ bool passJson_scObj(char* line, int length, aqs_cron *values)
} else if (line[i] == '"' && keystart==0 && invalue==false && readingvalue==false) {
keystart=i+1;
} else if (line[i] == '"' && keystart > 0 && invalue==false && readingvalue==false) {
keyend=i;
//keyend=i;
} else if (line[i] == ':' && keystart > 0 ) {
invalue=true;
} else if (line[i] == '"' && invalue == true && readingvalue == false && keystart > 0 ) {
@ -83,7 +83,10 @@ bool passJson_scObj(char* line, int length, aqs_cron *values)
valuestart=i+1;
} else if (line[i] == '"' && readingvalue == true) {
// i is end of key
if ( strncmp(&line[keystart], "min", 3) == 0) {
if ( strncmp(&line[keystart], "enabled", 7) == 0) {
values->enabled = (line[valuestart]=='0'?false:true);
captured++;
} else if ( strncmp(&line[keystart], "min", 3) == 0) {
strncpy(values->minute, &line[valuestart], (i-valuestart) );
values->minute[i-valuestart] = '\0';
captured++;
@ -113,7 +116,7 @@ bool passJson_scObj(char* line, int length, aqs_cron *values)
captured++;
}
keystart=0;
keyend=0;
//keyend=0;
valuestart=0;
invalue=false;
readingvalue=false;
@ -161,10 +164,9 @@ int save_schedules_js(char* inBuf, int inSize, char* outBuf, int outSize)
inarray=false;
} else if ( inarray && inBuf[i] == '{') {
passJson_scObj( &inBuf[i], (inSize-i), &cline);
//LOG(SCHD_LOG,LOG_NOTICE,"Saving Cron %s %s %s %s %s %s %s\n",cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, cline.url, cline.value);
LOG(SCHD_LOG,LOG_INFO, "Write to cron Min=%s Hour=%s DayM=%s Month=%s DayW %s URL %s Value %s\n",cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
LOG(SCHD_LOG,LOG_INFO, "%s %s %s %s %s curl localhost:%s%s -d value=%s -X PUT\n",cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
fprintf(fp, "%s %s %s %s %s root curl localhost:%s%s -d value=%s -X PUT\n",cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
LOG(SCHD_LOG,LOG_DEBUG, "Write to cron Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
LOG(SCHD_LOG,LOG_INFO, "%s%s %s %s %s %s curl localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
fprintf(fp, "%s%s %s %s %s %s root curl localhost:%s%s -d value=%s -X PUT\n",(cline.enabled?"":"#"),cline.minute, cline.hour, cline.daym, cline.month, cline.dayw, _aqconfig_.socket_port, cline.url, cline.value);
} else if ( inarray && inBuf[i] == '}') {
//inobj=false;
//objed=i;
@ -202,7 +204,10 @@ int build_schedules_js(char* buffer, int size)
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(/api/.*)\\s-d value=([^\\d]+)\\s(.*)";
// \d doesn't seem to be supported, so using [0-9]+ instead
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
char *regexString="(#{0,1})([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(\\/api\\/.*\\/set).* value=([0-9]+).*";
//char *regexString="([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s.*(/api/.*/set).*value=([0-9]+).*";
@ -232,25 +237,30 @@ int build_schedules_js(char* buffer, int size)
//lc++;
//rc = regexec(&regexCompiled, line, maxGroups, groupArray, 0);
if (0 == (rc = regexec(&regexCompiled, line, maxGroups, groupArray, REG_EXTENDED))) {
// Group 1 is minute
// Group 2 is hour
// Group 3 is day of month
// Group 4 is month
// Group 5 is day of week
// Group 6 is URL
// Group 7 is value
// Group 1 is # (enable or not)
// Group 2 is minute
// Group 3 is hour
// Group 4 is day of month
// Group 5 is month
// Group 6 is day of week
// Group 7 is root
// Group 8 is curl
// Group 9 is URL
// Group 10 is value
if (groupArray[8].rm_so == (size_t)-1) {
LOG(SCHD_LOG,LOG_ERR, "No matching information from cron file\n");
} else {
sprintf(cline.minute, "%.*s", (groupArray[1].rm_eo - groupArray[1].rm_so), (line + groupArray[1].rm_so));
sprintf(cline.hour, "%.*s", (groupArray[2].rm_eo - groupArray[2].rm_so), (line + groupArray[2].rm_so));
sprintf(cline.daym, "%.*s", (groupArray[3].rm_eo - groupArray[3].rm_so), (line + groupArray[3].rm_so));
sprintf(cline.month, "%.*s", (groupArray[4].rm_eo - groupArray[4].rm_so), (line + groupArray[4].rm_so));
sprintf(cline.dayw, "%.*s", (groupArray[5].rm_eo - groupArray[5].rm_so), (line + groupArray[5].rm_so));
sprintf(cline.url, "%.*s", (groupArray[8].rm_eo - groupArray[8].rm_so), (line + groupArray[8].rm_so));
sprintf(cline.value, "%.*s", (groupArray[9].rm_eo - groupArray[9].rm_so), (line + groupArray[9].rm_so));
LOG(SCHD_LOG,LOG_INFO, "Read from cron. Min=%s Hour=%s DayM=%s Month=%s DayW=%s URL=%s Value=%s\n",cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
length += sprintf(buffer+length, "{\"min\": \"%s\",\"hour\": \"%s\",\"daym\": \"%s\",\"month\": \"%s\",\"dayw\": \"%s\",\"url\": \"%s\",\"value\": \"%s\"},",
cline.enabled = (line[groupArray[1].rm_so] == '#')?false:true;
sprintf(cline.minute, "%.*s", (groupArray[2].rm_eo - groupArray[2].rm_so), (line + groupArray[2].rm_so));
sprintf(cline.hour, "%.*s", (groupArray[3].rm_eo - groupArray[3].rm_so), (line + groupArray[3].rm_so));
sprintf(cline.daym, "%.*s", (groupArray[4].rm_eo - groupArray[4].rm_so), (line + groupArray[4].rm_so));
sprintf(cline.month, "%.*s", (groupArray[5].rm_eo - groupArray[5].rm_so), (line + groupArray[5].rm_so));
sprintf(cline.dayw, "%.*s", (groupArray[6].rm_eo - groupArray[6].rm_so), (line + groupArray[6].rm_so));
sprintf(cline.url, "%.*s", (groupArray[9].rm_eo - groupArray[9].rm_so), (line + groupArray[9].rm_so));
sprintf(cline.value, "%.*s", (groupArray[10].rm_eo - groupArray[10].rm_so), (line + groupArray[10].rm_so));
LOG(SCHD_LOG,LOG_INFO, "Read from cron. Enabled:%d Min:%s Hour:%s DayM:%s Month:%s DayW:%s URL:%s Value:%s\n",cline.enabled,cline.minute,cline.hour,cline.daym,cline.month,cline.dayw,cline.url,cline.value);
length += sprintf(buffer+length, "{\"enabled\":\"%d\", \"min\":\"%s\",\"hour\":\"%s\",\"daym\":\"%s\",\"month\":\"%s\",\"dayw\":\"%s\",\"url\":\"%s\",\"value\":\"%s\"},",
cline.enabled,
cline.minute,
cline.hour,
cline.daym,

View File

@ -13,6 +13,7 @@
typedef struct aqs_cron
{
int enabled;
char minute[CV_SIZE];
char hour[CV_SIZE];
char daym[CV_SIZE];

View File

@ -647,8 +647,17 @@ void send_packet(int fd, unsigned char *packet, int length)
#endif
*/
// MAYBE Change this back to debug serial
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial write %d bytes\n",length-2);
//LOG(RSSD_LOG,LOG_DEBUG, "Serial write %d bytes, type 0x%02hhx cmd 0x%02hhx\n",length-2,packet[5],packet[6]);
logPacketWrite(&packet[1], length-2);
/*
if (getLogLevel(PDA_LOG) == LOG_DEBUG) {
char buff[1024];
beautifyPacket(buff, &packet[1], length, false);
LOG(PDA_LOG,LOG_DEBUG, "%s", buff);
}
*/
/*
if ( getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL || ) {
// Packet is padded with 0x00, so discard for logging

View File

@ -151,17 +151,19 @@ bool checkAqualinkTime()
char datestr[DATE_STRING_LEN];
#ifdef AQ_PDA
if (isPDA_PANEL) {
LOG(AQUA_LOG,LOG_DEBUG, "PDA Time Check\n");
// date is simply a day or week for PDA.
localtime_r(&now, &aq_tm);
int real_wday = aq_tm.tm_wday; // NSF Need to do this better, we could be off by 7 days
snprintf(datestr, DATE_STRING_LEN, "%s %s",_aqualink_data.date,_aqualink_data.time);
if (strptime(datestr, "%A %I:%M%p", &aq_tm) == NULL) {
LOG(AQUA_LOG,LOG_ERR, "Could not convert PDA RS time string '%s'", datestr);
last_checked = (time_t)NULL;
return true;
}
if (real_wday != aq_tm.tm_wday) {
LOG(PDA_LOG,LOG_INFO, "Day of the week incorrect - request time set\n");
LOG(AQUA_LOG,LOG_INFO, "PDA Day of the week incorrect - request time set\n");
return false;
}
}
@ -1166,7 +1168,7 @@ int main(int argc, char *argv[])
setLoggingPrms(_aqconfig_.log_level, _aqconfig_.deamonize, _aqconfig_.log_file, NULL);
LOG(AQUA_LOG,LOG_NOTICE, "%s v%s\n", AQUALINKD_NAME, AQUALINKD_VERSION);
/*
LOG(AQUA_LOG,LOG_NOTICE, "Panel set to %s%s-%d %s%s %s\n",
isRS_PANEL?"RS":"",
isPDA_PANEL?"PDA":"", // No need for both of these, but for error validation leave it in.
@ -1174,7 +1176,8 @@ int main(int argc, char *argv[])
isCOMBO_PANEL?"Combo Pool/Spa":"",
isSINGLE_DEV_PANEL?"Pool/Spa Only":"",
isDUAL_EQPT_PANEL?"Dual Equipment":"");
*/
LOG(AQUA_LOG,LOG_NOTICE, "Panel set to %s\n", getPanelString());
LOG(AQUA_LOG,LOG_NOTICE, "Config log_level = %d\n", _aqconfig_.log_level);
LOG(AQUA_LOG,LOG_NOTICE, "Config device_id = 0x%02hhx\n", _aqconfig_.device_id);
LOG(AQUA_LOG,LOG_NOTICE, "Config rssa_device_id = 0x%02hhx\n", _aqconfig_.rssa_device_id);

View File

@ -442,6 +442,7 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
length += sprintf(buffer+length, "{\"type\": \"status\"");
length += sprintf(buffer+length, ",\"status\":\"%s\"",getStatus(aqdata) );
length += sprintf(buffer+length, ",\"panel_message\":\"%s\"",aqdata->last_message );
length += sprintf(buffer+length, ",\"panel_type\":\"%s\"",getPanelString());
//length += sprintf(buffer+length, ",\"message\":\"%s\"",aqdata->message );
length += sprintf(buffer+length, ",\"version\":\"%s\"",aqdata->version );//8157 REV MMM",
length += sprintf(buffer+length, ",\"aqualinkd_version\":\"%s\"", AQUALINKD_VERSION ); //1.0b,

173
pda.c
View File

@ -30,9 +30,10 @@
#include "aq_panel.h"
#include "packetLogger.h"
#include "devices_jandy.h"
#include "rs_msg_utils.h"
// This needs to be tested on a real panel.
#define NEW_UPDATE_METHOD
//#define NEW_UPDATE_METHOD
// static struct aqualinkdata _aqualink_data;
@ -322,7 +323,7 @@ void process_pda_packet_msg_long_time(const char *msg)
{
LOG(AQRS_LOG,LOG_NOTICE, "RS time is NOT accurate '%s %s', re-setting on controller!\n", _aqualink_data->time, _aqualink_data->date);
aq_programmer(AQ_SET_TIME, NULL, _aqualink_data);
}
}
}
void process_pda_packet_msg_long_equipment_control(const char *msg)
@ -409,6 +410,21 @@ void setSingleDeviceMode()
}
}
void process_pda_packet_msg_long_set_time(const char *msg)
{
/*
// NOT Working at moment, also wrong format
LOG(PDA_LOG,LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n");
if (msg[4] == '/' && msg[7] == '/'){
//DATE
rsm_strncpycut(_aqualink_data->date, msg, AQ_MSGLEN-1, AQ_MSGLEN-1);
} else if (msg[6] == ':' && msg[11] == 'M') {
// TIME
rsm_strncpycut(_aqualink_data->time, msg, AQ_MSGLEN-1, AQ_MSGLEN-1);
}
*/
}
void process_pda_packet_msg_long_set_temp(const char *msg)
{
LOG(PDA_LOG,LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n");
@ -512,8 +528,70 @@ void process_pda_packet_msg_long_unknown(const char *msg)
{
if (stristr(msg, _aqualink_data->aqbuttons[i].label) != NULL)
{
printf("*** UNKNOWN Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg);
// set_pda_led(_aqualink_data->aqbuttons[i].led, msg[AQ_MSGLEN-1]);
//LOG(PDA_LOG,LOG_ERR," UNKNOWN Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg);
// This seems to keep everything off.
set_pda_led(_aqualink_data->aqbuttons[i].led, msg[AQ_MSGLEN-1]);
}
}
}
}
void log_pump_information() {
int i;
//bool rtn = false;
char *m2_line=pda_m_line(2);
char *m3_line=pda_m_line(3);
char *m4_line=pda_m_line(3);
char *m5_line=pda_m_line(3);
if (rsm_strcmp(m2_line,"Intelliflo VS") == 0 ||
rsm_strcmp(m2_line,"Intelliflo VF") == 0 ||
rsm_strcmp(m2_line,"Jandy ePUMP") == 0 ||
rsm_strcmp(m2_line,"ePump AC") == 0) {
//rtn = true;
int rpm = 0;
int watts = 0;
int gpm = 0;
int pump_index = rsm_atoi(&m2_line[14]);
if (pump_index <= 0)
pump_index = rsm_atoi(&m2_line[12]); // Pump inxed is in different position on line ` ePump AC 4`
// RPM displays differently depending on 3 or 4 digit rpm.
if (rsm_strcmp(m3_line,"RPM:") == 0){
rpm = rsm_atoi(&m3_line[10]);
if (rsm_strcmp(m4_line,"Watts:") == 0) {
watts = rsm_atoi(&m4_line[10]);
}
if (rsm_strcmp(m5_line,"GPM:") == 0) {
gpm = rsm_atoi(&m5_line[10]);
}
} else if (rsm_strcmp(m3_line,"*** Priming ***") == 0){
rpm = PUMP_PRIMING;
} else if (rsm_strcmp(m3_line,"(Offline)") == 0){
rpm = PUMP_OFFLINE;
} else if (rsm_strcmp(m3_line,"(Priming Error)") == 0){
rpm = PUMP_ERROR;
}
LOG(PDA_LOG,LOG_INFO, "PDA Pump %s, Index %d, RPM %d, Watts %d, GPM %d\n",m3_line,pump_index,rpm,watts,gpm);
for (i=0; i < _aqualink_data->num_pumps; i++) {
if (_aqualink_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(_aqualink_data, i);
_aqualink_data->pumps[i].rpm = rpm;
_aqualink_data->pumps[i].watts = watts;
_aqualink_data->pumps[i].gpm = gpm;
if (_aqualink_data->pumps[i].pumpType == PT_UNKNOWN){
if (rsm_strcmp(m2_line,"Intelliflo VS") == 0)
_aqualink_data->pumps[i].pumpType = VSPUMP;
else if (rsm_strcmp(m2_line,"Intelliflo VF") == 0)
_aqualink_data->pumps[i].pumpType = VFPUMP;
else if (rsm_strcmp(m2_line,"Jandy ePUMP") == 0 ||
rsm_strcmp(m2_line,"ePump AC") == 0)
_aqualink_data->pumps[i].pumpType = EPUMP;
}
//printf ("Set Pump Type to %d\n",aq_data->pumps[i].pumpType);
}
}
}
@ -523,19 +601,27 @@ void process_pda_packet_msg_long_equiptment_status(const char *msg_line, int lin
{
//pass_pda_equiptment_status_item(msg);
#ifdef NEW_UPDATE_METHOD
if (reset) {
equiptment_update_cycle(-1);
LOG(PDA_LOG,LOG_DEBUG, "*************** Equiptment reset\n");
return;
}
#endif
LOG(PDA_LOG,LOG_DEBUG, "*************** Pass Equiptment msg %.16s\n", msg_line);
LOG(PDA_LOG,LOG_DEBUG, "*************** Pass Equiptment msg '%.16s'\n", msg_line);
if (msg_line == NULL) {
LOG(PDA_LOG,LOG_DEBUG, "*************** Pass Equiptment msg is NULL do nothing\n");
return;
}
static char *index;
int i;
char *msg = (char *)msg_line;
while(isspace(*msg)) msg++;
//strncpy(labelBuff, msg, AQ_MSGLEN);
// EQUIPMENT STATUS
//
@ -568,61 +654,76 @@ void process_pda_packet_msg_long_equiptment_status(const char *msg_line, int lin
// Check message for status of device
// Loop through all buttons and match the PDA text.
if ((index = strcasestr(msg, "CHECK AquaPure")) != NULL)
// Should probably use strncasestr
if ((index = rsm_strnstr(msg, "CHECK AquaPure", AQ_MSGLEN)) != NULL)
{
LOG(PDA_LOG,LOG_DEBUG, "CHECK AquaPure\n");
}
else if ((index = strcasestr(msg, "FREEZE PROTECT")) != NULL)
else if ((index = rsm_strnstr(msg, "FREEZE PROTECT", AQ_MSGLEN)) != NULL)
{
_aqualink_data->frz_protect_state = ON;
LOG(PDA_LOG,LOG_DEBUG, "Freeze Protect is on\n");
}
else if ((index = strcasestr(msg, MSG_SWG_PCT)) != NULL)
else if ((index = rsm_strnstr(msg, MSG_SWG_PCT, AQ_MSGLEN)) != NULL)
{
changeSWGpercent(_aqualink_data, atoi(index + strlen(MSG_SWG_PCT)));
//_aqualink_data->swg_percent = atoi(index + strlen(MSG_SWG_PCT));
//if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;}
LOG(PDA_LOG,LOG_DEBUG, "AquaPure = %d\n", _aqualink_data->swg_percent);
}
else if ((index = strcasestr(msg, MSG_SWG_PPM)) != NULL)
else if ((index = rsm_strnstr(msg, MSG_SWG_PPM, AQ_MSGLEN)) != NULL)
{
_aqualink_data->swg_ppm = atoi(index + strlen(MSG_SWG_PPM));
//if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;}
LOG(PDA_LOG,LOG_DEBUG, "SALT = %d\n", _aqualink_data->swg_ppm);
}
else if ((index = strcasestr(msg, MSG_PMP_RPM)) != NULL)
else if ((index = rsm_strnstr(msg, MSG_PMP_RPM, AQ_MSGLEN)) != NULL)
{ // Default to pump 0, should check for correct pump
_aqualink_data->pumps[0].rpm = atoi(index + strlen(MSG_PMP_RPM));
LOG(PDA_LOG,LOG_DEBUG, "RPM = %d\n", _aqualink_data->pumps[0].rpm);
log_pump_information();
}
else if ((index = strcasestr(msg, MSG_PMP_WAT)) != NULL)
else if ((index = rsm_strnstr(msg, MSG_PMP_WAT, AQ_MSGLEN)) != NULL)
{ // Default to pump 0, should check for correct pump
_aqualink_data->pumps[0].watts = atoi(index + strlen(MSG_PMP_WAT));
LOG(PDA_LOG,LOG_DEBUG, "Watts = %d\n", _aqualink_data->pumps[0].watts);
log_pump_information();
}
else if ((index = rsm_strnstr(msg, MSG_PMP_GPM, AQ_MSGLEN)) != NULL)
{ // Default to pump 0, should check for correct pump
_aqualink_data->pumps[0].gpm = atoi(index + strlen(MSG_PMP_GPM));
LOG(PDA_LOG,LOG_DEBUG, "GPM = %d\n", _aqualink_data->pumps[0].gpm);
log_pump_information();
}
else if ((index = rsm_strnstr(msg, "(Offline)", AQ_MSGLEN)) != NULL)
{ // Default to pump 0, should check for correct pump
//_aqualink_data->pumps[0].gpm = atoi(index + strlen(MSG_PMP_GPM));
LOG(PDA_LOG,LOG_DEBUG, "Pump offline\n");
log_pump_information();
}
else if (rsm_strncmp(msg_line, "POOL HEAT ENA",AQ_MSGLEN) == 0)
{
_aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE;
LOG(PDA_LOG,LOG_DEBUG, "Pool Hearter is enabled\n");
}
else if (rsm_strncmp(msg_line, "SPA HEAT ENA",AQ_MSGLEN) == 0)
{
_aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE;
LOG(PDA_LOG,LOG_DEBUG, "Pool Hearter is enabled\n");
}
else
{
char labelBuff[AQ_MSGLEN + 2];
strncpy(labelBuff, msg, AQ_MSGLEN + 1);
msg = stripwhitespace(labelBuff);
if (strcasecmp(msg, "POOL HEAT ENA") == 0)
{
_aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE;
}
else if (strcasecmp(msg, "SPA HEAT ENA") == 0)
{
_aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE;
}
else
{
for (i = 0; i < _aqualink_data->total_buttons; i++)
{
if (strcasecmp(msg, _aqualink_data->aqbuttons[i].label) == 0)
//LOG(PDA_LOG,LOG_DEBUG, "*** check msg '%s' against '%s'\n",labelBuff,_aqualink_data->aqbuttons[i].label);
LOG(PDA_LOG,LOG_DEBUG, "*** check msg '%.*s' against '%s'\n",AQ_MSGLEN,msg_line,_aqualink_data->aqbuttons[i].label);
if (rsm_strncmp(msg_line, _aqualink_data->aqbuttons[i].label, AQ_MSGLEN-1) == 0)
//if (rsm_strcmp(_aqualink_data->aqbuttons[i].label, labelBuff) == 0)
{
#ifdef NEW_UPDATE_METHOD
equiptment_update_cycle(i);
#endif
LOG(PDA_LOG,LOG_DEBUG, "*** Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg);
LOG(PDA_LOG,LOG_DEBUG, "Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg_line);
// It's on (or delayed) if it's listed here.
if (_aqualink_data->aqbuttons[i].led->state != FLASH)
{
@ -631,8 +732,8 @@ void process_pda_packet_msg_long_equiptment_status(const char *msg_line, int lin
break;
}
}
}
}
}
@ -713,6 +814,8 @@ bool process_pda_packet(unsigned char *packet, int length)
beautifyPacket(buff, packet, length, true);
LOG(PDA_LOG,LOG_DEBUG, "%s", buff);
}
/*
// Some panels don't give the startup messages we used to key the init sequence, so check here
// need to put this in a better spot some time in the future
@ -750,6 +853,11 @@ bool process_pda_packet(unsigned char *packet, int length)
{
process_pda_packet_msg_long_equiptment_status(NULL, 0, true);
equiptment_updated = false;
} else if (_initWithRS == false && pda_m_type() == PM_FW_VERSION) {
_initWithRS = true;
LOG(PDA_LOG,LOG_DEBUG, "**** PDA INIT ****\n");
//aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data);
queueGetProgramData(AQUAPDA, _aqualink_data);
}
/*
// If we get a status packet, and we are on the status menu, this is a list of what's on
@ -859,11 +967,11 @@ bool process_pda_packet(unsigned char *packet, int length)
case PM_AUX_LABEL_DEVICE:
process_pda_packet_msg_long_level_aux_device(msg);
break;
/*
case PM_SET_TIME:
process_pda_packet_msg_long_set_time(index, msg);
process_pda_packet_msg_long_set_time(msg);
break;
*/
//case PM_FW_VERSION:
// process_pda_packet_msg_long_FW_version(msg);
//break;
@ -880,6 +988,7 @@ bool process_pda_packet(unsigned char *packet, int length)
}
case CMD_PDA_0x1B:
{
LOG(PDA_LOG,LOG_DEBUG, "**** CMD_PDA_0x1B ****\n");
// We get two of these on startup, one with 0x00 another with 0x01 at index 4. Just act on one.
// Think this is PDA finishd showing startup screen
if (packet[4] == 0x00) {

View File

@ -500,10 +500,14 @@ void *set_aqualink_PDA_device_on_off( void *ptr )
sprintf(device_name,"%-13s\n",aq_data->aqbuttons[device].label);
}
// NSF Added this since DEBUG hitting wrong command
//waitfor_queue2empty();
if ( find_pda_menu_item(aq_data, device_name, 13) ) {
if (aq_data->aqbuttons[device].led->state != state) {
//printf("*** Select State ***\n");
LOG(PDA_LOG,LOG_INFO, "PDA Device On/Off, found device '%s', changing state\n",aq_data->aqbuttons[device].label,state);
force_queue_delete(); // NSF This is a really shit thing to do. Need to fix this
send_cmd(KEY_PDA_SELECT);
while (get_aq_cmd_length() > 0) { delay(500); }
// If you are turning on a heater there will be a sub menu to set temp
@ -793,7 +797,7 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int cur_
delay(500); // Last message probably was CMD_PDA_HIGHLIGHT, so wait before checking.
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,2);
if (i > 10) {
LOG(PDA_LOG,LOG_ERR, "PDA numeric selector could not find string '%s'\n", select_label);
LOG(PDA_LOG,LOG_ERR, "Numeric selector could not find string '%s'\n", select_label);
return false;
}
i++;
@ -802,21 +806,21 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int cur_
}
if (val < cur_val) {
LOG(PDA_LOG,LOG_DEBUG, "PDA %s value : lower from %d to %d\n", select_label, cur_val, val);
LOG(PDA_LOG,LOG_DEBUG, "Numeric selector %s value : lower from %d to %d\n", select_label, cur_val, val);
for (i = cur_val; i > val; i=i-step) {
send_cmd(KEY_PDA_DOWN);
}
} else if (val > cur_val) {
LOG(PDA_LOG,LOG_DEBUG, "PDA %s value : raise from %d to %d\n", select_label, cur_val, val);
LOG(PDA_LOG,LOG_DEBUG, "Numeric selector %s value : raise from %d to %d\n", select_label, cur_val, val);
for (i = cur_val; i < val; i=i+step) {
send_cmd(KEY_PDA_UP);
}
} else {
LOG(PDA_LOG,LOG_INFO, "PDA %s value : already at %d\n", select_label, val);
LOG(PDA_LOG,LOG_INFO, "Numeric selector %s value : already at %d\n", select_label, val);
}
send_cmd(KEY_PDA_SELECT);
LOG(PDA_LOG,LOG_DEBUG, "PDA %s value : set to %d\n", select_label, val);
LOG(PDA_LOG,LOG_DEBUG, "Numeric selector %s value : set to %d\n", select_label, val);
return true;
}
@ -937,13 +941,18 @@ bool set_PDA_aqualink_time(struct aqualinkdata *aq_data) {
LOG(PDA_LOG,LOG_ERR, "Error finding freeze protect setpoints menu\n");
return false;
}
struct tm tm;
time_t now;
static char result[30];
time(&now); // get time now
localtime_r(&now, &tm);
LOG(PDA_LOG,LOG_DEBUG, "set_PDA_aqualink_time %s\n", asctime_r(&tm,result));
//struct tm *tm;
//time_t now;
//static char result[30];
//localtime_r(&now, &tm);
//LOG(PDA_LOG,LOG_DEBUG, "set_PDA_aqualink_time %s\n", asctime_r(&tm,result));
time_t now = time(0); // get time now
struct tm *tm = localtime(&now);
LOG(PDA_LOG, LOG_DEBUG, "Setting time to %d/%d/%d %d:%d\n", tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900, tm->tm_hour + 1 - tm->tm_isdst, tm->tm_min);
LOG(PDA_LOG, LOG_DEBUG, "Setting time to %s\n", asctime(tm));
/*
Debug: PDA: PDA Menu Line 0 = Set Time
Debug: PDA: PDA Menu Line 1 =
@ -960,17 +969,104 @@ Debug: PDA: PDA Menu Line 9 = to continue.
// Crap way to do this, we should use highlight chars, but I don't have enough debug/packet data
// info to code that at present. So just pull from lines.
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5);
//int cbuf = 0;
char *line = pda_m_hlight();
// This is a dam mess. Needs to be cleaned up.
// Basic check for date line.
printf("***** Char %c ****\n",line[4]);
if (line[4] == '/') {
send_cmd(KEY_PDA_SELECT);
line = pda_m_hlight();
// We should use the CMD_PDA_HIGHLIGHTCHARS to check we are on month
if (! set_PDA_numeric_field_value(aq_data, tm.tm_mon, atoi(&line[2]), NULL, 1)) {
if (! set_PDA_numeric_field_value(aq_data, tm->tm_mon+1, atoi(&line[2]), NULL, 1)) {
LOG(PDA_LOG,LOG_ERR, "Error failed to set month\n");
}
// No Need to send select, since set_PDA_numeric_field_value does that.
longwaitfor_queue2empty();
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5);
//line = pda_m_hlight(); The hlight line jumps down then back up, or we wait for two CMD_PDA_HIGHLIGHTCHARS
if (! set_PDA_numeric_field_value(aq_data, tm->tm_mday, atoi(&line[5]), NULL, 1)) {
LOG(PDA_LOG,LOG_ERR, "Error failed to set day\n");
}
longwaitfor_queue2empty();
//send_cmd(KEY_PDA_SELECT);
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5);
//line = pda_m_hlight();
int year=tm->tm_year - 100; // tm_year is a number relative to 1900. so 100 is 2000
LOG(PDA_LOG,LOG_DEBUG, "tm year=%d year=%d\n",tm->tm_year,year);
if (! set_PDA_numeric_field_value(aq_data, year, atoi(&line[8]), NULL, 1)) {
LOG(PDA_LOG,LOG_ERR, "Error failed to set year\n");
}
longwaitfor_queue2empty();
//send_cmd(KEY_PDA_SELECT);
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5);
//waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5);
int cnt=0;
while ( pda_m_hlightindex() != 3 && line[11] != 'M' ) {
delay(50);
waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHTCHARS,CMD_PDA_CLEAR,1);
line = pda_m_hlight();
if (cnt++ >= 30) {
LOG(PDA_LOG,LOG_ERR, "Error failed to get to time within date time menu\n");
break;
}
}
line = pda_m_hlight();
int index = 4;
if (line[index] == ' ') // Their is no leading 0 on hour
index++;
int hour = (tm->tm_hour+1) - tm->tm_isdst;
if (hour > 12) {
hour=hour-12;
// Still need to to AM PM check.
if (line[10] == 'A') {
// Need to change AM/PM
for (int i = 1; i > 12; i++) {
send_cmd(KEY_PDA_DOWN); // Just send 12 down. Can come back and to this better
}
}
} else {
if (line[10] == 'P') {
// Need to change PM/AM
for (int i = 1; i > 12; i++) {
send_cmd(KEY_PDA_DOWN); // Just send 12 down. Can come back and to this better
}
}
}
if (! set_PDA_numeric_field_value(aq_data, hour, atoi(&line[index]), NULL, 1)) {
LOG(PDA_LOG,LOG_ERR, "Error failed to set hour\n");
}
longwaitfor_queue2empty();
// See if we have AM / PM correct.
//send_cmd(KEY_PDA_SELECT);
waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5);
if (! set_PDA_numeric_field_value(aq_data, tm->tm_min+1, atoi(&line[7]), NULL, 1)) {
LOG(PDA_LOG,LOG_ERR, "Error failed to set minute\n");
}
longwaitfor_queue2empty();
send_cmd(KEY_PDA_SELECT);
send_cmd(KEY_PDA_BACK);
send_cmd(KEY_PDA_BACK);
} else {
LOG(PDA_LOG,LOG_ERR, "Error set time failed\n");
send_cmd(KEY_PDA_BACK);

View File

@ -26,6 +26,8 @@
#include "utils.h"
static int _hlightindex = -1;
static int _hlightcharindexstart = -1;
static int _hlightcharindexstop = -1;
static char _menu[PDA_LINES][AQ_MSGLEN+1];
void print_menu()
@ -38,8 +40,12 @@ void print_menu()
if (_hlightindex > -1) {
//printf("PDA highlighted line = %d = %s\n",_hlightindex,_menu[_hlightindex]);
LOG(PDA_LOG,LOG_DEBUG, "PDA Menu highlighted line = %d = %s\n",_hlightindex,_menu[_hlightindex]);
}
LOG(PDA_LOG,LOG_DEBUG, "PDA Menu highlighted line#=%d line='%s'\n",_hlightindex,_menu[_hlightindex]);
}
if (_hlightcharindexstart > -1) {
LOG(PDA_LOG,LOG_DEBUG, "PDA Menu highlighted characters numer=%d start=%d end=%d actual='%.*s'\n",(_hlightcharindexstop-_hlightcharindexstart),_hlightcharindexstart,_hlightcharindexstop,(_hlightcharindexstop-_hlightcharindexstart),&_menu[_hlightindex][_hlightcharindexstart+1]);
}
}
int pda_m_hlightindex()
@ -61,6 +67,12 @@ char *pda_m_line(int index)
// return NULL;
}
char *pda_m_hlightchars(int *len)
{
*len = _hlightcharindexstop - _hlightcharindexstart + 1;
return &_menu[_hlightindex][_hlightcharindexstart];
}
// Find exact menu item
int pda_find_m_index(char *text)
{
@ -197,6 +209,8 @@ bool process_pda_menu_packet(unsigned char* packet, int length)
switch (packet[PKT_CMD]) {
case CMD_PDA_CLEAR:
_hlightindex = -1;
_hlightcharindexstart = -1;
_hlightcharindexstop = -1;
memset(_menu, 0, PDA_LINES * (AQ_MSGLEN+1));
break;
case CMD_MSG_LONG:
@ -218,16 +232,24 @@ bool process_pda_menu_packet(unsigned char* packet, int length)
// when switching from hlight to hlightchars index 255 is sent to turn off hlight
if (packet[4] <= PDA_LINES) {
_hlightindex = packet[4];
_hlightcharindexstart = -1;
_hlightcharindexstop = -1;
} else {
_hlightindex = -1;
_hlightcharindexstart = -1;
_hlightcharindexstop = -1;
}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;
case CMD_PDA_HIGHLIGHTCHARS:
if (packet[4] <= PDA_LINES) {
_hlightindex = packet[4];
_hlightcharindexstart = packet[5];
_hlightcharindexstop = packet[6];
} else {
_hlightindex = -1;
_hlightcharindexstart = -1;
_hlightcharindexstop = -1;
}
if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();}
break;

View File

@ -76,6 +76,7 @@ pda_menu_type pda_m_type();
int pda_find_m_index(char *text);
int pda_find_m_index_case(char *text, int limit);
int pda_find_m_index_loose(char *text);
char *pda_m_hlightchars(int *len);
//int pda_find_m_index_swcase(char *text, int limit);
#endif

Binary file not shown.

View File

@ -18,8 +18,8 @@ web_directory=/nas/data/Development/Raspberry/AqualinkD/web
#log_level=DEBUG_SERIAL
#log_level=DEBUG
log_level=INFO
#log_level=NOTICE
#log_level=INFO
log_level=NOTICE
# AQUA_LOG 1
# NET_LOG 2
@ -30,7 +30,7 @@ log_level=INFO
# RSSA_LOG 64
# DJAN_LOG 128
# DPEN_LOG 256
# RSSD_LOG 512
# RSSD_LOG 512 // Serial connection
# PROG_LOG 1024
# DBGT_LOG 2048
# TIMR_LOG 4096
@ -41,7 +41,7 @@ log_level=INFO
#debug_log_mask = 4
#debug_log_mask = 8
#debug_log_mask = 16
debug_log_mask = 32
#debug_log_mask = 32
#debug_log_mask = 64
#debug_log_mask = 256
#debug_log_mask = 512
@ -53,7 +53,7 @@ display_warnings_in_web = yes
# The socket port that the daemon listens to
# If you change this from 80, remember to update aqualink.service.avahi
socket_port = 88
socket_port = 80
# The serial port the daemon access to read the Aqualink RS8
serial_port=/dev/ttyUSB0
@ -127,7 +127,7 @@ panel_type = PD-8 Combo
#network_poll_speed = 1
keep_paneltime_synced = no
keep_paneltime_synced = yes
#pda_mode = yes
@ -259,10 +259,10 @@ button_08_label=Aux6
#button_09_label=Fountain
#button_10_label=Pool Heater
button_10_label=Pool Heat
#button_10_dzidx=44
#button_11_label=Spa Heater
button_11_label=Spa Heat
#button_11_dzidx=56
#button_12_label=Solar Heater

Binary file not shown.

View File

@ -60,6 +60,12 @@ char *rsm_strstr(const char *haystack, const char *needle)
//LOG(AQUA_LOG,LOG_DEBUG, "Compare (reset)%d chars of '%s' to '%s'\n",strlen(sp2),sp1,sp2);
return strcasestr(sp1, sp2);
}
char *rsm_strnstr(const char *haystack, const char *needle, int length)
{
// NEED TO WRITE THIS MYSELF. Same as below but limit length
return strcasestr(haystack, needle);
}
// Check s2 exists in s1
int rsm_strcmp(const char *haystack, const char *needle)
{
@ -77,6 +83,48 @@ int rsm_strcmp(const char *haystack, const char *needle)
return strncasecmp(sp1, sp2, strlen(sp2));
}
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
int rsm_strncmp(const char *haystack, const char *needle, int length)
{
char *sp1 = (char *)haystack;
char *sp2 = (char *)needle;
char *ep1 = (sp1+length);
//int i=0;
// Get rid of all padding
while(isspace(*sp1)) sp1++;
while(isspace(*sp2)) sp2++;
if (strlen(sp1) == 0 || strlen(sp2) == 0)
return -1;
// Work out last char in haystack
while(isspace(*ep1)) ep1--;
//LOG(AQUA_LOG,LOG_DEBUG, "CHECK haystack SP1='%c' EP1='%c' SP2='%c' '%.*s' for '%s' length=%d\n",*sp1,*ep1,*sp2,(ep1-sp1)+1,sp1,sp2,(ep1-sp1)+1);
// Need to write this myself for speed
// Need to check if full length string (no space on end), that the +1 is accurate. MIN should do it
return strncasecmp(sp1, sp2, MIN((ep1-sp1)+1,length));
}
// NSF Check is this works correctly.
char *rsm_strncpycut(char *dest, const char *src, int dest_len, int src_len)
{
char *sp = (char *)src;
char *ep = (sp+dest_len);
while(isspace(*sp)) sp++;
while(isspace(*ep)) ep--;
int length=MIN((ep-sp)+1,dest_len);
memset(dest, '\0',dest_len);
return strncpy(dest, sp, length);
//dest[length] = '\0';
}
int _rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len, bool nulspace)
{
int i;

View File

@ -2,10 +2,13 @@
#define RS_MSG_UTILS_H_
char *rsm_strstr(const char *haystack, const char *needle);
char *rsm_strnstr(const char *haystack, const char *needle, int length);
int rsm_strncpy(char *dest, const unsigned char *src, int dest_len, int src_len);
int rsm_strcmp(const char *s1, const char *s2);
int rsm_strncmp(const char *haystack, const char *needle, int length);
int rsm_strncpy_nul2sp(char *dest, const unsigned char *src, int dest_len, int src_len);
int rsm_atoi(const char* str);
float rsm_atof(const char* str);
char *rsm_strncpycut(char *dest, const char *src, int dest_len, int src_len);
#endif //RS_MSG_UTILS_H_

View File

@ -95,6 +95,10 @@ unsigned char devID(int bIndex) {
// pool = 0; spa = 1; aux1 = 2 etc
// rssa pool / spa are different. aux1 = 21 (0x15) then goes up from their in order.
// NSF Pool Heat / Spa Heat / Solar Heater are also out of order. But have not accounted for that.
// It might be better to ass the RSS_ID's to the buttons in aq_panel in the future if we expand using
// this protocol.
// look at AllButton2RSsrialAdapter function at bottom of file.
if (bIndex==0)
return RS_SA_PUMP;
else if (bIndex==1)
@ -221,6 +225,8 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
if (cnt == 0 || cnt >= 250) {
LOG(RSSA_LOG,LOG_INFO, "Queue device update requests\n");
if (cnt == 0) {
// The below inturn calls get_aqualink_rssadapter_setpoints()
// But do it here as it's the first init, cnt=0 will only happen once
queueGetProgramData(RSSADAPTER, aq_data);
} else {
push_rssa_cmd(getPoolSP);
@ -305,6 +311,50 @@ bool process_rssadapter_packet(unsigned char *packet, int length, struct aqualin
return rtn;
}
/* 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;
}
*/
#ifdef DO_NOT_COMPILE
// Notes on protocol for Serial Adapter.
@ -319,7 +369,7 @@ What = 0x05 Query Value | 0x35 Set Value on next command.
0x10|0x02|0x48|ReplyType|DeviceID|????|Value|0x00|0xXX|0x10|0x03|
ReplyType 0x13=status, 0x07=set value next message
DeviceID
???? Not sure 0x00 modst of the time, 0x02 for (not set or vbat return)
???? Not sure 0x00 most of the time, 0x02 for (not set or vbat return)
Value What it's set to, except VBAT. or 0x07 set on next command
--------- Send reply to above if 0x07 ---------
0x10|0x02|0x00|0x01|0x00|Value|0x4f|0x10|0x03|

View File

@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
#define AQUALINKD_VERSION "2.3.0d"
#define AQUALINKD_VERSION "2.3.0e"

View File

@ -133,7 +133,7 @@
border-radius: 20px;
justify-content: center;
align-items: center;
width: 600px;
width: 650px;
padding: 10px;
/*overflow-y: scroll; didn't work*/
/*height: 100%;*/
@ -671,6 +671,7 @@
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
//alert(w+"x"+h+" = "+(w*h));
// 375x724 = 271500
if ((w * h) > 370000) { // 370000 is kind-a just guess
document.documentElement.style.setProperty('--tile-width', '125px');
@ -1588,6 +1589,31 @@
}
}
_displayMsgTimer=0;
_displayMsgTimeout=0;
function displayMessage(message, timeoutSeconds) {
// Check to see if we can display message
if (_displayMsgTimeout > 0) {
if ( _displayMsgTimer + (_displayMsgTimeout * 1000) > Date.now() ) {
// Can't diaply message, still on timer
//console.log("Can't display message '"+message+"'");
return;
}
_displayMsgTimer=0;
_displayMsgTimeout=0;
}
// Set the timer if needed
if (timeoutSeconds !== undefined && timeoutSeconds > 0) {
_displayMsgTimer = Date.now();
_displayMsgTimeout = timeoutSeconds;
}
document.getElementById("message").innerHTML = message;
}
/*********************************************************************
*
* SCHEDULER FUNCTIONS
@ -1606,15 +1632,20 @@
var V_GPM = 6;
function showScheduler(caller){
//if (_enable_schedules != false) {
// Default to enable.
if (typeof _enable_schedules === "undefined" || _enable_schedules != false)
{
if ( parseInt(getComputedStyle(document.querySelector('.scheduler_pane')).width) > Math.max(document.documentElement.clientWidth, window.innerWidth) ) {
//alert("Sorry, Scheduler won't fit on screen\nPlease use a different device");
displayMessage("Scheduler won't fit on screen", 3);
return;
}
import("./cronstrue.min.js");
caller.setAttribute('type', 'scheduler');
showTileOptions(true, caller.id);
}
}
// NSF CHANGE TO USING WS FOR THIS REQUEST
/*
function cs_loadJSON(path, success, error) {
@ -1632,6 +1663,7 @@
xhr.open('GET', path, true);
xhr.send();
}*/
function device2english(device, name) {
for (let i = 0, obj; i < _scheduler_devices_json.length, obj = _scheduler_devices_json[i]; i++) {
if (device == obj.id) {
@ -1747,7 +1779,7 @@
}
}
function cs_addschedule(min, hour, daym, month, dayw, device, subdev, value) {
function cs_addschedule(enabled, min, hour, daym, month, dayw, device, subdev, value) {
var table = document.getElementById("cronschedules");
//index = table.rows.length-ROW_INDEX;
@ -1768,7 +1800,10 @@
option = option + '<option value="' + obj.id + '">' + obj.name + '</option>';
}
}
var checked
if (enabled==1) {checked="checked";}else{ehecked="";}
var html = '<tr> \
<td><input type="checkbox" class="cs_inputcell" id="enabled" onkeyup="cs_crontext(this);" onclick="cs_crontext(this);" '+checked+'></td> \
<td><input type="text" class="cs_inputcell" id="min" value="'+ min + '" onkeyup="cs_crontext(this);" onclick="cs_crontext(this);"></td> \
<td><input type="text" class="cs_inputcell" id="hour" value="'+ hour + '" onkeyup="cs_crontext(this);" onclick="cs_crontext(this);"></td> \
<td><input type="text" class="cs_inputcell" id="daym" value="'+ daym + '" onkeyup="cs_crontext(this);" onclick="cs_crontext(this);"></td> \
@ -1881,7 +1916,7 @@
}
}
// If in release we add device, use obj.id rather than device in below and remove device from above.
cs_addschedule(obj.min, obj.hour, obj.daym, obj.month, obj.dayw, device, subdev, obj.value);
cs_addschedule(obj.enabled, obj.min, obj.hour, obj.daym, obj.month, obj.dayw, device, subdev, obj.value);
}
}
@ -1919,6 +1954,7 @@
var table = document.getElementById("cronschedules");
//console.log("ROWS = "+table.rows.length);
for (var r = CS_ROW_INDEX, row; row < table.rows.length-2, row = table.rows[r]; r++) {
enabled = Number(row.querySelector('#enabled')?.checked).toString();
min = row.querySelector('#min')?.value;
hour = row.querySelector('#hour')?.value;
daym = row.querySelector('#daym')?.value;
@ -1940,6 +1976,7 @@
command = "";
}
json.devices.push({
"enabled": enabled,
"min": min,
"hour": hour,
"daym": daym,
@ -1971,9 +2008,11 @@
if (document.getElementById("name").innerHTML == "AqualinkD") {
if (data.status != "Ready") {
document.getElementById("message").innerHTML = formatSatus(data.status);
//document.getElementById("message").innerHTML = formatSatus(data.status);
displayMessage(formatSatus(data.status));
} else {
document.getElementById("message").innerHTML = '';
//document.getElementById("message").innerHTML = '';
displayMessage(formatSatus(''));
}
}
@ -2288,6 +2327,8 @@
}
function showVersion(source) {
displayMessage("AqualinkD : " + _aqualink_data.aqualinkd_version + " | AqualinkRS : " + _aqualink_data.version, 5);
/*
if ((message = document.getElementById("message")) != null) {
message.innerHTML = "AqualinkD : " + _aqualink_data.aqualinkd_version + " | AqualinkRS : " + _aqualink_data.version;
}
@ -2295,6 +2336,7 @@
setTimeout(function() {
source.innerHTML = "AqualinkD";
}, 5000);
*/
}
function updatePwsitchOptions(source, light_type) {
@ -2580,11 +2622,12 @@
<div id='scheduler_options' class='options hide'>
<div id='scheduler_options_pane' class='scheduler_pane' onclick='event.stopPropagation();'>
<table id="cronschedules" border="0">
<th colspan='9'><span id="scheduler_options_title"></span></th>
<th colspan='10'><span id="scheduler_options_title"></span></th>
<tr>
<td colspan="9" align="center" id="crontext">&nbsp</td>
<td colspan="10" align="center" id="crontext">&nbsp</td>
</tr>
<tr class="sc_tablehead">
<td>Enable</td>
<td>Minute</td>
<td>Hour</td>
<td>Day<br><font size="-2">Month</font></td>
@ -2593,18 +2636,18 @@
<td>Device</td>
<td>Cmd</td>
<td>Value</td>
<td></td>
<td>Del</td>
</tr>
<!-- HTML will be added here -->
<tr class="sc_tablehead">
<td colspan="9">
<input type="button" class="options_button" id="Add" value="Add" onclick="cs_addschedule(0,0,'*','*','*','','','');">
<td colspan="10">
<input type="button" class="options_button" id="Add" value="Add" onclick="cs_addschedule(1,0,0,'*','*','*','','','');">
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" class="options_button" id="scheduler_options_close" value="Save" onclick="cs_createJSON();">
</td>
</tr>
<tr>
<td colspan="9" id="cronhelp"></td>
<td colspan="10" id="cronhelp"></td>
</tr>
<table>
</div>

View File

@ -78,6 +78,11 @@
background-color: rgb(116, 116, 116);
}
.error {
background-color: rgb(255, 0, 0) !important;
font-weight: 600;
}
.hidden {
display: none;
}
@ -246,6 +251,13 @@
function update_status(data) {
// Some form of error if PDA only panel.
if (data.panel_type.startsWith("PDA")) {
document.getElementById("title").innerHTML = ' !!! PDA only panels are not Supported !!! '
document.getElementById("title").classList.add("error");
document.getElementById("messages").innerHTML = ' !!! PDA Not Supported !!! '
document.getElementById("messages").classList.add("error");
}
if (document.getElementById("status").getAttribute("raw") != data.panel_message) {
document.getElementById("status_three").innerHTML = document.getElementById("status_two").innerHTML;