mirror of https://github.com/sfeakes/AqualinkD.git
parent
2d0647ab8d
commit
a97d058dda
|
@ -79,8 +79,10 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* Add set time to OneTouch protocol.
|
||||
* Publish AqualinkD Management console. (Configure, Restart, run serial_logger) within AqualinkD.
|
||||
|
||||
# Update in Release 2.3.2 (Current Development)
|
||||
# Update in Release 2.3.2
|
||||
* Added support for VSP on panel versions REV 0.1 & 0.2
|
||||
* Can change heater sliver min/max values in web UI. `./web/config.js`
|
||||
* Added reading ePump RPM/Watts directly from RS485 bus.
|
||||
|
||||
# Update in Release 2.3.1
|
||||
* Changed a lot of logic around different protocols.
|
||||
|
@ -104,7 +106,7 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
|
||||
# Update in Release 2.2.2
|
||||
* Fixed some Web UI bugs
|
||||
* Color lights now quicker when selecting existing comor mode.
|
||||
* Color lights now quicker when selecting existing color mode.
|
||||
|
||||
# Update in Release 2.2.1
|
||||
* Supports serial adapter protocol `rssa_device_id`, (provides instant heater setpoint changes & setpoint increment)
|
||||
|
|
14
aq_serial.c
14
aq_serial.c
|
@ -148,6 +148,20 @@ const char* get_packet_type(unsigned char* packet , int length)
|
|||
case RSSA_DEV_READY:
|
||||
return "RSSA SendCommand";
|
||||
break;
|
||||
case CMD_EPUMP_STATUS:
|
||||
if (packet[4] == CMD_EPUMP_RPM)
|
||||
return "ePump RPM";
|
||||
else if (packet[4] == CMD_EPUMP_WATTS)
|
||||
return "ePump Watts";
|
||||
else
|
||||
return "ePump (unknown)";
|
||||
break;
|
||||
case CMD_EPUMP_RPM:
|
||||
return "ePump set RPM";
|
||||
break;
|
||||
case CMD_EPUMP_WATTS:
|
||||
return "ePump get Watts";
|
||||
break;
|
||||
default:
|
||||
sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]);
|
||||
return buf;
|
||||
|
|
19
aq_serial.h
19
aq_serial.h
|
@ -36,10 +36,14 @@
|
|||
# Jandy pump ID's
|
||||
# 0x78, 0x79, 0x7A, 0x7B
|
||||
*/
|
||||
#define PENTAIR_DEC_PUMP_MIN 96
|
||||
#define PENTAIR_DEC_PUMP_MAX 111
|
||||
#define JANDY_DEC_PUMP_MIN 120
|
||||
#define JANDY_DEC_PUMP_MAX 123
|
||||
#define PENTAIR_DEC_PUMP_MIN 96 // 0x60
|
||||
#define PENTAIR_DEC_PUMP_MAX 111 // 0x6F
|
||||
#define JANDY_DEC_PUMP_MIN 120 // 0x80
|
||||
#define JANDY_DEC_PUMP_MAX 123 // 0x83
|
||||
#define JANDY_DEC_LX_MIN 56 // 0x40
|
||||
#define JANDY_DEC_LX_MAX 59 // 0x43
|
||||
#define JANDY_DEC_LXI_MIN 104 // 0x60
|
||||
#define JANDY_DEC_LXI_MAX 107 // 0x6B
|
||||
|
||||
|
||||
// PACKET DEFINES Jandy
|
||||
|
@ -315,6 +319,10 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
#define CMD_PDA_SHIFTLINES 0x0F
|
||||
#define CMD_PDA_HIGHLIGHTCHARS 0x10
|
||||
|
||||
/* ePump */
|
||||
#define CMD_EPUMP_STATUS 0x1F
|
||||
#define CMD_EPUMP_RPM 0x44
|
||||
#define CMD_EPUMP_WATTS 0x45
|
||||
// One Touch commands
|
||||
//#define CMD_PDA_0x04 0x04 // No idea, might be building menu
|
||||
|
||||
|
@ -417,7 +425,8 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
typedef enum {
|
||||
DRS_NONE,
|
||||
DRS_SWG,
|
||||
DRS_EPUMP
|
||||
DRS_EPUMP,
|
||||
DRS_LXI
|
||||
} rsDeviceType;
|
||||
|
||||
typedef enum {
|
||||
|
|
39
aqualinkd.c
39
aqualinkd.c
|
@ -1220,11 +1220,14 @@ int startup(char *self, char *cfgFile)
|
|||
_aqconfig_.log_raw_bytes = true;
|
||||
|
||||
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
setLoggingPrms(_aqconfig_.log_level, _aqconfig_.deamonize, (_aqconfig_.display_warnings_web?_aqualink_data.last_display_message:NULL));
|
||||
#else
|
||||
if (_aqconfig_.display_warnings_web == true)
|
||||
setLoggingPrms(_aqconfig_.log_level, _aqconfig_.deamonize, _aqconfig_.log_file, _aqualink_data.last_display_message);
|
||||
else
|
||||
setLoggingPrms(_aqconfig_.log_level, _aqconfig_.deamonize, _aqconfig_.log_file, NULL);
|
||||
#endif
|
||||
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "%s v%s\n", AQUALINKD_NAME, AQUALINKD_VERSION);
|
||||
/*
|
||||
|
@ -1284,13 +1287,16 @@ int startup(char *self, char *cfgFile)
|
|||
#endif
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config force SWG = %s\n", bool2text(_aqconfig_.force_swg));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config force PS setpoint = %s\n", bool2text(_aqconfig_.force_ps_setpoints));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config force Freeze Prot = %s\n", bool2text(_aqconfig_.force_frzprotect_setpoints));
|
||||
/* removed until domoticz has a better virtual thermostat
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config idx pool thermostat = %d\n", _aqconfig_.dzidx_pool_thermostat);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config idx spa thermostat = %d\n", _aqconfig_.dzidx_spa_thermostat);
|
||||
*/
|
||||
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config deamonize = %s\n", bool2text(_aqconfig_.deamonize));
|
||||
#ifndef AQ_MANAGER
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config log_file = %s\n", _aqconfig_.log_file);
|
||||
#endif
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config enable scheduler = %s\n", bool2text(_aqconfig_.enable_scheduler));
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Config light_pgm_mode = %.2f\n", _aqconfig_.light_programming_mode);
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Debug RS485 protocol = %s\n", bool2text(_aqconfig_.log_protocol_packets));
|
||||
|
@ -1741,7 +1747,6 @@ void main_loop()
|
|||
|
||||
LOG(AQUA_LOG,LOG_NOTICE, "Starting communication with Control Panel\n");
|
||||
|
||||
|
||||
// Not the best way to do this, but ok for moment
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed == 0)
|
||||
|
@ -1795,11 +1800,18 @@ void main_loop()
|
|||
|
||||
if (packet_length <= 0)
|
||||
{
|
||||
|
||||
// AQSERR_2SMALL // no reset (-5)
|
||||
// AQSERR_2LARGE // no reset (-4)
|
||||
// AQSERR_CHKSUM // no reset (-3)
|
||||
// AQSERR_TIMEOUT // reset blocking mode (-2)
|
||||
// AQSERR_READ // reset (-1)
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0) {
|
||||
#else
|
||||
//if (!_aqconfig_.readahead_b4_write) {
|
||||
if (serial_blockingmode()) {
|
||||
if (serial_blockingmode() && (packet_length == AQSERR_READ || packet_length == AQSERR_TIMEOUT) ) {
|
||||
#endif
|
||||
LOG(AQUA_LOG,LOG_ERR, "Nothing read on blocking serial port\n");
|
||||
blank_read = blank_read_reconnect;
|
||||
|
@ -1957,4 +1969,25 @@ void main_loop()
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
void debugtestePump()
|
||||
{
|
||||
LOG(DJAN_LOG, LOG_INFO, "Jandy Pump code check\n");
|
||||
|
||||
unsigned char toPumpWatts[] = {0x10,0x02,0x78,0x45,0x00,0x05,0xd4,0x10,0x03};
|
||||
unsigned char fromPumpWatts[] = {0x10,0x02,0x00,0x1f,0x45,0x00,0x05,0x1d,0x05,0x9d,0x10,0x03};
|
||||
|
||||
|
||||
unsigned char toPumpRPM[] = {0x10,0x02,0x78,0x44,0x00,0x60,0x27,0x55,0x10,0x03};
|
||||
unsigned char fromPumpRPM[] = {0x10,0x02,0x00,0x1f,0x44,0x00,0x60,0x27,0x00,0xfc,0x10,0x03};
|
||||
|
||||
processJandyPacket(toPumpWatts, 8, &_aqualink_data);
|
||||
processJandyPacket(fromPumpWatts, 11, &_aqualink_data);
|
||||
|
||||
processJandyPacket(toPumpRPM, 8, &_aqualink_data);
|
||||
processJandyPacket(fromPumpRPM, 11, &_aqualink_data);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
|
14
config.c
14
config.c
|
@ -110,7 +110,9 @@ void init_parameters (struct aqconfig * parms)
|
|||
//parms->light_programming_button_pool = TEMP_UNKNOWN;
|
||||
//parms->light_programming_button_spa = TEMP_UNKNOWN;
|
||||
parms->deamonize = true;
|
||||
#ifndef AQ_MANAGER
|
||||
parms->log_file = '\0';
|
||||
#endif
|
||||
#ifdef AQ_PDA
|
||||
parms->pda_sleep_mode = false;
|
||||
#endif
|
||||
|
@ -126,6 +128,7 @@ void init_parameters (struct aqconfig * parms)
|
|||
|
||||
parms->force_swg = false;
|
||||
parms->force_ps_setpoints = false;
|
||||
parms->force_frzprotect_setpoints = false;
|
||||
//parms->swg_pool_and_spa = false;
|
||||
parms->swg_zero_ignore = DEFAULT_SWG_ZERO_IGNORE_COUNT;
|
||||
parms->display_warnings_web = false;
|
||||
|
@ -428,9 +431,11 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
} else if (strncasecmp(param, "web_directory", 13) == 0) {
|
||||
_aqconfig_.web_directory = cleanalloc(value);
|
||||
rtn=true;
|
||||
#ifndef AQ_MANAGER
|
||||
} else if (strncasecmp(param, "log_file", 8) == 0) {
|
||||
_aqconfig_.log_file = cleanalloc(value);
|
||||
rtn=true;
|
||||
#endif
|
||||
} else if (strncasecmp(param, "mqtt_address", 12) == 0) {
|
||||
_aqconfig_.mqtt_server = cleanalloc(value);
|
||||
rtn=true;
|
||||
|
@ -550,6 +555,12 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_PEN_PUMP;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "read_RS485_LXi", 14) == 0) {
|
||||
if (text2bool(value))
|
||||
_aqconfig_.read_RS485_devmask |= READ_RS485_JAN_LXI;
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~READ_RS485_JAN_LXI;
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "use_panel_aux_labels", 20) == 0) {
|
||||
_aqconfig_.use_panel_aux_labels = text2bool(value);
|
||||
rtn=true;
|
||||
|
@ -559,6 +570,9 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) {
|
|||
} else if (strncasecmp (param, "force_ps_setpoints", 18) == 0) {
|
||||
_aqconfig_.force_ps_setpoints = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "force_frzprotect_setpoints", 26) == 0) {
|
||||
_aqconfig_.force_frzprotect_setpoints = text2bool(value);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "debug_RSProtocol_bytes", 22) == 0) {
|
||||
_aqconfig_.log_raw_bytes = text2bool(value);
|
||||
rtn=true;
|
||||
|
|
6
config.h
6
config.h
|
@ -27,6 +27,8 @@
|
|||
#define READ_RS485_SWG (1 << 0) // 1 SWG
|
||||
#define READ_RS485_JAN_PUMP (1 << 1) // 2 Jandy Pump
|
||||
#define READ_RS485_PEN_PUMP (1 << 2) // 4 Pentair Pump
|
||||
#define READ_RS485_JAN_LXI (1 << 3) // Jandy LX & LXi heater
|
||||
//#define READ_RS485_JAN_LXI (1 << 4) // Jandy LXi heater
|
||||
|
||||
struct aqconfig
|
||||
{
|
||||
|
@ -43,7 +45,9 @@ struct aqconfig
|
|||
bool extended_device_id_programming;
|
||||
#endif
|
||||
bool deamonize;
|
||||
#ifndef AQ_MANAGER // Need to uncomment and clean up referances in future.
|
||||
char *log_file;
|
||||
#endif
|
||||
char *mqtt_dz_sub_topic;
|
||||
char *mqtt_dz_pub_topic;
|
||||
char *mqtt_aq_topic;
|
||||
|
@ -74,6 +78,7 @@ struct aqconfig
|
|||
bool use_panel_aux_labels;
|
||||
bool force_swg;
|
||||
bool force_ps_setpoints;
|
||||
bool force_frzprotect_setpoints;
|
||||
int swg_zero_ignore;
|
||||
bool display_warnings_web;
|
||||
bool log_protocol_packets; // Read & Write as packets
|
||||
|
@ -102,6 +107,7 @@ struct aqconfig _aqconfig_;
|
|||
#define READ_RSDEV_SWG ((_aqconfig_.read_RS485_devmask & READ_RS485_SWG) == READ_RS485_SWG)
|
||||
#define READ_RSDEV_ePUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_PUMP) == READ_RS485_JAN_PUMP)
|
||||
#define READ_RSDEV_vsfPUMP ((_aqconfig_.read_RS485_devmask & READ_RS485_PEN_PUMP) == READ_RS485_PEN_PUMP)
|
||||
#define READ_RSDEV_LXI ((_aqconfig_.read_RS485_devmask & READ_RS485_JAN_LXI) == READ_RS485_JAN_LXI)
|
||||
|
||||
//#define isPDA ((_aqconfig_.paneltype_mask & RSP_PDA) == RSP_PDA)
|
||||
|
||||
|
|
182
devices_jandy.c
182
devices_jandy.c
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "devices_jandy.h"
|
||||
#include "aq_serial.h"
|
||||
|
@ -47,7 +48,11 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
}
|
||||
else if (interestedInNextAck == DRS_EPUMP)
|
||||
{
|
||||
rtn = processPacketFromJandyPump(packet_buffer, packet_length, aqdata);
|
||||
rtn = processPacketFromJandyPump(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
else if (interestedInNextAck == DRS_LXI)
|
||||
{
|
||||
rtn = processPacketFromJandyHeater(packet_buffer, packet_length, aqdata, previous_packet_to);
|
||||
}
|
||||
interestedInNextAck = DRS_NONE;
|
||||
previous_packet_to = NUL;
|
||||
|
@ -78,12 +83,25 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
rtn = processPacketToJandyPump(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else if (READ_RSDEV_LXI && ( (packet_buffer[PKT_DEST] >= JANDY_DEC_LX_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LX_MAX)
|
||||
|| (packet_buffer[PKT_DEST] >= JANDY_DEC_LXI_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_LXI_MAX)))
|
||||
{
|
||||
interestedInNextAck = DRS_LXI;
|
||||
rtn = processPacketToJandyHeater(packet_buffer, packet_length, aqdata);
|
||||
previous_packet_to = packet_buffer[PKT_DEST];
|
||||
}
|
||||
else
|
||||
{
|
||||
interestedInNextAck = DRS_NONE;
|
||||
previous_packet_to = NUL;
|
||||
}
|
||||
|
||||
/*
|
||||
if (packet_buffer[PKT_CMD] != CMD_PROBE && getLogLevel(DJAN_LOG) >= LOG_DEBUG) {
|
||||
char msg[1000];
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Jandy : %s\n", msg);
|
||||
}
|
||||
*/
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
@ -188,8 +206,10 @@ bool isSWGDeviceErrorState(unsigned char status)
|
|||
}
|
||||
|
||||
void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, unsigned char status) {
|
||||
if (aqdata->ar_swg_device_status == status)
|
||||
if (aqdata->ar_swg_device_status == status) {
|
||||
//LOG(DJAN_LOG, LOG_DEBUG, "Set SWG device state to '0x%02hhx', request from %d\n", aqdata->ar_swg_device_status, requester);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get (ALLBUTTON, SWG_STATUS_CHECK_PCB), it sends this for many status, like clean cell.
|
||||
// So if we are in one of those states, don't use it.
|
||||
|
@ -197,7 +217,7 @@ void setSWGdeviceStatus(struct aqualinkdata *aqdata, emulation_type requester, u
|
|||
if (requester == ALLBUTTON && status == SWG_STATUS_CHECK_PCB ) {
|
||||
if (aqdata->ar_swg_device_status > SWG_STATUS_ON &&
|
||||
aqdata->ar_swg_device_status < SWG_STATUS_TURNING_OFF) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Ignoreing set SWG device state to '0x%02hhx', request from %d\n", aqdata->ar_swg_device_status, requester);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Ignoring set SWG device state to '0x%02hhx', request from %d\n", aqdata->ar_swg_device_status, requester);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -437,17 +457,45 @@ void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#define EP_HI_B_WAT 8
|
||||
#define EP_LO_B_WAT 7
|
||||
#define EP_HI_B_RPM 7
|
||||
#define EP_LO_B_RPM 6
|
||||
|
||||
bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
char msg[1000];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s\n", msg);
|
||||
/*
|
||||
Set & Sataus Watts. Looks like send to ePump type 0x45, return type 0xf1|0x45
|
||||
JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x1d|0x05|0x9d|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 69| 0| 5| 29| 5|0x9d|0x10|0x03| (Decimal)
|
||||
Type 0x1F and cmd 0x45 is Watts = 5 * (256) + 29 = 1309 or Byte 8 * 265 + Byte 7
|
||||
*/
|
||||
/*
|
||||
Set & Sataus RPM. Looks like send to ePump type 0x44, return type 0xf1|0x44
|
||||
JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 96| 39| 0|0xfc|0x10|0x03| (Decimal)
|
||||
PDA: PDA Menu Line 3 = SET TO 2520 RPM
|
||||
|
||||
Type 0x1F and cmd 0x45 is RPM = 39 * (256) + 96 / 4 = 2520 or Byte 8 * 265 + Byte 7 / 4
|
||||
*/
|
||||
|
||||
// If type 0x45 and 0x44 set to interested in next command.
|
||||
if (packet_buffer[3] == CMD_EPUMP_RPM) {
|
||||
// All we need to do is set we are interested in next packet, but ca lling function already did this.
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "ControlPanel request Pump ID 0x%02hhx set RPM to %d\n",packet_buffer[PKT_DEST], ( (packet_buffer[EP_HI_B_RPM-1] * 256) + packet_buffer[EP_LO_B_RPM-1]) / 4 );
|
||||
} else if (packet_buffer[3] == CMD_EPUMP_WATTS) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "ControlPanel request Pump ID 0x%02hhx get watts\n",packet_buffer[PKT_DEST]);
|
||||
}
|
||||
|
||||
if (getLogLevel(DJAN_LOG) >= LOG_DEBUG) {
|
||||
char msg[1000];
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "To ePump: %s\n", msg);
|
||||
//find pump for message
|
||||
if ( 1 == 0 /*SOME_DEBUG_TEST*/) {
|
||||
int i;
|
||||
for (i=0; i < aqdata->num_pumps; i++) {
|
||||
for (int i=0; i < aqdata->num_pumps; i++) {
|
||||
if (aqdata->pumps[i].pumpID == packet_buffer[PKT_DEST]) {
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "Last panel info RPM:%d GPM:%d WATTS:%d\n", aqdata->pumps[i].rpm, aqdata->pumps[i].gpm, aqdata->pumps[i].watts);
|
||||
break;
|
||||
|
@ -457,26 +505,110 @@ bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, s
|
|||
|
||||
return false;
|
||||
}
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to)
|
||||
{
|
||||
char msg[1000];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s\n", msg);
|
||||
bool found=false;
|
||||
|
||||
if (packet_buffer[3] == CMD_EPUMP_STATUS && packet_buffer[4] == CMD_EPUMP_RPM) {
|
||||
for (int i = 0; i < MAX_PUMPS; i++) {
|
||||
if ( aqdata->pumps[i].prclType == JANDY && aqdata->pumps[i].pumpID == previous_packet_to ) {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Jandy Pump Status message = RPM %d\n",( (packet_buffer[EP_HI_B_RPM] * 256) + packet_buffer[EP_LO_B_RPM]) / 4 );
|
||||
aqdata->pumps[i].rpm = ( (packet_buffer[EP_HI_B_RPM] * 256) + packet_buffer[EP_LO_B_RPM] ) / 4;
|
||||
found=true;
|
||||
}
|
||||
}
|
||||
} else if (packet_buffer[3] == CMD_EPUMP_STATUS && packet_buffer[4] == CMD_EPUMP_WATTS) {
|
||||
for (int i = 0; i < MAX_PUMPS; i++) {
|
||||
if ( aqdata->pumps[i].prclType == JANDY && aqdata->pumps[i].pumpID == previous_packet_to ) {
|
||||
LOG(DJAN_LOG, LOG_INFO, "Jandy Pump Status message = WATTS %d\n", (packet_buffer[EP_HI_B_WAT] * 256) + packet_buffer[EP_LO_B_WAT]);
|
||||
aqdata->pumps[i].watts = (packet_buffer[EP_HI_B_WAT] * 256) + packet_buffer[EP_LO_B_WAT];
|
||||
found=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (packet_buffer[4] == CMD_EPUMP_RPM)
|
||||
LOG(DJAN_LOG, LOG_NOTICE, "Jandy Pump found at ID 0x%02hhx with RPM %d, but not configured, information ignored!\n",previous_packet_to,( (packet_buffer[EP_HI_B_RPM] * 256) + packet_buffer[EP_LO_B_RPM]) / 4 );
|
||||
else if (packet_buffer[4] == CMD_EPUMP_WATTS)
|
||||
LOG(DJAN_LOG, LOG_NOTICE, "Jandy Pump found at ID 0x%02hhx with WATTS %d, but not configured, information ignored!\n",previous_packet_to, (packet_buffer[EP_HI_B_WAT] * 256) + packet_buffer[EP_LO_B_WAT]);
|
||||
}
|
||||
|
||||
if (getLogLevel(DJAN_LOG) >= LOG_DEBUG) {
|
||||
char msg[1000];
|
||||
//logMessage(LOG_DEBUG, "Need to log ePump message here for future\n");
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_DEBUG, "From ePump: %s\n", msg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqualinkdata *aqdata)
|
||||
{
|
||||
// Do nothing for the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Messages to ePump so far.
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x42|0xcc|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x44|0x00|0x10|0x27|0x05|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x44|0x00|0x58|0x1b|0x41|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x46|0x00|0x00|0x03|0xd3|0x10|0x03|
|
||||
Debug: To ePump: Jandy Packet | HEX: 0x10|0x02|0x78|0x46|0x00|0x04|0x00|0xd4|0x10|0x03|
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool processPacketToJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
char msg[1000];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "To Heater: %s\n", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
for (int i=0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0) {
|
||||
length += sprintf(msg+length, ", Pool Heat LED=%d ",aqdata->aqbuttons[i].led->state);
|
||||
}
|
||||
if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name) == 0) {
|
||||
length += sprintf(msg+length, ", Spa Heat LED=%d ",aqdata->aqbuttons[i].led->state);
|
||||
}
|
||||
}
|
||||
|
||||
length += sprintf(msg+length, ", Pool SP=%d, Spa SP=%d",aqdata->pool_htr_set_point, aqdata->spa_htr_set_point);
|
||||
length += sprintf(msg+length, ", Pool temp=%d, Spa temp=%d",aqdata->pool_temp, aqdata->spa_temp);
|
||||
|
||||
LOG(DJAN_LOG, LOG_INFO, "%s\n", msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool processPacketFromJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to)
|
||||
{
|
||||
char msg[1000];
|
||||
int length = 0;
|
||||
|
||||
beautifyPacket(msg, packet_buffer, packet_length, true);
|
||||
LOG(DJAN_LOG, LOG_INFO, "From Heater: %s\n", msg);
|
||||
|
||||
length += sprintf(msg+length, "Last panel info ");
|
||||
|
||||
for (int i=0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if ( strcmp(BTN_POOL_HTR,aqdata->aqbuttons[i].name) == 0) {
|
||||
length += sprintf(msg+length, ", Pool Heat LED=%d ",aqdata->aqbuttons[i].led->state);
|
||||
}
|
||||
if ( strcmp(BTN_SPA_HTR,aqdata->aqbuttons[i].name) == 0) {
|
||||
length += sprintf(msg+length, ", Spa Heat LED=%d ",aqdata->aqbuttons[i].led->state);
|
||||
}
|
||||
}
|
||||
|
||||
length += sprintf(msg+length, ", Pool SP=%d, Spa SP=%d",aqdata->pool_htr_set_point, aqdata->spa_htr_set_point);
|
||||
length += sprintf(msg+length, ", Pool temp=%d, Spa temp=%d",aqdata->pool_temp, aqdata->spa_temp);
|
||||
|
||||
LOG(DJAN_LOG, LOG_INFO, "%s\n", msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,10 +10,13 @@ bool processJandyPacket(unsigned char *packet_buffer, int packet_length, struct
|
|||
bool processPacketToSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata, int swg_zero_ignore);
|
||||
bool processPacketFromSWG(unsigned char *packet, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketToJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
bool processPacketFromJandyPump(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to);
|
||||
void processMissingAckPacketFromSWG(unsigned char destination, struct aqualinkdata *aqdata);
|
||||
void processMissingAckPacketFromJandyPump(unsigned char destination, struct aqualinkdata *aqdata);
|
||||
|
||||
bool processPacketFromJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to );
|
||||
bool processPacketToJandyHeater(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata);
|
||||
|
||||
void get_swg_status_mqtt(struct aqualinkdata *aqdata, char *message, int *status, int *dzalert);
|
||||
aqledstate get_swg_led_state(struct aqualinkdata *aqdata);
|
||||
|
||||
|
|
35
epump.h
35
epump.h
|
@ -15,6 +15,41 @@ Nothing seems to change these, need real pump to test
|
|||
0x10|0x02|0x7a|0x41|0xcd|0x10|0x03|
|
||||
|
||||
|
||||
----------------
|
||||
|
||||
Set & Sataus WATTS. Looks like send to ePump type 0x45, return type 0xf1|0x45
|
||||
|
||||
JandyDvce: To ePump: Read To 0x78 of type Unknown '0x45' | HEX: 0x10|0x02|0x78|0x45|0x00|0x05|0xd4|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x45|0x00|0x05|0x1d|0x05|0x9d|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 69| 0| 5| 29| 5|0x9d|0x10|0x03|
|
||||
Jun-24-23 08:30:53 AM Debug: PDA: PDA Menu Line 4 = WATTS: 1309
|
||||
|
||||
Type 0x1f (command 0x45 or 69)
|
||||
Watts = 5 * (256) + 29 = 1309 or Byte 8 * 265 + Byte 7
|
||||
|
||||
----------------
|
||||
|
||||
Set & Sataus RPM. Looks like send to ePump type 0x44, return type 0xf1|0x44
|
||||
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0xe8|0x35|0x00|0x92|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 232| 53| 0|0x92|0x10|0x03|
|
||||
PDA Menu Line 3 = SET TO 3450 RPM
|
||||
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x50|0x2d|0x00|0xf2|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 80| 45| 0|0xf2|0x10|0x03|
|
||||
PDA: PDA Menu Line 3 = SET TO 2900 RPM
|
||||
|
||||
JandyDvce: To ePump: Read To 0x78 of type Unknown '0x44' | HEX: 0x10|0x02|0x78|0x44|0x00|0x60|0x27|0x55|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f|0x44|0x00|0x60|0x27|0x00|0xfc|0x10|0x03|
|
||||
JandyDvce: From ePump: Read To 0x00 of type Unknown '0x1f' | HEX: 0x10|0x02|0x00|0x1f| 68| 0| 96| 39| 0|0xfc|0x10|0x03|
|
||||
PDA: PDA Menu Line 3 = SET TO 2520 RPM
|
||||
|
||||
Type 0x1F and cmd 0x44 is RPM = 39 * (256) + 96 / 4 = 2520 or Byte 7 * 265 + Byte 6 / 4
|
||||
|
||||
Other commands on 0x1f are 67 & 68 (0x43 )
|
||||
|
||||
|
||||
|
||||
|
||||
Some form of ping for being alive
|
||||
Jun-23-23 17:41:00 PM Debug: JandyDvce: To ePump: Read To 0x78 of type Unknown '0x41' | HEX: 0x10|0x02|0x78|0x41|0xcb|0x10|0x03|
|
||||
|
|
|
@ -62,8 +62,10 @@ int json_chars(char *dest, const char *src, int dest_len, int src_len)
|
|||
}
|
||||
|
||||
i--;
|
||||
/* // Don't delete trailing whitespace
|
||||
while (dest[i] == ' ')
|
||||
i--;
|
||||
*/
|
||||
|
||||
if (dest[i] != '\0') {
|
||||
if (i < (dest_len-1))
|
||||
|
@ -71,7 +73,7 @@ int json_chars(char *dest, const char *src, int dest_len, int src_len)
|
|||
|
||||
dest[i] = '\0';
|
||||
}
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -268,7 +270,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
int i;
|
||||
|
||||
// IF temp units are F assume homekit is using F
|
||||
bool homekit_f = (homekit && aqdata->temp_units==FAHRENHEIT);
|
||||
bool homekit_f = (homekit && ( aqdata->temp_units==FAHRENHEIT || aqdata->temp_units == UNKNOWN) );
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"devices\"");
|
||||
length += sprintf(buffer+length, ",\"date\":\"%s\"",aqdata->date );//"09/01/16 THU",
|
||||
|
@ -351,7 +353,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
}*/
|
||||
}
|
||||
|
||||
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) {
|
||||
if ( _aqconfig_.force_frzprotect_setpoints || (aqdata->frz_protect_set_point != TEMP_UNKNOWN && aqdata->air_temp != TEMP_UNKNOWN) ) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"setpoint_freeze\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"spvalue\": \"%.*f\", \"value\": \"%.*f\", \"int_status\": \"%d\" },",
|
||||
FREEZE_PROTECT,
|
||||
"Freeze Protection",
|
||||
|
@ -390,6 +392,7 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
((homekit_f)?2:0),
|
||||
((homekit_f)?degFtoC(aqdata->swg_percent):aqdata->swg_percent));
|
||||
//if (!homekit) { // For the moment keep boost off homekit
|
||||
|
||||
length += sprintf(buffer+length, "{\"type\": \"switch\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\"},",
|
||||
SWG_BOOST_TOPIC,
|
||||
"SWG Boost",
|
||||
|
@ -624,8 +627,9 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", SWG_BOOST_TOPIC, aqdata->boost?JSON_ON:JSON_OFF);
|
||||
}
|
||||
//NSF Need to come back and read what the display states when Freeze protection is on
|
||||
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN ) {
|
||||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, aqdata->frz_protect_state==ON?JSON_ON:JSON_ENABLED);
|
||||
if ( aqdata->frz_protect_set_point != TEMP_UNKNOWN || _aqconfig_.force_frzprotect_setpoints ) {
|
||||
//length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, aqdata->frz_protect_state==ON?JSON_ON:JSON_ENABLED);
|
||||
length += sprintf(buffer+length, ", \"%s\": \"%s\"", FREEZE_PROTECT, LED2text(aqdata->frz_protect_state) );
|
||||
}
|
||||
|
||||
//length += sprintf(buffer+length, "}, \"extra\":{" );
|
||||
|
|
188
net_services.c
188
net_services.c
|
@ -155,6 +155,41 @@ void ws_send_logmsg(struct mg_connection *nc, char *msg) {
|
|||
}
|
||||
}
|
||||
|
||||
sd_journal *open_journal() {
|
||||
sd_journal *journal;
|
||||
char filter[51];
|
||||
|
||||
if (sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY) < 0)
|
||||
{
|
||||
LOGSystemError(errno, NET_LOG, "Failed to open journal");
|
||||
return journal;
|
||||
}
|
||||
snprintf(filter, 50, "SYSLOG_IDENTIFIER=%s",_aqualink_data->self );
|
||||
if (sd_journal_add_match(journal, filter, 0) < 0)
|
||||
{
|
||||
LOGSystemError(errno, NET_LOG, "Failed to set journal syslog filter");
|
||||
sd_journal_close(journal);
|
||||
return journal;
|
||||
}
|
||||
// Daemon will change PID after printing startup message, so don't filter on current PID
|
||||
if (_aqconfig_.deamonize != true) {
|
||||
snprintf(filter, 50, "_PID=%d",getpid());
|
||||
if (sd_journal_add_match(journal, filter, 0) < 0)
|
||||
{
|
||||
LOGSystemError(errno, NET_LOG, "Failed to set journal pid filter");
|
||||
sd_journal_close(journal);
|
||||
return journal;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd_journal_set_data_threshold(journal, LOGBUFFER) < 0)
|
||||
{
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to set journal message size\n");
|
||||
}
|
||||
|
||||
return journal;
|
||||
}
|
||||
|
||||
void find_aqualinkd_startupmsg(sd_journal *journal)
|
||||
{
|
||||
static bool once=false;
|
||||
|
@ -184,14 +219,26 @@ void find_aqualinkd_startupmsg(sd_journal *journal)
|
|||
sd_journal_previous_skip(journal, 100);
|
||||
}
|
||||
|
||||
#define BLANK_JOURNAL_READ_RESET 100
|
||||
|
||||
bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection);
|
||||
|
||||
bool broadcast_systemd_logmessages(bool aqMgrActive) {
|
||||
return _broadcast_systemd_logmessages(aqMgrActive, false);
|
||||
}
|
||||
|
||||
bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection) {
|
||||
static sd_journal *journal;
|
||||
static bool active = false;
|
||||
char msg[WS_LOG_LENGTH];
|
||||
static int cnt=0;
|
||||
static char *cursor = NULL;
|
||||
char filter[51];
|
||||
//char filter[51];
|
||||
|
||||
if (reOpenStaleConnection) {
|
||||
sd_journal_close(journal);
|
||||
active = false;
|
||||
}
|
||||
if (!aqMgrActive) {
|
||||
if (!active) {
|
||||
return true;
|
||||
|
@ -204,25 +251,11 @@ bool broadcast_systemd_logmessages(bool aqMgrActive) {
|
|||
}
|
||||
// aqManager is active
|
||||
if (!active) {
|
||||
if ( sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY) < 0) {
|
||||
if ( (journal = open_journal()) < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to open journal", WS_LOG_LENGTH,22);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
return false;
|
||||
}
|
||||
snprintf(filter, 50, "SYSLOG_IDENTIFIER=%s",_aqualink_data->self );
|
||||
if (sd_journal_add_match(journal, "SYSLOG_IDENTIFIER=aqualinkd", 0) < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to set journal syslog filter", WS_LOG_LENGTH,35);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
sd_journal_close(journal);
|
||||
return false;
|
||||
}
|
||||
snprintf(filter, 50, "_PID=%d",getpid());
|
||||
if (sd_journal_add_match(journal, filter, 0) < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to set journal PID filter", WS_LOG_LENGTH,32);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
sd_journal_close(journal);
|
||||
return false;
|
||||
}
|
||||
if (sd_journal_seek_tail(journal) < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to seek to journal end", WS_LOG_LENGTH,29);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
|
@ -268,17 +301,26 @@ bool broadcast_systemd_logmessages(bool aqMgrActive) {
|
|||
} else if (rtn == 0) {
|
||||
// Sometimes we get no errors, and nothing to read, even when their is.
|
||||
// So if we get too many, restart but don;t reset the cursor.
|
||||
// Could tesd moving sd_journal_get_cursor(journal, &cursor); line to here from above.
|
||||
if (cnt++ == 100) {
|
||||
//printf("**** %d Too many blank reads, resetting!! ****\n",cnt);
|
||||
sd_journal_close(journal);
|
||||
active = false;
|
||||
// Could test moving sd_journal_get_cursor(journal, &cursor); line to here from above.
|
||||
|
||||
// Quick way to times blank reads by log level, since less logs written higher number of blank reads
|
||||
if ( cnt++ >= BLANK_JOURNAL_READ_RESET * ( (LOG_DEBUG_SERIAL+1) - getSystemLogLevel() ) ) {
|
||||
/* Stale connection, call ourselves to reopen*/
|
||||
if (!reOpenStaleConnection) {
|
||||
//LOG(NET_LOG, LOG_WARNING, "**** %d Too many blank reads, resetting!! ****\n",cnt);
|
||||
return _broadcast_systemd_logmessages(aqMgrActive, true);
|
||||
}
|
||||
//LOG(NET_LOG, LOG_WARNING, "**** Reset didn't work ****\n",cnt);
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define USEC_PER_SEC 1000000L
|
||||
|
||||
bool write_systemd_logmessages_2file(char *fname, int lines)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
|
@ -287,35 +329,21 @@ bool write_systemd_logmessages_2file(char *fname, int lines)
|
|||
size_t len;
|
||||
const void *pri;
|
||||
size_t plen;
|
||||
char filter[51];
|
||||
char tsbuffer[20];
|
||||
uint64_t realtime;
|
||||
struct tm tm;
|
||||
time_t sec;
|
||||
|
||||
|
||||
fp = fopen (fname, "w");
|
||||
if (fp == NULL) {
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to open tmp log file '%s'\n",fname);
|
||||
return false;
|
||||
}
|
||||
if (sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY) < 0)
|
||||
{
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to open journal");
|
||||
if ( (journal = open_journal()) < 0) {
|
||||
fclose (fp);
|
||||
return false;
|
||||
}
|
||||
snprintf(filter, 50, "SYSLOG_IDENTIFIER=%s",_aqualink_data->self );
|
||||
if (sd_journal_add_match(journal, "SYSLOG_IDENTIFIER=aqualinkd", 0) < 0)
|
||||
{
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to set journal syslog filter");
|
||||
fclose (fp);
|
||||
sd_journal_close(journal);
|
||||
return false;
|
||||
}
|
||||
snprintf(filter, 50, "_PID=%d",getpid());
|
||||
if (sd_journal_add_match(journal, filter, 0) < 0)
|
||||
{
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to set journal pid filter");
|
||||
fclose (fp);
|
||||
sd_journal_close(journal);
|
||||
return false;
|
||||
}
|
||||
if (sd_journal_seek_tail(journal) < 0)
|
||||
{
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to seek to journal end");
|
||||
|
@ -336,9 +364,14 @@ bool write_systemd_logmessages_2file(char *fname, int lines)
|
|||
if (sd_journal_get_data(journal, "MESSAGE", &log, &len) < 0) {
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to get journal message");
|
||||
} else if (sd_journal_get_data(journal, "PRIORITY", &pri, &plen) < 0) {
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to seek to journal message priority");
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to get journal message priority");
|
||||
} else if (sd_journal_get_realtime_usec(journal, &realtime) < 0) {
|
||||
LOG(NET_LOG, LOG_WARNING, "Failed to get journal message timestamp");
|
||||
} else {
|
||||
fprintf(fp, "%-7s %.*s\n",elevel2text(atoi((const char *)pri+9)), (int)len-8,(const char *)log+8);
|
||||
sec = (time_t)(realtime/USEC_PER_SEC);
|
||||
localtime_r(&sec, &tm);
|
||||
strftime(tsbuffer, sizeof(tsbuffer), "%b %d %T", &tm); // need to capture return of this
|
||||
fprintf(fp, "%-15s %-7s %.*s\n",tsbuffer,elevel2text(atoi((const char *)pri+9)), (int)len-8,(const char *)log+8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,61 +383,6 @@ bool write_systemd_logmessages_2file(char *fname, int lines)
|
|||
|
||||
#endif
|
||||
|
||||
/* superseded with systemd/sd-journal
|
||||
#define MAX_LOGSTACK 30
|
||||
#define WS_LOG_LENGTH 200
|
||||
char _logstack[MAX_LOGSTACK][WS_LOG_LENGTH];
|
||||
int _logstack_place=0;
|
||||
pthread_mutex_t logmsg_mutex;
|
||||
|
||||
void send_ws_logmessages()
|
||||
{
|
||||
pthread_mutex_lock(&logmsg_mutex);
|
||||
// This pulls them off in the wrong order.
|
||||
while (_logstack_place > 0) {
|
||||
ws_send_logmsg(_mgr.active_connections, _logstack[0]);
|
||||
memmove(&_logstack[0], &_logstack[1], WS_LOG_LENGTH * _logstack_place ) ;
|
||||
_logstack_place--;
|
||||
}
|
||||
pthread_mutex_unlock(&logmsg_mutex);
|
||||
}
|
||||
|
||||
void broadcast_log(char *msg) {
|
||||
// NSF This causes mongoose to core dump after a period of time due to number of messages
|
||||
// so remove until get time to update to new mongoose version.
|
||||
//return;
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_keepNetServicesRunning && !_aqconfig_.thread_netservices && _aqualink_data != NULL && _aqualink_data->aqManagerActive)
|
||||
{
|
||||
char message[WS_LOG_LENGTH];
|
||||
build_logmsg_JSON(message, msg, WS_LOG_LENGTH, strlen(msg));
|
||||
_ws_send_logmsg(_mgr.active_connections , message);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// See if we have and manager runnig first so we return ASAP.
|
||||
// Since this get's called long before net_Services is started, also check we are running.
|
||||
if (_keepNetServicesRunning && _net_thread_id != 0 && _aqualink_data != NULL && _aqualink_data->aqManagerActive)
|
||||
{
|
||||
pthread_mutex_lock(&logmsg_mutex);
|
||||
if (_logstack_place < MAX_LOGSTACK)
|
||||
{
|
||||
//printf("**** Add message %s\n",msg);
|
||||
// This need mutex lock on _logstack
|
||||
build_logmsg_JSON(_logstack[_logstack_place++], msg, WS_LOG_LENGTH, strlen(msg) );
|
||||
} else {
|
||||
// Need to figure this out, can't send error message as that will put us in a infinate loop.
|
||||
fprintf(stderr, "*** ERROR Log queue full ***\n");
|
||||
// Use the last message to let UI know
|
||||
build_logmsg_JSON(_logstack[MAX_LOGSTACK-1], "Error: *** Logs truncated, see server to complete list of message ***\n", LOGBUFFER, strlen(msg) );
|
||||
}
|
||||
pthread_mutex_unlock(&logmsg_mutex);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void _broadcast_aqualinkstate(struct mg_connection *nc)
|
||||
{
|
||||
static int mqtt_count=0;
|
||||
|
@ -997,7 +975,7 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
} else if (strncmp(ri1, "removelogmask", 13) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
removeDebugLogMask(round(value));
|
||||
return uAQmanager; // Want to resent updated status
|
||||
} else if (strncmp(ri1, "log2file", 5) == 0) {
|
||||
} else if (strncmp(ri1, "logfile", 7) == 0) {
|
||||
/*
|
||||
if (ri2 != NULL && strncmp(ri2, "start", 5) == 0) {
|
||||
startInlineLog2File();
|
||||
|
@ -1485,8 +1463,16 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
break;
|
||||
#else
|
||||
case uLogDownload:
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading log of max %d lines\n",value>0?(int)value:1000);
|
||||
if (write_systemd_logmessages_2file("/dev/shm/aqualinkd.log", value>0?(int)value:1000) ) {
|
||||
//int lines = 1000;
|
||||
#define DEFAULT_LOG_DOWNLOAD_LINES 100
|
||||
// If lines was passed in post use it, if not see if it's next path in URI is a number
|
||||
if (value == 0.0) {
|
||||
// /api/<downloadmsg>/<lines>
|
||||
char *pt = rsm_lastindexof(buf, "/", strlen(buf));
|
||||
value = atoi(pt+1);
|
||||
}
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading log of max %d lines\n",value>0?(int)value:DEFAULT_LOG_DOWNLOAD_LINES);
|
||||
if (write_systemd_logmessages_2file("/dev/shm/aqualinkd.log", value>0?(int)value:DEFAULT_LOG_DOWNLOAD_LINES) ) {
|
||||
mg_http_serve_file(nc, http_msg, "/dev/shm/aqualinkd.log", mg_mk_str("text/plain"), mg_mk_str("Content-Disposition: attachment; filename=\"aqualinkd.log\""));
|
||||
remove("/dev/shm/aqualinkd.log");
|
||||
}
|
||||
|
|
24
onetouch.c
24
onetouch.c
|
@ -56,16 +56,16 @@ void print_onetouch_menu()
|
|||
int i;
|
||||
for (i=0; i < ONETOUCH_LINES; i++) {
|
||||
//printf("PDA Line %d = %s\n",i,_menu[i]);
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu Line %d = %s\n",i,_menu[i]);
|
||||
LOG(ONET_LOG,LOG_INFO, "Menu Line %d = %s\n",i,_menu[i]);
|
||||
}
|
||||
|
||||
if (_ot_hlightcharindexstart > -1) {
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
|
||||
LOG(ONET_LOG,LOG_INFO, "Menu highlighted line = %d, '%s' hligh-char(s) '%.*s'\n",
|
||||
_ot_hlightindex,_menu[_ot_hlightindex],
|
||||
(_ot_hlightcharindexstop - _ot_hlightcharindexstart + 1),
|
||||
&_menu[_ot_hlightindex][_ot_hlightcharindexstart]);
|
||||
} else if (_ot_hlightindex > -1) {
|
||||
LOG(ONET_LOG,LOG_INFO, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
LOG(ONET_LOG,LOG_INFO, "Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ bool process_onetouch_menu_packet(struct aqualinkdata *aq_data, unsigned char* p
|
|||
_ot_hlightcharindexstart = -1;
|
||||
_ot_hlightcharindexstart = -1;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
LOG(ONET_LOG,LOG_DEBUG, "Menu highlighted line = %d = %s\n",_ot_hlightindex,_menu[_ot_hlightindex]);
|
||||
//if (getLogLevel() >= LOG_DEBUG){print_onetouch_menu();}
|
||||
break;
|
||||
case CMD_PDA_HIGHLIGHTCHARS:
|
||||
|
@ -195,7 +195,7 @@ bool process_onetouch_menu_packet(struct aqualinkdata *aq_data, unsigned char* p
|
|||
_ot_hlightcharindexstart = -1;
|
||||
_ot_hlightcharindexstart = -1;
|
||||
}
|
||||
LOG(ONET_LOG,LOG_DEBUG, "OneTouch Menu highlighted line = %d, '%s' chars '%.*s'\n",
|
||||
LOG(ONET_LOG,LOG_DEBUG, "Menu highlighted line = %d, '%s' chars '%.*s'\n",
|
||||
_ot_hlightindex,
|
||||
_menu[_ot_hlightindex],
|
||||
(_ot_hlightcharindexstop - _ot_hlightcharindexstart) + 1,
|
||||
|
@ -368,7 +368,7 @@ bool get_pumpinfo_from_menu_OLD(struct aqualinkdata *aq_data, int menuLineIdx)
|
|||
rpm = PUMP_ERROR;
|
||||
}
|
||||
|
||||
LOG(ONET_LOG, LOG_DEBUG, "Found OneTouch Pump '%s', Index %d, RPM %d, Watts %d, GPM %d\n", _menu[menuLineIdx], pump_index, rpm, watts, gpm);
|
||||
LOG(ONET_LOG, LOG_DEBUG, "Found Pump '%s', Index %d, RPM %d, Watts %d, GPM %d\n", _menu[menuLineIdx], pump_index, rpm, watts, gpm);
|
||||
|
||||
for (int i = 0; i < aq_data->num_pumps; i++)
|
||||
{
|
||||
|
@ -381,7 +381,7 @@ bool get_pumpinfo_from_menu_OLD(struct aqualinkdata *aq_data, int menuLineIdx)
|
|||
aq_data->pumps[i].watts = watts;
|
||||
aq_data->pumps[i].gpm = gpm;
|
||||
// LOG(ONET_LOG,LOG_INFO, "Matched OneTouch Pump to Index %d, RPM %d, Watts %d, GPM %d\n",i,rpm,watts,gpm);
|
||||
LOG(ONET_LOG, LOG_INFO, "Matched OneTouch Pump to '%s', Index %d, RPM %d, Watts %d, GPM %d\n", aq_data->pumps[i].button->name, i, rpm, watts, gpm);
|
||||
LOG(ONET_LOG, LOG_INFO, "Matched Pump to '%s', Index %d, RPM %d, Watts %d, GPM %d\n", aq_data->pumps[i].button->name, i, rpm, watts, gpm);
|
||||
if (aq_data->pumps[i].pumpType == PT_UNKNOWN)
|
||||
{
|
||||
if (rsm_strcmp(_menu[2], "Intelliflo VS") == 0)
|
||||
|
@ -392,7 +392,7 @@ bool get_pumpinfo_from_menu_OLD(struct aqualinkdata *aq_data, int menuLineIdx)
|
|||
rsm_strcmp(_menu[2], "ePump AC") == 0)
|
||||
aq_data->pumps[i].pumpType = EPUMP;
|
||||
|
||||
LOG(ONET_LOG, LOG_INFO, "OneTouch Pump index %d set PumpType to %d\n", i, aq_data->pumps[i].pumpType);
|
||||
LOG(ONET_LOG, LOG_INFO, "Pump index %d set PumpType to %d\n", i, aq_data->pumps[i].pumpType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ bool get_pumpinfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx, int p
|
|||
return true;
|
||||
}
|
||||
}
|
||||
LOG(ONET_LOG,LOG_WARNING, "PDA Could not find config for Pump %s, Number %d, RPM %d, Watts %d, GPM %d\n",_menu[menuLineIdx],pump_number,rpm,watts,gpm);
|
||||
LOG(ONET_LOG,LOG_WARNING, "Could not find config for Pump %s, Number %d, RPM %d, Watts %d, GPM %d\n",_menu[menuLineIdx],pump_number,rpm,watts,gpm);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ bool get_chemlinkinfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx)
|
|||
int orp = atoi(&_menu[menuLineIdx + 1][4]);
|
||||
char *indx = strchr(_menu[menuLineIdx + 1], '/');
|
||||
float ph = atof(indx + 3);
|
||||
LOG(ONET_LOG, LOG_INFO, "OneTouch Cemlink ORP = %d PH = %f\n", orp, ph);
|
||||
LOG(ONET_LOG, LOG_INFO, "Cemlink ORP = %d PH = %f\n", orp, ph);
|
||||
if (aq_data->ph != ph || aq_data->orp != orp)
|
||||
{
|
||||
aq_data->ph = ph;
|
||||
|
@ -517,7 +517,7 @@ bool get_aquapureinfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx)
|
|||
aq_data->swg_ppm = ppm;
|
||||
rtn = true;
|
||||
}
|
||||
LOG(ONET_LOG, LOG_INFO, "OneTouch Aquapure SWG %d%, %d PPM\n", swgp, ppm);
|
||||
LOG(ONET_LOG, LOG_INFO, "Aquapure SWG %d%, %d PPM\n", swgp, ppm);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -533,7 +533,7 @@ bool get_RS16buttoninfo_from_menu(struct aqualinkdata *aq_data, int menuLineIdx)
|
|||
if (rsm_strcmp(_menu[menuLineIdx], aq_data->aqbuttons[i].label) == 0)
|
||||
{
|
||||
// Matched must be on.
|
||||
LOG(ONET_LOG, LOG_INFO, "OneTouch RS16 equiptment status '%s' matched '%s'\n", _menu[menuLineIdx], aq_data->aqbuttons[i].label);
|
||||
LOG(ONET_LOG, LOG_INFO, "RS16 equiptment status '%s' matched '%s'\n", _menu[menuLineIdx], aq_data->aqbuttons[i].label);
|
||||
rs16led_update(aq_data, i);
|
||||
aq_data->aqbuttons[i].led->state = ON;
|
||||
return true;
|
||||
|
|
Binary file not shown.
|
@ -161,6 +161,10 @@ force_SWG = no
|
|||
# heaters to be listed as thermostats vs switches on startup, helps with homekit.
|
||||
force_PS_setpoints = no
|
||||
|
||||
# AqualinkD can take sime time to find freeze protect (if panel supports it), This will force the freeze protect
|
||||
# to be listed as thermostat on startup.
|
||||
force_Frzprotect_setpoints = no
|
||||
|
||||
# Lights can be programmed by control panel or AqualinkD (if controlpanel doesn;t support specific light or light mode you want)
|
||||
# IF YOU WANT AQUALINKD TO PROGRAM THE LIGHT, IT MUST NOT BE CONFIGURED AS A COLOR LIGHT IN THE JANDY CONTROL PANEL.
|
||||
# Light probramming mode. 0=safe mode, but slow.
|
||||
|
|
Binary file not shown.
|
@ -196,6 +196,28 @@ int rsm_strcmp(const char *haystack, const char *needle)
|
|||
return strncasecmp(sp1, sp2, strlen(sp2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find last index of char in string.
|
||||
* char *sp;
|
||||
* sp = rsm_lastindexof("/api/crap/something/100", "/", 23);
|
||||
* printf("Next char after '/' = %c\n",*sp+1);
|
||||
* printf("Next string after '/' = %s\n",sp+1);
|
||||
*/
|
||||
|
||||
char *rsm_lastindexof(const char *haystack, const char *needle, size_t length)
|
||||
{
|
||||
char *ep = (char *)haystack + length;
|
||||
|
||||
for ( ; ep != (char *)haystack; ep--) {
|
||||
if ( *ep == *needle) {
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ char *rsm_strstr(const char *haystack, const char *needle);
|
|||
//char *rsm_strnstr(const char *haystack, const char *needle, int length);
|
||||
char *rsm_strnstr(const char *haystack, const char *needle, size_t slen);
|
||||
char *rsm_strncasestr(const char *haystack, const char *needle, size_t length);
|
||||
char *rsm_lastindexof(const char *haystack, const char *needle, size_t 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);
|
||||
|
|
|
@ -110,13 +110,14 @@ int serial_logger (int rs_fd, char *port_name, int logLevel) {
|
|||
#define KEYPAD " <-- RS Keypad"
|
||||
#define SPA_R " <-- Spa remote"
|
||||
#define AQUA " <-- Aqualink (iAqualink / Touch)"
|
||||
#define HEATER " <-- LX Heater"
|
||||
#define LX_HEATER " <-- LX Heater"
|
||||
#define ONE_T " <-- Onetouch device"
|
||||
#define RS_SERL " <-- RS Serial Adapter"
|
||||
#define PC_DOCK " <-- PC Interface (RS485 to RS232)"
|
||||
#define PDA " <-- PDA Remote"
|
||||
#define EPUMP " <-- Jandy VSP ePump"
|
||||
#define CHEM " <-- Chemlink"
|
||||
#define LXI_LRZ_HEATER " <-- LXi / LRZ Heater"
|
||||
|
||||
#define UNKNOWN " <-- Unknown Device"
|
||||
|
||||
|
@ -140,7 +141,7 @@ const char *getDevice(unsigned char ID) {
|
|||
if (ID >= 0x30 && ID <= 0x33)
|
||||
return AQUA;
|
||||
if (ID >= 0x38 && ID <= 0x3B)
|
||||
return HEATER;
|
||||
return LX_HEATER;
|
||||
if (ID >= 0x40 && ID <= 0x43)
|
||||
return ONE_T;
|
||||
if (ID >= 0x48 && ID <= 0x4B)
|
||||
|
@ -149,6 +150,8 @@ const char *getDevice(unsigned char ID) {
|
|||
return PC_DOCK;
|
||||
if (ID >= 0x60 && ID <= 0x63)
|
||||
return PDA;
|
||||
if (ID >= 0x68 && ID <= 0x6B)
|
||||
return LXI_LRZ_HEATER;
|
||||
//if (ID >= 0x70 && ID <= 0x73)
|
||||
if (ID >= 0x78 && ID <= 0x7B)
|
||||
return EPUMP;
|
||||
|
@ -422,7 +425,11 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
setLoggingPrms(logLevel, false, NULL);
|
||||
#else
|
||||
setLoggingPrms(logLevel, false, false, NULL);
|
||||
#endif
|
||||
|
||||
if (_playback_file) {
|
||||
rs_fd = open(argv[1], O_RDONLY | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
|
|
48
utils.c
48
utils.c
|
@ -54,20 +54,29 @@ void broadcast_log(char *msg);
|
|||
|
||||
static bool _daemonise = false;
|
||||
|
||||
#ifndef AD_MANAGER
|
||||
#ifndef AQ_MANAGER
|
||||
static bool _log2file = false;
|
||||
//static int _log_level = LOG_ERR;
|
||||
static int _log_level = LOG_WARNING;
|
||||
static char *_log_filename = NULL;
|
||||
static bool _cfg_log2file;
|
||||
static int _cfg_log_level;
|
||||
#endif
|
||||
static int _log_level = LOG_WARNING;
|
||||
|
||||
static char *_loq_display_message = NULL;
|
||||
int16_t _logforcemask = 0;
|
||||
|
||||
//static char _log_filename[256];
|
||||
|
||||
#ifdef AQ_MANAGER
|
||||
void setLoggingPrms(int level , bool deamonized, char *error_messages)
|
||||
{
|
||||
_log_level = level;
|
||||
_daemonise = deamonized;
|
||||
_loq_display_message = error_messages;
|
||||
|
||||
//_cfg_log_level = _log_level;
|
||||
}
|
||||
#else
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages)
|
||||
{
|
||||
_log_level = level;
|
||||
|
@ -85,6 +94,7 @@ void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_mes
|
|||
//strcpy(_log_filename, log_file);
|
||||
}
|
||||
}
|
||||
#endif // AQ_MANAGER
|
||||
|
||||
void setSystemLogLevel( int level)
|
||||
{
|
||||
|
@ -174,10 +184,9 @@ bool islogFileReady()
|
|||
|
||||
|
||||
/*
|
||||
* This function reports the error and
|
||||
* exits back to the shell:
|
||||
* This function reports the last error
|
||||
*/
|
||||
void displayLastSystemError (const char *on_what)
|
||||
void LOGSystemError (int errnum, int16_t from, const char *on_what)
|
||||
{
|
||||
fputs (strerror (errno), stderr);
|
||||
fputs (": ", stderr);
|
||||
|
@ -187,10 +196,27 @@ void displayLastSystemError (const char *on_what)
|
|||
if (_daemonise == TRUE)
|
||||
{
|
||||
//logMessage (LOG_ERR, "%d : %s", errno, on_what);
|
||||
LOG(AQUA_LOG, LOG_ERR, "%d : %s", errno, on_what);
|
||||
LOG(AQUA_LOG, LOG_ERR, "%s (%d) : %s\n", strerror (errno), errno, on_what);
|
||||
closelog ();
|
||||
}
|
||||
}
|
||||
void displayLastSystemError (const char *on_what)
|
||||
{
|
||||
LOGSystemError(errno, AQUA_LOG, on_what);
|
||||
/*
|
||||
fputs (strerror (errno), stderr);
|
||||
fputs (": ", stderr);
|
||||
fputs (on_what, stderr);
|
||||
fputc ('\n', stderr);
|
||||
|
||||
if (_daemonise == TRUE)
|
||||
{
|
||||
//logMessage (LOG_ERR, "%d : %s", errno, on_what);
|
||||
LOG(AQUA_LOG, LOG_ERR, "%s (%d) : %s", strerror (errno), errno, on_what);
|
||||
closelog ();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
From -- syslog.h --
|
||||
|
@ -540,7 +566,7 @@ void _LOG(int16_t from, int msg_level, char *message)
|
|||
closelog ();
|
||||
}
|
||||
|
||||
#ifdef AQ_MANAGER // Always use syslog with aqmanager
|
||||
#ifdef AQ_MANAGER // Always use systemd journel with aqmanager
|
||||
//sd_journal_print()
|
||||
//openlog("aqualinkd", 0, LOG_DAEMON);
|
||||
if (msg_level > LOG_DEBUG) // Let's not confuse syslog with custom levels
|
||||
|
@ -560,7 +586,7 @@ void _LOG(int16_t from, int msg_level, char *message)
|
|||
closelog ();
|
||||
//return;
|
||||
}
|
||||
#endif
|
||||
#endif //AQ_MANAGER
|
||||
|
||||
//int len;
|
||||
message[8] = ' ';
|
||||
|
@ -583,6 +609,7 @@ void _LOG(int16_t from, int msg_level, char *message)
|
|||
snprintf(_loq_display_message, 127, "%s\n",message);
|
||||
}
|
||||
|
||||
#ifndef AQ_MANAGER
|
||||
if (_log2file == TRUE && _log_filename != NULL) {
|
||||
char time[TIMESTAMP_LENGTH];
|
||||
int fp = open(_log_filename, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
@ -604,7 +631,8 @@ void _LOG(int16_t from, int msg_level, char *message)
|
|||
fprintf (stderr, "Can't open debug log %s\n %s", _log_filename, message);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //AQ_MANAGER
|
||||
|
||||
if (_daemonise == FALSE) {
|
||||
if (msg_level == LOG_ERR) {
|
||||
fprintf(stderr, "%s", message);
|
||||
|
|
8
utils.h
8
utils.h
|
@ -53,13 +53,17 @@ typedef enum
|
|||
} bool;
|
||||
*/
|
||||
//void setLoggingPrms(int level , bool deamonized, char* log_file);
|
||||
#ifdef AQ_MANAGER
|
||||
void setLoggingPrms(int level , bool deamonized, char *error_messages);
|
||||
#else
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages);
|
||||
#endif
|
||||
int getLogLevel(int16_t from);
|
||||
int getSystemLogLevel();
|
||||
void setSystemLogLevel( int level);
|
||||
void daemonise ( char *pidFile, void (*main_function)(void) );
|
||||
//void debugPrint (char *format, ...);
|
||||
void displayLastSystemError (const char *on_what);
|
||||
|
||||
|
||||
|
||||
void addDebugLogMask(int16_t flag);
|
||||
|
@ -76,6 +80,8 @@ const char* loglevel2name(int level);
|
|||
|
||||
//void LOG(int from, int level, char *format, ...);
|
||||
void LOG(int16_t from, int msg_level, const char *format, ...);
|
||||
void LOGSystemError (int errnum, int16_t from, const char *on_what);
|
||||
void displayLastSystemError (const char *on_what);
|
||||
|
||||
int count_characters(const char *str, char character);
|
||||
//void readCfg (char *cfgFile);
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
flex-direction: column-reverse;
|
||||
background-color: #2b2b2b;
|
||||
color: white;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
|
@ -264,7 +265,7 @@
|
|||
|
||||
// disable the download log button on startup
|
||||
//disablebutton("downloadlog");
|
||||
//disabletoggle("log2file");
|
||||
//disabletoggle("logfile");
|
||||
//disabletoggle("seriallog");
|
||||
}
|
||||
|
||||
|
@ -310,6 +311,8 @@
|
|||
}
|
||||
|
||||
var last_message_element = null;
|
||||
var log_element_count = 0;
|
||||
const LOGS2DISPLAY = 500;
|
||||
|
||||
function update_log_message(message) {
|
||||
var element = document.createElement("div");
|
||||
|
@ -317,8 +320,22 @@
|
|||
element.classList.add("logmsgerror");
|
||||
}
|
||||
|
||||
var logcontainer = document.getElementById("logs");
|
||||
|
||||
if (log_element_count >= LOGS2DISPLAY) {
|
||||
try {
|
||||
console.log("Removing "+logcontainer.lastElementChild.innerHTML);
|
||||
logcontainer.lastElementChild.remove();
|
||||
} catch(e) {
|
||||
console.log("ERROR Removing log '"+logcontainer.lastElementChild.innerHTML+"'");
|
||||
log_element_count++;
|
||||
}
|
||||
} else {
|
||||
log_element_count++;
|
||||
}
|
||||
|
||||
element.appendChild(document.createTextNode(message));
|
||||
document.getElementById("logs").insertBefore(element, last_message_element);
|
||||
logcontainer.insertBefore(element, last_message_element);
|
||||
last_message_element = element;
|
||||
}
|
||||
|
||||
|
@ -352,7 +369,8 @@
|
|||
}
|
||||
function setlogfile(caller) {
|
||||
var msg = {};
|
||||
if (caller.id == "log2file") {
|
||||
/*
|
||||
if (caller.id == "logfile") {
|
||||
var startstop = "";
|
||||
if (caller.checked) {
|
||||
startstop = "start";
|
||||
|
@ -360,18 +378,19 @@
|
|||
startstop = "stop";
|
||||
}
|
||||
msg = {
|
||||
uri: "log2file/" + startstop,
|
||||
uri: "logfile/" + startstop,
|
||||
value: 0
|
||||
};
|
||||
} else if (caller.id == "cleanlog") {
|
||||
msg = {
|
||||
uri: "log2file/clean",
|
||||
uri: "logfile/clean",
|
||||
value: 0
|
||||
};
|
||||
} else if (caller.id == "downloadlog") {
|
||||
} else*/
|
||||
if (caller.id == "downloadlog") {
|
||||
|
||||
//window.location = '/api/debug/download';
|
||||
downloadFile('/api/log2file/download/aqualinkd.log', document.getElementById("logsize").value);
|
||||
downloadFile('/api/logfile/download', document.getElementById("logsize").value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -380,23 +399,26 @@
|
|||
|
||||
function downloadFile(filePath, lines) {
|
||||
console.log("Lines=" + lines);
|
||||
/*
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = filePath;
|
||||
link.download = filePath.substr(filePath.lastIndexOf('/') + 1);
|
||||
link.href = filePath+"/"+lines;
|
||||
//link.download = filePath.substr(filePath.lastIndexOf('/') + 1);
|
||||
link.download = "aqualinkd.log"
|
||||
link.click();
|
||||
*/
|
||||
|
||||
// Can't get a form post to cleanly download, and "a download" above can only do get. So add value
|
||||
/*
|
||||
var form = document.createElement('form');
|
||||
form.setAttribute("style", "display: none;");
|
||||
form.method='POST';
|
||||
form.action=filePath;
|
||||
form.target='aqd'; // Set trget to iframe "aqd"(aqualinkd), this stops WS for resetting
|
||||
element=document.createElement('INPUT');
|
||||
element.name='value';
|
||||
element.value=lines;
|
||||
form.appendChild(element);
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
@ -461,14 +483,16 @@
|
|||
if logfilename=NULL we can turn on/off logging to file.
|
||||
logging2file will tell us if it's currently on or off
|
||||
*/
|
||||
console.log("deamonized=" + data['deamonized']);
|
||||
console.log("logfilename=" + data['logfilename']);
|
||||
console.log("logfileready=" + data['logfileready']);
|
||||
if (data['deamonized'] == 'off') {
|
||||
console.log("deamonized=" + data['deamonized'] + " Need to rename Restart to Reload");
|
||||
}
|
||||
|
||||
/*
|
||||
if (data['logfilename'] == "(null)")
|
||||
enabletoggle("log2file");
|
||||
enabletoggle("logfile");
|
||||
else
|
||||
disabletoggle("log2file");
|
||||
disabletoggle("logfile");
|
||||
*/
|
||||
/*
|
||||
if (data['logfileready'] == "on") {
|
||||
enablebutton("downloadlog");
|
||||
|
@ -633,7 +657,7 @@
|
|||
disablebutton("restart");
|
||||
disablebutton("seriallog");
|
||||
disablebutton("downloadlog");
|
||||
//disabletoggle("log2file");
|
||||
//disabletoggle("logfile");
|
||||
|
||||
var coll = document.getElementsByClassName("collapsible");
|
||||
var i;
|
||||
|
@ -723,7 +747,7 @@
|
|||
<button class="collapsible">Log File</button>
|
||||
<div class="content" id="loglevels">
|
||||
<!--
|
||||
<label class="toggle logtoggle"><input class="toggle-checkbox" type="checkbox" id="log2file"
|
||||
<label class="toggle logtoggle"><input class="toggle-checkbox" type="checkbox" id="logfile"
|
||||
onclick="setlogfile(this);">
|
||||
<div class="toggle-switch"></div><span class="toggle-label">Log to file</span>
|
||||
</label>
|
||||
|
@ -752,6 +776,7 @@
|
|||
<!--<div class="inner">END</div>-->
|
||||
</div>
|
||||
</div>
|
||||
<!--<iframe src='about:blank' id="logdownload"></iframe>-->
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -99,6 +99,9 @@
|
|||
// This will turn on/off the Spa Heater when you turn on/off Spa Mode.
|
||||
//var link_spa_and_spa_heater = true;
|
||||
|
||||
// Change the min max for heater slider
|
||||
var heater_slider_min = 36;
|
||||
var heater_slider_max = 104;
|
||||
// Change the slider for timers
|
||||
var timer_slider_min = 0;
|
||||
//var timer_slider_max = 360;
|
||||
|
|
|
@ -1389,8 +1389,10 @@
|
|||
}
|
||||
} else if (type == 'setpoint_thermo') {
|
||||
if (_temperature_units != 'c') { // Change to DegF
|
||||
slider.min = 36;
|
||||
slider.max = 104;
|
||||
//slider.min = 36;
|
||||
//slider.max = 104;
|
||||
slider.min = ((typeof heater_slider_min !== 'undefined')?heater_slider_min:36);
|
||||
slider.max = ((typeof heater_slider_max !== 'undefined')?heater_slider_max:104);
|
||||
slider.step = 1;
|
||||
} else { // Change to DegF
|
||||
slider.min = 0;
|
||||
|
|
Loading…
Reference in New Issue