Browse Source

RPN rules web interface, MQTT inputs

rules-rpn
Xose Pérez 5 years ago
parent
commit
6e8c0780ff
26 changed files with 24342 additions and 23700 deletions
  1. +5
    -1
      code/espurna/config/general.h
  2. +7
    -0
      code/espurna/config/hardware.h
  3. BIN
      code/espurna/data/index.all.html.gz
  4. BIN
      code/espurna/data/index.light.html.gz
  5. BIN
      code/espurna/data/index.lightfox.html.gz
  6. BIN
      code/espurna/data/index.rfbridge.html.gz
  7. BIN
      code/espurna/data/index.rfm69.html.gz
  8. BIN
      code/espurna/data/index.sensor.html.gz
  9. BIN
      code/espurna/data/index.small.html.gz
  10. BIN
      code/espurna/data/index.thermostat.html.gz
  11. +3
    -0
      code/espurna/espurna.ino
  12. +204
    -15
      code/espurna/rpnrules.ino
  13. +10
    -1
      code/espurna/sensor.ino
  14. +3261
    -3227
      code/espurna/static/index.all.html.gz.h
  15. +3090
    -3056
      code/espurna/static/index.light.html.gz.h
  16. +2642
    -2606
      code/espurna/static/index.lightfox.html.gz.h
  17. +2701
    -2667
      code/espurna/static/index.rfbridge.html.gz.h
  18. +4167
    -4135
      code/espurna/static/index.rfm69.html.gz.h
  19. +2754
    -2719
      code/espurna/static/index.sensor.html.gz.h
  20. +2642
    -2606
      code/espurna/static/index.small.html.gz.h
  21. +2690
    -2655
      code/espurna/static/index.thermostat.html.gz.h
  22. +3
    -1
      code/espurna/ws.ino
  23. +3
    -1
      code/html/custom.css
  24. +82
    -7
      code/html/custom.js
  25. +77
    -2
      code/html/index.html
  26. +1
    -1
      code/platformio.ini

+ 5
- 1
code/espurna/config/general.h View File

@ -531,7 +531,7 @@
// there are no special requirements. Any static web server will do (NGinx, Apache, Lighttpd,...). // there are no special requirements. Any static web server will do (NGinx, Apache, Lighttpd,...).
// The only requirement is that the resource must be available under this domain. // The only requirement is that the resource must be available under this domain.
#ifndef WEB_REMOTE_DOMAIN #ifndef WEB_REMOTE_DOMAIN
#define WEB_REMOTE_DOMAIN "http://espurna.io"
#define WEB_REMOTE_DOMAIN "*"
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -916,6 +916,10 @@
#define BROKER_SUPPORT 1 // The broker is a poor-man's pubsub manager #define BROKER_SUPPORT 1 // The broker is a poor-man's pubsub manager
#endif #endif
#ifndef BROKER_REAL_TIME
#define BROKER_REAL_TIME 1 // Report real time data
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// SETTINGS // SETTINGS
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 7
- 0
code/espurna/config/hardware.h View File

@ -139,6 +139,13 @@
#define MANUFACTURER "WEMOS" #define MANUFACTURER "WEMOS"
#define DEVICE "D1_TARPUNA_SHIELD" #define DEVICE "D1_TARPUNA_SHIELD"
// Relays
#define RELAY1_PIN 5
#define RELAY1_TYPE RELAY_TYPE_NORMAL
#define DHT_SUPPORT 1
#define DHT_PIN 12
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ESPurna // ESPurna
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


BIN
code/espurna/data/index.all.html.gz View File


BIN
code/espurna/data/index.light.html.gz View File


BIN
code/espurna/data/index.lightfox.html.gz View File


BIN
code/espurna/data/index.rfbridge.html.gz View File


BIN
code/espurna/data/index.rfm69.html.gz View File


BIN
code/espurna/data/index.sensor.html.gz View File


BIN
code/espurna/data/index.small.html.gz View File


BIN
code/espurna/data/index.thermostat.html.gz View File


+ 3
- 0
code/espurna/espurna.ino View File

