diff --git a/README.md b/README.md index 0ed0559a..16be500e 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smar It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries. [![version](https://img.shields.io/badge/version-1.13.6--dev-brightgreen.svg)](CHANGELOG.md) -[![branch](https://img.shields.io/badge/branch-dev-orange.svg)](https://github.com/xoseperez/espurna/tree/dev/) +[![branch](https://img.shields.io/badge/branch-rules--rpn-orange.svg)](https://github.com/xoseperez/espurna/tree/rules-rpn/) [![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE) -[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna) +[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=rules-rpn)](https://travis-ci.org/xoseperez/espurna) [![codacy](https://api.codacy.com/project/badge/Grade/c9496e25cf07434cba786b462cb15f49)](https://www.codacy.com/app/xoseperez/espurna/dashboard) [![downloads](https://img.shields.io/github/downloads/xoseperez/espurna/total.svg)](https://github.com/xoseperez/espurna/releases)
diff --git a/code/espurna/config/dependencies.h b/code/espurna/config/dependencies.h index 281a2437..a371ae75 100644 --- a/code/espurna/config/dependencies.h +++ b/code/espurna/config/dependencies.h @@ -38,6 +38,11 @@ #define BROKER_SUPPORT 1 // If Alexa enabled enable BROKER #endif +#if RPN_RULES_SUPPORT +#undef BROKER_SUPPORT +#define BROKER_SUPPORT 1 // If RPN Rules enabled enable BROKER +#endif + #if INFLUXDB_SUPPORT #undef BROKER_SUPPORT #define BROKER_SUPPORT 1 // If InfluxDB enabled enable BROKER diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 48139989..4ef67dd5 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -843,6 +843,7 @@ #define MQTT_TOPIC_VERSION "version" #define MQTT_TOPIC_UPTIME "uptime" #define MQTT_TOPIC_DATETIME "datetime" +#define MQTT_TOPIC_TIMESTAMP "timestamp" #define MQTT_TOPIC_FREEHEAP "freeheap" #define MQTT_TOPIC_VCC "vcc" #define MQTT_TOPIC_STATUS "status" @@ -1167,6 +1168,18 @@ #define SCHEDULER_MAX_SCHEDULES 10 // Max schedules alowed #endif +// ----------------------------------------------------------------------------- +// RPN RULES +// ----------------------------------------------------------------------------- + +#ifndef RPN_RULES_SUPPORT +#define RPN_RULES_SUPPORT 1 // Enable RPN Rules (?Kb) +#endif + +#ifndef RPN_BUFFER_DELAY +#define RPN_BUFFER_DELAY 100 // Execute rules after 100ms without messages +#endif + // ----------------------------------------------------------------------------- // NTP // ----------------------------------------------------------------------------- diff --git a/code/espurna/ntp.ino b/code/espurna/ntp.ino index de9353e0..103ec6b7 100644 --- a/code/espurna/ntp.ino +++ b/code/espurna/ntp.ino @@ -135,6 +135,7 @@ void inline _ntpBroker() { if (ntpSynced() && (minute() != last_minute)) { last_minute = minute(); brokerPublish(BROKER_MSG_TYPE_DATETIME, MQTT_TOPIC_DATETIME, ntpDateTime().c_str()); + brokerPublish(BROKER_MSG_TYPE_DATETIME, MQTT_TOPIC_TIMESTAMP, String(now()).c_str()); } } diff --git a/code/espurna/rpnrules.ino b/code/espurna/rpnrules.ino new file mode 100644 index 00000000..ae2c2b0a --- /dev/null +++ b/code/espurna/rpnrules.ino @@ -0,0 +1,117 @@ +/* + +NTP MODULE + +Copyright (C) 2016-2019 by Xose PĂ©rez + +*/ + +#if RPN_RULES_SUPPORT + +#include "rpnlib.h" +#include + +// ----------------------------------------------------------------------------- +// Custom commands +// ----------------------------------------------------------------------------- + +rpn_context _rpn_ctxt; +bool _rpn_run = false; +unsigned long _rpn_last = 0; + +// ----------------------------------------------------------------------------- + +bool _rpnWebSocketOnReceive(const char * key, JsonVariant& value) { + return (strncmp(key, "rpn", 3) == 0); +} + +void _rpnWebSocketOnSend(JsonObject& root) { + + root["rpnVisible"] = 1; + JsonArray& rules = root.createNestedArray("rpnRules"); + + unsigned char i = 0; + while (String rule = getSetting("rule", i, NULL)) { + rules.add(rule); + } + +} + +void _rpnConfigure() { + +} + +void _rpnBrokerCallback(const unsigned char type, const char * topic, unsigned char id, const char * payload) { + + char name[32] = {0}; + + if (BROKER_MSG_TYPE_STATUS == type || BROKER_MSG_TYPE_SENSOR == type) { + snprintf(name, sizeof(name), "%s%d", topic, id); + } else if (BROKER_MSG_TYPE_DATETIME == type) { + strncpy(name, topic, sizeof(name)); + } else { + return; + } + + rpn_variable_set(_rpn_ctxt, name, atof(payload)); + _rpn_last = millis(); + _rpn_run = true; + +} + +void _rpnInit() { + + // Init context + rpn_init(_rpn_ctxt); + + // Add relay operator + rpn_operator_set(_rpn_ctxt, "relay", 2, [](rpn_context & ctxt) { + float a, b; + rpn_stack_pop(ctxt, b); // new status + rpn_stack_pop(ctxt, a); // relay number + relayStatus(int(a), int(b)); + return true; + }); + +} + +void _rpnRun() { + + unsigned char i = 0; + while (String rule = getSetting("rule", i, NULL)) { + rpn_stack_clear(_rpn_ctxt); + rpn_process(_rpn_ctxt, rule.c_str()); + } + +} + +void _rpnLoop() { + + if (_rpn_run && (millis() - _rpn_last > RPN_BUFFER_DELAY)) { + _rpnRun(); + _rpn_run = false; + } + +} + +void rpnSetup() { + + // Init context + _rpnInit(); + + // Load & cache settings + _rpnConfigure(); + + // Websockets + #if WEB_SUPPORT + wsOnSendRegister(_rpnWebSocketOnSend); + wsOnReceiveRegister(_rpnWebSocketOnReceive); + #endif + + brokerRegister(_rpnBrokerCallback); + espurnaRegisterReload(_rpnConfigure); + espurnaRegisterLoop(_rpnLoop); + +} + +#endif diff --git a/code/platformio.ini b/code/platformio.ini index 983261f5..602daf89 100644 --- a/code/platformio.ini +++ b/code/platformio.ini @@ -99,6 +99,7 @@ lib_deps = PubSubClient rc-switch https://github.com/LowPowerLab/RFM69#1.1.3 + https://github.com/xoseperez/rpnlib.git#0.0.2 https://github.com/xoseperez/Time NewPing https://github.com/sparkfun/SparkFun_VEML6075_Arduino_Library#V_1.0.3