mirror of https://github.com/sfeakes/AqualinkD.git
Version 1.3.6
parent
ed66368ad7
commit
107fff314a
3
Makefile
3
Makefile
|
@ -6,7 +6,8 @@
|
|||
# define the C compiler to use
|
||||
CC = gcc
|
||||
|
||||
LIBS := -lpthread -lm
|
||||
#LIBS := -lpthread -lm
|
||||
LIBS := -l pthread -l m
|
||||
#LIBS := -lpthread -lwebsockets
|
||||
|
||||
# debug of not
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Aqualinkd
|
||||
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.
|
||||
Binaries are supplied for Raspberry Pi, Has bean, and can be compiled for many different SBC's.
|
||||
|
||||
### 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.
|
||||
|
||||
|
@ -64,7 +65,8 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* 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,b,c,d
|
||||
# Update in Release 1.3.5a,b,c,d,e
|
||||
* Can now debug inline from a web ui. (http://aqualinkd.ip.address/debug.html)
|
||||
* Note to Homekit users. Upgrading to 1.3.5c (and above) will add an aditional SWG PPM tile, (look in default room). You'll need to update homebridge-aqualinkd to 0.0.8 (or later) to remove the old PPM tile (or delete you homebridge cache). This is due to a bug in homebridge-aqualinkd < 0.0.7 that didn't delete unused tiles.
|
||||
* Logic for SWG RS486 checksum_errors.
|
||||
* Fixed pentair packet logging, missing last byte.
|
||||
|
@ -72,6 +74,8 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
|
|||
* Can now display warnings and errors in the web UI (as well as log).
|
||||
* Memory issue with PDA.
|
||||
* Better support for "single device mode" on PDA.
|
||||
* Memory leak in web UI with some browsers.
|
||||
* Changes for better portability when compiling on other systems.
|
||||
# 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 and general speed increase.
|
||||
|
|
1
config.c
1
config.c
|
@ -93,7 +93,6 @@ void init_parameters (struct aqconfig * parms)
|
|||
generate_mqtt_id(parms->mqtt_ID, MQTT_ID_LEN);
|
||||
}
|
||||
|
||||
|
||||
char *cleanalloc(char*str)
|
||||
{
|
||||
char *result;
|
||||
|
|
|
@ -740,6 +740,39 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
mg_send_head(nc, 200, strlen(GET_RTN_ERROR), "Content-Type: text/plain");
|
||||
mg_send(nc, GET_RTN_ERROR, strlen(GET_RTN_ERROR));
|
||||
}
|
||||
} else if (strcmp(command, "debug") == 0) {
|
||||
char value[80];
|
||||
char *rtn;
|
||||
mg_get_http_var(&http_msg->query_string, "value", value, sizeof(value));
|
||||
if (strcmp(value, "start") == 0) {
|
||||
startInlineDebug();
|
||||
rtn = GET_RTN_OK;
|
||||
logMessage(LOG_DEBUG, "WEB: Started inline debug mode\n");
|
||||
} else if (strcmp(value, "stop") == 0) {
|
||||
logMessage(LOG_DEBUG, "WEB: Stoped inline debug mode\n");
|
||||
stopInlineDebug();
|
||||
rtn = GET_RTN_OK;
|
||||
} else if (strcmp(value, "serialstart") == 0) {
|
||||
rtn = GET_RTN_OK;
|
||||
} else if (strcmp(value, "serialstop") == 0) {
|
||||
rtn = GET_RTN_OK;
|
||||
} else if (strcmp(value, "status") == 0) {
|
||||
snprintf(value,80,"{\"sLevel\":\"%s\", \"iLevel\":%d, \"logReady\":\"%s\"}\n",elevel2text(getLogLevel()),getLogLevel(),islogFileReady()?"true":"false" );
|
||||
mg_send_head(nc, 200, strlen(value), "Content-Type: text/json");
|
||||
mg_send(nc, value, strlen(value));
|
||||
return;
|
||||
//rtn = value;
|
||||
} else if (strcmp(value, "clean") == 0) {
|
||||
cleanInlineDebug();
|
||||
rtn = GET_RTN_OK;
|
||||
} else if (strcmp(value, "download") == 0) {
|
||||
mg_http_serve_file(nc, http_msg, getInlineLogFName(), mg_mk_str("text/plain"), mg_mk_str(""));
|
||||
return;
|
||||
} else {
|
||||
rtn = GET_RTN_UNKNOWN;
|
||||
}
|
||||
mg_send_head(nc, 200, strlen(rtn), "Content-Type: text/plain");
|
||||
mg_send(nc, rtn, strlen(rtn));
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < TOTAL_BUTTONS; i++) {
|
||||
|
@ -798,8 +831,8 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
}
|
||||
}
|
||||
// If we get here, got a bad query
|
||||
mg_send_head(nc, 200, sizeof(GET_RTN_UNKNOWN), "Content-Type: text/plain");
|
||||
mg_send(nc, GET_RTN_UNKNOWN, sizeof(GET_RTN_UNKNOWN));
|
||||
mg_send_head(nc, 200, strlen(GET_RTN_UNKNOWN), "Content-Type: text/plain");
|
||||
mg_send(nc, GET_RTN_UNKNOWN, strlen(GET_RTN_UNKNOWN));
|
||||
|
||||
} else {
|
||||
struct mg_serve_http_opts opts;
|
||||
|
|
Binary file not shown.
Binary file not shown.
45
utils.c
45
utils.c
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
#define DEFAULT_LOG_FILE "/tmp/aqualinkd-inline.log"
|
||||
//#define MAXCFGLINE 265
|
||||
#define TIMESTAMP_LENGTH 30
|
||||
|
||||
|
@ -47,6 +49,8 @@ static bool _daemonise = false;
|
|||
static bool _log2file = false;
|
||||
static int _log_level = LOG_ERR;
|
||||
static char *_log_filename = NULL;
|
||||
static bool _cfg_log2file;
|
||||
static int _cfg_log_level;
|
||||
|
||||
static char *_loq_display_message = NULL;
|
||||
//static char _log_filename[256];
|
||||
|
@ -56,6 +60,9 @@ void setLoggingPrms(int level , bool deamonized, char* log_file, char *error_mes
|
|||
_log_level = level;
|
||||
_daemonise = deamonized;
|
||||
_loq_display_message = error_messages;
|
||||
|
||||
_cfg_log_level = _log_level;
|
||||
_cfg_log2file = _log2file;
|
||||
|
||||
if (log_file == NULL || strlen(log_file) <= 0) {
|
||||
_log2file = false;
|
||||
|
@ -72,6 +79,44 @@ int getLogLevel()
|
|||
}
|
||||
|
||||
|
||||
void startInlineDebug()
|
||||
{
|
||||
_log_level = LOG_DEBUG;
|
||||
_log2file = true;
|
||||
if (_log_filename == NULL)
|
||||
_log_filename = DEFAULT_LOG_FILE;
|
||||
}
|
||||
|
||||
void stopInlineDebug()
|
||||
{
|
||||
_log_level = _cfg_log_level;
|
||||
_log2file = _cfg_log2file;
|
||||
}
|
||||
|
||||
char *getInlineLogFName()
|
||||
{
|
||||
return _log_filename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool islogFileReady()
|
||||
{
|
||||
if (_log_filename != NULL) {
|
||||
struct stat st;
|
||||
stat(_log_filename, &st);
|
||||
if ( st.st_size > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cleanInlineDebug() {
|
||||
if (_log_filename != NULL) {
|
||||
fclose(fopen(_log_filename, "w"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reports the error and
|
||||
* exits back to the shell:
|
||||
|
|
5
utils.h
5
utils.h
|
@ -54,6 +54,11 @@ int ascii(char *destination, char *source);
|
|||
char *prittyString(char *str);
|
||||
//void writePacketLog(char *buff);
|
||||
//void closePacketLog();
|
||||
void startInlineDebug();
|
||||
void stopInlineDebug();
|
||||
void cleanInlineDebug();
|
||||
char *getInlineLogFName();
|
||||
bool islogFileReady();
|
||||
|
||||
//#ifndef _UTILS_C_
|
||||
extern bool _daemon_;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
|
||||
#define AQUALINKD_NAME "Aqualink Daemon"
|
||||
#define AQUALINKD_VERSION "1.3.5d"
|
||||
#define AQUALINKD_VERSION "1.3.6"
|
||||
|
|
|
@ -461,6 +461,7 @@
|
|||
</style>
|
||||
|
||||
<script type='text/javascript'>
|
||||
//'use strict';
|
||||
var _lightProgramDropdown = false;
|
||||
var _pressEvent;
|
||||
var _ignoreMouseEvent = false;
|
||||
|
@ -498,13 +499,15 @@
|
|||
var tbody = document.getElementById('pswitch_table').getElementsByTagName('tbody')[0];
|
||||
var html1 = '';
|
||||
var html2 = '';
|
||||
fLen = light_program.length;
|
||||
var fLen = light_program.length;
|
||||
var i;
|
||||
for (i = 0; i < fLen; i++) {
|
||||
if (light_program[i].endsWith(" - Show"))
|
||||
html2 = html2 + "<div class='option_radiocontainer'><label><span class='radio'><input type='radio' name='light_program' value='" + (i+1) + "' onchange='updatePwsitchOptions(this);'><span class='option_radio-value' aria-hidden='true'></span></span>" + light_program[i].substr(0, (light_program[i].length - 7)) + "</label></div>";
|
||||
else
|
||||
html1 = html1 + "<div class='option_radiocontainer'><label><span class='radio'><input type='radio' name='light_program' value='" + (i+1) + "' onchange='updatePwsitchOptions(this);'><span class='option_radio-value' aria-hidden='true'></span></span>" + light_program[i] + "</label></div>";
|
||||
}
|
||||
var row;
|
||||
row = tbody.deleteRow(2);
|
||||
row = tbody.insertRow(2);
|
||||
row.innerHTML = "<td align='center'>Solid Color</td><td align='center'>Light Show</td>";
|
||||
|
@ -658,17 +661,17 @@
|
|||
}
|
||||
|
||||
function add_tile(id, name, status, type, subtype, off_imgurl, on_imgurl) {
|
||||
height = getComputedStyle(document.documentElement).getPropertyValue('--tile_icon-height');
|
||||
div = document.createElement('div');
|
||||
var height = getComputedStyle(document.documentElement).getPropertyValue('--tile_icon-height');
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('class', 'tile');
|
||||
div.setAttribute('id', id);
|
||||
div.setAttribute('type', subtype);
|
||||
//div.setAttribute('onclick', "switchTileState('" + id + "')");
|
||||
subdiv = document.createElement('div');
|
||||
var subdiv = document.createElement('div');
|
||||
subdiv.setAttribute('class', 'tile_icon');
|
||||
subdiv.setAttribute('id', id + '_icon');
|
||||
if (off_imgurl != null) {
|
||||
imgdiv = document.createElement('img');
|
||||
var imgdiv = document.createElement('img');
|
||||
imgdiv.setAttribute('height', height + 'px');
|
||||
imgdiv.setAttribute('src', off_imgurl);
|
||||
subdiv.appendChild(imgdiv);
|
||||
|
@ -685,7 +688,7 @@
|
|||
div.appendChild(subdiv);
|
||||
}
|
||||
} else if (type == "value" || type == "thermostat") {
|
||||
valdiv = document.createElement('div');
|
||||
var valdiv = document.createElement('div');
|
||||
valdiv.setAttribute('class', 'tile_icon_value disabled');
|
||||
valdiv.setAttribute('id', id + '_tile_icon_value');
|
||||
valdiv.textContent = '--';
|
||||
|
@ -741,6 +744,7 @@
|
|||
}
|
||||
|
||||
function setThermostatSetpoint(id, sp_value) {
|
||||
var tile;
|
||||
if ((tile = document.getElementById(id)) == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -765,6 +769,7 @@
|
|||
}
|
||||
}
|
||||
//document.getElementById(id + '_tile_icon_value').textContent = value;
|
||||
var tile;
|
||||
if ((tile = document.getElementById(id + '_tile_icon_value')) != null)
|
||||
tile.innerHTML = value + ext;
|
||||
}
|
||||
|
@ -781,12 +786,14 @@
|
|||
|
||||
function setThermostatTile(id, value, sp_value) {
|
||||
setTileValue(id, value);
|
||||
var tile;
|
||||
if ((tile = document.getElementById(id)) != null) {
|
||||
tile.setAttribute('setpoint', sp_value);
|
||||
}
|
||||
}
|
||||
|
||||
function formatSatus(status) {
|
||||
var index;
|
||||
if ((index = status.indexOf("AUX")) >= 0) {
|
||||
aux = status.substr(index, 4);
|
||||
status = status.charAt(0).toUpperCase() + status.substr(1).toLowerCase();
|
||||
|
@ -824,11 +831,14 @@
|
|||
tile.classList.remove("flash");
|
||||
text = "On";
|
||||
}
|
||||
var offimg;
|
||||
var onimg;
|
||||
if ((offimg = document.getElementById(id + '_icon')) != null &&
|
||||
(onimg = document.getElementById(id + '_icon_on')) != null) {
|
||||
offimg.style.display = 'none';
|
||||
onimg.style.display = 'table';
|
||||
}
|
||||
var type;
|
||||
if ((type = tile.getAttribute('type')) != null) {
|
||||
if (type == 'setpoint_swg')
|
||||
text = 'Generating';
|
||||
|
@ -851,7 +861,7 @@
|
|||
text = "Off";
|
||||
}
|
||||
document.getElementById(id + '_status').innerHTML = text;
|
||||
tile_icon = document.getElementById(id + '_tile_icon_value');
|
||||
var tile_icon = document.getElementById(id + '_tile_icon_value');
|
||||
type = tile.getAttribute('type');
|
||||
if (status != null && tile_icon != null) {
|
||||
if (status == 'enabled' || status == 'flash') {
|
||||
|
@ -922,7 +932,7 @@
|
|||
document.getElementById('pswitch_options').style.display = 'none';
|
||||
}
|
||||
active_option.style.display = 'flex';
|
||||
optionH = window.getComputedStyle(active_option, null).getPropertyValue("height");
|
||||
var optionH = window.getComputedStyle(active_option, null).getPropertyValue("height");
|
||||
if (optionH <= wrapH)
|
||||
active_option.style.height = wrapH;
|
||||
|
||||
|
@ -946,9 +956,9 @@
|
|||
}
|
||||
if (show == true) {
|
||||
var tile = document.getElementById(id);
|
||||
sp_value = tile.getAttribute('setpoint');
|
||||
var sp_value = tile.getAttribute('setpoint');
|
||||
//tile_state = tile.classList.contains("on");
|
||||
tile_state = !(tile.getAttribute('status') == 'off');
|
||||
var tile_state = !(tile.getAttribute('status') == 'off');
|
||||
var type = tile.getAttribute('type');
|
||||
var slider;
|
||||
var slider_output;
|
||||
|
@ -1046,7 +1056,7 @@
|
|||
document.getElementById("body_wrap").addEventListener("click", clickHandler);
|
||||
close_button.onclick = function() {
|
||||
document.getElementById("body_wrap").removeEventListener("click", clickHandler);
|
||||
state = oswitch.checked;
|
||||
var state = oswitch.checked;
|
||||
if (type == 'switch_program') {
|
||||
var mode=false;
|
||||
if (_lightProgramDropdown) {
|
||||
|
@ -1056,6 +1066,7 @@
|
|||
}
|
||||
} else {
|
||||
var radio = document.getElementsByName("light_program");
|
||||
var x;
|
||||
for (x = 0; x < radio.length; x++) {
|
||||
if (radio[x].checked == true) {
|
||||
send_light_mode(radio[x].value, id);
|
||||
|
@ -1069,7 +1080,7 @@
|
|||
setTileState(id, state);
|
||||
}
|
||||
} else {
|
||||
value = slider.value;
|
||||
var value = slider.value;
|
||||
if (state == (tile.getAttribute('status') == 'off'))
|
||||
setTileState(id, state);
|
||||
if (sp_value != slider.value)
|
||||
|
@ -1248,6 +1259,7 @@
|
|||
|
||||
function send_setpoint(id) {
|
||||
var temperature = {};
|
||||
var tile;
|
||||
if ((tile = document.getElementById(id)) == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=windows-1252'>
|
||||
<title>AqualinkD</title>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
<meta name='mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-capable' content='yes'>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
|
||||
<link href='aqualinkd.png' rel='apple-touch-icon'>
|
||||
<link href='aqualinkd.png' rel='icon'>
|
||||
</head>
|
||||
<style>
|
||||
/*
|
||||
******************************************************************************
|
||||
Taken from https://github.com/ubuwaits/css3-buttons */
|
||||
button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button.blue-pill {
|
||||
background-color: #a5b8da;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a5b8da), color-stop(100%, #7089b3));
|
||||
background-image: -webkit-linear-gradient(top, #a5b8da, #7089b3);
|
||||
background-image: -moz-linear-gradient(top, #a5b8da, #7089b3);
|
||||
background-image: -ms-linear-gradient(top, #a5b8da, #7089b3);
|
||||
background-image: -o-linear-gradient(top, #a5b8da, #7089b3);
|
||||
background-image: linear-gradient(top, #a5b8da, #7089b3);
|
||||
border-top: 1px solid #758fba;
|
||||
border-right: 1px solid #6c84ab;
|
||||
border-bottom: 1px solid #5c6f91;
|
||||
border-left: 1px solid #6c84ab;
|
||||
border-radius: 18px;
|
||||
-webkit-box-shadow: inset 0 1px 0 0 #aec3e5;
|
||||
box-shadow: inset 0 1px 0 0 #aec3e5;
|
||||
color: #fff;
|
||||
font: bold 11px/1 "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
|
||||
padding: 8px 0;
|
||||
text-align: center;
|
||||
text-shadow: 0 -1px 1px #64799e;
|
||||
text-transform: uppercase;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
button.blue-pill:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type='text/javascript'>
|
||||
var _poller;
|
||||
|
||||
function action(element) {
|
||||
var query;
|
||||
|
||||
if (element.id == "start") {
|
||||
document.getElementById('messages').innerHTML = "Debug Starting!"
|
||||
} else if (element.id == "stop") {
|
||||
document.getElementById('messages').innerHTML = "Debug Stopping!"
|
||||
} else if (element.id == "clean") {
|
||||
document.getElementById('messages').innerHTML = "Cleaning Debug File!"
|
||||
} else if (element.id == "download") {
|
||||
window.location = location.href + '?command=debug&value=download';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open('GET', location.href + '?command=debug&value='+element.id);
|
||||
http.send(null);
|
||||
|
||||
setTimeout(function () {
|
||||
forceupdate();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function forceupdate() {
|
||||
clearTimeout(_poller);
|
||||
update();
|
||||
}
|
||||
|
||||
function update() {
|
||||
var http = new XMLHttpRequest();
|
||||
if (http) {
|
||||
http.onreadystatechange = function () {
|
||||
if (http.readyState === 4) {
|
||||
if (http.status == 200 && http.status < 300) {
|
||||
var data = JSON.parse(http.responseText);
|
||||
//console.log(data.iLevel + " : " + data.sLevel);
|
||||
if ( data.iLevel >= 7 ) {
|
||||
document.getElementById('start').disabled = true;
|
||||
document.getElementById('stop').disabled = false;
|
||||
document.getElementById('messages').innerHTML = "Debug Running!"
|
||||
} else if ( data.iLevel < 7 ) {
|
||||
document.getElementById('start').disabled = false;
|
||||
document.getElementById('stop').disabled = true;
|
||||
document.getElementById('messages').innerHTML = " "
|
||||
}
|
||||
if (data.logReady == "true") {
|
||||
document.getElementById('download').disabled = false;
|
||||
if (document.getElementById('stop').disabled == true) {
|
||||
document.getElementById('clean').disabled = false;
|
||||
} else {
|
||||
document.getElementById('clean').disabled = true;
|
||||
}
|
||||
} else {
|
||||
document.getElementById('download').disabled = true;
|
||||
document.getElementById('clean').disabled = true;
|
||||
}
|
||||
}
|
||||
else if (http.status >= 400 || http.status == 0) {
|
||||
document.getElementById('messages').innerHTML = 'Error connecting to AqualinkD';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
http.open('GET', location.href + '?command=debug&value=status');
|
||||
http.send(null);
|
||||
_poller = setTimeout(update, 5000);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<body onload="update();">
|
||||
<table cellpadding="10" border="0" align="center">
|
||||
<tr><td colspan="2" align="center">
|
||||
<div id="messages"> </div>
|
||||
</td></tr>
|
||||
<tr><td align="center">
|
||||
<button class="blue-pill" id="start" type="button" onclick='action(this);'>Start Debug</button>
|
||||
</td><td align="center">
|
||||
<button class="blue-pill" id="stop" type="button" onclick='action(this);'>Stop Debug</button>
|
||||
</td></tr>
|
||||
<tr><td colspan="2" align="center">
|
||||
<button class="blue-pill" id="download" type="button" onclick='action(this);'>Download Debug File</button>
|
||||
</td></tr>
|
||||
<tr><td colspan="2" align="center">
|
||||
<button class="blue-pill" id="clean" type="button" onclick='action(this);'>Clean Debug File</button>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue