mirror of https://github.com/sfeakes/AqualinkD.git
Dev 3.0.0 update
Initial update for serial HAT. (USB not working) Initial mongoose update (working needs cleanup)pull/465/head
parent
b3219ac0b4
commit
819cab1e7a
6
Makefile
6
Makefile
|
|
@ -51,8 +51,10 @@ DBGFLAGS = -g -O0 -Wall -D AQ_DEBUG -D AQ_TM_DEBUG
|
|||
# Mongoose flags
|
||||
#MGFLAGS = -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
|
||||
# Mongoose 6.18 flags
|
||||
MGFLAGS = -D MG_ENABLE_HTTP_SSI=0 -D MG_ENABLE_DIRECTORY_LISTING=0 -D MG_ENABLE_HTTP_CGI=0
|
||||
#MGFLAGS =
|
||||
#MGFLAGS = -D MG_ENABLE_HTTP_SSI=0 -D MG_ENABLE_DIRECTORY_LISTING=0 -D MG_ENABLE_HTTP_CGI=0
|
||||
|
||||
# Mongoose 7.19 flags
|
||||
MGFLAGS = -D MG_ENABLE_HTTP_SSI=0
|
||||
|
||||
# Detect OS and set some specifics
|
||||
ifeq ($(OS),Windows_NT)
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -136,9 +136,18 @@ NEED TO FIX FOR THIS RELEASE.
|
|||
* Use set_allbutton_light_dimmer for all lights (ie color lights)
|
||||
|
||||
-->
|
||||
# Updates in 2.6.12 (dev)
|
||||
# Updates in 3.0.0 (dev)
|
||||
* Serial optimization for HAT.
|
||||
* Added options to force upgrades in aqmanager. (add ?upgrade or ?devupgrade to url to enable upgrade button)
|
||||
|
||||
* Need to finish off :-
|
||||
* ToDo HAT serial optimizations broke some USB serial adapters
|
||||
* Code cleanup of old stuff. (THREAD_NET_SERVICE / BLOCKING SERIAL PORT)
|
||||
* Reading TruSense. (Jandy protocols working, need to finish off read_RS485_TruSense support)
|
||||
* ToDo assigning light mode & functionality to a vbutton (for JAndy Infinate water color support)
|
||||
* ToDo Cleanup the upgrade of Mongoose code
|
||||
* ToDo Finish off assigning light mode & functionality to a vbutton (for Jandy Infinite water color support )
|
||||
* ToDo Remove Domoticz support ???????
|
||||
* ToDo cleanup rs_msg_utils.c
|
||||
|
||||
# Updates in 2.6.11 (Sept 14 2025)
|
||||
* Cleaned up exit codes.
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -689,8 +689,9 @@ aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex) {
|
|||
snprintf(name, 9, "%s%d", BTN_VAUX, index);
|
||||
button->name = name;
|
||||
|
||||
button->special_mask_ptr = malloc(sizeof(vbutton_detail));
|
||||
((vbutton_detail *)button->special_mask_ptr)->altlabel = NUL;
|
||||
// NSF THIS NEEDS TO BE REMOVED
|
||||
//button->special_mask_ptr = malloc(sizeof(altlabel_detail));
|
||||
//((altlabel_detail *)button->special_mask_ptr)->altlabel = NUL;
|
||||
|
||||
if (label == NULL || strlen(label) <= 0) {
|
||||
//button->label = name;
|
||||
|
|
@ -701,7 +702,8 @@ aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex) {
|
|||
|
||||
button->code = NUL;
|
||||
button->dz_idx = DZ_NULL_IDX;
|
||||
button->special_mask |= VIRTUAL_BUTTON; // Could change to special mask vbutton
|
||||
setButtonSpecialMask(button, VIRTUAL_BUTTON);
|
||||
//button->special_mask |= VIRTUAL_BUTTON; // Could change to special mask vbutton
|
||||
button->led->state = OFF;
|
||||
|
||||
return button;
|
||||
|
|
@ -727,13 +729,22 @@ bool setVirtualButtonLabel(aqkey *button, const char *label) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool setVirtualButtonAltLabel(aqkey *button, const char *label) {
|
||||
|
||||
bool setVirtualButtonAltLabel(aqkey *button, char *label) {
|
||||
if (label == NULL )
|
||||
return false;
|
||||
|
||||
((vbutton_detail *)button->special_mask_ptr)->altlabel = (char *)label;
|
||||
((vbutton_detail *)button->special_mask_ptr)->in_alt_mode = false;
|
||||
button->special_mask |= VIRTUAL_BUTTON_ALT_LABEL;
|
||||
if (! isMASK_SET(button->special_mask, VIRTUAL_BUTTON_ALT_LABEL) ) {
|
||||
button->special_mask_ptr = malloc(sizeof(altlabel_detail));
|
||||
((altlabel_detail *)button->special_mask_ptr)->altlabel = cleanalloc(label);
|
||||
setButtonSpecialMask(button, VIRTUAL_BUTTON_ALT_LABEL);
|
||||
}
|
||||
|
||||
((altlabel_detail *)button->special_mask_ptr)->altlabel = (char *)label;
|
||||
((altlabel_detail *)button->special_mask_ptr)->in_alt_mode = false;
|
||||
|
||||
//setButtonSpecialMask(button, VIRTUAL_BUTTON_ALT_LABEL);
|
||||
//button->special_mask |= VIRTUAL_BUTTON_ALT_LABEL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1475,7 +1486,17 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIn
|
|||
|
||||
char buf[LIGHT_MODE_BUFER];
|
||||
|
||||
if (light->lightType == LC_PROGRAMABLE ) {
|
||||
if (isMASK_SET(light->button->special_mask, VIRTUAL_BUTTON)) {
|
||||
// We can only program a light on virtual button on iaqtouch or onetouch
|
||||
if (isIAQT_ENABLED ) {
|
||||
sprintf(buf, "%-5d%-5d%-5d",value, deviceIndex, light->lightType);
|
||||
aq_programmer(AQ_SET_IAQTOUCH_LIGHTCOLOR_MODE, buf, aqdata);
|
||||
} else if (isONET_ENABLED ) {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode on virtual button not implimented on OneTouch protocol (needs AqualinkTouch)\n");
|
||||
} else {
|
||||
LOG(PANL_LOG,LOG_ERR, "Light mode on virtual button needs AqualinkTouch protocol\n");
|
||||
}
|
||||
} else if (light->lightType == LC_PROGRAMABLE ) {
|
||||
//sprintf(buf, "%-5s%-5d%-5d%-5d%.2f",value,
|
||||
sprintf(buf, "%-5d%-5d%-5d%-5d%.2f",value,
|
||||
deviceIndex,
|
||||
|
|
@ -1483,7 +1504,7 @@ void programDeviceLightMode(struct aqualinkdata *aqdata, int value, int deviceIn
|
|||
_aqconfig_.light_programming_initial_off,
|
||||
_aqconfig_.light_programming_mode );
|
||||
aq_programmer(AQ_SET_LIGHTPROGRAM_MODE, buf, aqdata);
|
||||
} else if (isRSSA_ENABLED) {
|
||||
} else if (isRSSA_ENABLED ) {
|
||||
// If we are using rs-serial then turn light on first.
|
||||
if (light->button->led->state != ON) {
|
||||
set_aqualink_rssadapter_aux_state(light->button, TRUE);
|
||||
|
|
@ -1678,3 +1699,58 @@ pump_detail *getPumpDetail(struct aqualinkdata *aqdata, int button)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const char *getButtontSpecialMaskName(uint16_t mask) {
|
||||
switch(mask) {
|
||||
case VS_PUMP:
|
||||
return "VSpump";
|
||||
break;
|
||||
case PROGRAM_LIGHT:
|
||||
return "lightMode";
|
||||
break;
|
||||
case VIRTUAL_BUTTON_ALT_LABEL:
|
||||
return "altLabel";
|
||||
break;
|
||||
case VIRTUAL_BUTTON:
|
||||
return "Virtual Button";
|
||||
break;
|
||||
case VIRTUAL_BUTTON_CHILLER:
|
||||
return "Virtual Button Chiller";
|
||||
default:
|
||||
return "unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
void checkButtonSpecialMask(aqkey *button, uint16_t mask2remove) {
|
||||
if (isMASK_SET(button->special_mask,mask2remove)) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error can only have one type for button `%s`, removing `%s`\n",
|
||||
button->name,
|
||||
getButtontSpecialMaskName(mask2remove));
|
||||
removeMASK(button->special_mask, mask2remove);
|
||||
}
|
||||
}
|
||||
void setButtonSpecialMask(aqkey *button, uint16_t mask2set)
|
||||
{
|
||||
switch(mask2set) {
|
||||
case VS_PUMP: // assign struct pump_detail
|
||||
checkButtonSpecialMask(button, PROGRAM_LIGHT);
|
||||
checkButtonSpecialMask(button, VIRTUAL_BUTTON_ALT_LABEL);
|
||||
break;
|
||||
case PROGRAM_LIGHT: // assign struct clight_detail
|
||||
checkButtonSpecialMask(button, VIRTUAL_BUTTON_ALT_LABEL);
|
||||
checkButtonSpecialMask(button, VS_PUMP);
|
||||
break;
|
||||
case VIRTUAL_BUTTON_ALT_LABEL: // assign struct altlabel_detail (Maybe delete VIRTUAL_BUTTON)
|
||||
checkButtonSpecialMask(button, PROGRAM_LIGHT);
|
||||
checkButtonSpecialMask(button, VS_PUMP);
|
||||
break;
|
||||
case VIRTUAL_BUTTON: // Type can be added to above
|
||||
break;
|
||||
case VIRTUAL_BUTTON_CHILLER: // Type can be added to above
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
button->special_mask |= mask2set;
|
||||
}
|
||||
|
|
@ -87,10 +87,11 @@ uint16_t getPanelSupport( char *rev_string, int rev_len);
|
|||
|
||||
aqkey *addVirtualButton(struct aqualinkdata *aqdata, char *label, int vindex);
|
||||
bool setVirtualButtonLabel(aqkey *button, const char *label);
|
||||
bool setVirtualButtonAltLabel(aqkey *button, const char *label);
|
||||
bool setVirtualButtonAltLabel(aqkey *button, char *label);
|
||||
|
||||
clight_detail *getProgramableLight(struct aqualinkdata *aqdata, int button);
|
||||
pump_detail *getPumpDetail(struct aqualinkdata *aqdata, int button);
|
||||
void setButtonSpecialMask(aqkey *button, uint16_t masktoset);
|
||||
|
||||
//void panneltest();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,36 +26,22 @@
|
|||
// Below is needed to set low latency.
|
||||
#include <linux/serial.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "aq_serial.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "packetLogger.h"
|
||||
#include "timespec_subtract.h"
|
||||
#include "aqualink.h"
|
||||
#include <sys/select.h>
|
||||
|
||||
/*
|
||||
Notes for serial usb speed
|
||||
|
||||
File should exist if using ftdi chip, ie ftdi_sio driver.
|
||||
/sys/bus/usb-serial/devices/ttyUSB0/latency_timer
|
||||
Set to 1 for fastest latency.
|
||||
#define SERIAL_READ_TIMEOUT_SEC 1;
|
||||
|
||||
Can also be set in code
|
||||
ioctl(fd, TIOCGSERIAL, &serial);
|
||||
serial.flags |= ASYNC_LOW_LATENCY;
|
||||
ioctl(fd, TIOCSSERIAL, &serial);
|
||||
|
||||
*/
|
||||
|
||||
// Default to send command with leading NUL, this changes that
|
||||
//#define SEND_CMD_WITH_TRAILING_NUL
|
||||
|
||||
//#define BLOCKING_MODE
|
||||
|
||||
static bool _blocking_mode = false;
|
||||
static int _blocking_fds = -1;
|
||||
|
||||
static struct termios _oldtio;
|
||||
static int _RS485_fds = -1;
|
||||
|
||||
static struct timespec _last_serial_read_time;
|
||||
|
||||
|
|
@ -420,98 +406,6 @@ protocolType getProtocolType(const unsigned char* packet) {
|
|||
|
||||
return P_UNKNOWN;
|
||||
}
|
||||
/*
|
||||
unsigned char getProtocolType(unsigned char* packet) {
|
||||
if (packet[0] == DLE)
|
||||
return PCOL_JANDY;
|
||||
else if (packet[0] == PP1)
|
||||
return PCOL_PENTAIR;
|
||||
|
||||
return PCOL_UNKNOWN;
|
||||
}
|
||||
*/
|
||||
|
||||
#ifndef PLAYBACK_MODE
|
||||
/*
|
||||
Open and Initialize the serial communications port to the Aqualink RS8 device.
|
||||
Arg is tty or port designation string
|
||||
returns the file descriptor
|
||||
*/
|
||||
//#define TXDEN_DUMMY_RS485_MODE
|
||||
|
||||
#ifdef TXDEN_DUMMY_RS485_MODE
|
||||
|
||||
#include <linux/serial.h>
|
||||
/* RS485 ioctls: */
|
||||
#define TIOCGRS485 0x542E
|
||||
#define TIOCSRS485 0x542F
|
||||
|
||||
int init_serial_port_Pi(const char* tty)
|
||||
{
|
||||
struct serial_rs485 rs485conf = {0};
|
||||
|
||||
//int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
int fd = open(tty, O_RDWR);
|
||||
if (fd < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s\n", tty);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Openeded serial port %s\n",tty);
|
||||
|
||||
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Error reading ioctl port (%d): %s\n", errno, strerror( errno ));
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Port currently RS485 mode is %s\n", (rs485conf.flags & SER_RS485_ENABLED) ? "set" : "NOT set");
|
||||
|
||||
/* Enable RS485 mode: */
|
||||
rs485conf.flags |= SER_RS485_ENABLED;
|
||||
|
||||
/* Set logical level for RTS pin equal to 1 when sending: */
|
||||
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
|
||||
/* or, set logical level for RTS pin equal to 0 when sending: */
|
||||
//rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
|
||||
|
||||
/* Set logical level for RTS pin equal to 1 after sending: */
|
||||
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
|
||||
/* or, set logical level for RTS pin equal to 0 after sending: */
|
||||
//rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
|
||||
|
||||
/* Set this flag if you want to receive data even whilst sending data */
|
||||
//rs485conf.flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to set port to RS485 %s (%d): %s\n", tty, errno, strerror( errno ));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif // TXDEN_DUMMY_RS485_MODE
|
||||
|
||||
int _init_serial_port(const char* tty, bool blocking, bool readahead);
|
||||
|
||||
int init_serial_port(const char* tty)
|
||||
{
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0) {
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
}
|
||||
#else
|
||||
return init_blocking_serial_port(_aqconfig_.serial_port);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int init_blocking_serial_port(const char* tty)
|
||||
{
|
||||
_blocking_fds = _init_serial_port(tty, true, false);
|
||||
return _blocking_fds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int set_port_low_latency(int fd, const char* tty)
|
||||
|
|
@ -573,112 +467,137 @@ int is_valid_port(int fd) {
|
|||
}
|
||||
|
||||
|
||||
void print_file_flags(int fd) {
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
perror("fcntl(F_GETFL)");
|
||||
return;
|
||||
}
|
||||
if (flags & O_RDONLY) {
|
||||
printf(" - O_RDONLY (Read-only access)\n");
|
||||
}
|
||||
if (flags & O_WRONLY) {
|
||||
printf(" - O_WRONLY (Write-only access)\n");
|
||||
}
|
||||
if (flags & O_RDWR) {
|
||||
printf(" - O_RDWR (Read/write access)\n");
|
||||
}
|
||||
if (flags & O_ACCMODE) {
|
||||
printf(" - O_ACCMODE (mask for above modes)\n");
|
||||
}
|
||||
if (flags & O_NONBLOCK) {
|
||||
printf(" - O_NONBLOCK (Non-blocking I/O)\n");
|
||||
}
|
||||
if (flags & O_APPEND) {
|
||||
printf(" - O_APPEND (Append mode)\n");
|
||||
}
|
||||
/*
|
||||
if (flags & O_SHLOCK) {
|
||||
printf(" - O_SHLOCK (open with shared file lock)\n");
|
||||
}
|
||||
if (flags & O_EXLOCK) {
|
||||
printf(" - O_EXLOCK (open with exclusive file lock)\n");
|
||||
}
|
||||
*/
|
||||
if (flags & O_ASYNC) {
|
||||
printf(" - O_ASYNC (Asynchronous I/O signal)\n");
|
||||
}
|
||||
if (flags & O_NOFOLLOW) {
|
||||
printf(" - O_NOFOLLOW (don't follow symlinks)\n");
|
||||
}
|
||||
if (flags & O_DSYNC) {
|
||||
printf(" - O_DSYNC (Synchronous I/O data integrity)\n");
|
||||
}
|
||||
if (flags & O_SYNC) {
|
||||
printf(" - O_SYNC (Synchronous I/O file integrity)\n");
|
||||
}
|
||||
if (flags & O_NOCTTY) {
|
||||
printf(" - O_NOCTTY (don't assign controlling terminal)\n");
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.cmrr.umn.edu/~strupp/serial.html#2_5_2
|
||||
// http://unixwiz.net/techtips/termios-vmin-vtime.html
|
||||
|
||||
// Unless AQ_RS_EXTRA_OPTS is defined, blocking will always be true
|
||||
int _init_serial_port(const char* tty, bool blocking, bool readahead)
|
||||
int init_serial_port(const char* port)
|
||||
{
|
||||
//B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400
|
||||
const int BAUD = B9600;
|
||||
const int PARITY = 0;
|
||||
struct termios newtio;
|
||||
struct termios tty;
|
||||
|
||||
_blocking_mode = blocking;
|
||||
// Have to open with O_NONBLOCK so we don't wait for the Data Carrier Detect (DCD) signal to go high
|
||||
int _RS485_fds = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
|
||||
|
||||
//int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
|
||||
int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY | O_CLOEXEC);
|
||||
|
||||
|
||||
//int fd = open(tty, O_RDWR | O_NOCTTY | O_SYNC); // This is way to slow at reading
|
||||
if (fd < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s, error %d\n", tty, errno);
|
||||
if (_RS485_fds < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to open port: %s, error %d\n", port, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Openeded serial port %s\n",tty);
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "Openeded serial port %s\n",port);
|
||||
//print_file_flags(fd);
|
||||
|
||||
if (tcgetattr(fd, &newtio) != 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to get port attributes: %s, error %d\n", tty,errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( lock_port(fd, tty) < 0) {
|
||||
//LOG(RSSD_LOG,LOG_ERR, "Unable to lock port: %s, error %d\n", tty, errno);
|
||||
return -1;
|
||||
if ( lock_port(_RS485_fds, port) < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to lock port: %s, error %d\n", tty, errno);
|
||||
//return -1;
|
||||
}
|
||||
|
||||
if (_aqconfig_.ftdi_low_latency)
|
||||
set_port_low_latency(fd, tty);
|
||||
|
||||
memcpy(&_oldtio, &newtio, sizeof(struct termios));
|
||||
|
||||
cfsetospeed(&newtio, BAUD);
|
||||
cfsetispeed(&newtio, BAUD);
|
||||
|
||||
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8; // 8-bit chars
|
||||
// disable IGNBRK for mismatched speed tests; otherwise receive break
|
||||
// as \000 chars
|
||||
//newtio.c_iflag &= ~IGNBRK; // disable break processing
|
||||
newtio.c_iflag = 0; // raw input
|
||||
newtio.c_lflag = 0; // no signaling chars, no echo,
|
||||
// no canonical processing
|
||||
newtio.c_oflag = 0; // no remapping, no delays, raw output
|
||||
|
||||
if (_blocking_mode) {
|
||||
fcntl(fd, F_SETFL, 0); //efficient blocking for the read
|
||||
//newtio.c_cc[VMIN] = 1; // read blocks for 1 character or timeout below
|
||||
//newtio.c_cc[VTIME] = 0; // 0.5 seconds read timeout
|
||||
//newtio.c_cc[VTIME] = 255; // 25 seconds read timeout
|
||||
//newtio.c_cc[VTIME] = 10; // (1 to 255) 1 = 0.1 sec, 255 = 25.5 sec
|
||||
newtio.c_cc[VTIME] = SERIAL_BLOCKING_TIME;
|
||||
newtio.c_cc[VMIN] = 0;
|
||||
} else {
|
||||
newtio.c_cc[VMIN]= 0; // read doesn't block
|
||||
//newtio.c_cc[VTIME]= 1;
|
||||
newtio.c_cc[VTIME]= (readahead?0:1);
|
||||
}
|
||||
/*
|
||||
Raw output is selected by resetting the OPOST option in the c_oflag member:
|
||||
newtio.c_oflag &= ~OPOST;
|
||||
When the OPOST option is disabled, all other option bits in c_oflag are ignored.
|
||||
*/
|
||||
//newtio.c_oflag &= ~OPOST; // Raw output
|
||||
|
||||
newtio.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
|
||||
|
||||
newtio.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
|
||||
// enable reading
|
||||
newtio.c_cflag &= ~(PARENB | PARODD); // shut off parity
|
||||
newtio.c_cflag |= PARITY;
|
||||
newtio.c_cflag &= ~CSTOPB;
|
||||
newtio.c_cflag &= ~CRTSCTS;
|
||||
|
||||
tcflush(fd, TCIFLUSH);
|
||||
if (tcsetattr(fd, TCSANOW, &newtio) != 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to set port attributes: %s, error %d\n", tty,errno);
|
||||
set_port_low_latency(_RS485_fds, port);
|
||||
|
||||
if (tcgetattr(_RS485_fds, &tty) != 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Unable to get port attributes: %s, error %d\n", port,errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(RSSD_LOG,LOG_INFO, "Port %s set I/O %s attributes\n",tty,_blocking_mode?"blocking":"non blocking");
|
||||
// Set up Modbus protocol in raw mode (no canonical processing)
|
||||
// This function automatically unsets ICRNL and other processing flags. (stops conversion of 0x0d to 0x0a rc to lf)
|
||||
cfmakeraw(&tty); // Going to be more precise using below
|
||||
|
||||
return fd;
|
||||
}
|
||||
// Set baud rates to 9600
|
||||
cfsetispeed(&tty, B9600);
|
||||
cfsetospeed(&tty, B9600);
|
||||
|
||||
// 8 data bits (CS8), no parity (PARENB cleared), 1 stop bit (CSTOPB cleared)
|
||||
// Note: CSIZE is a mask, so we must first clear it before setting CS8.
|
||||
tty.c_cflag &= ~PARENB; // No parity
|
||||
tty.c_cflag &= ~CSTOPB; // 1 stop bit
|
||||
tty.c_cflag &= ~CSIZE; // Clear all data bit size flags.
|
||||
tty.c_cflag |= CS8; // 8 data bits.
|
||||
|
||||
// Disable hardware (RTS/CTS) and software (XON/XOFF) flow control
|
||||
tty.c_cflag &= ~CRTSCTS; // Disable hardware flow control
|
||||
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable software flow control
|
||||
|
||||
void close_blocking_serial_port()
|
||||
{
|
||||
if (_blocking_fds >= 0) {
|
||||
LOG(RSSD_LOG,LOG_INFO, "Forcing close of blocking serial port, ignore following read errors\n");
|
||||
close_serial_port(_blocking_fds);
|
||||
} else {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Didn't find valid blocking serial port file descriptor\n");
|
||||
// Set other control options for "raw" mode
|
||||
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Non-canonical input, disable echo
|
||||
tty.c_oflag &= ~OPOST; // Raw output
|
||||
|
||||
// Enable receiver and ignore modem control lines
|
||||
tty.c_cflag |= (CREAD | CLOCAL);
|
||||
|
||||
// Set timeout for read operations
|
||||
// VMIN = 0, VTIME > 0 for a read timeout
|
||||
// In this case, 1 second (10 * 0.1s) timeout.
|
||||
tty.c_cc[VMIN] = 0;
|
||||
tty.c_cc[VTIME] = 10;
|
||||
|
||||
// Below resets the open with O_NONBLOCK
|
||||
//fcntl(fd, F_SETFL, 0);
|
||||
|
||||
// Write the modified settings
|
||||
if (tcsetattr(_RS485_fds, TCSANOW, &tty) != 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR,"Error %i from tcsetattr: %s\n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Clear out buffer
|
||||
if (tcflush(_RS485_fds, TCIFLUSH) == -1) {
|
||||
LOG(RSSD_LOG,LOG_ERR,"Error %i from tcflush: %s\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
return _RS485_fds;
|
||||
}
|
||||
|
||||
/* close tty port */
|
||||
void close_serial_port(int fd)
|
||||
void _close_serial_port(int fd)
|
||||
{
|
||||
if ( fcntl(fd, F_GETFD, 0) == -1 || errno == EBADF ) {
|
||||
// Looks like bad fd or already closed. return with no error since we can get called twice
|
||||
|
|
@ -686,14 +605,23 @@ void close_serial_port(int fd)
|
|||
}
|
||||
|
||||
unlock_port(fd);
|
||||
tcsetattr(fd, TCSANOW, &_oldtio);
|
||||
close(fd);
|
||||
LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Closed serial port\n");
|
||||
}
|
||||
|
||||
bool serial_blockingmode()
|
||||
// Can pass NULL for serialport
|
||||
void close_serial_port(int port)
|
||||
{
|
||||
return _blocking_mode;
|
||||
if (port >= 0) {
|
||||
_close_serial_port(port);
|
||||
} else {
|
||||
if (_RS485_fds < 0) {
|
||||
LOG(RSSD_LOG,LOG_ERR, "Didn't find valid blocking serial port file descriptor\n");
|
||||
return;
|
||||
}
|
||||
LOG(RSSD_LOG,LOG_INFO, "Forcing close of serial port, ignore following read errors\n");
|
||||
_close_serial_port(_RS485_fds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -890,7 +818,7 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
|
||||
if (_blocking_mode) {
|
||||
if (true) {
|
||||
//int nwrite = write(fd, packet, length);
|
||||
//LOG(RSSD_LOG,LOG_DEBUG, "Serial write %d bytes of %d\n",nwrite,length);
|
||||
int nwrite = write(fd, packet, length);
|
||||
|
|
@ -945,8 +873,7 @@ void send_packet(int fd, unsigned char *packet, int length)
|
|||
#ifndef SERIAL_LOGGER
|
||||
if (_aqconfig_.frame_delay > 0) {
|
||||
timespec_subtract(&elapsed_time, &now, &_last_serial_read_time);
|
||||
LOG(RSTM_LOG, LOG_DEBUG, "Time from recv to %s send is %.3f sec\n",
|
||||
(_blocking_mode?"blocking":"non-blocking"),
|
||||
LOG(RSTM_LOG, LOG_DEBUG, "Time from recv to send is %.3f sec\n",
|
||||
roundf3(timespec2float(&elapsed_time)));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1144,6 +1071,14 @@ int fix_packet(unsigned char *packet_buffer, int packet_length, bool getCached)
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
LXi status | HEX: 0x10|0x02|0x00|0x0d|0x00|0x00|0x00|0x1f|0x10|0x03|
|
||||
HEX: 0x10|0x02|0x00|0x0a|0x00|0x00|0x00|0x1f|0x10|0x03| // New read seems to use 0x0a and not 0x0d
|
||||
*/
|
||||
|
||||
|
||||
int get_packet(int fd, unsigned char* packet)
|
||||
{
|
||||
unsigned char byte = 0x00;
|
||||
|
|
@ -1161,46 +1096,48 @@ int get_packet(int fd, unsigned char* packet)
|
|||
struct timespec packet_elapsed;
|
||||
struct timespec packet_end_time;
|
||||
|
||||
int wait_val;
|
||||
struct timeval read_tv;
|
||||
read_tv.tv_sec = SERIAL_READ_TIMEOUT_SEC; // 1-second timeout
|
||||
read_tv.tv_usec = 0;
|
||||
|
||||
memset(packet, 0, AQ_MAXPKTLEN);
|
||||
|
||||
#ifdef DUMMY_READER
|
||||
static bool haveFixedPacket = false;
|
||||
if (haveFixedPacket) {
|
||||
haveFixedPacket = false;
|
||||
int rtn = fix_packet(packet, AQ_MAXPKTLEN, true);
|
||||
if (rtn > 0) {
|
||||
LOG(RSSD_LOG,LOG_DEBUG, "RETURNING PART 2 OF FIXED PACKET:\n");
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Read packet in byte order below
|
||||
// DLE STX ........ ETX DLE
|
||||
// sometimes we get ETX DLE and no start, so for now just ignoring that. Seem to be more applicable when busy RS485 traffic
|
||||
|
||||
//#ifndef OLD_SERIAL_INIT .. Need to re-do ERROR like EAGAIN with new init
|
||||
|
||||
|
||||
while (!endOfPacket) {
|
||||
//printf("READ SERIAL\n");
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(fd, &readfds);
|
||||
// Wait for up to read_tv.tv_sec second for data to become available
|
||||
wait_val = select(fd + 1, &readfds, NULL, NULL, &read_tv);
|
||||
if (wait_val == -1) {
|
||||
return AQSERR_READ;
|
||||
} else if (wait_val == 0) {
|
||||
//return AQSERR_TIMEOUT;
|
||||
return 0; // Should probably change to above
|
||||
}
|
||||
|
||||
bytesRead = read(fd, &byte, 1);
|
||||
//printf("Read %d 0x%02hhx err=%d fd=%d\n",bytesRead,byte,errno,fd);
|
||||
//if (bytesRead < 0 && errno == EAGAIN && packetStarted == FALSE && lastByteDLE == FALSE) {
|
||||
//if (bytesRead < 0 && (errno == EAGAIN || errno == 0) &&
|
||||
if (bytesRead <= 0 && (errno == EAGAIN || errno == 0 || errno == ENOTTY) ) { // We also get ENOTTY on some non FTDI adapters
|
||||
if (_blocking_mode) {
|
||||
// Something is wrong wrong
|
||||
return AQSERR_TIMEOUT;
|
||||
} else if (jandyPacketStarted == false && pentairPacketStarted == false && lastByteDLE == false) {
|
||||
// We just have nothing else to read
|
||||
|
||||
if (bytesRead <= 0 && errno == EAGAIN ) { // We also get ENOTTY on some non FTDI adapters
|
||||
if (jandyPacketStarted == false && pentairPacketStarted == false && lastByteDLE == false) {
|
||||
return 0;
|
||||
} else if (++retry > 120 ) {
|
||||
} else if (++retry > 10 ) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Serial read timeout\n");
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
if (index > 0) { logPacketError(packet, index); }
|
||||
return AQSERR_TIMEOUT;
|
||||
return AQSERR_READ;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if(bytesRead <= 0) {
|
||||
if (! isAqualinkDStopping() ) {
|
||||
return AQSERR_READ;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
delay(1);
|
||||
} else if (bytesRead == 1) {
|
||||
retry = 0;
|
||||
if (_aqconfig_.log_raw_bytes)
|
||||
|
|
@ -1283,20 +1220,6 @@ int get_packet(int fd, unsigned char* packet)
|
|||
else if (byte != PP1) // Don't reset counter if multiple PP1's
|
||||
PentairPreCnt = 0;
|
||||
}
|
||||
} else if(bytesRead < 0) {
|
||||
// Got a read error. Wait one millisecond for the next byte to
|
||||
// arrive.
|
||||
if (! isAqualinkDStopping() ) {
|
||||
LOG(RSSD_LOG,LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
|
||||
if(errno == 9) {
|
||||
// Bad file descriptor. Port has been disconnected for some reason.
|
||||
// Return a -1.
|
||||
return AQSERR_READ;
|
||||
}
|
||||
delay(100);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Break out of the loop if we exceed maximum packet
|
||||
|
|
@ -1309,7 +1232,6 @@ int get_packet(int fd, unsigned char* packet)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Report any unusual size packets.
|
||||
if (index >= AQ_MAXPKTLEN_WARNING) {
|
||||
|
|
@ -1388,19 +1310,6 @@ int get_packet(int fd, unsigned char* packet)
|
|||
|
||||
|
||||
|
||||
#else // PLAYBACKMODE
|
||||
|
||||
// Need to re-write this if we ever use playback mode again. Pull info from aq_serial.old.c
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ const char *getJandyDeviceName(emulation_type etype);
|
|||
#define CONNECTION_RUNNING_SLOG "Running serial_logger, this will take some time"
|
||||
#endif
|
||||
|
||||
//#define SERIAL_BLOCKING_TIME 50 // (1 to 255) in 1/10th second so 1 = 0.1 sec, 255 = 25.5 sec
|
||||
#define SERIAL_BLOCKING_TIME 10
|
||||
#define SERIAL_BLOCKING_TIME 50 // (1 to 255) in 1/10th second so 1 = 0.1 sec, 255 = 25.5 sec
|
||||
//#define SERIAL_BLOCKING_TIME 10
|
||||
|
||||
// Protocol types
|
||||
#define PCOL_JANDY 0xFF
|
||||
|
|
@ -575,8 +575,8 @@ int init_blocking_serial_port(const char* tty);
|
|||
//int init_readahead_serial_port(const char* tty);
|
||||
|
||||
void close_serial_port(int file_descriptor);
|
||||
void close_blocking_serial_port();
|
||||
bool serial_blockingmode();
|
||||
//void close_blocking_serial_port();
|
||||
//bool serial_blockingmode();
|
||||
|
||||
//#ifdef AQ_PDA
|
||||
//void set_pda_mode(bool mode);
|
||||
|
|
|
|||
|
|
@ -135,17 +135,21 @@ bool copy_file(const char *source_path, const char *destination_path)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool run_aqualinkd_upgrade(bool onlycheck)
|
||||
bool run_aqualinkd_upgrade(uint8_t type)
|
||||
{
|
||||
int pipe_curl_to_bash[2];
|
||||
pid_t pid_curl, pid_bash;
|
||||
//char *curl_args[] = {"curl", "-fsSl", "http://tiger/scratch/remote_install.sh", NULL};
|
||||
char *curl_args[] = {"curl", "-fsSl", "-H", "Accept: application/vnd.github.raw", "https://api.github.com/repos/AqualinkD/AqualinkD/contents/release/remote_install.sh", NULL};
|
||||
char *bash_args[] = {"bash", "-s", "--", "check", NULL};
|
||||
char *bash_args[] = {"bash", "-s", "--", "", NULL};
|
||||
int status_curl, status_bash;
|
||||
|
||||
if (!onlycheck) {
|
||||
bash_args[3] = NULL;
|
||||
if (isMASK_SET(type, CHECKONLY)) {
|
||||
bash_args[3] = "check";
|
||||
} else {
|
||||
if (isMASK_SET(type, INSTALLDEVRELEASE)) {
|
||||
bash_args[3] = "development";
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe(pipe_curl_to_bash) == -1)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
FILE *aq_open_file( char *filename, bool *ro_root, bool* created_file);
|
||||
bool aq_close_file(FILE *file, bool ro_root);
|
||||
bool copy_file(const char *source_path, const char *destination_path);
|
||||
bool run_aqualinkd_upgrade(bool onlycheck);
|
||||
bool run_aqualinkd_upgrade(uint8_t type);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,26 +17,14 @@
|
|||
#define SIGRESTART SIGUSR1
|
||||
#define SIGRUPGRADE SIGUSR2
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
#define DEFAULT_POLL_SPEED -1
|
||||
#define DEFAULT_POLL_SPEED_NON_THREADDED 2
|
||||
#endif
|
||||
|
||||
|
||||
#define CLIGHT_PANEL_FIX // Overcome bug in some jandy panels where color light status of on is not in LED status
|
||||
|
||||
#define TIME_CHECK_INTERVAL 3600
|
||||
//#define TIME_CHECK_INTERVAL 100 // DEBUG ONLY
|
||||
#define ACCEPTABLE_TIME_DIFF 120
|
||||
|
||||
// Use these settings to test time
|
||||
//#define TIME_CHECK_INTERVAL 100
|
||||
//#define ACCEPTABLE_TIME_DIFF 10
|
||||
|
||||
#define MAX_ZERO_READ_BEFORE_RECONNECT_NONBLOCKING 100000 // 10k normally
|
||||
#define MAX_ZERO_READ_BEFORE_RECONNECT_BLOCKING (25 / (SERIAL_BLOCKING_TIME / 10) ) // Want this to be 25 seconds, so it's depdand on how long the serial blocking is
|
||||
// Time in ms to delay between read requests in non blocking serial port. Have to set something to stop CPU spiking.
|
||||
#define NONBLOCKING_SERIAL_DELAY 2
|
||||
#define MAX_ZERO_READ_BEFORE_RECONNECT 10
|
||||
|
||||
// The below will change state of devices before that are actually set on the control panel, this helps
|
||||
// with duplicate messages that come in quick succession that can catch the state before it happens.
|
||||
|
|
@ -257,6 +245,12 @@ typedef enum panel_vsp_status
|
|||
#define ERROR_NO_DEVICE_ID ( 1 << 8 ) // maybe covered in NOT_CONNECTED
|
||||
#define ERROR_SERIAL ( 1 << 9 )
|
||||
|
||||
|
||||
|
||||
#define INSTALLDEVRELEASE ( 1 << 0 )
|
||||
#define UPDATERELEASE ( 1 << 1 )
|
||||
#define CHECKONLY ( 1 << 3 )
|
||||
|
||||
typedef struct pumpd
|
||||
{
|
||||
int rpm;
|
||||
|
|
@ -304,13 +298,13 @@ typedef enum {
|
|||
MD_HEATPUMP
|
||||
} heatmump_mode;
|
||||
*/
|
||||
typedef struct vbuttond
|
||||
typedef struct altlabeld
|
||||
{
|
||||
char *altlabel;
|
||||
bool in_alt_mode; // Example if altlabel="chiller", if last seen was chiller message this is true.
|
||||
//heatmump_mode chiller_mode;
|
||||
// Add any other special params for virtual button
|
||||
} vbutton_detail;
|
||||
} altlabel_detail;
|
||||
|
||||
typedef enum {
|
||||
NET_MQTT=0,
|
||||
|
|
@ -343,7 +337,7 @@ struct aqualinkdata
|
|||
uint16_t status_mask;
|
||||
char version[AQ_MSGLEN*2]; // Will be replaced by below in future
|
||||
char revision[AQ_MSGLEN]; // Will be replaced by below in future
|
||||
|
||||
uint8_t updatetype;
|
||||
// The below 4 are set (sometimes) but not used yet
|
||||
char panel_rev[AQ_MSGLEN]; // From panel
|
||||
char panel_cpu[AQ_MSGLEN]; // From panel
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ bool isAqualinkDStopping() {
|
|||
void intHandler(int sig_num)
|
||||
{
|
||||
if (sig_num == SIGRUPGRADE) {
|
||||
if (! run_aqualinkd_upgrade(false)) {
|
||||
if (! run_aqualinkd_upgrade(_aqualink_data.updatetype)) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "AqualinkD upgrade failed!\n");
|
||||
}
|
||||
return; // Let the upgrade process terminate us.
|
||||
|
|
@ -132,20 +132,9 @@ void intHandler(int sig_num)
|
|||
//LOG(AQUA_LOG,LOG_NOTICE, "Stopping!\n");
|
||||
//if (dummy){}// stop compile warnings
|
||||
|
||||
// In blocking mode, die as cleanly as possible.
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0) {
|
||||
stopPacketLogger();
|
||||
// This should force port to close and do somewhat gracefull exit.
|
||||
close_blocking_serial_port();
|
||||
//exit(-1);
|
||||
}
|
||||
#else
|
||||
stopPacketLogger();
|
||||
// This should force port to close and do somewhat gracefull exit.
|
||||
if (serial_blockingmode())
|
||||
close_blocking_serial_port();
|
||||
#endif
|
||||
close_serial_port(-1);
|
||||
|
||||
}
|
||||
|
||||
bool isVirtualButtonEnabled() {
|
||||
|
|
@ -941,7 +930,7 @@ void main_loop()
|
|||
bool got_probe_extended = false;
|
||||
bool got_probe_rssa = false;
|
||||
bool print_once = false;
|
||||
int blank_read_reconnect = MAX_ZERO_READ_BEFORE_RECONNECT_BLOCKING; // Will get reset if non blocking
|
||||
int blank_read_reconnect = MAX_ZERO_READ_BEFORE_RECONNECT; // Will get reset if non blocking
|
||||
bool auto_config_complete = true;
|
||||
|
||||
|
||||
|
|
@ -1067,8 +1056,8 @@ void main_loop()
|
|||
AddAQDstatusMask(ERROR_SERIAL);
|
||||
}
|
||||
|
||||
if (!serial_blockingmode())
|
||||
blank_read_reconnect = MAX_ZERO_READ_BEFORE_RECONNECT_NONBLOCKING;
|
||||
//if (!serial_blockingmode())
|
||||
// blank_read_reconnect = MAX_ZERO_READ_BEFORE_RECONNECT_NONBLOCKING;
|
||||
|
||||
#ifdef AQ_PDA
|
||||
if (isPDA_PANEL) {
|
||||
|
|
@ -1207,15 +1196,7 @@ void main_loop()
|
|||
|
||||
else if (packet_length <= 0) {
|
||||
blank_read++;
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqconfig_.rs_poll_speed < 0)
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Blank RS485 read\n");
|
||||
else
|
||||
delay(2);
|
||||
#else
|
||||
if (serial_blockingmode())
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Blank RS485 read\n");
|
||||
#endif
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Blank RS485 read\n");
|
||||
}
|
||||
else if (packet_length > 0) {
|
||||
blank_read = 0;
|
||||
|
|
@ -1306,10 +1287,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)
|
||||
blank_read_reconnect = blank_read_reconnect * 50;
|
||||
#endif
|
||||
|
||||
//int loopnum=0;
|
||||
blank_read = 0;
|
||||
|
|
@ -1331,10 +1308,6 @@ void main_loop()
|
|||
//broadcast_aqualinkstate_error(CONNECTION_ERROR);
|
||||
broadcast_aqualinkstate_error(getAqualinkDStatusMessage(&_aqualink_data));
|
||||
sleep(10);
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
poll_net_services(1000);
|
||||
poll_net_services(3000);
|
||||
#endif
|
||||
// broadcast_aqualinkstate_error(mgr.active_connections, "No connection to RS control panel");
|
||||
}
|
||||
else
|
||||
|
|
@ -1368,29 +1341,26 @@ void main_loop()
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
packet_length = get_packet(rs_fd, packet_buffer);
|
||||
|
||||
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 (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;
|
||||
// AQSERR_READ // reset (-1)
|
||||
if (packet_length == AQSERR_TIMEOUT) {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Timeout read on serial port\n");
|
||||
//blank_read = blank_read_reconnect;
|
||||
} else if (packet_length == AQSERR_READ) {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Error read on serial port, resetting\n");
|
||||
blank_read = blank_read_reconnect;
|
||||
} else {
|
||||
// In non blocking, so sleep for 2 milliseconds
|
||||
delay(NONBLOCKING_SERIAL_DELAY);
|
||||
//delay(NONBLOCKING_SERIAL_DELAY);
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Nothing read on serial port\n");
|
||||
}
|
||||
//if (blank_read > max_blank_read) {
|
||||
// LOG(AQUA_LOG,LOG_NOTICE, "Nothing read on serial %d\n",blank_read);
|
||||
|
|
@ -1495,19 +1465,7 @@ void main_loop()
|
|||
} else {
|
||||
DEBUG_TIMER_CLEAR(_rs_packet_timer); // Clear timer, no need to print anything
|
||||
}
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (_aqualink_data.updated) {
|
||||
broadcast_aqualinkstate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
poll_net_services(packet_length>0?0:_aqconfig_.rs_poll_speed); // Don;t wait if we read something.
|
||||
#endif
|
||||
// NSF might want to wait if we are on a non blocking serial port.
|
||||
|
||||
// Any unactioned commands
|
||||
if (_aqualink_data.unactioned.type != NO_ACTION)
|
||||
{
|
||||
|
|
|
|||
169
source/config.c
169
source/config.c
|
|
@ -60,6 +60,7 @@ char *generate_mqtt_id(char *buf, int len);
|
|||
pump_detail *getpump(struct aqualinkdata *aqdata, int button);
|
||||
bool populatePumpData(struct aqualinkdata *aqdata, char *pumpcfg ,aqkey *button, char *value);
|
||||
bool populateLightData(struct aqualinkdata *aqdata, char *lightcfg ,aqkey *button, char *value);
|
||||
bool populateAltLabel(aqkey *button, char *value);
|
||||
pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button);
|
||||
clight_detail *getLightFromButtonID(struct aqualinkdata *aqdata, aqkey *button);
|
||||
aqkey *getVirtualButton(struct aqualinkdata *aqdata, int num);
|
||||
|
|
@ -168,6 +169,7 @@ const int _dcfg_light_programming_mode = 0;
|
|||
const int _dcfg_light_programming_initial_on = 15;
|
||||
const int _dcfg_light_programming_initial_off = 12;
|
||||
|
||||
|
||||
const int _dcfg_sensor_poll_time = 300;
|
||||
|
||||
void init_parameters (struct aqconfig * parms)
|
||||
|
|
@ -203,6 +205,16 @@ void init_parameters (struct aqconfig * parms)
|
|||
_cfgParams[_numCfgParams].valid_values = CFG_V_log_level;
|
||||
_cfgParams[_numCfgParams].default_value = (void *) &_dcfg_loglevel;
|
||||
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.mg_log_level;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_INT; // Set with _aqconfig_.log_level = text2elevel(cleanalloc(value));
|
||||
_cfgParams[_numCfgParams].name = CFG_N_MG_log_level;
|
||||
_cfgParams[_numCfgParams].config_mask |= CFG_READONLY;
|
||||
_cfgParams[_numCfgParams].default_value = (void *) &_dcfg_zero;
|
||||
|
||||
|
||||
|
||||
_numCfgParams++;
|
||||
_cfgParams[_numCfgParams].value_ptr = &_aqconfig_.web_directory;
|
||||
_cfgParams[_numCfgParams].value_type = CFG_STRING;
|
||||
|
|
@ -691,11 +703,6 @@ void init_parameters (struct aqconfig * parms)
|
|||
parms->log_protocol_packets = false; // Read & Write as packets write to file
|
||||
parms->log_raw_bytes = false; // bytes read and write to file
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
parms->rs_poll_speed = DEFAULT_POLL_SPEED;
|
||||
parms->thread_netservices = true;
|
||||
#endif
|
||||
|
||||
parms->device_pre_state = true;
|
||||
|
||||
clearDebugLogMask();
|
||||
|
|
@ -707,103 +714,6 @@ void init_parameters (struct aqconfig * parms)
|
|||
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
|
||||
|
||||
set_config_defaults();
|
||||
|
||||
//set_config_defaults();
|
||||
|
||||
//int i;
|
||||
//char *p;
|
||||
//parms->rs_panel_size = 8;
|
||||
/*
|
||||
parms->serial_port = DEFAULT_SERIALPORT;
|
||||
parms->log_level = DEFAULT_LOG_LEVEL;
|
||||
parms->socket_port = DEFAULT_WEBPORT;
|
||||
parms->web_directory = DEFAULT_WEBROOT;
|
||||
//parms->device_id = strtoul(DEFAULT_DEVICE_ID, &p, 16);
|
||||
parms->device_id = strtoul(DEFAULT_DEVICE_ID, NULL, 16);
|
||||
parms->rssa_device_id = NUL;
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
parms->extended_device_id = NUL;
|
||||
parms->extended_device_id_programming = false;
|
||||
|
||||
*/
|
||||
/*
|
||||
//sscanf(DEFAULT_DEVICE_ID, "0x%x", &parms->device_id);
|
||||
parms->override_freeze_protect = FALSE;
|
||||
|
||||
parms->mqtt_dz_sub_topic = DEFAULT_MQTT_DZ_OUT;
|
||||
parms->mqtt_dz_pub_topic = DEFAULT_MQTT_DZ_IN;
|
||||
parms->mqtt_hass_discover_topic = DEFAULT_HASS_DISCOVER;
|
||||
parms->mqtt_aq_topic = DEFAULT_MQTT_AQ_TP;
|
||||
parms->mqtt_server = DEFAULT_MQTT_SERVER;
|
||||
parms->mqtt_user = DEFAULT_MQTT_USER;
|
||||
parms->mqtt_passwd = DEFAULT_MQTT_PASSWD;
|
||||
parms->mqtt_hass_discover_use_mac = false;
|
||||
|
||||
parms->dzidx_air_temp = TEMP_UNKNOWN;
|
||||
parms->dzidx_pool_water_temp = TEMP_UNKNOWN;
|
||||
parms->dzidx_spa_water_temp = TEMP_UNKNOWN;
|
||||
parms->dzidx_swg_percent = TEMP_UNKNOWN;
|
||||
parms->dzidx_swg_ppm = TEMP_UNKNOWN;
|
||||
parms->dzidx_swg_status = TEMP_UNKNOWN;
|
||||
//parms->dzidx_pool_thermostat = TEMP_UNKNOWN; // removed until domoticz has a better virtual thermostat
|
||||
//parms->dzidx_spa_thermostat = TEMP_UNKNOWN; // removed until domoticz has a better virtual thermostat
|
||||
parms->light_programming_mode = 0;
|
||||
parms->light_programming_initial_on = 15;
|
||||
parms->light_programming_initial_off = 12;
|
||||
//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
|
||||
//parms->onetouch_mode = false;
|
||||
parms->convert_mqtt_temp = true;
|
||||
parms->convert_dz_temp = true;
|
||||
parms->report_zero_pool_temp = true;
|
||||
parms->report_zero_spa_temp = true;
|
||||
//parms->read_all_devices = true;
|
||||
//parms->read_pentair_packets = false;
|
||||
parms->read_RS485_devmask = 0;
|
||||
parms->use_panel_aux_labels = false;
|
||||
|
||||
//parms->force_swg = false;
|
||||
//parms->force_ps_setpoints = false;
|
||||
//parms->force_frzprotect_setpoints = false;
|
||||
//parms->force_chem_feeder = false;
|
||||
|
||||
//parms->swg_pool_and_spa = false;
|
||||
//parms->swg_zero_ignore = DEFAULT_SWG_ZERO_IGNORE_COUNT;
|
||||
parms->display_warnings_web = false;
|
||||
|
||||
parms->log_protocol_packets = false; // Read & Write as packets write to file
|
||||
parms->log_raw_bytes = false; // bytes read and write to file
|
||||
|
||||
parms->sync_panel_time = true;
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
parms->rs_poll_speed = DEFAULT_POLL_SPEED;
|
||||
parms->thread_netservices = true;
|
||||
#endif
|
||||
|
||||
parms->enable_scheduler = true;
|
||||
|
||||
parms->schedule_event_mask = 0;
|
||||
//parms->sched_chk_poweron = false;
|
||||
//parms->sched_chk_freezeprotectoff = false;
|
||||
//parms->sched_chk_boostoff = false;
|
||||
parms->sched_chk_pumpon_hour = 0;
|
||||
parms->sched_chk_pumpoff_hour = 0;
|
||||
|
||||
parms->ftdi_low_latency = true;
|
||||
parms->frame_delay = 0;
|
||||
parms->device_pre_state = true;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1127,6 +1037,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
_aqconfig_.read_RS485_devmask |= READ_RS485_JAN_CHEM_FEDR;
|
||||
else
|
||||
_aqconfig_.read_RS485_devmask &= ~ READ_RS485_JAN_CHEM_FEDR;
|
||||
rtn=true;
|
||||
} else if ((strncasecmp(param, CFG_N_mqtt_hass_discover_topic, strlen(CFG_N_mqtt_hass_discover_topic)) == 0) ||
|
||||
(strncasecmp(param, "mqtt_hassio_discover_topic", 26) == 0) ||
|
||||
(strncasecmp(param, "mqtt_hass_discover_topic", 24) == 0)) {
|
||||
|
|
@ -1273,7 +1184,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
|
||||
if ( ! populateLightData(aqdata, param + 10, &aqdata->aqbuttons[num], value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, %s=%s Ignored!",param,value);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, %s Ignored!",param,value);
|
||||
}
|
||||
|
||||
rtn=true;
|
||||
|
|
@ -1318,10 +1229,14 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
}
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param + 17, "_altLabel", 9) == 0) {
|
||||
char *label = cleanalloc(value);
|
||||
aqkey *button = getVirtualButton(aqdata, num);
|
||||
if (button != NULL) {
|
||||
setVirtualButtonAltLabel(button, label);
|
||||
//char *label = cleanalloc(value);
|
||||
aqkey *vbutton = getVirtualButton(aqdata, num);
|
||||
if (vbutton != NULL) {
|
||||
//setVirtualButtonAltLabel(vbutton, label);
|
||||
if ( ! populateAltLabel(vbutton, value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, setting alt_label for %d\n",vbutton->label);
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_WARNING, "Error with '%s', total buttons=%d, config has %d already, ignoring!\n",param, TOTAL_BUTTONS, aqdata->total_buttons);
|
||||
}
|
||||
|
|
@ -1343,7 +1258,7 @@ if (strlen(cleanwhitespace(value)) <= 0) {
|
|||
if (vbutton != NULL) {
|
||||
if ( ! populateLightData(aqdata, param + 18, vbutton, value) )
|
||||
{
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, %s=%s Ignored!",param,value);
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, couldn't find light. `%s` Ignored!",param);
|
||||
}
|
||||
} else {
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error, could not find vitrual button for `%s`",param);
|
||||
|
|
@ -1500,6 +1415,20 @@ bool populatePumpData(struct aqualinkdata *aqdata, char *pumpcfg ,aqkey *button,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool populateAltLabel(aqkey *button, char *value)
|
||||
{
|
||||
return setVirtualButtonAltLabel(button, cleanalloc(value));
|
||||
/*
|
||||
setButtonSpecialMask(button, VIRTUAL_BUTTON_ALT_LABEL);
|
||||
|
||||
button->special_mask_ptr = malloc(sizeof(altlabel_detail));
|
||||
((altlabel_detail *)button->special_mask_ptr)->altlabel = cleanalloc(value);
|
||||
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
|
||||
// lightcfg is pointer to lightMode, lightID, lightModeCacheValue (ie pull off button_??_ or vurtual_button_??_)
|
||||
bool populateLightData(struct aqualinkdata *aqdata, char *lightcfg ,aqkey *button, char *value)
|
||||
{
|
||||
|
|
@ -1533,6 +1462,8 @@ bool populateLightData(struct aqualinkdata *aqdata, char *lightcfg ,aqkey *butto
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
||||
{
|
||||
int pi;
|
||||
|
|
@ -1547,7 +1478,10 @@ pump_detail *getPumpFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
|||
// Create new entry
|
||||
if (aqdata->num_pumps < MAX_PUMPS) {
|
||||
//printf ("Creating pump %d\n",button);
|
||||
button->special_mask |= VS_PUMP;
|
||||
|
||||
setButtonSpecialMask(button, VS_PUMP);
|
||||
//button->special_mask |= VS_PUMP;
|
||||
|
||||
button->special_mask_ptr = (void*)&aqdata->pumps[aqdata->num_pumps];
|
||||
aqdata->pumps[aqdata->num_pumps].button = button;
|
||||
aqdata->pumps[aqdata->num_pumps].pumpType = PT_UNKNOWN;
|
||||
|
|
@ -1580,13 +1514,16 @@ clight_detail *getLightFromButtonID(struct aqualinkdata *aqdata, aqkey *button)
|
|||
|
||||
// Create new entry
|
||||
if (aqdata->num_lights < MAX_LIGHTS) {
|
||||
button->special_mask |= PROGRAM_LIGHT;
|
||||
setButtonSpecialMask(button, PROGRAM_LIGHT);
|
||||
//button->special_mask |= PROGRAM_LIGHT;
|
||||
button->special_mask_ptr = (void*)&aqdata->lights[aqdata->num_lights];
|
||||
aqdata->lights[aqdata->num_lights].button = button;
|
||||
aqdata->num_lights++;
|
||||
return &aqdata->lights[aqdata->num_lights-1];
|
||||
}
|
||||
|
||||
LOG(AQUA_LOG,LOG_ERR, "Config error couldn't add light, max lights of %d reached\n",MAX_LIGHTS);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1764,7 +1701,7 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
if (_aqconfig_.extended_device_id >= 0x30 && _aqconfig_.extended_device_id <= 0x33) {
|
||||
for (i = 0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask) && (rsm_strmatch(((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel, "Chiller") == 0) ){
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask) && (rsm_strmatch(((altlabel_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel, "Chiller") == 0) ){
|
||||
aqdata->chiller_button = &aqdata->aqbuttons[i];
|
||||
//aqdata->chiller_button->special_mask |= VIRTUAL_BUTTON_CHILLER;
|
||||
setMASK(aqdata->chiller_button->special_mask, VIRTUAL_BUTTON_CHILLER);
|
||||
|
|
@ -1992,7 +1929,7 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
for (i = 0; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
//char ext[] = " VSP ID None | AL ID 0 ";
|
||||
char ext[60];
|
||||
char ext[120];
|
||||
ext[0] = '\0';
|
||||
for (j = 0; j < aqdata->num_pumps; j++) {
|
||||
if (aqdata->pumps[j].button == &aqdata->aqbuttons[i]) {
|
||||
|
|
@ -2004,16 +1941,16 @@ void check_print_config (struct aqualinkdata *aqdata)
|
|||
}
|
||||
for (j = 0; j < aqdata->num_lights; j++) {
|
||||
if (aqdata->lights[j].button == &aqdata->aqbuttons[i]) {
|
||||
sprintf(ext,"Light Progm | CTYPE %-1d |",aqdata->lights[j].lightType);
|
||||
sprintf(ext,"Light Progm %-1d |",aqdata->lights[j].lightType);
|
||||
}
|
||||
}
|
||||
if (isVBUTTON(aqdata->aqbuttons[i].special_mask)) {
|
||||
if (aqdata->aqbuttons[i].rssd_code != NUL) {
|
||||
sprintf(ext,"OneTouch %d |",aqdata->aqbuttons[i].rssd_code - 15);
|
||||
sprintf(ext,"OneTouch %d |",aqdata->aqbuttons[i].rssd_code - 15);
|
||||
}
|
||||
}
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask)) {
|
||||
sprintf(ext,"%-12s|", ((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel);
|
||||
sprintf(ext,"%-12s|", ((altlabel_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel);
|
||||
}
|
||||
if (aqdata->aqbuttons[i].dz_idx > 0) {
|
||||
sprintf(ext+strlen(ext), "dzidx %-3d",aqdata->aqbuttons[i].dz_idx);
|
||||
|
|
@ -2434,7 +2371,7 @@ bool writeCfg (struct aqualinkdata *aqdata)
|
|||
}
|
||||
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask)) {
|
||||
fprintf(fp,"%s_altLabel=%s\n", prefix, ((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel);
|
||||
fprintf(fp,"%s_altLabel=%s\n", prefix, ((altlabel_detail *)aqdata->aqbuttons[i].special_mask_ptr)->altlabel);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ struct aqconfig
|
|||
char *config_file;
|
||||
char *serial_port;
|
||||
unsigned int log_level;
|
||||
unsigned int mg_log_level;
|
||||
char *socket_port;
|
||||
char *web_directory;
|
||||
unsigned char device_id;
|
||||
|
|
@ -112,10 +113,6 @@ struct aqconfig
|
|||
bool save_debug_log_masks;
|
||||
bool save_light_programming_value;
|
||||
int sensor_poll_time;
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
int rs_poll_speed; // Need to remove
|
||||
bool thread_netservices; // Need to remove
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CONFIG_C
|
||||
|
|
@ -175,6 +172,8 @@ bool mac(char *buf, int len, bool useDelimiter);
|
|||
char *cleanalloc(char *str);
|
||||
char *ncleanalloc(char *str, int length);
|
||||
|
||||
|
||||
|
||||
const char *pumpType2String(pump_type ptype);
|
||||
|
||||
int save_config_js(const char* inBuf, int inSize, char* outBuf, int outSize, struct aqualinkdata *aqdata);
|
||||
|
|
@ -236,6 +235,7 @@ int _numCfgParams;
|
|||
|
||||
#define CFG_N_serial_port "serial_port"
|
||||
#define CFG_N_log_level "log_level"
|
||||
#define CFG_N_MG_log_level "mg_log_level"
|
||||
#define CFG_V_log_level "[\"DEBUG_SERIAL\", \"DEBUG\", \"INFO\", \"NOTICE\", \"WARNING\", \"ERROR\"]"
|
||||
#define CFG_N_socket_port "socket_port"
|
||||
#define CFG_N_web_directory "web_directory"
|
||||
|
|
|
|||
|
|
@ -977,6 +977,7 @@ bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_l
|
|||
LOG(DJAN_LOG, LOG_INFO, "%s\n", msg);
|
||||
|
||||
/*
|
||||
I think the below may be accurate
|
||||
ph_setpoint = float(raw_data[8]) / 10
|
||||
acl_setpoint = raw_data[9] * 10
|
||||
ph_current = float(raw_data[10]) / 10
|
||||
|
|
@ -988,6 +989,61 @@ bool processPacketFromJandyChemFeeder(unsigned char *packet_buffer, int packet_l
|
|||
|
||||
|
||||
|
||||
|
||||
// ---- pH ----
|
||||
float ph_from_counts(int counts, float temp_c) {
|
||||
|
||||
// Convert ADC counts + water temperature to pH.
|
||||
// counts : ADC counts (0..4095)
|
||||
// temp_c : water temperature in °C
|
||||
// returns : pH value
|
||||
|
||||
|
||||
const int n_bits = 12;
|
||||
const float v_ref = 3.3f; // ADC reference voltage
|
||||
const float v_mid = 1.650f; // mid-rail voltage representing pH 7
|
||||
const float gain_pH = 12.745f; // amplifier gain
|
||||
|
||||
// Step 1: counts -> voltage
|
||||
float v = ((float)counts / (float)((1 << n_bits) - 1)) * v_ref;
|
||||
|
||||
// Step 2: electrode mV after gain removal
|
||||
float v_elec_mV = (v - v_mid) * 1000.0f / gain_pH;
|
||||
|
||||
// Step 3: Nernst slope at water temperature
|
||||
float slope = 59.16f * (temp_c + 273.15f) / 298.15f; // mV/pH
|
||||
|
||||
// Step 4: pH
|
||||
return 7.0f + (v_elec_mV / slope);
|
||||
}
|
||||
|
||||
// ---- ORP ----
|
||||
float orp_from_counts(int counts) {
|
||||
/*
|
||||
Convert ADC counts to ORP (mV)
|
||||
counts : ADC counts (0..4095)
|
||||
returns: ORP in millivolts
|
||||
*/
|
||||
return -1909.25f + 0.93294f * (float)counts;
|
||||
}
|
||||
|
||||
// ---- Example usage ----
|
||||
/*
|
||||
int main(void) {
|
||||
int counts_ph = 2341; // example from Group 1
|
||||
int counts_orp = 2916; // example from Group 2
|
||||
float temp_c = 38.0f; // water temperature in °C
|
||||
|
||||
float ph_value = ph_from_counts(counts_ph, temp_c);
|
||||
float orp_value = orp_from_counts(counts_orp);
|
||||
|
||||
printf("pH = %.2f\n", ph_value);
|
||||
printf("ORP = %.0f mV\n", orp_value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
bool processPacketToJandyChemAnalyzer(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata)
|
||||
{
|
||||
|
||||
|
|
@ -998,13 +1054,34 @@ bool processPacketToJandyChemAnalyzer(unsigned char *packet_buffer, int packet_l
|
|||
|
||||
bool processPacketFromJandyChemAnalyzer(unsigned char *packet_buffer, int packet_length, struct aqualinkdata *aqdata, const unsigned char previous_packet_to){
|
||||
|
||||
int watertemp = 0;
|
||||
|
||||
if (isCOMBO_PANEL && aqdata->aqbuttons[SPA_INDEX].led->state == ON) {
|
||||
watertemp = aqdata->spa_temp;
|
||||
LOG(DJAN_LOG, LOG_INFO, "Last panel info pH=%f, ORP=%d, Spa water temp=%d (Spamode)\n",aqdata->ph, aqdata->orp, aqdata->spa_temp );
|
||||
} else {
|
||||
watertemp = aqdata->pool_temp;
|
||||
LOG(DJAN_LOG, LOG_INFO, "Last panel info pH=%f, ORP=%d, Pool water temp=%d\n",aqdata->ph, aqdata->orp, aqdata->pool_temp );
|
||||
}
|
||||
|
||||
|
||||
if (watertemp <= 0) {
|
||||
if (previous_packet_to == 0x84){
|
||||
if (packet_buffer[3] == 0x28 && packet_buffer[5] == 0x01) {
|
||||
float ph = ph_from_counts( ((packet_buffer[6] * 256) + packet_buffer[7]),
|
||||
aqdata->temp_units==FAHRENHEIT?roundf(degFtoC(watertemp)):watertemp);
|
||||
LOG(DJAN_LOG, LOG_INFO, "Guess at caculating pH=%f\n", ph);
|
||||
}
|
||||
} else if (previous_packet_to == 0x84){
|
||||
if (packet_buffer[3] == 0x28 && packet_buffer[5] == 0x02) {
|
||||
float orp = orp_from_counts( ((packet_buffer[6] * 256) + packet_buffer[7]));
|
||||
LOG(DJAN_LOG, LOG_INFO, "Guess at caculating ORP=%f\n", orp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(DJAN_LOG, LOG_INFO, "ORP & pH not caculated as watertemp %d is out of range\n", watertemp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1108,7 +1185,7 @@ void processHeatPumpDisplayMessage(char *msg, struct aqualinkdata *aqdata) {
|
|||
// are we heat pump or chiller
|
||||
if (stristr(msg,"Chiller") != NULL) {
|
||||
// NSF Should check alt_mode is Chiller and not Heat Pump
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
((altlabel_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
hpstate = HP_COOL;
|
||||
}
|
||||
if (stristr(msg," ENA") != NULL) {
|
||||
|
|
@ -1120,7 +1197,7 @@ void processHeatPumpDisplayMessage(char *msg, struct aqualinkdata *aqdata) {
|
|||
}
|
||||
|
||||
LOG(AQUA_LOG,LOG_DEBUG, "Set %s to %s from message '%s'",
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->altlabel:aqdata->chiller_button->label,
|
||||
((altlabel_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?((altlabel_detail *)aqdata->chiller_button->special_mask_ptr)->altlabel:aqdata->chiller_button->label,
|
||||
LED2text(aqdata->chiller_button->led->state), msg);
|
||||
}
|
||||
|
||||
|
|
@ -1142,9 +1219,9 @@ void updateHeatPumpLed(heatpumpstate state, aqledstate ledstate, struct aqualink
|
|||
}
|
||||
|
||||
if (state == HP_COOL) {
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
((altlabel_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = true;
|
||||
} else if (state == HP_HEAT) {
|
||||
((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = false;
|
||||
((altlabel_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode = false;
|
||||
}
|
||||
/*
|
||||
// If LED state is enable (that's a reqest), so only change if off.
|
||||
|
|
@ -1383,4 +1460,83 @@ packet To 0x00 of type iAq receive read | HEX: 0x10|0x02|0x00|0x31|0x2d|0x06|0x0
|
|||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
**************
|
||||
|
||||
TruSense
|
||||
|
||||
Below is the repeat look (looks like 2 ID's) = is one for ORP and other pH ?????
|
||||
|
||||
First 3 to 0x84, are requests 0x00,0x01,0x03. So ignore that in reply and everything else you get data at
|
||||
Last 2 bytes (below)
|
||||
0x02|0x14
|
||||
0x09|0x21
|
||||
0x00|0x00
|
||||
|
||||
Similar for 0x86 at you get
|
||||
0x0b|0x6a
|
||||
|
||||
|
||||
As two independent bytes 9 and 33
|
||||
Unsigned 16-bit, big-endian (0x09 is high byte)
|
||||
0x09 × 256 + 0x21 = 2304 + 33 = 2337
|
||||
0x09×256+0x21= 2304+33 =2337
|
||||
|
||||
Unsigned 16-bit, little-endian (0x21 is high byte)
|
||||
0x21 × 256 + 0x09 = 8448 + 9 = 8457
|
||||
0x21×256+0x09= 8448+9 = 8457
|
||||
|
||||
|
||||
|
||||
To 0x84 of type Probe | HEX: 0x10|0x02|0x84|0x00|0x96|0x10|0x03|
|
||||
To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
|
||||
To 0x84 of type Unknown '0x20' | HEX: 0x10|0x02|0x84|0x20|0x00|0xb6|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x00|0x02|0x14|0x70|0x10|0x03|
|
||||
|
||||
To 0x84 of type Unknown '0x20' | HEX: 0x10|0x02|0x84|0x20|0x01|0xb7|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x01|0x09|0x21|0x85|0x10|0x03|
|
||||
|
||||
To 0x84 of type Unknown '0x20' | HEX: 0x10|0x02|0x84|0x20|0x03|0xb9|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x03|0x00|0x00|0x5d|0x10|0x03|
|
||||
|
||||
To 0x86 of type Probe | HEX: 0x10|0x02|0x86|0x00|0x98|0x10|0x03|
|
||||
To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
|
||||
To 0x86 of type Unknown '0x20' | HEX: 0x10|0x02|0x86|0x20|0x02|0xba|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x6a|0xd1|0x10|0x03|
|
||||
|
||||
|
||||
|
||||
# list of unique 0x84 returns all represent ORP:810 or pH:7.3 (water temp 100 and 102)
|
||||
To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x00|0x02|0x14|0x70|0x10|0x03|
|
||||
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x01|0x09|0x21|0x85|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x01|0x09|0x22|0x86|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x01|0x09|0x27|0x8b|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x01|0x09|0x28|0x8c|0x10|0x03|
|
||||
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x03|0x00|0x00|0x5d|0x10|0x03|
|
||||
|
||||
# list of unique 0x86 returns all represent ORP:810 or pH:7.3 (water temp 100 and 102)
|
||||
To 0x00 of type Ack | HEX: 0x10|0x02|0x00|0x01|0x00|0x00|0x13|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x54|0xbb|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x55|0xbc|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x57|0xbe|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x59|0xc0|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x69|0xd0|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x6a|0xd1|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x6b|0xd2|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x6c|0xd3|0x10|0x03|
|
||||
To 0x00 of type iAq PageEnd | HEX: 0x10|0x02|0x00|0x28|0x20|0x02|0x0b|0x6d|0xd4|0x10|0x03|
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -294,13 +294,13 @@ int matchLabel2Button(const char* pageButtonName, aqkey *aqbutton, int ignorecha
|
|||
int rtn = rsm_strmatch_ignore(pageButtonName, aqbutton->label, ignorechars);
|
||||
|
||||
if (rtn == 0 && isVBUTTON_ALTLABEL(aqbutton->special_mask) ) {
|
||||
((vbutton_detail *)aqbutton->special_mask_ptr)->in_alt_mode = false;
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Virtual Button `%s` is NOT in alternate state of `%s`\n", aqbutton->label, ((vbutton_detail *)aqbutton->special_mask_ptr)->altlabel);
|
||||
((altlabel_detail *)aqbutton->special_mask_ptr)->in_alt_mode = false;
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Virtual Button `%s` is NOT in alternate state of `%s`\n", aqbutton->label, ((altlabel_detail *)aqbutton->special_mask_ptr)->altlabel);
|
||||
} else if (rtn != 0 && isVBUTTON_ALTLABEL(aqbutton->special_mask) ) {
|
||||
rtn = rsm_strmatch_ignore(pageButtonName, ((vbutton_detail *)aqbutton->special_mask_ptr)->altlabel,ignorechars );
|
||||
rtn = rsm_strmatch_ignore(pageButtonName, ((altlabel_detail *)aqbutton->special_mask_ptr)->altlabel,ignorechars );
|
||||
if (rtn == 0 ) {
|
||||
((vbutton_detail *)aqbutton->special_mask_ptr)->in_alt_mode = true;
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Virtual Button `%s` is in alternate state of `%s`\n", aqbutton->label, ((vbutton_detail *)aqbutton->special_mask_ptr)->altlabel);
|
||||
((altlabel_detail *)aqbutton->special_mask_ptr)->in_alt_mode = true;
|
||||
LOG(IAQT_LOG,LOG_DEBUG, "Virtual Button `%s` is in alternate state of `%s`\n", aqbutton->label, ((altlabel_detail *)aqbutton->special_mask_ptr)->altlabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ void *set_aqualink_iaqtouch_device_on_off( void *ptr )
|
|||
button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].label);
|
||||
|
||||
if (button == NULL && isVBUTTON_ALTLABEL(aq_data->aqbuttons[device].special_mask) ) { // Try alt button name
|
||||
button = iaqtFindButtonByLabel(((vbutton_detail *)aq_data->aqbuttons[device].special_mask_ptr)->altlabel);
|
||||
button = iaqtFindButtonByLabel(((altlabel_detail *)aq_data->aqbuttons[device].special_mask_ptr)->altlabel);
|
||||
}
|
||||
|
||||
if (button == NULL) {
|
||||
|
|
@ -523,7 +523,7 @@ void *set_aqualink_iaqtouch_device_on_off( void *ptr )
|
|||
button = iaqtFindButtonByLabel(aq_data->aqbuttons[device].label);
|
||||
|
||||
if (button == NULL && isVBUTTON_ALTLABEL(aq_data->aqbuttons[device].special_mask) ) { // Try alt button name
|
||||
button = iaqtFindButtonByLabel(((vbutton_detail *)aq_data->aqbuttons[device].special_mask_ptr)->altlabel);
|
||||
button = iaqtFindButtonByLabel(((altlabel_detail *)aq_data->aqbuttons[device].special_mask_ptr)->altlabel);
|
||||
}
|
||||
|
||||
// If not found see if page has next
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
|
|||
}
|
||||
if (isVBUTTON_ALTLABEL(button->special_mask))
|
||||
{
|
||||
length += sprintf(buffer, ",\"alt_label\":\"%s\", \"in_alt_mode\": \"%s\" ",((vbutton_detail *)button->special_mask_ptr)->altlabel, ((vbutton_detail *)button->special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
length += sprintf(buffer, ",\"alt_label\":\"%s\", \"in_alt_mode\": \"%s\" ",((altlabel_detail *)button->special_mask_ptr)->altlabel, ((altlabel_detail *)button->special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
//return buffer;
|
||||
}
|
||||
|
||||
|
|
@ -588,6 +588,12 @@ int build_device_JSON(struct aqualinkdata *aqdata, char* buffer, int size, bool
|
|||
|
||||
length += sprintf(buffer+length, "]}");
|
||||
|
||||
// Really crap test
|
||||
if (length >= size) {
|
||||
LOG(NET_LOG,LOG_ERR, "JSON: %s went over buffer size %d of %d\n", homekit?"homebridge":"web", length, size);
|
||||
buffer[size - 1] = '\0';
|
||||
}
|
||||
|
||||
LOG(NET_LOG,LOG_DEBUG, "JSON: %s used %d of %d\n", homekit?"homebridge":"web", length, size);
|
||||
|
||||
buffer[length] = '\0';
|
||||
|
|
@ -717,7 +723,7 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si
|
|||
if ( (ENABLE_CHILLER || aqdata->chiller_set_point != TEMP_UNKNOWN) && aqdata->chiller_button != NULL) {
|
||||
length += sprintf(buffer+length, ",\"chiller_set_pnt\":\"%d\"",aqdata->chiller_set_point );//"0",
|
||||
if (isVBUTTON_CHILLER(aqdata->chiller_button->special_mask))
|
||||
length += sprintf(buffer+length, ",\"chiller_mode\":\"%s\"",((vbutton_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?"cool":"heat");
|
||||
length += sprintf(buffer+length, ",\"chiller_mode\":\"%s\"",((altlabel_detail *)aqdata->chiller_button->special_mask_ptr)->in_alt_mode?"cool":"heat");
|
||||
}
|
||||
|
||||
if ( aqdata->air_temp == TEMP_UNKNOWN )
|
||||
|
|
@ -860,7 +866,7 @@ printf("Pump Type %d\n",aqdata->pumps[i].pumpType);
|
|||
for (i=aqdata->virtual_button_start; i < aqdata->total_buttons; i++)
|
||||
{
|
||||
if (isVBUTTON_ALTLABEL(aqdata->aqbuttons[i].special_mask)) {
|
||||
length += sprintf(buffer+length, "\"%s\": \"%s\",",aqdata->aqbuttons[i].name, ((vbutton_detail *)aqdata->aqbuttons[i].special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
length += sprintf(buffer+length, "\"%s\": \"%s\",",aqdata->aqbuttons[i].name, ((altlabel_detail *)aqdata->aqbuttons[i].special_mask_ptr)->in_alt_mode?JSON_ON:JSON_OFF );
|
||||
}
|
||||
}
|
||||
if (buffer[length-1] == ',')
|
||||
|
|
@ -1561,7 +1567,7 @@ int build_aqualink_config_JSON(char* buffer, int size, struct aqualinkdata *aq_d
|
|||
length += result;
|
||||
} else if ( isVBUTTON_ALTLABEL(aq_data->aqbuttons[i].special_mask)) {
|
||||
sprintf(buf,"%s_altlabel", prefix);
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &((vbutton_detail *)aq_data->aqbuttons[i].special_mask_ptr)->altlabel, CFG_STRING, 0, NULL, 0)) <= 0) {
|
||||
if ((result = json_cfg_element(buffer+length, size-length, buf, &((altlabel_detail *)aq_data->aqbuttons[i].special_mask_ptr)->altlabel, CFG_STRING, 0, NULL, 0)) <= 0) {
|
||||
LOG(NET_LOG,LOG_ERR, "Config json buffer full in, result truncated! size=%d curently used=%d\n",size,length);
|
||||
return length;
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
#ifndef AQ_MONGOOSE_ADDITIONAL_H_
|
||||
#define AQ_MONGOOSE_ADDITIONAL_H_
|
||||
|
||||
|
||||
/* Flags left for application */
|
||||
/*. mongoose 6.x had the below that we used & depend on.
|
||||
#define MG_F_USER_1 (1 << 20)
|
||||
#define MG_F_USER_2 (1 << 21)
|
||||
#define MG_F_USER_3 (1 << 22)
|
||||
#define MG_F_USER_4 (1 << 23)
|
||||
#define MG_F_USER_5 (1 << 24)
|
||||
#define MG_F_USER_6 (1 << 25)
|
||||
|
||||
|
||||
struct mg_connection {
|
||||
....
|
||||
...
|
||||
..
|
||||
unsigned long flags;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define AQ_M_USER_1 (1 << 0)
|
||||
#define AQ_M_USER_2 (1 << 1)
|
||||
#define AQ_M_USER_3 (1 << 2)
|
||||
#define AQ_M_USER_4 (1 << 3)
|
||||
#define AQ_M_USER_5 (1 << 4)
|
||||
#define AQ_M_USER_6 (1 << 5)
|
||||
|
||||
#define MG_F_USER_1 AQ_M_USER_1
|
||||
#define MG_F_USER_2 AQ_M_USER_2
|
||||
#define MG_F_USER_3 AQ_M_USER_3
|
||||
#define MG_F_USER_4 AQ_M_USER_4
|
||||
#define MG_F_USER_5 AQ_M_USER_5
|
||||
|
||||
/*
|
||||
struct mg_connection {
|
||||
unsigned short aq_flags;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif //AQ_MONGOOSE_ADDITIONAL_H_
|
||||
40306
source/mongoose.c
40306
source/mongoose.c
File diff suppressed because it is too large
Load Diff
9707
source/mongoose.h
9707
source/mongoose.h
File diff suppressed because it is too large
Load Diff
|
|
@ -13,6 +13,7 @@
|
|||
*
|
||||
* https://github.com/sfeakes/aqualinkd
|
||||
*/
|
||||
#define _GNU_SOURCE 1 // for strcasestr
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -52,6 +53,12 @@
|
|||
#include "pda.h"
|
||||
#endif
|
||||
|
||||
|
||||
struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
|
||||
return conn == NULL ? s->conns : conn->next;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
#if defined AQ_DEBUG || defined AQ_TM_DEBUG
|
||||
#include "timespec_subtract.h"
|
||||
|
|
@ -79,31 +86,19 @@ void reset_last_mqtt_status();
|
|||
bool uri_strcmp(const char *uri, const char *string);
|
||||
|
||||
//static const char *s_http_port = "8080";
|
||||
static struct mg_serve_http_opts _http_server_opts;
|
||||
//static struct mg_serve_http_opts _http_server_opts;
|
||||
static struct mg_http_serve_opts _http_server_opts;
|
||||
|
||||
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
static sig_atomic_t s_signal_received = 0;
|
||||
#endif
|
||||
|
||||
static void net_signal_handler(int sig_num) {
|
||||
//printf("** net_signal_handler **\n");
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
if (!_aqconfig_.thread_netservices) {
|
||||
signal(sig_num, net_signal_handler); // Reinstantiate signal handler to aqualinkd.c
|
||||
s_signal_received = sig_num;
|
||||
} else {
|
||||
intHandler(sig_num); // Force signal handler to aqualinkd.c
|
||||
}
|
||||
#else
|
||||
intHandler(sig_num); // Force signal handler to aqualinkd.c
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int is_websocket(const struct mg_connection *nc) {
|
||||
//return nc->flags & MG_F_IS_WEBSOCKET && !(nc->flags & MG_F_USER_2); // WS only, not WS simulator
|
||||
return nc->flags & MG_F_IS_WEBSOCKET;
|
||||
//return nc->flags & MG_F_IS_WEBSOCKET;
|
||||
return nc->is_websocket;
|
||||
}
|
||||
static void set_websocket_simulator(struct mg_connection *nc) {
|
||||
nc->flags |= MG_F_USER_2;
|
||||
|
|
@ -128,7 +123,7 @@ static void ws_send(struct mg_connection *nc, char *msg)
|
|||
{
|
||||
int size = strlen(msg);
|
||||
|
||||
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, msg, size);
|
||||
mg_ws_send(nc, msg, size, WEBSOCKET_OP_TEXT);
|
||||
|
||||
//LOG(NET_LOG,LOG_DEBUG, "WS: Sent %d characters '%s'\n",size, msg);
|
||||
}
|
||||
|
|
@ -291,13 +286,13 @@ bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection
|
|||
if ( (journal = open_journal()) == NULL) {
|
||||
//printf("Open faied\n");
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to open journal", WS_LOG_LENGTH,22);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
return false;
|
||||
}
|
||||
//printf("Open good %d\n",journal);
|
||||
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);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
sd_journal_close(journal);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -322,20 +317,20 @@ bool _broadcast_systemd_logmessages(bool aqMgrActive, bool reOpenStaleConnection
|
|||
{
|
||||
if (sd_journal_get_data(journal, "MESSAGE", &log, &len) < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to get journal message", WS_LOG_LENGTH,29);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
} else if (sd_journal_get_data(journal, "PRIORITY", &pri, &plen) < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to seek to journal message priority", WS_LOG_LENGTH,42);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
} else {
|
||||
build_logmsg_JSON(msg, atoi((const char *)pri+9), (const char *)log+8, WS_LOG_LENGTH,(int)len-8);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
cnt=0;
|
||||
sd_journal_get_cursor(journal, &cursor);
|
||||
}
|
||||
}
|
||||
if (rtn < 0) {
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Failed to seek to next journal message", WS_LOG_LENGTH,42);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
sd_journal_close(journal);
|
||||
active = false;
|
||||
} else if (rtn == 0) {
|
||||
|
|
@ -477,15 +472,21 @@ void _broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
|
||||
void send_mqtt(struct mg_connection *nc, const char *toppic, const char *message)
|
||||
{
|
||||
static uint16_t msg_id = 0;
|
||||
//static uint16_t msg_id = 0;
|
||||
|
||||
if (toppic == NULL)
|
||||
return;
|
||||
|
||||
if (msg_id >= 65535){msg_id=1;}else{msg_id++;}
|
||||
//if (msg_id >= 65535){msg_id=1;}else{msg_id++;}
|
||||
|
||||
//mg_mqtt_publish(nc, toppic, msg_id, MG_MQTT_QOS(0), message, strlen(message));
|
||||
mg_mqtt_publish(nc, toppic, msg_id, MG_MQTT_RETAIN | MG_MQTT_QOS(1), message, strlen(message));
|
||||
//mg_mqtt_publish(nc, toppic, msg_id, MG_MQTT_RETAIN | MG_MQTT_QOS(1), message, strlen(message));
|
||||
|
||||
struct mg_mqtt_opts pub_opts = {.topic = mg_str(toppic),
|
||||
.message = mg_str(message),
|
||||
.qos = 1,
|
||||
.retain = true};
|
||||
uint16_t msg_id = mg_mqtt_pub(nc, &pub_opts);
|
||||
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Published id=%d: %s %s\n", msg_id, toppic, message);
|
||||
}
|
||||
|
|
@ -649,7 +650,7 @@ void send_mqtt_temp_msg_new(struct mg_connection *nc, char *dev_name, long value
|
|||
void send_mqtt_setpoint_msg(struct mg_connection *nc, char *dev_name, long value)
|
||||
{
|
||||
static char mqtt_pub_topic[250];
|
||||
static char degC[10];
|
||||
static char degC[11];
|
||||
// Use "not CELS" over "equal FAHR" so we default to FAHR for unknown units
|
||||
//sprintf(degC, "%.2f", (_aqualink_data->temp_units==FAHRENHEIT && _aqconfig_.convert_mqtt_temp)?degFtoC(value):value );
|
||||
sprintf(degC, "%.2f", (_aqualink_data->temp_units!=CELSIUS && _aqconfig_.convert_mqtt_temp)?degFtoC(value):value );
|
||||
|
|
@ -659,7 +660,7 @@ void send_mqtt_setpoint_msg(struct mg_connection *nc, char *dev_name, long value
|
|||
void send_mqtt_numeric_msg(struct mg_connection *nc, char *dev_name, int value)
|
||||
{
|
||||
static char mqtt_pub_topic[250];
|
||||
static char msg[10];
|
||||
static char msg[11];
|
||||
|
||||
sprintf(msg, "%d", value);
|
||||
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
|
||||
|
|
@ -667,7 +668,7 @@ void send_mqtt_numeric_msg(struct mg_connection *nc, char *dev_name, int value)
|
|||
}
|
||||
void send_mqtt_float_msg(struct mg_connection *nc, char *dev_name, float value) {
|
||||
static char mqtt_pub_topic[250];
|
||||
static char msg[10];
|
||||
static char msg[11];
|
||||
|
||||
sprintf(msg, "%.2f", value);
|
||||
sprintf(mqtt_pub_topic, "%s/%s", _aqconfig_.mqtt_aq_topic, dev_name);
|
||||
|
|
@ -807,13 +808,13 @@ void mqtt_broadcast_aqualinkstate(struct mg_connection *nc)
|
|||
}
|
||||
|
||||
// Chiller is only on when in_alt_mode = true and led != off
|
||||
if ( _aqualink_data->chiller_button != NULL && ((vbutton_detail *) _aqualink_data->chiller_button->special_mask_ptr)->in_alt_mode == false ) {
|
||||
if ( _aqualink_data->chiller_button != NULL && ((altlabel_detail *) _aqualink_data->chiller_button->special_mask_ptr)->in_alt_mode == false ) {
|
||||
// Chiller is off (in heat pump mode)
|
||||
if (OFF != _last_mqtt_chiller_led.state) {
|
||||
_last_mqtt_chiller_led.state = OFF;
|
||||
send_mqtt_led_state_msg(nc, CHILLER, OFF, MQTT_COOL, MQTT_OFF);
|
||||
}
|
||||
} else if (_aqualink_data->chiller_button != NULL && ((vbutton_detail *) _aqualink_data->chiller_button->special_mask_ptr)->in_alt_mode == true ) {
|
||||
} else if (_aqualink_data->chiller_button != NULL && ((altlabel_detail *) _aqualink_data->chiller_button->special_mask_ptr)->in_alt_mode == true ) {
|
||||
// post actual LED state, in chiller mode
|
||||
if (_aqualink_data->chiller_button->led->state != _last_mqtt_chiller_led.state) {
|
||||
_last_mqtt_chiller_led.state = _aqualink_data->chiller_button->led->state;
|
||||
|
|
@ -1193,6 +1194,12 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
return uActioned;
|
||||
} else if (strncmp(ri1, "upgrade", 7) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
LOG(NET_LOG,LOG_NOTICE, "Received upgrade request!\n");
|
||||
setMASK(_aqualink_data->updatetype, UPDATERELEASE);
|
||||
raise(SIGRUPGRADE);
|
||||
return uActioned;
|
||||
} else if (strncmp(ri1, "installdevrelease", 17) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
LOG(NET_LOG,LOG_NOTICE, "Received install dev release request!\n");
|
||||
setMASK(_aqualink_data->updatetype, INSTALLDEVRELEASE);
|
||||
raise(SIGRUPGRADE);
|
||||
return uActioned;
|
||||
} else if (strncmp(ri1, "seriallogger", 12) == 0 && from == NET_WS) { // Only valid from websocket.
|
||||
|
|
@ -1201,7 +1208,7 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
_aqualink_data->slogger_packets = round(value);
|
||||
if (ri2 != NULL) {
|
||||
//MIN( 19, (ri3 - ri2));
|
||||
snprintf(_aqualink_data->slogger_ids, MIN( 19, (ri3 - ri2)+1 ), ri2); // 0x01 0x02 0x03 0x04
|
||||
snprintf(_aqualink_data->slogger_ids, AQ_MIN( 19, (ri3 - ri2)+1 ), ri2); // 0x01 0x02 0x03 0x04
|
||||
} else {
|
||||
_aqualink_data->slogger_ids[0] = '\0';
|
||||
}
|
||||
|
|
@ -1410,7 +1417,7 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
for (i=0; i < _aqualink_data->total_buttons ; i++) {
|
||||
//if (strncmp(ri1, _aqualink_data->aqbuttons[i].name, strlen(_aqualink_data->aqbuttons[i].name)) == 0 ){
|
||||
if ( uri_strcmp(ri1, _aqualink_data->aqbuttons[i].name) ||
|
||||
( isVBUTTON_ALTLABEL(_aqualink_data->aqbuttons[i].special_mask) && uri_strcmp(ri1, ((vbutton_detail *)_aqualink_data->aqbuttons[i].special_mask_ptr)->altlabel)) ) {
|
||||
( isVBUTTON_ALTLABEL(_aqualink_data->aqbuttons[i].special_mask) && uri_strcmp(ri1, ((altlabel_detail *)_aqualink_data->aqbuttons[i].special_mask_ptr)->altlabel)) ) {
|
||||
int pi;
|
||||
for (pi=0; pi < _aqualink_data->num_pumps; pi++) {
|
||||
if (_aqualink_data->pumps[pi].button == &_aqualink_data->aqbuttons[i]) {
|
||||
|
|
@ -1497,7 +1504,7 @@ uriAtype action_URI(request_source from, const char *URI, int uri_length, float
|
|||
//if ( uri_strcmp(ri1, _aqualink_data->aqbuttons[i].name) || uri_strcmp(ri1, _aqualink_data->aqbuttons[i].label) )
|
||||
|
||||
if ( uri_strcmp(ri1, _aqualink_data->aqbuttons[i].name) || uri_strcmp(ri1, _aqualink_data->aqbuttons[i].label) ||
|
||||
( isVBUTTON_ALTLABEL(_aqualink_data->aqbuttons[i].special_mask) && uri_strcmp(ri1, ((vbutton_detail *)_aqualink_data->aqbuttons[i].special_mask_ptr)->altlabel)) )
|
||||
( isVBUTTON_ALTLABEL(_aqualink_data->aqbuttons[i].special_mask) && uri_strcmp(ri1, ((altlabel_detail *)_aqualink_data->aqbuttons[i].special_mask_ptr)->altlabel)) )
|
||||
{
|
||||
found = true;
|
||||
//create_panel_request(from, i, value, istimer);
|
||||
|
|
@ -1550,19 +1557,19 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
|
|||
int tid;
|
||||
#endif
|
||||
//unsigned int i;
|
||||
//LOG(NET_LOG,LOG_DEBUG, "MQTT: topic %.*s %.2f\n",msg->topic.len, msg->topic.p, atof(msg->payload.p));
|
||||
//LOG(NET_LOG,LOG_DEBUG, "MQTT: topic %.*s %.2f\n",msg->topic.len, msg->topic.buf, atof(msg->data.buf));
|
||||
// If message doesn't end in set or increment we don't care about it.
|
||||
if (strncmp(&msg->topic.p[msg->topic.len -4], "/set", 4) != 0 && strncmp(&msg->topic.p[msg->topic.len -10], "/increment", 10) != 0) {
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: Ignore %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
|
||||
if (strncmp(&msg->topic.buf[msg->topic.len -4], "/set", 4) != 0 && strncmp(&msg->topic.buf[msg->topic.len -10], "/increment", 10) != 0) {
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: Ignore %.*s %.*s\n",msg->topic.len, msg->topic.buf, msg->data.len, msg->data.buf);
|
||||
return;
|
||||
}
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: topic %.*s %.*s\n",msg->topic.len, msg->topic.buf, msg->data.len, msg->data.buf);
|
||||
|
||||
DEBUG_TIMER_START(&tid);
|
||||
//Need to do this in a better manor, but for present it's ok.
|
||||
static char tmp[20];
|
||||
strncpy(tmp, msg->payload.p, msg->payload.len);
|
||||
tmp[msg->payload.len] = '\0';
|
||||
strncpy(tmp, msg->data.buf, msg->data.len);
|
||||
tmp[msg->data.len] = '\0';
|
||||
|
||||
//float value = atof(tmp);
|
||||
|
||||
|
|
@ -1575,16 +1582,16 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
|
|||
if (rsm_strcmp(tmp, "on")==0 || rsm_strcmp(tmp, "heat")==0 || rsm_strcmp(tmp, "cool")==0)
|
||||
value = 1;
|
||||
|
||||
LOG(NET_LOG,LOG_NOTICE, "MQTT: converted value from '%s' to '%.0f', from message '%.*s'\n",tmp,value,msg->topic.len, msg->topic.p);
|
||||
LOG(NET_LOG,LOG_NOTICE, "MQTT: converted value from '%s' to '%.0f', from message '%.*s'\n",tmp,value,msg->topic.len, msg->topic.buf);
|
||||
}
|
||||
|
||||
|
||||
//int val = _aqualink_data->unactioned.value = (_aqualink_data->temp_units != CELSIUS && _aqconfig_.convert_mqtt_temp) ? round(degCtoF(value)) : round(value);
|
||||
bool convert = (_aqualink_data->temp_units != CELSIUS && _aqconfig_.convert_mqtt_temp)?true:false;
|
||||
int offset = strlen(_aqconfig_.mqtt_aq_topic)+1;
|
||||
if ( action_URI(NET_MQTT, &msg->topic.p[offset], msg->topic.len - offset, value, convert, &rtnmsg) == uBad ) {
|
||||
if ( action_URI(NET_MQTT, &msg->topic.buf[offset], msg->topic.len - offset, value, convert, &rtnmsg) == uBad ) {
|
||||
// Check if it was something that can't be changed, if so send back current state. Homekit thermostat for SWG and Freezeprotect.
|
||||
if ( strncmp(&msg->topic.p[offset], FREEZE_PROTECT, strlen(FREEZE_PROTECT)) == 0) {
|
||||
if ( strncmp(&msg->topic.buf[offset], FREEZE_PROTECT, strlen(FREEZE_PROTECT)) == 0) {
|
||||
if (_aqualink_data->frz_protect_set_point != TEMP_UNKNOWN ) {
|
||||
send_mqtt_setpoint_msg(nc, FREEZE_PROTECT, _aqualink_data->frz_protect_set_point);
|
||||
send_mqtt_string_msg(nc, FREEZE_PROTECT_ENABELED, MQTT_ON);
|
||||
|
|
@ -1592,7 +1599,7 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
|
|||
send_mqtt_string_msg(nc, FREEZE_PROTECT_ENABELED, MQTT_OFF);
|
||||
}
|
||||
send_mqtt_string_msg(nc, FREEZE_PROTECT, _aqualink_data->frz_protect_state==ON?MQTT_ON:MQTT_OFF);
|
||||
} else if ( strncmp(&msg->topic.p[offset], SWG_TOPIC, strlen(SWG_TOPIC)) == 0) {
|
||||
} else if ( strncmp(&msg->topic.buf[offset], SWG_TOPIC, strlen(SWG_TOPIC)) == 0) {
|
||||
if (_aqualink_data->swg_led_state != LED_S_UNKNOWN) {
|
||||
send_mqtt_swg_state_msg(nc, SWG_TOPIC, _aqualink_data->swg_led_state);
|
||||
send_mqtt_int_msg(nc, SWG_BOOST_TOPIC, _aqualink_data->boost);
|
||||
|
|
@ -1607,7 +1614,7 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg)
|
|||
|
||||
|
||||
float pass_mg_body(struct mg_str *body) {
|
||||
LOG(NET_LOG,LOG_INFO, "Message body:'%.*s'\n", body->len, body->p);
|
||||
LOG(NET_LOG,LOG_INFO, "Message body:'%.*s'\n", body->len, body->buf);
|
||||
// Quick n dirty pass value from either of below.
|
||||
// value=1.5&arg2=val2
|
||||
// {"value":"1.5"}
|
||||
|
|
@ -1622,11 +1629,11 @@ float pass_mg_body(struct mg_str *body) {
|
|||
// NSF Really need to come back and clean this up
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
if ( body->p[i] == '=' || body->p[i] == ':' ) {
|
||||
while (!isdigit((unsigned char) body->p[i]) && body->p[i] != '-' && i < len) {i++;}
|
||||
if ( body->buf[i] == '=' || body->buf[i] == ':' ) {
|
||||
while (!isdigit((unsigned char) body->buf[i]) && body->buf[i] != '-' && i < len) {i++;}
|
||||
if(i < len) {
|
||||
// Need to copy to buffer so we can terminate correctly.
|
||||
strncpy(buf, &body->p[i], len - i);
|
||||
strncpy(buf, &body->buf[i], len - i);
|
||||
buf[len - i] = '\0';
|
||||
return atof(buf);
|
||||
}
|
||||
|
|
@ -1636,18 +1643,18 @@ float pass_mg_body(struct mg_str *body) {
|
|||
return TEMP_UNKNOWN;
|
||||
}
|
||||
|
||||
void log_http_request(int level, char *message, struct http_message *http_msg) {
|
||||
char *uri = (char *)malloc(http_msg->uri.len + http_msg->query_string.len + 2);
|
||||
void log_http_request(int level, char *message, struct mg_http_message *http_msg) {
|
||||
char *uri = (char *)malloc(http_msg->uri.len + http_msg->query.len + 2);
|
||||
|
||||
strncpy(uri, http_msg->uri.p, http_msg->uri.len + http_msg->query_string.len + 1);
|
||||
uri[http_msg->uri.len + http_msg->query_string.len + 1] = '\0';
|
||||
strncpy(uri, http_msg->uri.buf, http_msg->uri.len + http_msg->query.len + 1);
|
||||
uri[http_msg->uri.len + http_msg->query.len + 1] = '\0';
|
||||
|
||||
LOG(NET_LOG,level, "%s: '%s'\n", message, uri);
|
||||
|
||||
free(uri);
|
||||
}
|
||||
|
||||
void action_web_request(struct mg_connection *nc, struct http_message *http_msg) {
|
||||
void action_web_request(struct mg_connection *nc, struct mg_http_message *http_msg) {
|
||||
char *msg = NULL;
|
||||
// struct http_message *http_msg = (struct http_message *)ev_data;
|
||||
#ifdef AQ_TM_DEBUG
|
||||
|
|
@ -1671,12 +1678,17 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
//LOG(NET_LOG,LOG_INFO, "Message request:\n'%.*s'\n", http_msg->message.len, http_msg->message.p);
|
||||
|
||||
// If we have a get request, pass it
|
||||
if (strncmp(http_msg->uri.p, "/api", 4 ) != 0) {
|
||||
if (strncmp(http_msg->uri.buf, "/api", 4 ) != 0) {
|
||||
//if (strstr(http_msg->method.p, "GET") && http_msg->query_string.len > 0) {
|
||||
// log_http_request(LOG_ERR, "Old API stanza requested, ignoring request :", http_msg);
|
||||
//} else {
|
||||
DEBUG_TIMER_START(&tid);
|
||||
mg_serve_http(nc, http_msg, _http_server_opts);
|
||||
|
||||
//mg_serve_http(nc, http_msg, _http_server_opts);
|
||||
//mg_http_serve_file(nc, http_msg, _http_server_opts.root_dir, &_http_server_opts);
|
||||
mg_http_serve_dir(nc, http_msg, &_http_server_opts);
|
||||
// _aqconfig_.web_directory
|
||||
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "action_web_request() serve file took");
|
||||
//}
|
||||
//} else if (strstr(http_msg->method.p, "PUT")) {
|
||||
|
|
@ -1686,96 +1698,106 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
DEBUG_TIMER_START(&tid);
|
||||
|
||||
// If query string.
|
||||
if (http_msg->query_string.len > 1) {
|
||||
mg_get_http_var(&http_msg->query_string, "value", buf, sizeof(buf));
|
||||
if (http_msg->query.len > 1) {
|
||||
//mg_get_http_var(&http_msg->query, "value", buf, sizeof(buf)); // Old mosquitto
|
||||
mg_http_get_var(&http_msg->query, "value", buf, sizeof(buf));
|
||||
value = atof(buf);
|
||||
} else if (http_msg->body.len > 1) {
|
||||
value = pass_mg_body(&http_msg->body);
|
||||
}
|
||||
|
||||
int len = mg_url_decode(http_msg->uri.p, http_msg->uri.len, buf, 50, 0);
|
||||
int len = mg_url_decode(http_msg->uri.buf, http_msg->uri.len, buf, 50, 0);
|
||||
|
||||
if (strncmp(http_msg->uri.p, "/api/",4) == 0) {
|
||||
if (strncmp(http_msg->uri.buf, "/api/",4) == 0) {
|
||||
switch (action_URI(NET_API, &buf[5], len-5, value, false, &msg)) {
|
||||
case uActioned:
|
||||
mg_send_head(nc, 200, strlen(GET_RTN_OK), CONTENT_TEXT);
|
||||
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
|
||||
//mg_send_head(nc, 200, strlen(GET_RTN_OK), CONTENT_TEXT);
|
||||
//mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
|
||||
mg_http_reply(nc, 200, CONTENT_TEXT, GET_RTN_OK);
|
||||
break;
|
||||
case uDevices:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
int size = build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, false);
|
||||
build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, false);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_device_JSON took");
|
||||
mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
mg_send(nc, message, size);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uHomebridge:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
int size = build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, true);
|
||||
mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
mg_send(nc, message, size);
|
||||
build_device_JSON(_aqualink_data, message, JSON_BUFFER_SIZE, true);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uStatus:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
int size = build_aqualink_status_JSON(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
build_aqualink_status_JSON(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_aqualink_status_JSON took");
|
||||
mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
mg_send(nc, message, size);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uDynamicconf:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
int size = build_webconfig_js(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
build_webconfig_js(_aqualink_data, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_webconfig_js took");
|
||||
mg_send_head(nc, 200, size, CONTENT_JS);
|
||||
mg_send(nc, message, size);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JS);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uSchedules:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
int size = build_schedules_js(message, JSON_BUFFER_SIZE);
|
||||
build_schedules_js(message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_schedules_js took");
|
||||
mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
mg_send(nc, message, size);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uSetSchedules:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
int size = save_schedules_js(http_msg->body.p, http_msg->body.len, message, JSON_BUFFER_SIZE);
|
||||
save_schedules_js(http_msg->body.buf, http_msg->body.len, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() save_schedules_js took");
|
||||
mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
mg_send(nc, message, size);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
case uConfig:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
DEBUG_TIMER_START(&tid2);
|
||||
int size = build_aqualink_config_JSON(message, JSON_BUFFER_SIZE, _aqualink_data);
|
||||
build_aqualink_config_JSON(message, JSON_BUFFER_SIZE, _aqualink_data);
|
||||
DEBUG_TIMER_STOP(tid2, NET_LOG, "action_web_request() build_aqualink_config_JSON took");
|
||||
mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
mg_send(nc, message, size);
|
||||
//mg_send_head(nc, 200, size, CONTENT_JSON);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JSON, message);
|
||||
}
|
||||
break;
|
||||
#ifndef AQ_MANAGER
|
||||
case uDebugStatus:
|
||||
{
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
int size = snprintf(message,80,"{\"sLevel\":\"%s\", \"iLevel\":%d, \"logReady\":\"%s\"}\n",elevel2text(getLogLevel(NET_LOG)),getLogLevel(NET_LOG),islogFileReady()?"true":"false" );
|
||||
mg_send_head(nc, 200, size, CONTENT_JS);
|
||||
mg_send(nc, message, size);
|
||||
snprintf(message,80,"{\"sLevel\":\"%s\", \"iLevel\":%d, \"logReady\":\"%s\"}\n",elevel2text(getLogLevel(NET_LOG)),getLogLevel(NET_LOG),islogFileReady()?"true":"false" );
|
||||
//mg_send_head(nc, 200, size, CONTENT_JS);
|
||||
//mg_send(nc, message, size);
|
||||
mg_http_reply(nc, 200, CONTENT_JS, message);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
|
|
@ -1790,40 +1812,45 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
}
|
||||
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\""));
|
||||
//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\""));
|
||||
mg_http_serve_file(nc, http_msg, "/dev/shm/aqualinkd.log", &_http_server_opts);
|
||||
remove("/dev/shm/aqualinkd.log");
|
||||
}
|
||||
break;
|
||||
|
||||
case uConfigDownload:
|
||||
LOG(NET_LOG, LOG_DEBUG, "Downloading config\n");
|
||||
mg_http_serve_file(nc, http_msg, _aqconfig_.config_file, mg_mk_str("text/plain"), mg_mk_str("Content-Disposition: attachment; filename=\"aqualinkd.conf\""));
|
||||
//mg_http_serve_file(nc, http_msg, _aqconfig_.config_file, mg_mk_str("text/plain"), mg_mk_str("Content-Disposition: attachment; filename=\"aqualinkd.conf\""));
|
||||
mg_http_serve_file(nc, http_msg, _aqconfig_.config_file, &_http_server_opts);
|
||||
break;
|
||||
#endif
|
||||
case uBad:
|
||||
default:
|
||||
if (msg == NULL) {
|
||||
mg_send_head(nc, 400, strlen(GET_RTN_UNKNOWN), CONTENT_TEXT);
|
||||
mg_send(nc, GET_RTN_UNKNOWN, strlen(GET_RTN_UNKNOWN));
|
||||
//mg_send_head(nc, 400, strlen(GET_RTN_UNKNOWN), CONTENT_TEXT);
|
||||
//mg_send(nc, GET_RTN_UNKNOWN, strlen(GET_RTN_UNKNOWN));
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, GET_RTN_UNKNOWN);
|
||||
} else {
|
||||
mg_send_head(nc, 400, strlen(msg), CONTENT_TEXT);
|
||||
mg_send(nc, msg, strlen(msg));
|
||||
//mg_send_head(nc, 400, strlen(msg), CONTENT_TEXT);
|
||||
//mg_send(nc, msg, strlen(msg));
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mg_send_head(nc, 200, strlen(GET_RTN_UNKNOWN), CONTENT_TEXT);
|
||||
mg_send(nc, GET_RTN_UNKNOWN, strlen(GET_RTN_UNKNOWN));
|
||||
//mg_send_head(nc, 200, strlen(GET_RTN_UNKNOWN), CONTENT_TEXT);
|
||||
//mg_send(nc, GET_RTN_UNKNOWN, strlen(GET_RTN_UNKNOWN));
|
||||
mg_http_reply(nc, 400, CONTENT_TEXT, GET_RTN_UNKNOWN);
|
||||
}
|
||||
|
||||
sprintf(buf, "action_web_request() request '%.*s' took",(int)http_msg->uri.len, http_msg->uri.p);
|
||||
sprintf(buf, "action_web_request() request '%.*s' took",(int)http_msg->uri.len, http_msg->uri.buf);
|
||||
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void action_websocket_request(struct mg_connection *nc, struct websocket_message *wm) {
|
||||
void action_websocket_request(struct mg_connection *nc, struct mg_ws_message *wm) {
|
||||
char buffer[100];
|
||||
struct JSONkvptr jsonkv;
|
||||
int i;
|
||||
|
|
@ -1839,8 +1866,8 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
|
|||
pda_reset_sleep();
|
||||
#endif
|
||||
|
||||
strncpy(buffer, (char *)wm->data, MIN(wm->size, 99));
|
||||
buffer[wm->size] = '\0';
|
||||
strncpy(buffer, (char *)wm->data.buf, AQ_MIN(wm->data.len, 99));
|
||||
buffer[wm->data.len] = '\0';
|
||||
|
||||
parseJSONrequest(buffer, &jsonkv);
|
||||
|
||||
|
|
@ -1927,7 +1954,7 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
|
|||
{
|
||||
DEBUG_TIMER_START(&tid);
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
save_schedules_js((char *)wm->data, wm->size, message, JSON_BUFFER_SIZE);
|
||||
save_schedules_js((char *)wm->data.buf, wm->data.len, message, JSON_BUFFER_SIZE);
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "action_websocket_request() save_schedules_js took");
|
||||
ws_send(nc, message);
|
||||
}
|
||||
|
|
@ -1945,7 +1972,7 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
|
|||
{
|
||||
DEBUG_TIMER_START(&tid);
|
||||
char message[JSON_BUFFER_SIZE];
|
||||
save_config_js((char *)wm->data, wm->size, message, JSON_BUFFER_SIZE, _aqualink_data);
|
||||
save_config_js((char *)wm->data.buf, wm->data.len, message, JSON_BUFFER_SIZE, _aqualink_data);
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "action_websocket_request() save_config_js took");
|
||||
ws_send(nc, message);
|
||||
}
|
||||
|
|
@ -1967,7 +1994,7 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
|
|||
int i;
|
||||
char svalue[DZ_SVALUE_LEN+1];
|
||||
|
||||
if (parseJSONmqttrequest(msg->payload.p, msg->payload.len, &idx, &nvalue, svalue) && idx > 0) {
|
||||
if (parseJSONmqttrequest(msg->data.buf, msg->data.len, &idx, &nvalue, svalue) && idx > 0) {
|
||||
for (i=0; i < _aqualink_data->total_buttons; i++) {
|
||||
if (_aqualink_data->aqbuttons[i].dz_idx == idx){
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: DZ: Received message IDX=%d nValue=%d sValue=%s\n", idx, nvalue, svalue);
|
||||
|
|
@ -2001,8 +2028,8 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
|
|||
|
||||
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
struct mg_mqtt_message *mqtt_msg;
|
||||
struct http_message *http_msg;
|
||||
struct websocket_message *ws_msg;
|
||||
struct mg_http_message *http_msg;
|
||||
struct mg_ws_message *ws_msg;
|
||||
char aq_topic[30];
|
||||
#ifdef AQ_TM_DEBUG
|
||||
int tid;
|
||||
|
|
@ -2011,23 +2038,35 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|||
|
||||
// LOG(NET_LOG,LOG_DEBUG, "Event\n");
|
||||
switch (ev) {
|
||||
case MG_EV_HTTP_REQUEST:
|
||||
//case MG_EV_HTTP_REQUEST:
|
||||
case MG_EV_HTTP_MSG:
|
||||
//nc->user_data = WEB;
|
||||
http_msg = (struct http_message *)ev_data;
|
||||
http_msg = (struct mg_http_message *)ev_data;
|
||||
|
||||
//if ( strstr(http_msg->head.buf, "Upgrade: websocket") ) {
|
||||
//if ( strstr(http_msg->head.buf, "Sec-WebSocket-Key") ) {
|
||||
if ( mg_http_get_header(http_msg, "Sec-WebSocket-Key") != NULL) {
|
||||
LOG(NET_LOG,LOG_DEBUG, "Enable websockets\n");
|
||||
mg_ws_upgrade(nc, http_msg, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_TIMER_START(&tid);
|
||||
action_web_request(nc, http_msg);
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "WEB Request action_web_request() took");
|
||||
LOG(NET_LOG,LOG_DEBUG, "Served WEB request\n");
|
||||
break;
|
||||
|
||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
|
||||
//case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
|
||||
case MG_EV_WS_OPEN:
|
||||
//nc->user_data = WS;
|
||||
_aqualink_data->open_websockets++;
|
||||
LOG(NET_LOG,LOG_DEBUG, "++ Websocket joined\n");
|
||||
break;
|
||||
|
||||
case MG_EV_WEBSOCKET_FRAME:
|
||||
ws_msg = (struct websocket_message *)ev_data;
|
||||
//case MG_EV_WEBSOCKET_FRAME:
|
||||
case MG_EV_WS_MSG:
|
||||
ws_msg = (struct mg_ws_message *)ev_data;
|
||||
DEBUG_TIMER_START(&tid);
|
||||
action_websocket_request(nc, ws_msg);
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "Websocket Request action_websocket_request() took");
|
||||
|
|
@ -2051,90 +2090,59 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|||
break;
|
||||
|
||||
case MG_EV_CONNECT: {
|
||||
//nc->user_data = MQTT;
|
||||
//nc->flags |= MG_F_USER_1; // NFS Need to readup on this
|
||||
set_mqtt(nc);
|
||||
_mqtt_exit_flag = false;
|
||||
//char *MQTT_id = "AQUALINK_MQTT_TEST_ID";
|
||||
struct mg_send_mqtt_handshake_opts opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.user_name = _aqconfig_.mqtt_user;
|
||||
opts.password = _aqconfig_.mqtt_passwd;
|
||||
opts.keep_alive = 5;
|
||||
opts.flags |= MG_MQTT_CLEAN_SESSION; // NFS Need to readup on this
|
||||
|
||||
snprintf(aq_topic, 24, "%s/%s", _aqconfig_.mqtt_aq_topic,MQTT_LWM_TOPIC);
|
||||
opts.will_topic = aq_topic;
|
||||
opts.will_message = MQTT_OFF;
|
||||
|
||||
mg_set_protocol_mqtt(nc);
|
||||
mg_send_mqtt_handshake_opt(nc, _aqconfig_.mqtt_ID, opts);
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing mqtt with id of: %s\n", _aqconfig_.mqtt_ID);
|
||||
//last_control_time = mg_time();
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: Connected to : %s, id : %s\n", _aqconfig_.mqtt_server, _aqconfig_.mqtt_ID);
|
||||
} break;
|
||||
|
||||
case MG_EV_MQTT_CONNACK:
|
||||
//case MG_EV_MQTT_CONNACK:
|
||||
case MG_EV_MQTT_OPEN:
|
||||
{
|
||||
struct mg_mqtt_topic_expression topics[2];
|
||||
|
||||
int qos=0;// can't be bothered with ack, so set to 0
|
||||
//struct mg_mqtt_opts sub_opts
|
||||
static uint8_t qos=1;// PUT IN FUNCTION HEADDER can't be bothered with ack, so set to 0
|
||||
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: Connection open %lu\n", nc->id);
|
||||
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: Connection acknowledged\n");
|
||||
mqtt_msg = (struct mg_mqtt_message *)ev_data;
|
||||
if (mqtt_msg->connack_ret_code != MG_EV_MQTT_CONNACK_ACCEPTED) {
|
||||
LOG(NET_LOG,LOG_WARNING, "Got mqtt connection error: %d\n", mqtt_msg->connack_ret_code);
|
||||
_mqtt_exit_flag = true;
|
||||
}
|
||||
|
||||
snprintf(aq_topic, 29, "%s/#", _aqconfig_.mqtt_aq_topic);
|
||||
if (_aqconfig_.mqtt_aq_topic != NULL && _aqconfig_.mqtt_dz_sub_topic != NULL) {
|
||||
topics[0].topic = aq_topic;
|
||||
topics[0].qos = qos;
|
||||
topics[1].topic = _aqconfig_.mqtt_dz_sub_topic;
|
||||
topics[1].qos = qos;
|
||||
mg_mqtt_subscribe(nc, topics, 2, 42);
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing to '%s'\n", aq_topic);
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing to '%s'\n", _aqconfig_.mqtt_dz_sub_topic);
|
||||
}
|
||||
else if (_aqconfig_.mqtt_aq_topic != NULL) {
|
||||
topics[0].topic = aq_topic;
|
||||
topics[0].qos = qos;
|
||||
mg_mqtt_subscribe(nc, topics, 1, 42);
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing to '%s'\n", aq_topic);
|
||||
}
|
||||
else if (_aqconfig_.mqtt_dz_sub_topic != NULL) {
|
||||
topics[0].topic = _aqconfig_.mqtt_dz_sub_topic;;
|
||||
topics[0].qos = qos;
|
||||
mg_mqtt_subscribe(nc, topics, 1, 42);
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing to '%s'\n", _aqconfig_.mqtt_dz_sub_topic);
|
||||
|
||||
struct mg_mqtt_opts sub_opts;
|
||||
memset(&sub_opts, 0, sizeof(sub_opts));
|
||||
sub_opts.topic = mg_str(aq_topic);
|
||||
sub_opts.qos = qos;
|
||||
mg_mqtt_sub(nc, &sub_opts);
|
||||
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscribing to '%s'\n", aq_topic);
|
||||
|
||||
if (_aqconfig_.mqtt_dz_sub_topic != NULL) {
|
||||
LOG(NET_LOG,LOG_ERR,"MQTT: Domoticz not supported\n");
|
||||
}
|
||||
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: send last will message\n");
|
||||
snprintf(aq_topic, 24, "%s/%s", _aqconfig_.mqtt_aq_topic,MQTT_LWM_TOPIC);
|
||||
send_mqtt(nc, aq_topic ,MQTT_ON);
|
||||
|
||||
publish_mqtt_hassio_discover( _aqualink_data, nc);
|
||||
}
|
||||
break;
|
||||
case MG_EV_MQTT_PUBACK:
|
||||
mqtt_msg = (struct mg_mqtt_message *)ev_data;
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: Message publishing acknowledged (msg_id: %d)\n", mqtt_msg->message_id);
|
||||
|
||||
case MG_EV_MQTT_CMD:
|
||||
//LOG(NET_LOG,LOG_NOTICE, "MQTT: MG_EV_MQTT_CMD command, add code / need to replocate MG_EV_MQTT_PUBACK MG_EV_MQTT_SUBACK\n");
|
||||
break;
|
||||
case MG_EV_MQTT_SUBACK:
|
||||
LOG(NET_LOG,LOG_INFO, "MQTT: Subscription(s) acknowledged\n");
|
||||
snprintf(aq_topic, 24, "%s/%s", _aqconfig_.mqtt_aq_topic,MQTT_LWM_TOPIC);
|
||||
send_mqtt(nc, aq_topic ,MQTT_ON);
|
||||
break;
|
||||
case MG_EV_MQTT_PUBLISH:
|
||||
//case MG_EV_MQTT_PUBLISH:
|
||||
case MG_EV_MQTT_MSG:
|
||||
mqtt_msg = (struct mg_mqtt_message *)ev_data;
|
||||
|
||||
if (mqtt_msg->message_id != 0) {
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: received (msg_id: %d), looks like my own message, ignoring\n", mqtt_msg->message_id);
|
||||
if (mqtt_msg->id != 0) { // NSF Not good check mongoose.h # 2842
|
||||
LOG(NET_LOG,LOG_DEBUG, "MQTT: received (msg_id: %d), looks like my own message, ignoring\n", mqtt_msg->id);
|
||||
}
|
||||
// NSF Need to change strlen to a global so it's not executed every time we check a topic
|
||||
if (_aqconfig_.mqtt_aq_topic != NULL && strncmp(mqtt_msg->topic.p, _aqconfig_.mqtt_aq_topic, strlen(_aqconfig_.mqtt_aq_topic)) == 0)
|
||||
if (_aqconfig_.mqtt_aq_topic != NULL && strncmp(mqtt_msg->topic.buf, _aqconfig_.mqtt_aq_topic, strlen(_aqconfig_.mqtt_aq_topic)) == 0)
|
||||
{
|
||||
DEBUG_TIMER_START(&tid);
|
||||
action_mqtt_message(nc, mqtt_msg);
|
||||
DEBUG_TIMER_STOP(tid, NET_LOG, "MQTT Request action_mqtt_message() took");
|
||||
}
|
||||
if (_aqconfig_.mqtt_dz_sub_topic != NULL && strncmp(mqtt_msg->topic.p, _aqconfig_.mqtt_dz_sub_topic, strlen(_aqconfig_.mqtt_dz_sub_topic)) == 0) {
|
||||
if (_aqconfig_.mqtt_dz_sub_topic != NULL && strncmp(mqtt_msg->topic.buf, _aqconfig_.mqtt_dz_sub_topic, strlen(_aqconfig_.mqtt_dz_sub_topic)) == 0) {
|
||||
action_domoticz_mqtt_message(nc, mqtt_msg);
|
||||
}
|
||||
break;
|
||||
|
|
@ -2196,14 +2204,32 @@ void reset_last_mqtt_status()
|
|||
|
||||
void start_mqtt(struct mg_mgr *mgr) {
|
||||
|
||||
//LOG(NET_LOG,LOG_WARNING, "NOT Starting MQTT client, need to check code\n");
|
||||
|
||||
if ( _aqconfig_.mqtt_server == NULL ||
|
||||
( _aqconfig_.mqtt_aq_topic == NULL && _aqconfig_.mqtt_dz_pub_topic == NULL && _aqconfig_.mqtt_dz_sub_topic == NULL) )
|
||||
return;
|
||||
|
||||
char aq_topic[30];
|
||||
LOG(NET_LOG,LOG_NOTICE, "Starting MQTT client to %s\n", _aqconfig_.mqtt_server);
|
||||
|
||||
if (mg_connect(mgr, _aqconfig_.mqtt_server, ev_handler) == NULL) {
|
||||
LOG(NET_LOG,LOG_ERR, "Failed to create MQTT listener to %s\n", _aqconfig_.mqtt_server);
|
||||
snprintf(aq_topic, 24, "%s/%s", _aqconfig_.mqtt_aq_topic,MQTT_LWM_TOPIC);
|
||||
|
||||
struct mg_mqtt_opts opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.user = mg_str(_aqconfig_.mqtt_user);
|
||||
opts.pass = mg_str(_aqconfig_.mqtt_passwd);
|
||||
opts.client_id = mg_str(_aqconfig_.mqtt_ID);
|
||||
|
||||
//opts.keepalive = 5; // This seems to kill connection for some reason, and not sent heartbeat
|
||||
opts.clean = true;
|
||||
//opts.version = 4; // Maybe 5
|
||||
opts.message = mg_str(MQTT_OFF); // will_message
|
||||
opts.topic = mg_str(aq_topic); // will_topic
|
||||
|
||||
|
||||
if ( mg_mqtt_connect(mgr, _aqconfig_.mqtt_server, &opts, ev_handler, NULL) == NULL ) {
|
||||
LOG(NET_LOG,LOG_ERR, "Failed to create MQTT listener to %s\n", _aqconfig_.mqtt_server);
|
||||
} else {
|
||||
//int i;
|
||||
#ifdef AQ_MEMCMP
|
||||
|
|
@ -2212,6 +2238,7 @@ void start_mqtt(struct mg_mgr *mgr) {
|
|||
reset_last_mqtt_status();
|
||||
_mqtt_exit_flag = false; // set here to stop multiple connects, if it fails truley fails it will get set to false.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//bool start_web_server(struct mg_mgr *mgr, struct aqualinkdata *aqdata, char *port, char* web_root) {
|
||||
|
|
@ -2227,28 +2254,30 @@ bool _start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata) {
|
|||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
|
||||
mg_mgr_init(mgr, NULL);
|
||||
LOG(NET_LOG,LOG_NOTICE, "Starting web server on port %s\n", _aqconfig_.socket_port);
|
||||
nc = mg_bind(mgr, _aqconfig_.socket_port, ev_handler);
|
||||
mg_log_set(_aqconfig_.mg_log_level);
|
||||
|
||||
mg_mgr_init(mgr);
|
||||
|
||||
char url[256];
|
||||
if ( strcasestr(_aqconfig_.socket_port, "http") != NULL ) {
|
||||
sprintf(url, "%s",_aqconfig_.socket_port);
|
||||
} else {
|
||||
sprintf(url, "http://0.0.0.0:%s",_aqconfig_.socket_port);
|
||||
}
|
||||
LOG(NET_LOG,LOG_NOTICE, "Starting web server on %s\n", url);
|
||||
//nc = mg_bind(mgr, _aqconfig_.socket_port, ev_handler);
|
||||
nc = mg_http_listen(mgr, url, ev_handler, mgr);
|
||||
if (nc == NULL) {
|
||||
LOG(NET_LOG,LOG_ERR, "Failed to create listener on port %s\n",_aqconfig_.socket_port);
|
||||
LOG(NET_LOG,LOG_ERR, "Failed to create listener on port %s\n",url);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up HTTP server parameters
|
||||
mg_set_protocol_http_websocket(nc);
|
||||
|
||||
// Set default web options
|
||||
//struct mg_serve_http_opts opts;
|
||||
//memset(&opts, 0, sizeof(opts)); // Reset all options to defaults
|
||||
//opts.document_root = _web_root; // Serve files from the current directory
|
||||
//opts.extra_headers = "Cache-Control: public, max-age=604800, immutable";
|
||||
|
||||
memset(&_http_server_opts, 0, sizeof(_http_server_opts)); // Reset all options to defaults
|
||||
_http_server_opts.document_root = _aqconfig_.web_directory; // Serve current directory
|
||||
_http_server_opts.enable_directory_listing = "yes";
|
||||
//_http_server_opts.extra_headers = "Cache-Control: public, max-age=604800, immutable";
|
||||
_http_server_opts.extra_headers = "Cache-Control: public,max-age=31536000,immutable"; // Let's be as agressive on browser caching.
|
||||
LOG(NET_LOG,LOG_WARNING, "TODO web server TODO disable directory_listing somehow\n");
|
||||
_http_server_opts.root_dir = _aqconfig_.web_directory; // Serve current directory
|
||||
_http_server_opts.extra_headers = "Cache-Control: public, max-age=604800, immutable"; // 7 days
|
||||
//_http_server_opts.extra_headers = "Cache-Control: public,max-age=31536000,immutable"; // 1 year. Let's be as agressive on browser caching.
|
||||
// Need to disable directory_listing somehow
|
||||
|
||||
#ifndef MG_DISABLE_MQTT
|
||||
// Start MQTT
|
||||
|
|
@ -2274,6 +2303,7 @@ void *net_services_thread( void *ptr )
|
|||
struct aqualinkdata *aqdata = (struct aqualinkdata *) ptr;
|
||||
int journald_fail = 0;
|
||||
//struct mg_mgr mgr;
|
||||
|
||||
if (!_start_net_services(&_mgr, aqdata)) {
|
||||
//LOG(NET_LOG,LOG_ERR, "Failed to start network services\n");
|
||||
// Not the best way to do this (have thread exit process), but forks for the moment.
|
||||
|
|
@ -2292,7 +2322,7 @@ void *net_services_thread( void *ptr )
|
|||
|
||||
if (aqdata->updated == true /*|| _broadcast == true*/) {
|
||||
//LOG(NET_LOG,LOG_DEBUG, "********** Broadcast ************\n");
|
||||
_broadcast_aqualinkstate(_mgr.active_connections);
|
||||
_broadcast_aqualinkstate(_mgr.conns);
|
||||
aqdata->updated = false;
|
||||
}
|
||||
#ifdef AQ_MANAGER
|
||||
|
|
@ -2308,7 +2338,7 @@ void *net_services_thread( void *ptr )
|
|||
} else if (journald_fail == JOURNAL_FAIL_RETRY) {
|
||||
char msg[WS_LOG_LENGTH];
|
||||
build_logmsg_JSON(msg, LOG_ERR, "Giving up on journal, don't expect to see logs", WS_LOG_LENGTH,46);
|
||||
ws_send_logmsg(_mgr.active_connections, msg);
|
||||
ws_send_logmsg(_mgr.conns, msg);
|
||||
journald_fail = JOURNAL_FAIL_RETRY+1;
|
||||
}
|
||||
// Reset failures when manager is not active.
|
||||
|
|
@ -2320,7 +2350,7 @@ void *net_services_thread( void *ptr )
|
|||
*/
|
||||
#endif
|
||||
if (aqdata->simulator_active != SIM_NONE && aqdata->simulator_packet_updated == true ) {
|
||||
_broadcast_simulator_message(_mgr.active_connections);
|
||||
_broadcast_simulator_message(_mgr.conns);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2331,17 +2361,11 @@ f_end:
|
|||
pthread_exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef AQ_NO_THREAD_NETSERVICE
|
||||
|
||||
|
||||
void broadcast_aqualinkstate() {
|
||||
_aqualink_data->updated = true;
|
||||
}
|
||||
void broadcast_aqualinkstate_error(const char *msg) {
|
||||
_broadcast_aqualinkstate_error(_mgr.active_connections, msg);
|
||||
_broadcast_aqualinkstate_error(_mgr.conns, msg);
|
||||
}
|
||||
void broadcast_simulator_message() {
|
||||
_aqualink_data->simulator_packet_updated = true;
|
||||
|
|
@ -2375,72 +2399,3 @@ bool start_net_services(struct aqualinkdata *aqdata)
|
|||
return true;
|
||||
}
|
||||
|
||||
#else // DON'T THREAD NET SERVICES
|
||||
|
||||
void stop_net_services() {
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
mg_mgr_free(&_mgr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void broadcast_aqualinkstate(/*struct mg_connection *nc*/)
|
||||
{
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
_broadcast_aqualinkstate(_mgr.active_connections);
|
||||
_aqualink_data->updated = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
void broadcast_aqualinkstate_error(/*struct mg_connection *nc,*/ char *msg)
|
||||
{
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
return _broadcast_aqualinkstate_error(_mgr.active_connections, msg);
|
||||
}
|
||||
LOG(NET_LOG,LOG_NOTICE, "Broadcast error to network\n");
|
||||
}
|
||||
void broadcast_simulator_message() {
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
return _broadcast_simulator_message();
|
||||
}
|
||||
}
|
||||
time_t poll_net_services(/*struct mg_mgr *mgr,*/ int timeout_ms)
|
||||
{
|
||||
if (timeout_ms < 0)
|
||||
timeout_ms = 0;
|
||||
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
//return mg_mgr_poll(mgr, timeout_ms);
|
||||
return mg_mgr_poll(&_mgr, timeout_ms);
|
||||
}
|
||||
|
||||
if (timeout_ms > 5)
|
||||
delay(5);
|
||||
else if (timeout_ms > 0)
|
||||
delay(timeout_ms);
|
||||
|
||||
//LOG(NET_LOG,LOG_NOTICE, "Poll network services\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
bool start_net_services(/*struct mg_mgr *mgr, */struct aqualinkdata *aqdata)
|
||||
{
|
||||
_keepNetServicesRunning = true;
|
||||
|
||||
if ( ! _aqconfig_.thread_netservices) {
|
||||
//return _start_net_services(mgr, aqdata);
|
||||
return _start_net_services(&_mgr, aqdata);
|
||||
}
|
||||
|
||||
LOG(NET_LOG,LOG_NOTICE, "Starting network services thread\n");
|
||||
|
||||
if( pthread_create( &_net_thread_id , NULL , net_services_thread, (void*)aqdata) < 0) {
|
||||
LOG(NET_LOG, LOG_ERR, "could not create network thread\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_detach(_net_thread_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -7,23 +7,19 @@
|
|||
#define GET_RTN_ERROR "Error"
|
||||
|
||||
|
||||
#define CONTENT_JSON "Content-Type: application/json"
|
||||
#define CONTENT_JS "Content-Type: text/javascript"
|
||||
#define CONTENT_TEXT "Content-Type: text/plain"
|
||||
//#define CONTENT_JSON "Content-Type: application/json"
|
||||
//#define CONTENT_JS "Content-Type: text/javascript"
|
||||
//#define CONTENT_TEXT "Content-Type: text/plain"
|
||||
|
||||
#define CONTENT_JSON "Content-Type: application/json\r\n"
|
||||
#define CONTENT_JS "Content-Type: text/javascript\r\n"
|
||||
#define CONTENT_TEXT "Content-Type: text/plain\r\n"
|
||||
|
||||
//void main_server();
|
||||
//void main_server_TEST(struct aqualinkdata *aqdata, char *s_http_port);
|
||||
//bool start_web_server(struct mg_mgr *mgr, struct aqualinkdata *aqdata, char *port, char* web_root);
|
||||
//bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata, struct aqconfig *aqconfig);
|
||||
|
||||
/*
|
||||
#ifdef AQ_NO_THREAD_NETSERVICE
|
||||
bool start_net_services(struct mg_mgr *mgr, struct aqualinkdata *aqdata);
|
||||
void stop_net_services(struct mg_mgr *mgr);
|
||||
time_t poll_net_services(struct mg_mgr *mgr, int timeout_ms);
|
||||
void broadcast_aqualinkstate(struct mg_connection *nc);
|
||||
void broadcast_aqualinkstate_error(struct mg_connection *nc, char *msg);
|
||||
#else*/
|
||||
bool start_net_services(struct aqualinkdata *aqdata);
|
||||
void stop_net_services();
|
||||
time_t poll_net_services(int timeout_ms);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
#define PACKET_MAX 1200
|
||||
#define PROBE_CYCLES 2
|
||||
|
||||
#define VERSION "serial_logger V2.10"
|
||||
#define VERSION "serial_logger V2.11"
|
||||
|
||||
/*
|
||||
typedef enum used {
|
||||
|
|
@ -553,7 +553,6 @@ int main(int argc, char *argv[]) {
|
|||
int logLevel = LOG_NOTICE;
|
||||
bool panleProbe = true;
|
||||
bool rsSerialSpeedTest = false;
|
||||
bool serialBlocking = true;
|
||||
bool errorMonitor = false;
|
||||
bool printAllIDs = false;
|
||||
bool timePackets = false;
|
||||
|
|
@ -626,7 +625,6 @@ int main(int argc, char *argv[]) {
|
|||
panleProbe = false;
|
||||
} else if (strcmp(argv[i], "-s") == 0) {
|
||||
rsSerialSpeedTest = true;
|
||||
serialBlocking = false;
|
||||
} else if (strcmp(argv[i], "-e") == 0) {
|
||||
errorMonitor = true;
|
||||
} else if (strcmp(argv[i], "-a") == 0) {
|
||||
|
|
@ -651,11 +649,7 @@ int main(int argc, char *argv[]) {
|
|||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!serialBlocking)
|
||||
rs_fd = init_serial_port(argv[1]);
|
||||
else
|
||||
rs_fd = init_blocking_serial_port(argv[1]);
|
||||
|
||||
rs_fd = init_serial_port(argv[1]);
|
||||
if (rs_fd < 0) {
|
||||
LOG(SLOG_LOG, LOG_ERR, "Unable to open port: %s\n", argv[1]);
|
||||
displayLastSystemError(argv[1]);
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
#define AQUALINKD_SHORT_NAME "AqualinkD"
|
||||
|
||||
// Use Magor . Minor . Patch
|
||||
#define AQUALINKD_VERSION "2.6.12 (dev 1)"
|
||||
#define AQUALINKD_VERSION "3.0.0 (dev)"
|
||||
|
||||
|
|
@ -149,10 +149,13 @@
|
|||
}
|
||||
|
||||
.statusmsg {
|
||||
font-size: clamp(0.5rem, 1vw, 1rem);
|
||||
font-size: clamp(0.2rem, 1vw, 1rem);
|
||||
white-space: nowrap; /* Keep text on a single line */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
/*text-overflow: clip;*/
|
||||
width: var(--aqualinkd-container);
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.error {
|
||||
|
|
@ -368,6 +371,7 @@
|
|||
var _panel_size = 6;
|
||||
var _panel_set = 0;
|
||||
var _latestVersionAvailable = 0;
|
||||
var _latestDevVersionAvailable = 0;
|
||||
var _rssd_logmask = 0;
|
||||
const RSSD_MASK_ID = 512; // Must match RSSD_LOG in utils.c
|
||||
|
||||
|
|
@ -1567,6 +1571,12 @@
|
|||
} else {
|
||||
disablebutton("upgrade");
|
||||
}
|
||||
|
||||
if (_urlParams.get('devupgrade') != null) {
|
||||
enablebutton("upgrade");
|
||||
var button = document.getElementById("upgrade");
|
||||
button.setAttribute("upgrade_type", "dev")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1596,10 +1606,11 @@
|
|||
}
|
||||
|
||||
delayedVersionCheck(data['aqualinkd_version']);
|
||||
|
||||
/*
|
||||
if (_urlParams.get('upgrade') != null) {
|
||||
enablebutton("upgrade");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1857,6 +1868,7 @@
|
|||
|
||||
startWebsockets();
|
||||
getLatestVersion();
|
||||
getLatestDevVersion();
|
||||
}
|
||||
|
||||
function set_unavailable(message) {
|
||||
|
|
@ -1893,13 +1905,23 @@
|
|||
//cmd.uri = "rawcommand"
|
||||
switch (source.id) {
|
||||
case "upgrade":
|
||||
if (confirm("Are you sure you want to proceed upgrading AqualinkD?")) {
|
||||
console.log("Upgrading");
|
||||
update_log_message("***** AqualinkD upgrade in progress *****");
|
||||
} else {
|
||||
return;
|
||||
if (source.getAttribute("upgrade_type") == "dev") {
|
||||
if (confirm("Are you sure you want to proceed installing AqualinkD to Dev version '"+_latestDevVersionAvailable+"'' ?")) {
|
||||
//console.log("Upgrading to dev release");
|
||||
update_log_message("***** AqualinkD upgrade in progress *****");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
cmd.uri = "installdevrelease"
|
||||
} else {
|
||||
if (confirm("Are you sure you want to proceed upgrading AqualinkD to '"+_latestVersionAvailable+"'' ?")) {
|
||||
console.log("Upgrading");
|
||||
update_log_message("***** AqualinkD upgrade in progress *****");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
cmd.uri = "upgrade"
|
||||
}
|
||||
cmd.uri = "upgrade"
|
||||
// NEED TO REGET aqmanager after restart.
|
||||
break;
|
||||
case "restart":
|
||||
|
|
@ -1961,6 +1983,24 @@
|
|||
xmlhttp.open("GET", url);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function getLatestDevVersion(url="https://api.github.com/repos/AqualinkD/AqualinkD/contents/source/version.h", tryagain=true) {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
//console.log(this.responseText);
|
||||
_latestDevVersionAvailable = this.responseText.match(/AQUALINKD_VERSION "(.*)"/i)[1];
|
||||
} else if (this.readyState == 4 && this.status == 404) {
|
||||
if (tryagain) {
|
||||
// Try sfeakes repo
|
||||
getLatestDevVersion("https://api.github.com/repos/AqualinkD/AqualinkD/contents/source/version.h", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlhttp.open("GET", url);
|
||||
xmlhttp.setRequestHeader("Accept","application/vnd.github.raw");
|
||||
xmlhttp.send();
|
||||
}
|
||||
</script>
|
||||
|
||||
<body onload="init();init_collapsible();">
|
||||
|
|
|
|||
Loading…
Reference in New Issue