@ -195,6 +195,9 @@ void setup() {
#if SCHEDULER_SUPPORT #if SCHEDULER_SUPPORT
schSetup(); schSetup();
#endif #endif
#if RPN_RULES_SUPPORT
rpnSetup();
#endif
#if UART_MQTT_SUPPORT #if UART_MQTT_SUPPORT
uartmqttSetup(); uartmqttSetup();
#endif #endif


+ 204
- 15
code/espurna/rpnrules.ino View File

@ -1,15 +1,14 @@
/* /*
NTP MODULE
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
RPN RULES MODULE
Use RPNLib library (https://github.com/xoseperez/rpnlib)
Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
*/ */
#if RPN_RULES_SUPPORT #if RPN_RULES_SUPPORT
#include "rpnlib.h" #include "rpnlib.h"
#include <Ticker.h>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Custom commands // Custom commands
@ -17,6 +16,9 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
rpn_context _rpn_ctxt; rpn_context _rpn_ctxt;
bool _rpn_run = false; bool _rpn_run = false;
bool _rpn_inject = true;
unsigned long _rpn_delay = RPN_BUFFER_DELAY;
float _rpn_value = 0;
unsigned long _rpn_last = 0; unsigned long _rpn_last = 0;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -28,17 +30,78 @@ bool _rpnWebSocketOnReceive(const char * key, JsonVariant& value) {
void _rpnWebSocketOnSend(JsonObject& root) { void _rpnWebSocketOnSend(JsonObject& root) {
root["rpnVisible"] = 1; root["rpnVisible"] = 1;
root["rpnSticky"] = getSetting("rpnSticky", 1).toInt();
root["rpnDelay"] = getSetting("rpnDelay", RPN_BUFFER_DELAY).toInt();
JsonArray& rules = root.createNestedArray("rpnRules"); JsonArray& rules = root.createNestedArray("rpnRules");
JsonArray& topics = root.createNestedArray("rpnTopics");
JsonArray& names = root.createNestedArray("rpnNames");
unsigned char i = 0; unsigned char i = 0;
while (String rule = getSetting("rule", i, NULL)) {
String rule = getSetting("rpnRule", i, "");
while (rule.length()) {
rules.add(rule); rules.add(rule);
rule = getSetting("rpnRule", ++i, "");
} }
#if MQTT_SUPPORT
i=0;
String rpn_topic = getSetting("rpnTopic", i, "");
String rpn_name = getSetting("rpnName", i, "");
while (rpn_topic.length() > 0) {
topics.add(rpn_topic);
names.add(rpn_name);
rpn_topic = getSetting("rpnTopic", ++i, "");
rpn_name = getSetting("rpnName", i, "");
}
#endif
} }
void _rpnConfigure() {
#if MQTT_SUPPORT
void _rpnMQTTSubscribe() {
unsigned char i = 0;
String rpn_topic = getSetting("rpnTopic", i, "");
while (rpn_topic.length()) {
mqttSubscribeRaw(rpn_topic.c_str());
rpn_topic = getSetting("rpnTopic", ++i, "");
}
}
void _rpnMQTTCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) {
_rpnMQTTSubscribe();
}
if (type == MQTT_MESSAGE_EVENT) {
unsigned char i = 0;
String rpn_topic = getSetting("rpnTopic", i, "");
while (rpn_topic.length()) {
if (rpn_topic.equals(topic)) {
String rpn_name = getSetting("rpnName", i, "");
if (rpn_name.length()) {
rpn_variable_set(_rpn_ctxt, rpn_name.c_str(), atof(payload));
} else {
_rpn_value = atof(payload);
_rpn_inject = true;
}
_rpn_last = millis();
_rpn_run = true;
break;
}
rpn_topic = getSetting("rpnTopic", ++i, "");
}
}
}
#endif // MQTT_SUPPORT
void _rpnConfigure() {
#if MQTT_SUPPORT
if (mqttConnected()) _rpnMQTTSubscribe();
#endif
_rpn_delay = getSetting("rpnDelay", RPN_BUFFER_DELAY).toInt();
} }
void _rpnBrokerCallback(const unsigned char type, const char * topic, unsigned char id, const char * payload) { void _rpnBrokerCallback(const unsigned char type, const char * topic, unsigned char id, const char * payload) {
@ -47,13 +110,13 @@ void _rpnBrokerCallback(const unsigned char type, const char * topic, unsigned c
if (BROKER_MSG_TYPE_STATUS == type || BROKER_MSG_TYPE_SENSOR == type) { if (BROKER_MSG_TYPE_STATUS == type || BROKER_MSG_TYPE_SENSOR == type) {
snprintf(name, sizeof(name), "%s%d", topic, id); snprintf(name, sizeof(name), "%s%d", topic, id);
rpn_variable_set(_rpn_ctxt, name, atof(payload));
} else if (BROKER_MSG_TYPE_DATETIME == type) { } else if (BROKER_MSG_TYPE_DATETIME == type) {
strncpy(name, topic, sizeof(name));
// Timestamp is always available via de "now" operator
} else { } else {
return; return;
} }
rpn_variable_set(_rpn_ctxt, name, atof(payload));
_rpn_last = millis(); _rpn_last = millis();
_rpn_run = true; _rpn_run = true;
@ -64,30 +127,150 @@ void _rpnInit() {
// Init context // Init context
rpn_init(_rpn_ctxt); rpn_init(_rpn_ctxt);
// Add relay operator
char name[10] = {0};
// Time functions
rpn_operator_set(_rpn_ctxt, "now", 0, [](rpn_context & ctxt) {
rpn_stack_push(ctxt, now());
return true;
});
rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
float a;
rpn_stack_pop(ctxt, a);
unsigned char dow = (weekday(int(a)) + 5) % 7;
rpn_stack_push(ctxt, dow);
return true;
});
rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
float a;
rpn_stack_pop(ctxt, a);
rpn_stack_push(ctxt, hour(int(a)));
return true;
});
rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
float a;
rpn_stack_pop(ctxt, a);
rpn_stack_push(ctxt, minute(int(a)));
return true;
});
// Debug
rpn_operator_set(_rpn_ctxt, "debug", 0, [](rpn_context & ctxt) {
_rpnDump();
return true;
});
// Relay operators
rpn_operator_set(_rpn_ctxt, "relay", 2, [](rpn_context & ctxt) { rpn_operator_set(_rpn_ctxt, "relay", 2, [](rpn_context & ctxt) {
float a, b; float a, b;
rpn_stack_pop(ctxt, b); // new status
rpn_stack_pop(ctxt, a); // relay number
relayStatus(int(a), int(b));
rpn_stack_pop(ctxt, b); // relay number
rpn_stack_pop(ctxt, a); // new status
if (int(a) == 2) {
relayToggle(int(b));
} else {
relayStatus(int(b), int(a) == 1);
}
return true; return true;
}); });
// Channel operators
#if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
rpn_operator_set(_rpn_ctxt, "update", 0, [](rpn_context & ctxt) {
lightUpdate(true, true);
return true;
});
rpn_operator_set(_rpn_ctxt, "black", 0, [](rpn_context & ctxt) {
lightColor(0);
return true;
});
rpn_operator_set(_rpn_ctxt, "channel", 2, [](rpn_context & ctxt) {
float a, b;
rpn_stack_pop(ctxt, b); // channel number
rpn_stack_pop(ctxt, a); // new value
lightChannel(int(b), int(a));
return true;
});
#endif
}
#if TERMINAL_SUPPORT
void _rpnInitCommands() {
terminalRegisterCommand(F("RPN.VARS"), [](Embedis* e) {
unsigned char num = rpn_variables_size(_rpn_ctxt);
if (0 == num) {
DEBUG_MSG_P(PSTR("[RPN] No variables\n"));
} else {
DEBUG_MSG_P(PSTR("[RPN] Variables:\n"));
for (unsigned char i=0; i<num; i++) {
char * name = rpn_variable_name(_rpn_ctxt, i);
float value;
rpn_variable_get(_rpn_ctxt, name, value);
DEBUG_MSG_P(PSTR(" %s: %s\n"), name, String(value).c_str());
}
}
terminalOK();
});
terminalRegisterCommand(F("RPN.TEST"), [](Embedis* e) {
if (e->argc == 2) {
DEBUG_MSG_P(PSTR("[RPN] Running \"%s\"\n"), e->argv[1]);
rpn_process(_rpn_ctxt, e->argv[1], true);
_rpnDump();
rpn_stack_clear(_rpn_ctxt);
terminalOK();
} else {
terminalError(F("Wrong arguments"));
}
});
}
#endif
void _rpnDump() {
float value;
DEBUG_MSG_P(PSTR("[RPN] Stack:\n"));
unsigned char num = rpn_stack_size(_rpn_ctxt);
if (0 == num) {
DEBUG_MSG_P(PSTR(" (empty)\n"));
} else {
unsigned char index = num - 1;
while (rpn_stack_get(_rpn_ctxt, index, value)) {
DEBUG_MSG_P(PSTR(" %02d: %s\n"), index--, String(value).c_str());
}
}
} }
void _rpnRun() { void _rpnRun() {
unsigned char i = 0; unsigned char i = 0;
while (String rule = getSetting("rule", i, NULL)) {
String rule = getSetting("rpnRule", i, "");
while (rule.length()) {
//DEBUG_MSG_P(PSTR("[RPN] Running \"%s\"\n"), rule.c_str());
if (_rpn_inject) rpn_stack_push(_rpn_ctxt, _rpn_value);
rpn_process(_rpn_ctxt, rule.c_str(), true);
//_rpnDump();
rule = getSetting("rpnRule", ++i, "");
rpn_stack_clear(_rpn_ctxt); rpn_stack_clear(_rpn_ctxt);
rpn_process(_rpn_ctxt, rule.c_str());
} }
if (getSetting("rpnSticky", 1).toInt() == 0) {
rpn_variables_clear(_rpn_ctxt);
}
_rpn_inject = false;
} }
void _rpnLoop() { void _rpnLoop() {
if (_rpn_run && (millis() - _rpn_last > RPN_BUFFER_DELAY)) {
if (_rpn_run && (millis() - _rpn_last > _rpn_delay)) {
_rpnRun(); _rpnRun();
_rpn_run = false; _rpn_run = false;
} }
@ -101,6 +284,7 @@ void rpnSetup() {
// Load & cache settings // Load & cache settings
_rpnConfigure(); _rpnConfigure();
_rpnInitCommands();
// Websockets // Websockets
#if WEB_SUPPORT #if WEB_SUPPORT
@ -108,6 +292,11 @@ void rpnSetup() {
wsOnReceiveRegister(_rpnWebSocketOnReceive); wsOnReceiveRegister(_rpnWebSocketOnReceive);
#endif #endif
// MQTT
#if MQTT_SUPPORT
mqttRegister(_rpnMQTTCallback);
#endif
brokerRegister(_rpnBrokerCallback); brokerRegister(_rpnBrokerCallback);
espurnaRegisterReload(_rpnConfigure); espurnaRegisterReload(_rpnConfigure);
espurnaRegisterLoop(_rpnLoop); espurnaRegisterLoop(_rpnLoop);


+ 10
- 1
code/espurna/sensor.ino View File

@ -1267,7 +1267,9 @@ void _sensorReport(unsigned char index, double value) {
dtostrf(value, 1-sizeof(buffer), decimals, buffer); dtostrf(value, 1-sizeof(buffer), decimals, buffer);
#if BROKER_SUPPORT #if BROKER_SUPPORT
brokerPublish(BROKER_MSG_TYPE_SENSOR ,magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer);
#if not BROKER_REAL_TIME
brokerPublish(BROKER_MSG_TYPE_SENSOR ,magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
#endif
#endif #endif
#if MQTT_SUPPORT #if MQTT_SUPPORT
@ -1521,6 +1523,13 @@ void sensorLoop() {
// ------------------------------------------------------------- // -------------------------------------------------------------
value_show = _magnitudeProcess(magnitude.type, magnitude.decimals, value_raw); value_show = _magnitudeProcess(magnitude.type, magnitude.decimals, value_raw);
#if BROKER_REAL_TIME
{
char buffer[64];
dtostrf(value_show, 1-sizeof(buffer), magnitude.decimals, buffer);
brokerPublish(BROKER_MSG_TYPE_SENSOR ,magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
}
#endif
// ------------------------------------------------------------- // -------------------------------------------------------------
// Debug // Debug


+ 3261
- 3227
code/espurna/static/index.all.html.gz.h
File diff suppressed because it is too large
View File


+ 3090
- 3056
code/espurna/static/index.light.html.gz.h
File diff suppressed because it is too large
View File


+ 2642
- 2606
code/espurna/static/index.lightfox.html.gz.h
File diff suppressed because it is too large
View File


+ 2701
- 2667
code/espurna/static/index.rfbridge.html.gz.h
File diff suppressed because it is too large
View File


+ 4167
- 4135
code/espurna/static/index.rfm69.html.gz.h
File diff suppressed because it is too large
View File


+ 2754
- 2719
code/espurna/static/index.sensor.html.gz.h
File diff suppressed because it is too large
View File


+ 2642
- 2606
code/espurna/static/index.small.html.gz.h
File diff suppressed because it is too large
View File


+ 2690
- 2655
code/espurna/static/index.thermostat.html.gz.h
File diff suppressed because it is too large
View File


+ 3
- 1
code/espurna/ws.ino View File

@ -557,7 +557,9 @@ void wsSetup() {
// CORS // CORS
#ifdef WEB_REMOTE_DOMAIN #ifdef WEB_REMOTE_DOMAIN
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", WEB_REMOTE_DOMAIN); DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", WEB_REMOTE_DOMAIN);
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true");
if (strcmp(WEB_REMOTE_DOMAIN, "*")) {
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true");
}
#endif #endif
webServer()->on("/auth", HTTP_GET, _onAuth); webServer()->on("/auth", HTTP_GET, _onAuth);


+ 3
- 1
code/html/custom.css View File

@ -160,7 +160,7 @@ div.state {
.button-rfb-forget, .button-rfb-forget,
.button-lightfox-clear, .button-lightfox-clear,
.button-del-network, .button-del-network,
.button-del-mapping,
.button-del-parent,
.button-del-schedule, .button-del-schedule,
.button-dbg-clear, .button-dbg-clear,
.button-upgrade, .button-upgrade,
@ -175,6 +175,8 @@ div.state {
.button-update-password, .button-update-password,
.button-add-network, .button-add-network,
.button-add-mapping, .button-add-mapping,
.button-add-rpnrule,
.button-add-rpntopic,
.button-upgrade-browse, .button-upgrade-browse,
.button-rfb-learn, .button-rfb-learn,
.button-lightfox-learn, .button-lightfox-learn,


+ 82
- 7
code/html/custom.js View File

@ -251,7 +251,8 @@ function addValue(data, name, value) {
"tspkRelay", "tspkMagnitude", "tspkRelay", "tspkMagnitude",
"ledMode", "ledRelay", "ledMode", "ledRelay",
"adminPass", "adminPass",
"node", "key", "topic"
"node", "key", "topic",
"rpnRule", "rpnTopic", "rpnName"
]; ];
@ -787,6 +788,11 @@ function doClearFilters() {
<!-- endRemoveIf(!rfm69)--> <!-- endRemoveIf(!rfm69)-->
function delParent() {
var parent = $(this).parent().parent();
$(parent).remove();
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Visualization // Visualization
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -842,11 +848,38 @@ function createMagnitudeList(data, container, template_name) {
} }
<!-- endRemoveIf(!sensor)--> <!-- endRemoveIf(!sensor)-->
// -----------------------------------------------------------------------------
// RPN Rules
// -----------------------------------------------------------------------------
function addRPNRule() {
var template = $("#rpnRuleTemplate .pure-g")[0];
var line = $(template).clone();
var tabindex = $("#rpnRules > div").length + 100;
$(line).find("input").each(function() {
$(this).attr("tabindex", tabindex++);
});
$(line).find("button").on('click', delParent);
line.appendTo("#rpnRules");
}
function addRPNTopic() {
var template = $("#rpnTopicTemplate .pure-g")[0];
var line = $(template).clone();
var tabindex = $("#rpnTopics > div").length + 120;
$(line).find("input").each(function() {
$(this).attr("tabindex", tabindex++);
});
$(line).find("button").on('click', delParent);
line.appendTo("#rpnTopics");
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// RFM69 // RFM69
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
<!-- removeIf(!rfm69)--> <!-- removeIf(!rfm69)-->
function addMapping() { function addMapping() {
var template = $("#nodeTemplate .pure-g")[0]; var template = $("#nodeTemplate .pure-g")[0];
var line = $(template).clone(); var line = $(template).clone();
@ -854,14 +887,10 @@ function addMapping() {
$(line).find("input").each(function() { $(line).find("input").each(function() {
$(this).attr("tabindex", tabindex++); $(this).attr("tabindex", tabindex++);
}); });
$(line).find("button").on('click', delMapping);
$(line).find("button").on('click', delParent);
line.appendTo("#mapping"); line.appendTo("#mapping");
} }
function delMapping() {
var parent = $(this).parent().parent();
$(parent).remove();
}
<!-- endRemoveIf(!rfm69)--> <!-- endRemoveIf(!rfm69)-->
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -1407,6 +1436,48 @@ function processData(data) {
<!-- endRemoveIf(!rfm69)--> <!-- endRemoveIf(!rfm69)-->
// ---------------------------------------------------------------------
// RPN Rules
// ---------------------------------------------------------------------
if (key == "rpnRules") {
for (var i in data.rpnRules) {
// add a new row
addRPNRule();
// get group
var line = $("#rpnRules .pure-g")[i];
// fill in the blanks
var rule = data.rpnRules[i];
$("input", line).val(rule).attr("original", rule);
}
return;
}
if (key == "rpnTopics") {
for (var i in data.rpnTopics) {
// add a new row
addRPNTopic();
// get group
var line = $("#rpnTopics .pure-g")[i];
// fill in the blanks
var topic = data.rpnTopics[i];
var name = data.rpnNames[i];
$("input[name='rpnTopic']", line).val(topic).attr("original", topic);
$("input[name='rpnName']", line).val(name).attr("original", name);
}
return;
}
if (key == "rpnNames") return;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Lights // Lights
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -1876,9 +1947,13 @@ $(function() {
$(".button-add-light-schedule").on("click", { schType: 2 }, addSchedule); $(".button-add-light-schedule").on("click", { schType: 2 }, addSchedule);
<!-- endRemoveIf(!light)--> <!-- endRemoveIf(!light)-->
$(".button-add-rpnrule").on('click', addRPNRule);
$(".button-add-rpntopic").on('click', addRPNTopic);
$(".button-del-parent").on('click', delParent);
<!-- removeIf(!rfm69)--> <!-- removeIf(!rfm69)-->
$(".button-add-mapping").on('click', addMapping); $(".button-add-mapping").on('click', addMapping);
$(".button-del-mapping").on('click', delMapping);
$(".button-clear-counts").on('click', doClearCounts); $(".button-clear-counts").on('click', doClearCounts);
$(".button-clear-messages").on('click', doClearMessages); $(".button-clear-messages").on('click', doClearMessages);
$(".button-clear-filters").on('click', doClearFilters); $(".button-clear-filters").on('click', doClearFilters);


+ 77
- 2
code/html/index.html View File

@ -158,6 +158,10 @@
</li> </li>
<!-- endRemoveIf(!rfbridge) --> <!-- endRemoveIf(!rfbridge) -->
<li class="pure-menu-item module module-rpn">
<a href="#" class="pure-menu-link" data="panel-rpn">RULES</a>
</li>
<li class="pure-menu-item module module-sch"> <li class="pure-menu-item module module-sch">
<a href="#" class="pure-menu-link" data="panel-schedule">SCHEDULE</a> <a href="#" class="pure-menu-link" data="panel-schedule">SCHEDULE</a>
</li> </li>
@ -1396,6 +1400,62 @@
</div> </div>
</form> </form>
<form id="form-rpn" class="pure-form form-settings">
<div class="panel" id="panel-rpn">
<div class="header">
<h1>RULES</h1>
<h2>
Here you can configure advanced rules based on RPN sentences.
</h2>
</div>
<div class="page">
<fieldset>
<legend>Configuration</legend>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Sticky variables</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="rpnSticky" tabindex="100" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
Sticky variables are persistent, once defined the first time they will be always available until next reboot (they do not persist across reboots).
Non sticky variables are only available during the next rule execution, just after being defined, and then removed. This applies to status, sensor and MQTT variables equally.
Mind that calling a non-existing variable from a rule will make it silently fail.
</div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4" for="rpnDelay">Execution delay (ms)</label>
<input class="pure-u-1 pure-u-lg-1-4" name="rpnDelay" type="number" min="100" tabindex="101" />
</div>
<legend>Rules</legend>
<div id="rpnRules"></div>
<button type="button" class="pure-button button-add-rpnrule">Add</button>
<legend>MQTT</legend>
<div class="pure-g">
<div class="pure-u-1-2">MQTT Topic</div>
<div class="pure-u-1-3">Variable Name</div>
</div>
<div id="rpnTopics"></div>
<button type="button" class="pure-button button-add-rpntopic">Add</button>
</fieldset>
</div>
</div>
</form>
<form id="form-dbg" class="pure-form"> <form id="form-dbg" class="pure-form">
<div class="panel" id="panel-dbg"> <div class="panel" id="panel-dbg">
@ -1691,7 +1751,7 @@
</div> <!-- layout --> </div> <!-- layout -->
<!-- Templates -->
<!-- Templates ------------------------------------------------------------------------------------------------------------------>
<div id="ledConfigTemplate" class="template"> <div id="ledConfigTemplate" class="template">
<div class="pure-g"> <div class="pure-g">
@ -1985,11 +2045,26 @@
<div class="pure-u-md-1-6 pure-u-1-2"><input name="node" type="text" class="pure-u-11-12" value="" size="8" tabindex="0" placeholder="Node ID" autocomplete="false"></div> <div class="pure-u-md-1-6 pure-u-1-2"><input name="node" type="text" class="pure-u-11-12" value="" size="8" tabindex="0" placeholder="Node ID" autocomplete="false"></div>
<div class="pure-u-md-1-6 pure-u-1-2"><input name="key" type="text" class="pure-u-11-12" value="" size="8" tabindex="0" placeholder="Key"></div> <div class="pure-u-md-1-6 pure-u-1-2"><input name="key" type="text" class="pure-u-11-12" value="" size="8" tabindex="0" placeholder="Key"></div>
<div class="pure-u-md-1-2 pure-u-3-4"><input name="topic" type="text" class="pure-md-11-12 pure-u-23-24" value="" size="8" tabindex="0" placeholder="MQTT Topic"></div> <div class="pure-u-md-1-2 pure-u-3-4"><input name="topic" type="text" class="pure-md-11-12 pure-u-23-24" value="" size="8" tabindex="0" placeholder="MQTT Topic"></div>
<div class="pure-u-md-1-6 pure-u-1-4"><button type="button" class="pure-button button-del-mapping pure-u-5-6 pure-u-md-5-6">Del</button></div>
<div class="pure-u-md-1-6 pure-u-1-4"><button type="button" class="pure-button button-del-parent pure-u-5-6 pure-u-md-5-6">Del</button></div>
</div> </div>
</div> </div>
<!-- endRemoveIf(!rfm69) --> <!-- endRemoveIf(!rfm69) -->
<div id="rpnRuleTemplate" class="template">
<div class="pure-g">
<div class="pure-u-5-6"><input name="rpnRule" type="text" class="pure-u-23-24" value="" tabindex="0" autocomplete="false" /></div>
<div class="pure-u-1-6"><button type="button" class="pure-button button-del-parent pure-u-1">Del</button></div>
</div>
</div>
<div id="rpnTopicTemplate" class="template">
<div class="pure-g">
<div class="pure-u-1-2"><input name="rpnTopic" type="text" class="pure-u-23-24" value="" tabindex="0" autocomplete="false" /></div>
<div class="pure-u-1-3"><input name="rpnName" type="text" class="pure-u-23-24" value="" tabindex="0" autocomplete="false" /></div>
<div class="pure-u-1-6"><button type="button" class="pure-button button-del-parent pure-u-1">Del</button></div>
</div>
</div>
<iframe id="downloader"></iframe> <iframe id="downloader"></iframe>
<input id="uploader" type="file" /> <input id="uploader" type="file" />


+ 1
- 1
code/platformio.ini View File

@ -99,7 +99,7 @@ lib_deps =
PubSubClient PubSubClient
rc-switch rc-switch
https://github.com/LowPowerLab/RFM69#1.1.3 https://github.com/LowPowerLab/RFM69#1.1.3
https://github.com/xoseperez/rpnlib.git#0.0.2
https://github.com/xoseperez/rpnlib.git#0.3.0
https://github.com/xoseperez/Time https://github.com/xoseperez/Time
NewPing NewPing
https://github.com/sparkfun/SparkFun_VEML6075_Arduino_Library#V_1.0.3 https://github.com/sparkfun/SparkFun_VEML6075_Arduino_Library#V_1.0.3


Loading…
Cancel
Save