Skip to content

Instantly share code, notes, and snippets.

@clclon
Last active October 7, 2020 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clclon/8c1ffa2b7d0566055a5b69b6fd9534a5 to your computer and use it in GitHub Desktop.
Save clclon/8c1ffa2b7d0566055a5b69b6fd9534a5 to your computer and use it in GitHub Desktop.
MySensors Advanced features I2C patch
#define MY_DEFAULT_LED_EXT 1
#define MY_INCLUSION_MODE_FEATURE
#define MY_INCLUSION_BUTTON_FEATURE
#define MY_INCLUSION_MODE_DURATION 10
#include <MySensors.h>
#include <core/MyInclusionMode.h>
#include <PCF8574.h>
const uint8_t scl_PIN = D1;
const uint8_t sda_PIN = D2;
const uint8_t led_device[4] { 2U, 3U, 6U, 4U };
const uint8_t btn_device[4] { 0U, 1U, 5U, 7U };
PCF8574 expander(0x22, sda_PIN, scl_PIN);
void setup() {
Wire.begin(sda_PIN, scl_PIN);
Serial.begin(115200);
while (!Serial) delay(50);
for (uint8_t i = 0; i < 4U; i++) {
expander.pinMode(led_device[i], OUTPUT);
expander.digitalWrite(led_device[i], HIGH);
Serial.printf("Init LED expander: %u/%u\n", (uint16_t)i, (uint16_t)led_device[i]);
}
for (uint8_t i = 0; i < 4U; i++) {
expander.pinMode(btn_device[i], INPUT);
expander.digitalWrite(btn_device[i], HIGH);
Serial.printf("Init BTN expander: %u/%u\n", (uint16_t)i, (uint16_t)btn_device[i]);
}
expander.begin();
ledsSetCb(
[=](uint8_t & state) { expander.digitalWrite(led_device[1], state); },
[=](uint8_t & state) { expander.digitalWrite(led_device[2], state); },
[=](uint8_t & state) { expander.digitalWrite(led_device[3], state); }
);
inclusionSetCb(
[=]() { return (expander.digitalRead(btn_device[0], true) == LOW); },
[=](uint8_t & state) { expander.digitalWrite(led_device[0], state); }
);
}
void loop() {}
--- E:/__BuildSource/__LIB__/Arduino/Sketch/MySensors-development/MySensors.h Sat Aug 22 11:07:35 2020
+++ E:/__BuildSource/__LIB__/Arduino/Sketch/libraries/MySensors/MySensors.h Tue Oct 6 11:28:48 2020
@@ -119,6 +119,8 @@
#if defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
#include "core/MyLeds.cpp"
+#elif defined(MY_DEFAULT_LED_EXT)
+#include "core/MyLedsExt.cpp"
#else
#include "core/MyLeds.h"
#endif
--- MyInclusionMode.cpp Sat Aug 22 11:07:35 2020
+++ MyInclusionMode.cpp Tue Oct 6 13:44:58 2020
@@ -18,25 +18,44 @@
*/
#include "MyInclusionMode.h"
+#if defined(ARDUINO_ARCH_ESP8266)
+# include <Esp.h>
+#endif
// global variables
extern MyMessage _msgTmp;
-unsigned long _inclusionStartTime;
-bool _inclusionMode;
+unsigned long _inclusionStartTime = 0U, _rebootStartTime = 0U;
+bool _inclusionMode, _rebootMode;
+
+#if (defined(MY_INCLUSION_BUTTON_FEATURE) && defined(MY_DEFAULT_LED_EXT))
+static btn_cb btnInclusionFunc = [](){ return false; };
+static led_cb ledInclusionFunc = [](uint8_t&){};
+
+void inclusionSetCb(btn_cb btn, led_cb led) {
+ btnInclusionFunc = btn;
+ ledInclusionFunc = led;
+}
+#endif
inline void inclusionInit()
{
+ _rebootMode = false;
_inclusionMode = false;
#if defined(MY_INCLUSION_BUTTON_FEATURE)
+# if defined(MY_DEFAULT_LED_EXT)
+ uint8_t state = static_cast<uint8_t>(LED_OFF);
+ ledInclusionFunc(state);
+# else
// Setup digital in that triggers inclusion mode
hwPinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT_PULLUP);
-#endif
#if defined (MY_INCLUSION_LED_PIN)
// Setup LED pin that indicates inclusion mode
hwPinMode(MY_INCLUSION_LED_PIN, OUTPUT);
hwDigitalWrite(MY_INCLUSION_LED_PIN, LED_OFF);
#endif
+# endif
+#endif
}
@@ -51,21 +70,44 @@
_inclusionStartTime = hwMillis();
}
}
-#if defined (MY_INCLUSION_LED_PIN)
+#if defined(MY_INCLUSION_BUTTON_FEATURE)
+# if defined(MY_DEFAULT_LED_EXT)
+ uint8_t state = static_cast<uint8_t>(_inclusionMode);
+ ledInclusionFunc(state);
+# elif defined (MY_INCLUSION_LED_PIN)
hwDigitalWrite(MY_INCLUSION_LED_PIN, _inclusionMode ? LED_ON : LED_OFF);
#endif
+#endif
}
inline void inclusionProcess()
{
-#ifdef MY_INCLUSION_BUTTON_FEATURE
- if (!_inclusionMode && hwDigitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == MY_INCLUSION_BUTTON_PRESSED) {
+#if defined(MY_INCLUSION_BUTTON_FEATURE)
+# if defined(MY_DEFAULT_LED_EXT)
+ bool b = btnInclusionFunc();
+# else
+ bool b = (hwDigitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == MY_INCLUSION_BUTTON_PRESSED);
+# endif
+
+ if (!_inclusionMode && b) {
// Start inclusion mode
inclusionModeSet(true);
}
-#endif
+# if defined(ARDUINO_ARCH_ESP8266)
+ if (!_rebootMode && b) {
+ _rebootStartTime = hwMillis() + 10000U;
+ _rebootMode = true;
+
+ } else if (_rebootMode && b) {
+ if (_rebootStartTime < hwMillis())
+ ESP.restart();
- if (_inclusionMode && hwMillis()-_inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) {
+ } else if (_rebootMode) {
+ _rebootMode = false;
+ }
+# endif
+#endif
+ if (_inclusionMode && (hwMillis() - _inclusionStartTime > MY_INCLUSION_MODE_DURATION * 1000L)) {
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
inclusionModeSet(false);
}
--- MyInclusionMode.h Sat Aug 22 11:07:35 2020
+++ MyInclusionMode.h Tue Oct 6 13:46:53 2020
@@ -22,6 +22,11 @@
#include "MySensorsCore.h"
+#if (defined(MY_INCLUSION_BUTTON_FEATURE) && defined(MY_DEFAULT_LED_EXT))
+typedef bool (*btn_cb)();
+typedef void (*led_cb)(uint8_t&);
+void inclusionSetCb(btn_cb, led_cb);
+#endif
extern bool gatewayTransportSend(MyMessage &message);
--- MyIndication.cpp Sat Aug 22 11:07:35 2020
+++ MyIndication.cpp Tue Oct 6 11:54:37 2020
@@ -18,23 +18,23 @@
*/
#include "MyIndication.h"
-#if defined(MY_DEFAULT_TX_LED_PIN)|| defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
+#if defined(MY_DEFAULT_TX_LED_PIN)|| defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) || defined(MY_DEFAULT_LED_EXT)
#include "MyLeds.h"
#endif
void setIndication( const indication_t ind )
{
-#if defined(MY_DEFAULT_TX_LED_PIN)
+#if (defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_LED_EXT))
if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind)) {
ledsBlinkTx(1);
} else
#endif
-#if defined(MY_DEFAULT_RX_LED_PIN)
+#if (defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_LED_EXT))
if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) {
ledsBlinkRx(1);
} else
#endif
-#if defined(MY_DEFAULT_ERR_LED_PIN)
+#if (defined(MY_DEFAULT_ERR_LED_PIN) || defined(MY_DEFAULT_LED_EXT))
if (ind > INDICATION_ERR_START) {
// Number of blinks indicates which error occurred.
ledsBlinkErr(ind-INDICATION_ERR_START);
--- MyLeds.h Sat Aug 22 11:07:35 2020
+++ MyLeds.h Tue Oct 6 11:45:46 2020
@@ -29,7 +29,12 @@
#define LED_OFF 0x1
#endif
-#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
+#if defined(MY_DEFAULT_LED_EXT)
+typedef void (*led_cb)(uint8_t&);
+void ledsSetCb(led_cb, led_cb, led_cb);
+#endif
+
+#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) || defined(MY_DEFAULT_LED_EXT)
#define ledBlinkTx(x,...) ledsBlinkTx(x)
#define ledBlinkRx(x,...) ledsBlinkRx(x)
#define ledBlinkErr(x,...) ledsBlinkErr(x)
--- /dev/null Thu Jan 1 03:00:00 1970
+++ MyLedsExt.cpp Tue Oct 6 13:46:02 2020
@@ -0,0 +1,111 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
+ * Copyright (C) 2013-2019 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MyLeds.h"
+
+#define LED_ON_OFF_RATIO (4) // Power of 2 please
+#define LED_PROCESS_INTERVAL_MS (MY_DEFAULT_LED_BLINK_PERIOD/LED_ON_OFF_RATIO)
+
+// these variables don't need to be volatile, since we are not using interrupts
+static uint8_t countRx;
+static uint8_t countTx;
+static uint8_t countErr;
+static unsigned long prevTime;
+
+static led_cb ledsInfoFunc[3]{
+ [](uint8_t&){},
+ [](uint8_t&){},
+ [](uint8_t&){}
+};
+
+void ledsSetCb(led_cb rxLed, led_cb txLed, led_cb errLed) {
+ ledsInfoFunc[0] = rxLed;
+ ledsInfoFunc[1] = txLed;
+ ledsInfoFunc[2] = errLed;
+}
+
+inline void ledsInit()
+{
+ // initialize counters
+ countRx = 0;
+ countTx = 0;
+ countErr = 0;
+
+ // Setup led pins
+ prevTime = hwMillis() -
+ LED_PROCESS_INTERVAL_MS; // Subtract some, to make sure leds gets updated on first run.
+ ledsProcess();
+}
+
+void ledsProcess()
+{
+ // Just return if it is not the time...
+ if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS) {
+ return;
+ }
+ prevTime = hwMillis();
+ uint8_t state;
+
+ // For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off]
+ // until the counter becomes 0.
+ if (countRx) {
+ --countRx;
+ }
+ state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
+ ledsInfoFunc[0](state); // MY_DEFAULT_RX_LED_PIN
+ if (countTx) {
+ --countTx;
+ }
+ state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
+ ledsInfoFunc[1](state); // MY_DEFAULT_TX_LED_PIN
+ if (countErr) {
+ --countErr;
+ }
+ state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
+ ledsInfoFunc[2](state); // MY_DEFAULT_ERR_LED_PIN
+}
+
+void ledsBlinkRx(uint8_t cnt)
+{
+ if (!countRx) {
+ countRx = cnt*LED_ON_OFF_RATIO;
+ }
+ ledsProcess();
+}
+
+void ledsBlinkTx(uint8_t cnt)
+{
+ if(!countTx) {
+ countTx = cnt*LED_ON_OFF_RATIO;
+ }
+ ledsProcess();
+}
+
+void ledsBlinkErr(uint8_t cnt)
+{
+ if(!countErr) {
+ countErr = cnt*LED_ON_OFF_RATIO;
+ }
+ ledsProcess();
+}
+
+bool ledsBlinking()
+{
+ return countRx || countTx || countErr;
+}
--- MySensorsCore.cpp Sat Aug 22 11:07:35 2020
+++ MySensorsCore.cpp Tue Oct 6 11:56:07 2020
@@ -144,7 +144,7 @@
before();
}
-#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
+#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) || defined(MY_DEFAULT_LED_EXT)
ledsInit();
#endif
@@ -310,7 +310,7 @@
return _coreConfig.controllerConfig;
}
-// cppcheck-suppress constParameter
+
bool _sendRoute(MyMessage &message)
{
#if defined(MY_CORE_ONLY)
@@ -620,20 +620,11 @@
{
hwWatchdogReset();
yield();
-#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
+#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) || defined(MY_DEFAULT_LED_EXT)
ledsProcess();
#endif
}
-#if !defined(MY_SLEEP_HANDLER)
-void sleepHandler(bool sleep)
-{
- (void)sleep;
- // empty function, resolves AVR-specific GCC optimization bug (<5.5) if handler not used
- // see here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77326
-}
-#endif
-
int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1,
const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2)
{
@@ -709,16 +700,13 @@
#endif
setIndication(INDICATION_SLEEP);
-#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
+#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) || defined(MY_DEFAULT_LED_EXT)
// Wait until leds finish their blinking pattern
while (ledsBlinking()) {
doYield();
}
#endif
- // Call the sleep handler to turn off peripherals optimally
- sleepHandler(true);
-
int8_t result = MY_SLEEP_NOT_POSSIBLE; // default
if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) {
// both IRQs
@@ -730,10 +718,6 @@
// no IRQ
result = hwSleep(sleepingTimeMS);
}
-
- // Call the sleep handler to turn on peripherals optimally
- sleepHandler(false);
-
setIndication(INDICATION_WAKEUP);
CORE_DEBUG(PSTR("MCO:SLP:WUP=%" PRIi8 "\n"), result); // sleep wake-up
#if defined(MY_SENSOR_NETWORK)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment