mirror of https://github.com/sfeakes/AqualinkD.git
Version 1.3.5b
parent
30fff5c21f
commit
e13deacf5c
4
Makefile
4
Makefile
|
|
@ -31,7 +31,7 @@ CFLAGS = $(GCCFLAGS) $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_
|
|||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
|
||||
# define the C source files
|
||||
SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c pda.c pda_menu.c pda_aq_programmer.c pentair_messages.c mongoose.c
|
||||
SRCS = aqualinkd.c utils.c config.c aq_serial.c init_buttons.c aq_programmer.c net_services.c json_messages.c pda.c pda_menu.c pda_aq_programmer.c packetLogger.c pentair_messages.c mongoose.c
|
||||
DBG_SRC = timespec_subtract.c
|
||||
|
||||
# If run with `make DEBUG=true` add debug files and pass parameter for compile
|
||||
|
|
@ -40,7 +40,7 @@ ifeq ($(DEBUG), true)
|
|||
CFLAGS := $(CFLAGS) -D AQ_DEBUG
|
||||
endif
|
||||
|
||||
SL_SRC = serial_logger.c aq_serial.c utils.c
|
||||
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c
|
||||
LR_SRC = log_reader.c aq_serial.c utils.c
|
||||
PL_EXSRC = aq_serial.c
|
||||
PL_EXOBJ = aq_serial_player.o
|
||||
|
|
|
|||
152
README.md
152
README.md
|
|
@ -1,7 +1,7 @@
|
|||
# Aqualinkd
|
||||
linux daemon to control Aqualink RS pool controllers. Provides web UI, MQTT client & HTTP API endpoints. So you can control your pool equiptment from any phone/tablet or computer, and should work with just about Home control systems, including Apple HomeKit, Samsung, Alexa, Google, etc home hubs.
|
||||
Linux daemon to control Aqualink RS pool controllers. Provides web UI, MQTT client & HTTP API endpoints. Control your pool equiptment from any phone/tablet or computer. Is also compatible with most Home control systems including Apple HomeKit, Samsung, Alexa, Google, etc.
|
||||
|
||||
### It does not, and will never provide any layer of security. NEVER directly expose the device running this software to the outside world, only indirectly through the use of Home Automation hub's or other securty measures, e.g. VPNs.
|
||||
### It does not, and will never provide any layer of security. NEVER directly expose the device running this software to the outside world; only indirectly through the use of Home Automation hub's or other security measures. e.g. VPNs.
|
||||
|
||||
|
||||
## Donation
|
||||
|
|
@ -11,19 +11,20 @@ If you like this project, you can buy me a cup of coffee :)
|
|||
|
||||
## AqualinkD forum now open
|
||||
http://aqualinkd.freeforums.net
|
||||
(Please use this for questions / issues / problems)
|
||||
For Bugs use issues link on top of page
|
||||
(Please use this for questions / issues / problems).
|
||||
|
||||
## Please see Wiki for install instructions
|
||||
For Bugs, please use issues link on top of page.
|
||||
|
||||
## Please see Wiki for installation instructions
|
||||
https://github.com/sfeakes/AqualinkD/wiki
|
||||
|
||||
Information on Control panel versions and upgrading the chips.<br>
|
||||
For information on Control panel versions and upgrading the chips.<br>
|
||||
https://github.com/sfeakes/AqualinkD/wiki/Upgrading-Jandy-Aqualink-PDA-to-RS-panel
|
||||
|
||||
Started to document what I know about the Jandy RS485 protocol.<br>
|
||||
Here's where I started to document what I know about the Jandy RS485 protocol.<br>
|
||||
https://github.com/sfeakes/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
|
||||
|
||||
## AqualinkD builtin WEB Interface(s).
|
||||
## AqualinkD built in WEB Interface(s).
|
||||
|
||||
<table width="100%" border="0" cellpadding="20px">
|
||||
<tr><th width="50%">Default web interface</th><th wifth="50%">Simple web interface</img></th><tr>
|
||||
|
|
@ -31,29 +32,29 @@ https://github.com/sfeakes/AqualinkD/wiki/Jandy-Aqualink-RS485-protocol
|
|||
<tr><td colspan="2">
|
||||
Both Interfaces
|
||||
<ul>
|
||||
<li>If you load the web page in a mobile device browser, then save to desktop an app will be created for you.</li>
|
||||
<li>Order and options shown are configurable</li>
|
||||
<li>If loading the web page in a mobile device browser, you will need to save to desktop where an app will be created for you.</li>
|
||||
<li>The order and options shown are configurable for your individual needs and/or preferences.</li>
|
||||
</ul>
|
||||
</td></tr>
|
||||
<tr><td colspan="2">
|
||||
Default Interfaces
|
||||
<ul>
|
||||
<li>The layout & functionality are a from Appple HomeKit interface, only this works in any browser or mobile device.</li>
|
||||
<li>Customizable tile icons & background image. (can hide any tile)</li>
|
||||
<li>Thermostst, SWG & Light tiles have more options (like setting heater setpoint, light mode etc) that can be accessed with a long press</li>
|
||||
<li>Support live background imags (ie poll camera for still image every X seconds)</li>
|
||||
<li>The layout and functionality are from the Apple HomeKit interface. This works in any browser or on any mobile device.</li>
|
||||
<li>Customizable tile icons & background images. (Tiles not used can be hidden).</li>
|
||||
<li>Thermostat, SWG & Light tiles have more options (ie: setting heater temperature, salt generating percentage and light mode etc). These options are accessible by pressing and holding the tile icon.</li>
|
||||
<li>Supports live background images (ie: poll camera for still image every X seconds).</li>
|
||||
</ul>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
### Simulator
|
||||
Designed to mimic AqualinkRS6 All Button keypad, and just like the keypad you can use it to completley configure the master control panel<br>
|
||||
Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to fully configure the master control panel<br>
|
||||
<img src="extras/simulator.png?raw=true" width="550">
|
||||
|
||||
### In Apple Home app.
|
||||
<img src="extras/HomeKit2.png?raw=true" width="800"></img>
|
||||
* (Salt Water Generator is configured as Thermostat as it's the closest homekit accessory type, so °=% and Cooling=Generating)
|
||||
* Full support for homekit scenes, so can make a "Spa scene" to turn spa on, set spa heater particular temperature, turn spa blower on, etc etc)
|
||||
* (NOTE: Salt Water Generator is configured as a Thermostat. It is the closest homekit accessory type; so °=% and Cooling=Generating).
|
||||
* Full support for homekit scenes: ie: Create a "Spa scene" to: "turn spa on, set spa heater to X temperature and turn spa blower on", etc etc).
|
||||
|
||||
### In Home Assistant
|
||||
<img src="extras/HomeAssistant2.png?raw=true" width="800"></img>
|
||||
|
|
@ -63,11 +64,14 @@ Designed to mimic AqualinkRS6 All Button keypad, and just like the keypad you ca
|
|||
* http://aqualink.ip/simple.html <- (Simple opion if you don't like the above)
|
||||
* http://aqualink.ip/simulator.html <- (RS8 All Button Control Panel simulator)
|
||||
#<a name="release"></a>
|
||||
# Update in Release 1.3.5a
|
||||
* Logic for SWG RS486 checksum_errors
|
||||
# Update in Release 1.3.5a,b
|
||||
* Logic for SWG RS486 checksum_errors.
|
||||
* Fixed pentair packet logging, missing last byte.
|
||||
* Support for two programmable lights. (Note must update your aqualinkd.conf).
|
||||
* Can now display warnings and errors in the web UI (as well as log).
|
||||
# Update in Release 1.3.5
|
||||
* Fixed SWG bug showing off/0% every ~15 seconds (introduced in 1.3.3)
|
||||
* PDA updates for freeze protect / SWG & general speed increase.
|
||||
* Fixed SWG bug showing off/0% every ~15 seconds (introduced in 1.3.3).
|
||||
* PDA updates for freeze protect/SWG and general speed increase.
|
||||
## Update in Release 1.3.4 (a)
|
||||
* Logging changes.
|
||||
* Fix issues in programming mode.
|
||||
|
|
@ -75,98 +79,98 @@ Designed to mimic AqualinkRS6 All Button keypad, and just like the keypad you ca
|
|||
* Changed to serial logger.
|
||||
* PDA changes for SWG and Setpoints.
|
||||
## Update in Release 1.3.3 (a,b,c,e,f)
|
||||
* Incremental PDA fixes / enhancements.
|
||||
* SWG bug fix
|
||||
* Incremental PDA fixes/enhancements.
|
||||
* SWG bug fix.
|
||||
## Update in Release 1.3.3
|
||||
* AqualinkD will now automaticaly find a usable ID if not specifically configured.
|
||||
* Support for reading (up to 4) Variable Speed Pump info & assigning per device. (Please see wiki for new config options).
|
||||
* <span style="color:red">*At present only Pentair VSP supported, if you have Jandy VSP (ePump) and are willing to do some testing, please post on forum as I'd like to get this supported as well.*</span>
|
||||
* For VSP you need to check config for `read_all_devices = yes` & `read_pentair_packets = yes` and assign RS485 Pump ID to Device ID in configuration. serial_logger should find ID's for you.
|
||||
* WebUI will display Pump RPM only. RPM,Watts,GPH information is also available from MQTT & API.
|
||||
* Support for reading (up to 4) Variable Speed Pump info and assigning per device. (Please see wiki for new config options).
|
||||
* <span style="color:red">*At present only Pentair VSP is supported, if you have Jandy VSP (ePump) and are willing to do some testing, please post on forum as I'd like to get this supported as well.*</span>
|
||||
* For VSP you will need to check configuration for `read_all_devices = yes` & `read_pentair_packets = yes` and assign RS485 Pump ID to Device ID in configuration. serial_logger should find ID's for you.
|
||||
* WebUI will display Pump RPM only. RPM, Watts and GPH information is also available from MQTT & API.
|
||||
## Update in Release 1.3.2c
|
||||
* Miscellaneous bug fixes and buffer overrun (could cause core dump).
|
||||
* VSP update & Pantair device support.
|
||||
## Update in Release 1.3.1
|
||||
* Changed the way PDA mode will sleep.
|
||||
* Added preliminary support for Variable Speed Pumps. (many limitations on support)
|
||||
* Added int status to Web API
|
||||
* Added preliminary support for Variable Speed Pumps. (Many limitations on support).
|
||||
* Added int status to Web API.
|
||||
## Update in Release 1.3.0
|
||||
* Large update for PDA only control panels (Majority of this is ballle98 work)
|
||||
* Can distinguish between AquaPalm and PDA supported control panels.
|
||||
* PDA Freeze & Heater setpoints now supported.
|
||||
* Added PDA Sleep mode so AqualinkD can work inconjunction with a real Jandy PDA.
|
||||
* PDA Freeze & Heater setpoints are now supported.
|
||||
* Added PDA Sleep mode so AqualinkD can work in conjunction with a real Jandy PDA.
|
||||
* Speeded up many PDA functions.
|
||||
* Fixed many PDA bugs.
|
||||
* Non PDA specific updates :-
|
||||
* Can get button labels from control panel (not in PDA mode)
|
||||
* Can get button labels from control panel (not in PDA mode).
|
||||
* RS485 Logging so users can submit information on Variable Speed Pumps & other devices for future support.
|
||||
* Force SWG status on startup, rather than wait for pump to turn on.
|
||||
* General bug fixes and improved code in many areas.
|
||||
## Update in Release 1.2.6f
|
||||
* Solution to overcome bug in Mosquitto 1.6.
|
||||
* Fixed Salt Water Generator when % was set to 0.
|
||||
* Added support for different SWG % for pool & spa. (SWG reports and sets the mode that's currently active)
|
||||
* Added support for different SWG % for pool & spa. (SWG reports and sets the mode that is currently active).
|
||||
* Increased speed of SWG messages.
|
||||
* Few other bug fixes (Thanks to ballle98)
|
||||
* Few other bug fixes (Thanks to ballle98).
|
||||
## Update in Release 1.2.6e (This is a quick update, please only use if you need one of the items below.)
|
||||
* Unstable update.
|
||||
## Update in Release 1.2.6c
|
||||
* Fix some merge issues
|
||||
* Fixed some merge issues.
|
||||
* Added MQTT topic for delayed start on buttons.
|
||||
* Removed MQTT flash option for delayed start (never worked well anyway)
|
||||
* Removed MQTT flash option for delayed start (never worked well anyway).
|
||||
## Update in Release 1.2.6b
|
||||
* Added MQTT topic for full SWG status (MQTT section in see wiki)
|
||||
* Config option to turn on/of listening to extended device information.
|
||||
* Added service mode topic to MQTT (Thanks to tcm0116)
|
||||
* Added report zero pool temp (Thanks to tcm0116)
|
||||
* Added MQTT topic for full SWG status (MQTT section in see wiki).
|
||||
* Configured option to turn on/off listening to extended device information.
|
||||
* Added service mode topic to MQTT (Thanks to tcm0116).
|
||||
* Added report zero pool temp (Thanks to tcm0116).
|
||||
## Update in Release 1.2.6a
|
||||
* more PDA fixes (Thanks to ballle98)
|
||||
* Fix in MQTT requests to change temp when temp units are unkown.
|
||||
* More PDA fixes (Thanks to ballle98).
|
||||
* Fix in MQTT requests to change temperature when temperature units are unkown.
|
||||
## Update in Release 1.2.6
|
||||
* fix for PDA with SPA messages. (Thanks to ballle98)
|
||||
* Added report 0 for pool temp when not available. (Thanks to tcm0116)
|
||||
* Fix for PDA with SPA messages. (Thanks to ballle98).
|
||||
* Added report 0 for pool temperature when not available. (Thanks to tcm0116).
|
||||
## Update in Release 1.2.5a
|
||||
* fix bug for MQTT freeze protect.
|
||||
* Fix bug for MQTT freeze protect.
|
||||
## Update in Release 1.2.4
|
||||
* Small fix for Freeze Protect.
|
||||
## Update in Release 1.2.3
|
||||
* Fix for setpoints on "Pool Only" configurations.
|
||||
## Update in Release 1.2.2
|
||||
* Support for Spa OR Pool OLNY mode with setpoints, (previous setpoints expected Spa & Pool mode)
|
||||
* Added support for MQTT Last Will Message
|
||||
* Fix spelling errors will effect your conficuration, and the install.sh script will not overwrite.
|
||||
* Please compare /var/www/aqualinkd/config.js to the new one, you will need to manualy edit or overide
|
||||
* MQTT spelling for enabled is now accurate, so anything using the /enabled message will nee to be changed
|
||||
* homekit will need to be changed. Please see the new homekit2mqtt.json or modify your existing one.
|
||||
* Support for Spa OR Pool ONLY mode with setpoints; (previous setpoints expected Spa & Pool mode)
|
||||
* Added support for MQTT Last Will Message.
|
||||
* NOTE: Fixed spelling errors will effect your configuration and the install.sh script will not overwrite.
|
||||
* Please compare /var/www/aqualinkd/config.js to the new one, you will need to manually edit or overide.
|
||||
* MQTT spelling for "enabled" is now accurate, so anything using the /enabled message will need to be changed.
|
||||
* Homekit will also need to be changed. Please see the new homekit2mqtt.json or modify your existing one.
|
||||
## Updates in Release 1.2
|
||||
* PDA support in BETA. (Please see WiKi for details)
|
||||
* Fixed bug in posting Heater Emables topics to MQTT. (order was reversed)
|
||||
* Serial read change. (detect escaped DTX in packet, 1 in 10000 chance or happening)
|
||||
* PDA support in BETA. (Please see WiKi for details).
|
||||
* Fixed bug in posting Heater enables topics to MQTT. (order was reversed).
|
||||
* Serial read change. (Detect escaped DTX in packet, 1 in 10000 chance of happening).
|
||||
## Updates in Release 1.1
|
||||
* Changed the way AqualinkD reads USB, fixes the checksum & serial read too small errors that happened on some RS485 networks.
|
||||
* Figex bug in SWG would read "high voltage" and not "check cell"
|
||||
* Figex bug in SWG would read "high voltage" and not "check cell".
|
||||
## Updates in release 1.0e
|
||||
* Web UI out of Beta
|
||||
* MQTT fix setpoints
|
||||
* Web UI out of Beta.
|
||||
* MQTT fix setpoints.
|
||||
* Simulator is now more stable.
|
||||
* updates to serial logger
|
||||
* UI updates
|
||||
* bug fix in MQTT_flash (still not prefect fix)
|
||||
* Updates to serial logger.
|
||||
* UI updates.
|
||||
* Bug fix in MQTT_flash (still not perfect).
|
||||
## Updates in Release 1.0c
|
||||
* New Simple interface.
|
||||
* New Simpler interface.
|
||||
* Start of a RS8 Simulator :-
|
||||
* So you can program the AqualinkRS form a web interface and not control panel.
|
||||
* Please make sure all other browsers & tabs are not using AqualinkD. it doesn't support multiple devices when in simulator mode.
|
||||
* You can now program the AqualinkRS from a web interface and not just the control panel.
|
||||
* Please make sure all other browsers and tabs are not using AqualinkD as it does not support multiple devices when in simulator mode.
|
||||
* Fixed a few bugs.
|
||||
* -- Release 1.0b --
|
||||
* NEW WEB UI !!!!!!!!!!!!! (in beta)
|
||||
* Flash buttons on/off in homekit for enabeling / disabeling / cooldown period as they do on control panel
|
||||
* Full SWG support (setting %, not just reporting current state). Also reports Salt Cell status such as (no flow, low salt, high curent, clean cell, low voltage, water temp low, check PCB)
|
||||
* Update to thermostats, colors are now correct in homekit, green=enabeled, orange=heating, blue=cooling (SWG only)
|
||||
* NEW WEB UI !!!!!!!!!!!!! (in beta).
|
||||
* Flash buttons on/off in homekit for enabeling/disabling/cooldown period as they do on the control panel.
|
||||
* Full SWG support (setting %, not just reporting current state). Also reports Salt Cell status such as (no flow, low salt, high curent, clean cell, low voltage, water temp low, check PCB).
|
||||
* Update to thermostats, colors are now correct in homekit, green=enabeled, orange=heating, blue=cooling (SWG only).
|
||||
* Light show program mode should now support most vendors lights.
|
||||
* config changes for (spa temp as pool temp / light program mode options / enable homekit button flash)
|
||||
* updated to serial_logger.
|
||||
* freeze protect, heater temperature & SWG set-points have been added to support for standard HTTP requests (MQTT & WS always had support)
|
||||
* Configuration changes for: Spa temp as pool temp/light program mode options/enable homekit button flash.
|
||||
* Updated to serial_logger.
|
||||
* Freeze protect, heater temperature and SWG set-points have been added to support for standard HTTP requests (MQTT & WS always had support).
|
||||
|
||||
# Please see Wiki for install instructions
|
||||
https://github.com/sfeakes/AqualinkD/wiki
|
||||
|
|
@ -174,8 +178,8 @@ https://github.com/sfeakes/AqualinkD/wiki
|
|||
#
|
||||
|
||||
# Aqualink Versions tested
|
||||
This was designed for Jandy Aqualink RS, so should work with AqualinkRS and iAqualink Combo controll panels. It will work with Aqualink PDA / AquaPalm and NON Combo iAqualink, but there are limitations.
|
||||
Below are varified versions (But should work with any AqualinkRS) :-
|
||||
This was designed for Jandy Aqualink RS, so should work with AqualinkRS and iAqualink Combo control panels. It will work with Aqualink PDA/AquaPalm and NON Combo iAqualink; but with limitations.
|
||||
Below are verified versions, but should work with any AqualinkRS :-
|
||||
|
||||
|
||||
| Version | Notes |
|
||||
|
|
@ -190,7 +194,7 @@ Below are varified versions (But should work with any AqualinkRS) :-
|
|||
| Jandy iAqualink E0260801 REV R | Everything working |
|
||||
| AquaLink PDA / AquaPalm | Works, please see WiKi for limitations|
|
||||
|
||||
If you have tested a version not listed here, please let me know by opening an issue
|
||||
If you have tested a version not listed here, please let me know by opening an issue.
|
||||
#
|
||||
<!--
|
||||
|
||||
|
|
@ -480,7 +484,7 @@ See License.md for more details.
|
|||
|
||||
|
||||
# Donation
|
||||
If you like this project, you can buy me a cup of coffee :)
|
||||
If you still like this project, please consider buying me a cup of coffee :)
|
||||
<br>
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SEGN9UNS38TXJ)
|
||||
|
||||
|
|
|
|||
|
|
@ -693,7 +693,7 @@ void *set_aqualink_light_colormode( void *ptr )
|
|||
aqkey *button = &aq_data->aqbuttons[btn];
|
||||
unsigned char code = button->code;
|
||||
|
||||
logMessage(LOG_NOTICE, "Pool Light Programming #: %d, on button: %s, with pause mode: %f (initial on=%d, initial off=%d)\n", val, button->label, pmode, iOn, iOff);
|
||||
logMessage(LOG_NOTICE, "Light Programming #: %d, on button: %s, with pause mode: %f (initial on=%d, initial off=%d)\n", val, button->label, pmode, iOn, iOff);
|
||||
|
||||
// Simply turn the light off if value is 0
|
||||
if (val <= 0) {
|
||||
|
|
|
|||
96
aq_serial.c
96
aq_serial.c
|
|
@ -29,8 +29,10 @@
|
|||
#include "aq_serial.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "packetLogger.h"
|
||||
|
||||
//#define BLOCKING_MODE
|
||||
#define PENTAIR_LENGTH_FIX
|
||||
|
||||
static struct termios _oldtio;
|
||||
|
||||
|
|
@ -73,24 +75,23 @@ void log_packet(int level, char *init_str, unsigned char* packet, int length)
|
|||
cnt += sprintf(buff+cnt, "\n");
|
||||
logMessage(level, buff);
|
||||
//logMessage(LOG_DEBUG_SERIAL, buff);
|
||||
/*
|
||||
int i;
|
||||
char temp_string[64];
|
||||
char message_buffer[MAXLEN];
|
||||
|
||||
sprintf(temp_string, "Send 0x%02hhx|", packet[0]);
|
||||
strcpy(message_buffer, temp_string);
|
||||
|
||||
for (i = 1; i < length; i++) {
|
||||
sprintf(temp_string, "0x%02hhx|", packet[i]);
|
||||
strcat(message_buffer, temp_string);
|
||||
}
|
||||
|
||||
strcat(message_buffer, "\n");
|
||||
logMessage(LOG_DEBUG, message_buffer);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const char* get_packet_type(unsigned char* packet , int length)
|
||||
{
|
||||
static char buf[15];
|
||||
|
|
@ -593,8 +594,13 @@ bool check_pentair_checksum(unsigned char* packet, int length)
|
|||
sum += (int) packet[i];
|
||||
}
|
||||
|
||||
#ifndef PENTAIR_LENGTH_FIX
|
||||
if (sum == (packet[length-1] * 256 + packet[length]))
|
||||
return true;
|
||||
#else
|
||||
if (sum == (packet[length-2] * 256 + packet[length-1]))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -674,7 +680,9 @@ int get_packet_new(int fd, unsigned char* packet)
|
|||
{
|
||||
endOfPacket = true;
|
||||
PentairPreCnt = -1;
|
||||
#ifndef PENTAIR_LENGTH_FIX
|
||||
index--;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (byte == DLE && jandyPacketStarted == false)
|
||||
|
|
@ -731,8 +739,9 @@ int get_packet_new(int fd, unsigned char* packet)
|
|||
// Break out of the loop if we exceed maximum packet
|
||||
// length.
|
||||
if (index >= AQ_MAXPKTLEN) {
|
||||
logPacketError(packet, index);
|
||||
logMessage(LOG_WARNING, "Serial packet too large\n");
|
||||
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -740,15 +749,17 @@ int get_packet_new(int fd, unsigned char* packet)
|
|||
|
||||
//logMessage(LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
|
||||
if (jandyPacketStarted) {
|
||||
if (generate_checksum(packet, index) != packet[index-3]){
|
||||
if (check_jandy_checksum(packet, index) != true){
|
||||
logPacketError(packet, index);
|
||||
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
|
||||
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return 0;
|
||||
}
|
||||
} else if (pentairPacketStarted) {
|
||||
if (check_pentair_checksum(packet, index) != true){
|
||||
logPacketError(packet, index);
|
||||
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
|
||||
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -758,12 +769,14 @@ int get_packet_new(int fd, unsigned char* packet)
|
|||
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return 0;
|
||||
} else*/ if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
|
||||
logPacketError(packet, index);
|
||||
logMessage(LOG_WARNING, "Serial read too small\n");
|
||||
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
//log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
|
||||
logPacket(packet, index);
|
||||
// Return the packet length.
|
||||
return index;
|
||||
}
|
||||
|
|
@ -773,6 +786,27 @@ int get_packet_new(int fd, unsigned char* packet)
|
|||
#include <stdlib.h>
|
||||
FILE *_fp;
|
||||
|
||||
|
||||
bool check_pentair_checksum(unsigned char* packet, int length)
|
||||
{
|
||||
int i, sum, n;
|
||||
n = packet[8] + 9;
|
||||
sum = 0;
|
||||
//printf("Pentair ");
|
||||
for (i = 3; i < n; i++) {
|
||||
sum += (int) packet[i];
|
||||
//printf("+ (0x%02hhx) %d = %d ",packet[i],(int)packet[i],sum);
|
||||
}
|
||||
|
||||
//printf("\nPentair checksum %d = %d (0x%02hhx) (0x%02hhx)\n",sum, (packet[length-1] * 256 + packet[length]),packet[length-1],packet[length]);
|
||||
|
||||
if (sum == (packet[length-1] * 256 + packet[length]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int init_serial_port(char* file)
|
||||
{
|
||||
_fp = fopen ( file, "r" );
|
||||
|
|
@ -817,6 +851,23 @@ int get_packet(int fd, unsigned char* packet_buffer)
|
|||
//printf("To 0x%02hhx, type %15.15s, length %2.2d ", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),packet_length);
|
||||
//fputs ( line, stdout );
|
||||
|
||||
if (getProtocolType(packet_buffer)==JANDY) {
|
||||
if (generate_checksum(packet_buffer, packet_length) != packet_buffer[packet_length-3]) {
|
||||
logPacketError(packet_buffer, packet_length);
|
||||
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
|
||||
} else
|
||||
logPacket(packet_buffer, packet_length);
|
||||
} else {
|
||||
//check_pentair_checksum(packet_buffer, packet_length);
|
||||
//check_pentair_checksum(packet_buffer, packet_length-1);
|
||||
//check_pentair_checksum(packet_buffer, packet_length+1);
|
||||
if (check_pentair_checksum(packet_buffer, packet_length-1) != true) {
|
||||
logPacketError(packet_buffer, packet_length);
|
||||
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
|
||||
} else
|
||||
logPacket(packet_buffer, packet_length);
|
||||
}
|
||||
|
||||
return packet_length;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -948,7 +999,10 @@ int get_packet_old(int fd, unsigned char* packet)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//if (_config_parameters.debug_RSProtocol_packets || getLogLevel() >= LOG_DEBUG_SERIAL)
|
||||
// logPacket(packet_buffer, packet_length);
|
||||
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
|
||||
|
||||
// Return the packet length.
|
||||
return index;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,9 +184,6 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
|
|||
|
||||
/* AQUAPURE SWG */
|
||||
|
||||
// Number of set SWG % to 0 messages to ignore.
|
||||
#define SWG_ZERO_IGNORE_COUNT 10
|
||||
|
||||
// These are madeup.
|
||||
#define SWG_STATUS_OFF 0xFF
|
||||
#define SWG_STATUS_UNKNOWN -128
|
||||
|
|
|
|||
43
aqualinkd.c
43
aqualinkd.c
|
|
@ -40,6 +40,7 @@
|
|||
#include "pda.h"
|
||||
#include "pentair_messages.h"
|
||||
#include "pda_aq_programmer.h"
|
||||
#include "packetLogger.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
|
|
@ -739,7 +740,10 @@ int main(int argc, char *argv[])
|
|||
if (cmdln_debugRS485)
|
||||
_config_parameters.debug_RSProtocol_packets = true;
|
||||
|
||||
setLoggingPrms(_config_parameters.log_level, _config_parameters.deamonize, _config_parameters.log_file);
|
||||
if (_config_parameters.display_warnings_web == true)
|
||||
setLoggingPrms(_config_parameters.log_level, _config_parameters.deamonize, _config_parameters.log_file, _aqualink_data.last_display_message);
|
||||
else
|
||||
setLoggingPrms(_config_parameters.log_level, _config_parameters.deamonize, _config_parameters.log_file, NULL);
|
||||
|
||||
logMessage(LOG_NOTICE, "%s v%s\n", AQUALINKD_NAME, AQUALINKD_VERSION);
|
||||
|
||||
|
|
@ -779,6 +783,11 @@ int main(int argc, char *argv[])
|
|||
//logMessage(LOG_NOTICE, "Use PDA 4 auxiliary info = %s\n", bool2text(_config_parameters.use_PDA_auxiliary));
|
||||
logMessage(LOG_NOTICE, "Read Pentair Packets = %s\n", bool2text(_config_parameters.read_pentair_packets));
|
||||
// logMessage (LOG_NOTICE, "Config serial_port = %s\n", config_parameters->serial_port);
|
||||
logMessage(LOG_NOTICE, "Display warnings in web = %s\n", bool2text(_config_parameters.display_warnings_web));
|
||||
|
||||
if (_config_parameters.swg_zero_ignore > 0)
|
||||
logMessage(LOG_NOTICE, "Ignore SWG 0 msg count = %d\n", _config_parameters.swg_zero_ignore);
|
||||
|
||||
|
||||
for (i = 0; i < TOTAL_BUTONS; i++)
|
||||
{
|
||||
|
|
@ -790,7 +799,15 @@ int main(int argc, char *argv[])
|
|||
//printf("Pump %d %d %d\n",_aqualink_data.pumps[j].pumpID, _aqualink_data.pumps[j].buttonID, _aqualink_data.pumps[j].ptype);
|
||||
}
|
||||
}
|
||||
logMessage(LOG_NOTICE, "Config BTN %-13s = label %-15s | VSP ID %-4s | PDAlabel %-15s | dzidx %d\n", _aqualink_data.aqbuttons[i].name, _aqualink_data.aqbuttons[i].label, vsp, _aqualink_data.aqbuttons[i].pda_label, _aqualink_data.aqbuttons[i].dz_idx);
|
||||
if (!_config_parameters.pda_mode) {
|
||||
logMessage(LOG_NOTICE, "Config BTN %-13s = label %-15s | VSP ID %-4s | dzidx %d | %s\n",
|
||||
_aqualink_data.aqbuttons[i].name, _aqualink_data.aqbuttons[i].label, vsp, _aqualink_data.aqbuttons[i].dz_idx,
|
||||
(i>0 && (i==_config_parameters.light_programming_button_pool || i==_config_parameters.light_programming_button_spa)?"Programable":"") );
|
||||
} else {
|
||||
logMessage(LOG_NOTICE, "Config BTN %-13s = label %-15s | VSP ID %-4s | PDAlabel %-15s | dzidx %d\n",
|
||||
_aqualink_data.aqbuttons[i].name, _aqualink_data.aqbuttons[i].label, vsp,
|
||||
_aqualink_data.aqbuttons[i].pda_label, _aqualink_data.aqbuttons[i].dz_idx );
|
||||
}
|
||||
//logMessage(LOG_NOTICE, "Button %d\n", i+1, _aqualink_data.aqbuttons[i].label , _aqualink_data.aqbuttons[i].dz_idx);
|
||||
}
|
||||
|
||||
|
|
@ -875,7 +892,7 @@ void logPacket(unsigned char *packet_buffer, int packet_length)
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
void logPacket_new(unsigned char* packet_buffer, int packet_length)
|
||||
{
|
||||
char buff[1000];
|
||||
|
|
@ -918,7 +935,7 @@ void logPacket(unsigned char *packet_buffer, int packet_length)
|
|||
else
|
||||
logMessage(LOG_DEBUG_SERIAL, "%s", buff);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#define MAX_BLOCK_ACK 12
|
||||
#define MAX_BUSY_ACK (50 + MAX_BLOCK_ACK)
|
||||
|
|
@ -1046,6 +1063,8 @@ void main_loop()
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
startPacketLogger(_config_parameters.debug_RSProtocol_packets, _config_parameters.read_pentair_packets);
|
||||
|
||||
signal(SIGINT, intHandler);
|
||||
signal(SIGTERM, intHandler);
|
||||
|
||||
|
|
@ -1113,10 +1132,10 @@ void main_loop()
|
|||
{
|
||||
blank_read = 0;
|
||||
changed = false;
|
||||
|
||||
/*
|
||||
if (_config_parameters.debug_RSProtocol_packets || getLogLevel() >= LOG_DEBUG_SERIAL)
|
||||
logPacket(packet_buffer, packet_length);
|
||||
|
||||
*/
|
||||
if (packet_length > 0 && packet_buffer[PKT_DEST] == _config_parameters.device_id)
|
||||
{
|
||||
|
||||
|
|
@ -1196,13 +1215,14 @@ void main_loop()
|
|||
if (packet_buffer[3] == CMD_PERCENT && _aqualink_data.active_thread.thread_id == 0)
|
||||
{
|
||||
// SWG can get ~10 messages to set to 0 then go back again for some reason, so don't go to 0 until 10 messages are received
|
||||
if (swg_zero_cnt <= SWG_ZERO_IGNORE_COUNT && packet_buffer[4] == 0x00 && packet_buffer[5] == 0x73) {
|
||||
logMessage(LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet_buffer[4],swg_zero_cnt,SWG_ZERO_IGNORE_COUNT,packet_buffer[4],packet_buffer[5]);
|
||||
if (swg_zero_cnt < _config_parameters.swg_zero_ignore && packet_buffer[4] == 0x00 && packet_buffer[5] == 0x73) {
|
||||
logMessage(LOG_DEBUG, "Ignoring SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet_buffer[4],swg_zero_cnt,_config_parameters.swg_zero_ignore,packet_buffer[4],packet_buffer[5]);
|
||||
swg_zero_cnt++;
|
||||
} else if (swg_zero_cnt > SWG_ZERO_IGNORE_COUNT && packet_buffer[4] == 0x00 && packet_buffer[5] == 0x73) {
|
||||
} else if (swg_zero_cnt > _config_parameters.swg_zero_ignore && packet_buffer[4] == 0x00 && packet_buffer[5] == 0x73) {
|
||||
_aqualink_data.swg_percent = (int)packet_buffer[4];
|
||||
changed = true;
|
||||
//logMessage(LOG_DEBUG, "SWG set to %d due to packet from control panel to SWG 0x%02hhx 0x%02hhx\n", _aqualink_data.swg_percent,packet_buffer[4],packet_buffer[5]);
|
||||
//logMessage(LOG_DEBUG, "SWG set to %d due to packet packet count %d <= %d from control panel to SWG 0x%02hhx 0x%02hhx\n", (int)packet_buffer[4],swg_zero_cnt,SWG_ZERO_IGNORE_COUNT,packet_buffer[4],packet_buffer[5]);
|
||||
//swg_zero_cnt++;
|
||||
} else {
|
||||
swg_zero_cnt = 0;
|
||||
_aqualink_data.swg_percent = (int)packet_buffer[4];
|
||||
|
|
@ -1259,7 +1279,8 @@ void main_loop()
|
|||
//}
|
||||
}
|
||||
|
||||
if (_config_parameters.debug_RSProtocol_packets) closePacketLog();
|
||||
//if (_config_parameters.debug_RSProtocol_packets) stopPacketLogger();
|
||||
stopPacketLogger();
|
||||
// Reset and close the port.
|
||||
close_serial_port(rs_fd);
|
||||
// Clear webbrowser
|
||||
|
|
|
|||
39
config.c
39
config.c
|
|
@ -71,7 +71,8 @@ void init_parameters (struct aqconfig * parms)
|
|||
parms->light_programming_mode = 0;
|
||||
parms->light_programming_initial_on = 15;
|
||||
parms->light_programming_initial_off = 12;
|
||||
parms->light_programming_button = 0;
|
||||
parms->light_programming_button_pool = TEMP_UNKNOWN;
|
||||
parms->light_programming_button_spa = TEMP_UNKNOWN;
|
||||
parms->deamonize = true;
|
||||
parms->log_file = '\0';
|
||||
parms->pda_mode = false;
|
||||
|
|
@ -86,6 +87,8 @@ void init_parameters (struct aqconfig * parms)
|
|||
parms->force_swg = false;
|
||||
//parms->swg_pool_and_spa = false;
|
||||
parms->read_pentair_packets = false;
|
||||
parms->swg_zero_ignore = 0;
|
||||
parms->display_warnings_web = false;
|
||||
|
||||
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
|
||||
}
|
||||
|
|
@ -365,8 +368,12 @@ bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqd
|
|||
} else if (strncasecmp(param, "light_programming_initial_off", 29) == 0) {
|
||||
config_parameters->light_programming_initial_off = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_button", 21) == 0) {
|
||||
config_parameters->light_programming_button = strtoul(value, NULL, 10) - 1;
|
||||
} else if (strncasecmp(param, "light_programming_button_spa", 28) == 0) {
|
||||
config_parameters->light_programming_button_spa = strtoul(value, NULL, 10) - 1;
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "light_programming_button", 24) == 0 ||
|
||||
strncasecmp(param, "light_programming_button_pool", 29) == 0) {
|
||||
config_parameters->light_programming_button_pool = strtoul(value, NULL, 10) - 1;
|
||||
rtn=true;
|
||||
} else if (strncasecmp(param, "SWG_percent_dzidx", 17) == 0) {
|
||||
config_parameters->dzidx_swg_percent = strtoul(value, NULL, 10);
|
||||
|
|
@ -421,7 +428,14 @@ bool setConfigValue(struct aqconfig *config_parameters, struct aqualinkdata *aqd
|
|||
config_parameters->read_pentair_packets = text2bool(value);
|
||||
config_parameters->read_all_devices = true;
|
||||
rtn=true;
|
||||
} /*
|
||||
} else if (strncasecmp (param, "swg_zero_ignore_count", 21) == 0) {
|
||||
config_parameters->swg_zero_ignore = strtoul(value, NULL, 10);
|
||||
rtn=true;
|
||||
} else if (strncasecmp (param, "display_warnings_in_web", 23) == 0) {
|
||||
config_parameters->display_warnings_web = text2bool(value);
|
||||
rtn=true;
|
||||
}
|
||||
/*
|
||||
else if (strncasecmp (param, "use_PDA_auxiliary", 17) == 0) {
|
||||
config_parameters->use_PDA_auxiliary = text2bool(value);
|
||||
if ( pda_mode() ) {
|
||||
|
|
@ -622,17 +636,18 @@ bool writeCfg (struct aqconfig *config_parameters, struct aqualinkdata *aqdata)
|
|||
fprintf(fp, "report_zero_pool_temp = %s\n", bool2text(config_parameters->report_zero_pool_temp));
|
||||
|
||||
fprintf(fp, "\n#** Programmable light **\n");
|
||||
if (config_parameters->light_programming_button <= 0) {
|
||||
fprintf(fp, "#light_programming_button = %d\n", config_parameters->light_programming_button);
|
||||
fprintf(fp, "#light_programming_mode = %f\n", config_parameters->light_programming_mode);
|
||||
fprintf(fp, "#light_programming_initial_on = %d\n", config_parameters->light_programming_initial_on);
|
||||
fprintf(fp, "#light_programming_initial_off = %d\n", config_parameters->light_programming_initial_off);
|
||||
} else {
|
||||
fprintf(fp, "light_programming_button = %d\n", config_parameters->light_programming_button);
|
||||
//if (config_parameters->light_programming_button_pool <= 0) {
|
||||
// fprintf(fp, "#light_programming_button_pool = %d\n", config_parameters->light_programming_button_pool);
|
||||
// fprintf(fp, "#light_programming_mode = %f\n", config_parameters->light_programming_mode);
|
||||
// fprintf(fp, "#light_programming_initial_on = %d\n", config_parameters->light_programming_initial_on);
|
||||
// fprintf(fp, "#light_programming_initial_off = %d\n", config_parameters->light_programming_initial_off);
|
||||
//} else {
|
||||
fprintf(fp, "light_programming_button_pool = %d\n", config_parameters->light_programming_button_pool);
|
||||
fprintf(fp, "light_programming_button_spa = %d\n", config_parameters->light_programming_button_spa);
|
||||
fprintf(fp, "light_programming_mode = %f\n", config_parameters->light_programming_mode);
|
||||
fprintf(fp, "light_programming_initial_on = %d\n", config_parameters->light_programming_initial_on);
|
||||
fprintf(fp, "light_programming_initial_off = %d\n", config_parameters->light_programming_initial_off);
|
||||
}
|
||||
//}
|
||||
|
||||
fprintf(fp, "\n#** Domoticz **\n");
|
||||
fprintf(fp, "convert_dz_temp_to_c = %s\n", bool2text(config_parameters->convert_dz_temp));
|
||||
|
|
|
|||
5
config.h
5
config.h
|
|
@ -47,7 +47,8 @@ struct aqconfig
|
|||
float light_programming_mode;
|
||||
int light_programming_initial_on;
|
||||
int light_programming_initial_off;
|
||||
int light_programming_button;
|
||||
int light_programming_button_pool;
|
||||
int light_programming_button_spa;
|
||||
bool override_freeze_protect;
|
||||
bool pda_mode;
|
||||
bool pda_sleep_mode;
|
||||
|
|
@ -59,6 +60,8 @@ struct aqconfig
|
|||
bool read_all_devices;
|
||||
bool use_panel_aux_labels;
|
||||
bool force_swg;
|
||||
int swg_zero_ignore;
|
||||
bool display_warnings_web;
|
||||
//bool swg_pool_and_spa;
|
||||
//bool use_PDA_auxiliary;
|
||||
bool read_pentair_packets;
|
||||
|
|
|
|||
|
|
@ -50,8 +50,28 @@ const char* getStatus(struct aqualinkdata *aqdata)
|
|||
return JSON_SERVICE;
|
||||
}
|
||||
|
||||
if (aqdata->last_display_message[0] != '\0')
|
||||
if (aqdata->last_display_message[0] != '\0') {
|
||||
int i;
|
||||
for(i=0; i < strlen(aqdata->last_display_message); i++ ) {
|
||||
if (aqdata->last_display_message[i] <= 31 || aqdata->last_display_message[i] >= 127) {
|
||||
aqdata->last_display_message[i] = ' ';
|
||||
} else {
|
||||
switch (aqdata->last_display_message[i]) {
|
||||
case '"':
|
||||
case '/':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\f':
|
||||
case '\r':
|
||||
case '\b':
|
||||
aqdata->last_display_message[i] = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("JSON Sending '%s'\n",aqdata->last_display_message);
|
||||
return aqdata->last_display_message;
|
||||
}
|
||||
/*
|
||||
if (aqdata->display_last_message == true) {
|
||||
return aqdata->last_message;
|
||||
|
|
@ -159,7 +179,7 @@ char *get_aux_information(aqkey *button, struct aqualinkdata *aqdata, char *buff
|
|||
return buffer;
|
||||
}
|
||||
|
||||
int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char* buffer, int size, bool homekit)
|
||||
int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch1, int programable_switch2, char* buffer, int size, bool homekit)
|
||||
{
|
||||
char aux_info[AUX_BUFFER_SIZE];
|
||||
memset(&buffer[0], 0, size);
|
||||
|
|
@ -202,7 +222,8 @@ int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char*
|
|||
((homekit)?2:0),
|
||||
((homekit && aqdata->temp_units==FAHRENHEIT)?degFtoC(aqdata->spa_temp):aqdata->spa_temp),
|
||||
LED2int(aqdata->aqbuttons[i].led->state));
|
||||
} else if (programable_switch > 0 && programable_switch == i) {
|
||||
} else if ( (programable_switch1 > 0 && programable_switch1 == i) ||
|
||||
(programable_switch2 > 0 && programable_switch2 == i)) {
|
||||
length += sprintf(buffer+length, "{\"type\": \"switch_program\", \"id\": \"%s\", \"name\": \"%s\", \"state\": \"%s\", \"status\": \"%s\", \"int_status\": \"%d\" %s},",
|
||||
aqdata->aqbuttons[i].name,
|
||||
aqdata->aqbuttons[i].label,
|
||||
|
|
@ -486,6 +507,8 @@ bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request)
|
|||
request->first.value = NULL;
|
||||
request->second.key = NULL;
|
||||
request->second.value = NULL;
|
||||
request->third.key = NULL;
|
||||
request->third.value = NULL;
|
||||
|
||||
int length = strlen(buffer);
|
||||
|
||||
|
|
@ -525,12 +548,19 @@ bool parseJSONwebrequest(char *buffer, struct JSONwebrequest *request)
|
|||
case 3:
|
||||
request->second.value = &buffer[i];
|
||||
break;
|
||||
case 4:
|
||||
request->third.key = &buffer[i];
|
||||
break;
|
||||
case 5:
|
||||
request->third.value = &buffer[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
//printf ("\n");
|
||||
if (found >= 4)
|
||||
// if (found >= 4)
|
||||
if (found >= 6)
|
||||
break;
|
||||
|
||||
i++;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ int build_mqtt_status_JSON(char* buffer, int size, int idx, int nvalue, float se
|
|||
bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue);
|
||||
int build_aqualink_error_status_JSON(char* buffer, int size, char *msg);
|
||||
int build_mqtt_status_message_JSON(char* buffer, int size, int idx, int nvalue, char *svalue);
|
||||
int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char* buffer, int size, bool homekit);
|
||||
//int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch, char* buffer, int size, bool homekit);
|
||||
int build_device_JSON(struct aqualinkdata *aqdata, int programable_switch1, int programable_switch2, char* buffer, int size, bool homekit);
|
||||
|
||||
|
||||
#endif /* JSON_MESSAGES_H_ */
|
||||
|
|
|
|||
|
|
@ -604,17 +604,22 @@ int getTempforMeteohub(char *buffer)
|
|||
return strlen(buffer);
|
||||
}
|
||||
|
||||
void set_light_mode(char *value)
|
||||
void set_light_mode(char *value, int button)
|
||||
{
|
||||
if (_aqualink_config->pda_mode == true) {
|
||||
logMessage(LOG_ERR, "Light mode control not supported in PDA mode\n");
|
||||
return;
|
||||
}
|
||||
if (_aqualink_config->light_programming_button_pool != button &&
|
||||
_aqualink_config->light_programming_button_spa != button) {
|
||||
logMessage(LOG_ERR, "Light mode control not configured for button %d\n",button);
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[LIGHT_MODE_BUFER];
|
||||
// 5 below is light index, need to look this up so it's not hard coded.
|
||||
sprintf(buf, "%-5s%-5d%-5d%-5d%.2f",value,
|
||||
_aqualink_config->light_programming_button,
|
||||
button,
|
||||
_aqualink_config->light_programming_initial_on,
|
||||
_aqualink_config->light_programming_initial_off,
|
||||
_aqualink_config->light_programming_mode );
|
||||
|
|
@ -659,7 +664,14 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
char value[20];
|
||||
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
|
||||
//aq_programmer(AQ_SET_COLORMODE, value, _aqualink_data);
|
||||
set_light_mode(value);
|
||||
set_light_mode(value, _aqualink_config->light_programming_button_pool);
|
||||
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
|
||||
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
|
||||
} else if (strcmp(command, "spalightmode") == 0) {
|
||||
char value[20];
|
||||
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
|
||||
//aq_programmer(AQ_SET_COLORMODE, value, _aqualink_data);
|
||||
set_light_mode(value, _aqualink_config->light_programming_button_spa);
|
||||
mg_send_head(nc, 200, strlen(GET_RTN_OK), "Content-Type: text/plain");
|
||||
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
|
||||
} else if (strcmp(command, "diag") == 0) {
|
||||
|
|
@ -696,12 +708,12 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
mg_send(nc, GET_RTN_OK, strlen(GET_RTN_OK));
|
||||
} else if (strcmp(command, "devices") == 0) {
|
||||
char message[JSON_LABEL_SIZE*10];
|
||||
int size = build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button, message, JSON_LABEL_SIZE*10, false);
|
||||
int size = build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button_pool, _aqualink_config->light_programming_button_spa, message, JSON_LABEL_SIZE*10, false);
|
||||
mg_send_head(nc, 200, size, "Content-Type: application/json");
|
||||
mg_send(nc, message, size);
|
||||
} else if (strcmp(command, "homebridge") == 0) {
|
||||
char message[JSON_LABEL_SIZE*10];
|
||||
int size = build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button, message, JSON_LABEL_SIZE*10, true);
|
||||
int size = build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button_pool, _aqualink_config->light_programming_button_spa, message, JSON_LABEL_SIZE*10, true);
|
||||
mg_send_head(nc, 200, size, "Content-Type: application/json");
|
||||
mg_send(nc, message, size);
|
||||
} else if (strcmp(command, "setconfigprm") == 0) {
|
||||
|
|
@ -839,7 +851,7 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
|
|||
ws_send(nc, labels);
|
||||
} else if (strcmp(request.first.value, "GET_DEVICES") == 0) {
|
||||
char message[JSON_LABEL_SIZE*10];
|
||||
build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button, message, JSON_LABEL_SIZE*10, false);
|
||||
build_device_JSON(_aqualink_data, _aqualink_config->light_programming_button_pool, _aqualink_config->light_programming_button_spa, message, JSON_LABEL_SIZE*10, false);
|
||||
ws_send(nc, message);
|
||||
} else if ( strcmp(request.first.value, "simulator") == 0) {
|
||||
_aqualink_data->simulate_panel = true;
|
||||
|
|
@ -884,9 +896,17 @@ void action_websocket_request(struct mg_connection *nc, struct websocket_message
|
|||
aq_programmer(AQ_SET_SWG_PERCENT, request.second.value, _aqualink_data);
|
||||
_aqualink_data->swg_percent = value; // Set the value as if it's already been set, just incase it's 0 as we won't get that message, or will update next time
|
||||
}
|
||||
} else if (strcmp(request.first.value, "POOL_LIGHT_MODE") == 0) {
|
||||
//aq_programmer(AQ_SET_COLORMODE, request.second.value, _aqualink_data);
|
||||
set_light_mode(request.second.value);
|
||||
} else if (strcmp(request.first.value, "POOL_LIGHT_MODE") == 0) {
|
||||
set_light_mode(request.second.value, _aqualink_config->light_programming_button_pool);
|
||||
} else if (strcmp(request.first.value, "LIGHT_MODE") == 0) {
|
||||
int i;
|
||||
for (i = 0; i < TOTAL_BUTTONS; i++) {
|
||||
if (strcmp(request.third.value, _aqualink_data->aqbuttons[i].name) == 0) {
|
||||
set_light_mode(request.second.value, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//set_light_mode(request.second.value, 0);
|
||||
} else {
|
||||
logMessage(LOG_DEBUG, "WS: Unknown parameter %s\n", request.first.value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "packetLogger.h"
|
||||
#include "aq_serial.h"
|
||||
#include "utils.h"
|
||||
|
||||
static FILE *_packetLogFile = NULL;
|
||||
static bool _log2file = false;
|
||||
static bool _includePentair = false;
|
||||
|
||||
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error);
|
||||
|
||||
void startPacketLogger(bool debug_RSProtocol_packets, bool read_pentair_packets) {
|
||||
_log2file = debug_RSProtocol_packets;
|
||||
_includePentair = read_pentair_packets;
|
||||
}
|
||||
|
||||
void stopPacketLogger() {
|
||||
if (_packetLogFile != NULL)
|
||||
fclose(_packetLogFile);
|
||||
}
|
||||
|
||||
|
||||
void writePacketLog(char *buffer) {
|
||||
if (_packetLogFile == NULL)
|
||||
_packetLogFile = fopen(RS485LOGFILE, "a");
|
||||
|
||||
if (_packetLogFile != NULL) {
|
||||
fputs(buffer, _packetLogFile);
|
||||
}
|
||||
}
|
||||
|
||||
void logPacket(unsigned char *packet_buffer, int packet_length) {
|
||||
_logPacket(packet_buffer, packet_length, false);
|
||||
}
|
||||
|
||||
void logPacketError(unsigned char *packet_buffer, int packet_length) {
|
||||
_logPacket(packet_buffer, packet_length, true);
|
||||
}
|
||||
|
||||
void _logPacket(unsigned char *packet_buffer, int packet_length, bool error)
|
||||
{
|
||||
// No point in continuing if loglevel is < debug_serial and not writing to file
|
||||
if ( error == false && getLogLevel() < LOG_DEBUG_SERIAL && _log2file == false)
|
||||
return;
|
||||
|
||||
char buff[1000];
|
||||
int i = 0;
|
||||
int cnt = 0;
|
||||
|
||||
if (_includePentair) {
|
||||
cnt = sprintf(buff, "%s%8.8s Packet | HEX: ",(error?"BAD PACKET ":""),getProtocolType(packet_buffer)==JANDY?"Jandy":"Pentair");
|
||||
} else {
|
||||
cnt = sprintf(buff, "%sTo 0x%02hhx of type %8.8s | HEX: ",(error?"BAD PACKET ":""), packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length));
|
||||
}
|
||||
|
||||
for (i = 0; i < packet_length; i++)
|
||||
cnt += sprintf(buff + cnt, "0x%02hhx|", packet_buffer[i]);
|
||||
|
||||
cnt += sprintf(buff + cnt, "\n");
|
||||
|
||||
if (_log2file)
|
||||
writePacketLog(buff);
|
||||
|
||||
if (error == true)
|
||||
logMessage(LOG_WARNING, "%s", buff);
|
||||
else
|
||||
logMessage(LOG_DEBUG_SERIAL, "%s", buff);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef PACKETLOGGER_H_
|
||||
#define PACKETLOGGER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define RS485LOGFILE "/tmp/RS485.log"
|
||||
|
||||
void startPacketLogger(bool debug_RSProtocol_packets, bool read_pentair_packets);
|
||||
void stopPacketLogger();
|
||||
//void logPacket(unsigned char *packet_buffer, int packet_length, bool checksumerror);
|
||||
void logPacket(unsigned char *packet_buffer, int packet_length);
|
||||
void logPacketError(unsigned char *packet_buffer, int packet_length);
|
||||
|
||||
|
||||
#endif //PACKETLOGGER_H_
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -20,6 +20,9 @@ log_level=DEBUG
|
|||
#log_level=INFO
|
||||
#log_level=NOTICE
|
||||
|
||||
# Display any ERROR or Warning messages in web interface.
|
||||
display_warnings_in_web=false
|
||||
|
||||
# The socket port that the daemon listens to
|
||||
# If you change this from 80, remember to update aqualink.service.avahi
|
||||
socket_port=80
|
||||
|
|
@ -86,7 +89,8 @@ read_pentair_packets = no
|
|||
force_SWG = no
|
||||
|
||||
# Button inxed light probramming button is assigned to. (look at your button labels below)
|
||||
light_programming_button = 0
|
||||
light_programming_button_pool = 0
|
||||
light_programming_button_spa = 0
|
||||
|
||||
# Light probramming mode. 0=safe mode, but slow.
|
||||
# any number greater is seconds to wait between button presses.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -289,7 +289,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
setLoggingPrms(logLevel, false, false);
|
||||
setLoggingPrms(logLevel, false, false, NULL);
|
||||
|
||||
if (_playback_file) {
|
||||
rs_fd = open(argv[1], O_RDONLY | O_NOCTTY | O_NONBLOCK | O_NDELAY);
|
||||
|
|
|
|||
16
utils.c
16
utils.c
|
|
@ -46,12 +46,15 @@ static bool _daemonise = false;
|
|||
static bool _log2file = false;
|
||||
static int _log_level = -1;
|
||||
static char *_log_filename = NULL;
|
||||
|
||||
static char *_loq_display_message = NULL;
|
||||
//static char _log_filename[256];
|
||||
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file)
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages)
|
||||
{
|
||||
_log_level = level;
|
||||
_daemonise = deamonized;
|
||||
_loq_display_message = error_messages;
|
||||
|
||||
if (log_file == NULL || strlen(log_file) <= 0) {
|
||||
_log2file = false;
|
||||
|
|
@ -322,7 +325,12 @@ void logMessage(int msg_level, char *format, ...)
|
|||
|
||||
if ( buffer[len-1] != '\n') {
|
||||
strcat(buffer, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (msg_level <= LOG_WARNING && _loq_display_message != NULL) {
|
||||
snprintf(_loq_display_message, 127, buffer);
|
||||
}
|
||||
|
||||
|
||||
if (_log2file == TRUE && _log_filename != NULL) {
|
||||
char time[TIMESTAMP_LENGTH];
|
||||
|
|
@ -548,6 +556,7 @@ char *prittyString(char *str)
|
|||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
static FILE *_packetLogFile = NULL;
|
||||
|
||||
void writePacketLog(char *buffer) {
|
||||
|
|
@ -560,4 +569,5 @@ void writePacketLog(char *buffer) {
|
|||
}
|
||||
void closePacketLog() {
|
||||
fclose(_packetLogFile);
|
||||
}
|
||||
}
|
||||
*/
|
||||
7
utils.h
7
utils.h
|
|
@ -27,7 +27,8 @@ typedef enum
|
|||
false = FALSE, true = TRUE
|
||||
} bool;
|
||||
*/
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file);
|
||||
//void setLoggingPrms(int level , bool deamonized, char* log_file);
|
||||
void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_messages);
|
||||
int getLogLevel();
|
||||
void daemonise ( char *pidFile, void (*main_function)(void) );
|
||||
//void debugPrint (char *format, ...);
|
||||
|
|
@ -51,8 +52,8 @@ float degCtoF(float degC);
|
|||
char* stristr(const char* haystack, const char* needle);
|
||||
int ascii(char *destination, char *source);
|
||||
char *prittyString(char *str);
|
||||
void writePacketLog(char *buff);
|
||||
void closePacketLog();
|
||||
//void writePacketLog(char *buff);
|
||||
//void closePacketLog();
|
||||
|
||||
//#ifndef _UTILS_C_
|
||||
extern bool _daemon_;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
|
||||
#define AQUALINKD_NAME "Aqualink Daemon"
|
||||
#define AQUALINKD_VERSION "1.3.5a"
|
||||
#define AQUALINKD_VERSION "1.3.5b"
|
||||
|
|
|
|||
|
|
@ -1051,14 +1051,14 @@
|
|||
var mode=false;
|
||||
if (_lightProgramDropdown) {
|
||||
if (pswitch.selectedIndex > 0) {
|
||||
send_light_mode(pswitch.selectedIndex);
|
||||
send_light_mode(pswitch.selectedIndex, id);
|
||||
mode=true;
|
||||
}
|
||||
} else {
|
||||
var radio = document.getElementsByName("light_program");
|
||||
for (x = 0; x < radio.length; x++) {
|
||||
if (radio[x].checked == true) {
|
||||
send_light_mode(radio[x].value);
|
||||
send_light_mode(radio[x].value, id);
|
||||
mode=true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1256,12 +1256,14 @@
|
|||
socket_di.send(JSON.stringify(temperature));
|
||||
}
|
||||
|
||||
function send_light_mode(value) {
|
||||
console.log("Set light mode "+value);
|
||||
function send_light_mode(value, id) {
|
||||
console.log("Set light mode to "+value+" id="+id);
|
||||
var mode = {};
|
||||
mode.parameter = 'POOL_LIGHT_MODE';
|
||||
//mode.parameter = 'POOL_LIGHT_MODE';
|
||||
mode.parameter = 'LIGHT_MODE';
|
||||
mode.value = value;
|
||||
socket_di.send(JSON.stringify(mode));
|
||||
mode.button = id;
|
||||
socket_di.send(JSON.stringify(mode));
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
|
|
|||
|
|
@ -424,12 +424,14 @@
|
|||
break;
|
||||
default: // type is null because it's a selector
|
||||
//name = source.id.substr(9); //remove 'selector_''
|
||||
cmd.parameter = 'POOL_LIGHT_MODE';
|
||||
cmd.parameter = 'LIGHT_MODE';
|
||||
cmd.value = source.value;
|
||||
cmd.button = source.id.substr(9); // remove 'selector_'
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(cmd);
|
||||
//console.log(source);
|
||||
//console.log(cmd);
|
||||
//console.log("*** NOT SENDING COMMAND ***");
|
||||
send_command(cmd);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue