From c8e0acf911b67e0629f0e59f6dc82bb9ba2ed269 Mon Sep 17 00:00:00 2001 From: matzman666 Date: Fri, 16 Mar 2018 22:25:13 +0100 Subject: [PATCH] Initial Commit. --- .cproject | 91 ++++++ .project | 75 +++++ MyNotificationLight.ino | 104 +++++++ NotificationLEDs.h | 622 ++++++++++++++++++++++++++++++++++++++++ SceneAnalogClock.h | 125 ++++++++ SceneColorWheel.h | 176 ++++++++++++ ScenePulse.h | 103 +++++++ nodemanager_config.h | 70 +++++ 8 files changed, 1366 insertions(+) create mode 100644 .cproject create mode 100644 .project create mode 100644 MyNotificationLight.ino create mode 100644 NotificationLEDs.h create mode 100644 SceneAnalogClock.h create mode 100644 SceneColorWheel.h create mode 100644 ScenePulse.h create mode 100644 nodemanager_config.h diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..5ea270d --- /dev/null +++ b/.cproject @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..5c3c06b --- /dev/null +++ b/.project @@ -0,0 +1,75 @@ + + + MyNotificationLight + + + + + + io.sloeber.core.inoToCpp + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + io.sloeber.arduinonature + + + + core/core + 2 + ECLIPSE_HOME/arduinoPlugin/packages/arduino/hardware/avr/1.6.18/cores/arduino + + + core/variant + 2 + ECLIPSE_HOME/arduinoPlugin/packages/arduino/hardware/avr/1.6.18/variants/eightanaloginputs + + + libraries/Adafruit_GFX_Library + 2 + ECLIPSE_HOME/arduinoPlugin/libraries/Adafruit_GFX_Library/1.1.8 + + + libraries/Adafruit_NeoPixel + 2 + ECLIPSE_HOME/arduinoPlugin/libraries/Adafruit_NeoPixel/1.0.6 + + + libraries/EEPROM + 2 + ECLIPSE_HOME/arduinoPlugin/packages/arduino/hardware/avr/1.6.18/libraries/EEPROM + + + libraries/MyNodeManager + 2 + ECLIPSE_HOME/arduinoPlugin/libraries/MyNodeManager/1.0.0 + + + libraries/MySensors + 2 + ECLIPSE_HOME/arduinoPlugin/libraries/MySensors/2.2.0 + + + libraries/SPI + 2 + ECLIPSE_HOME/arduinoPlugin/packages/arduino/hardware/avr/1.6.18/libraries/SPI + + + diff --git a/MyNotificationLight.ino b/MyNotificationLight.ino new file mode 100644 index 0000000..c0bcd9d --- /dev/null +++ b/MyNotificationLight.ino @@ -0,0 +1,104 @@ + +#include +#include +#include +#include "NotificationLEDs.h" + + +#define SENSOR_CHECK_INTERVAL 2000 +#define MSG_SEND_CYCLES 15 +#define MSG_SEND_INTERVAL 30000 + +#define PIN_BUZZER 3 +#define PIN_RGBW 5 +#define PIN_MOTION 6 +#define PIN_DOOR0 A0 +#define PIN_DOOR1 A1 +#define PIN_DOOR2 A2 +#define PIN_DOOR3 A3 +#define PIN_MOTION2 A5 + +#define SENSOR_ID_RGBW 0 +#define SENSOR_ID_DIMMER 1 +#define SENSOR_ID_POWERSWITCH 2 +#define SENSOR_ID_COMMAND 3 +#define SENSOR_ID_MOTION 10 +#define SENSOR_ID_DOOR0 11 +#define SENSOR_ID_DOOR1 12 +#define SENSOR_ID_DOOR2 13 +#define SENSOR_ID_DOOR3 14 +#define SENSOR_ID_MOTION2 15 +#define SENSOR_ID_VCC 210 + +#define DIN_DEBOUNCE 6 + +#define UNIXTIME_FETCH_INTERVAL_SEC 300 + +#define NEOPIXEL_LEDCOUNT 16 + + + + +// create a NodeManager instance +typedef NodeManager< + Tuple< + NotificationLEDs, + SensorMotion, + SensorMotion, + SensorDoor, + SensorDoor, + SensorDoor, + SensorDoor, + SensorVcc + > +> MyNodeManagerBase; + +class MyNodeManager : public MyNodeManagerBase { +protected: +} nodeManager; + + +void before() { + //nodeManager.setSleep(ALWAYS_ON, 1, SECONDS); + nodeManager.before(); +} + + +void presentation() { + nodeManager.presentation(); +} + + +void receive(const MyMessage &message) { + if (!message.isAck()) { + nodeManager.receive(message); + } +} + + +unsigned long unixTime = 0; +unsigned long unixTimeMillis = 0; + +void receiveTime(unsigned long ts) { + unixTime = ts; + unixTimeMillis = millis(); + nodeManager.receiveTime(ts); +} + + +void setup() { + nodeManager.setup(); +} + + +void loop() { + auto currentMillis = millis(); + auto diffMillis = currentMillis - unixTimeMillis; + auto diffSeconds = diffMillis/1000; + long currentUnixTime = unixTime + diffSeconds; + if (unixTime == 0 || diffSeconds >= UNIXTIME_FETCH_INTERVAL_SEC) { + requestTime(); + } + nodeManager.loop(currentUnixTime, currentMillis); +} + diff --git a/NotificationLEDs.h b/NotificationLEDs.h new file mode 100644 index 0000000..eb60dda --- /dev/null +++ b/NotificationLEDs.h @@ -0,0 +1,622 @@ +#ifndef NOTIFICATIONLEDS_H_ +#define NOTIFICATIONLEDS_H_ + + +#include +#include +#include +#include + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval = 60000 +> class NotificationLEDs : public Sensor { +public: + + void before() noexcept; + void setup() noexcept; + void presentation() noexcept; + void loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + bool process(const MyMessage& msg) noexcept; + + void enableDefaultScene(int id = -1) noexcept; + void setStaticColor(uint32_t color) noexcept; + void enableStaticColor() noexcept; + void showNotification(int id = -1) noexcept; + void powerOff() noexcept; + void powerOn() noexcept; + void returnToLastMode() noexcept; + + void defaultScene_config(uint8_t id) noexcept; + void defaultScene_init() noexcept; + void defaultScene_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + + void overrideScene_config(uint8_t id) noexcept; + void overrideScene_init() noexcept; + void overrideScene_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + + void analogClock_config() noexcept; + void analogClock_init() noexcept; + void analogClock_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + + void colorWheel1_config() noexcept; + void colorWheel1_init() noexcept; + void colorWheel1_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + + void colorWheel2_config() noexcept; + void colorWheel2_init() noexcept; + void colorWheel2_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + + void pulse1_config() noexcept; + void pulse1_init() noexcept; + void pulse1_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept; + +protected: + unsigned long lastSendTime = 0; + Adafruit_NeoPixel pixels = Adafruit_NeoPixel(_tpixelCount, _tpin, NEO_GRBW + NEO_KHZ800); + + uint8_t brightness = 25; + + uint8_t mode = 1; // 0: power down, 1: normal, 2: notification + uint8_t lastMode = 1; + uint8_t sceneMode = 0; // 0: default scene, 1: static color + + uint8_t defaultScene = 0; // 0: AnalogClock + uint8_t overrideScene = 0; + + const char* _configDelims = ":"; + + union { + uint8_t wrgb[4]; + uint32_t color; + } staticColor; + bool staticColorOn = true; + + struct { + struct { + int8_t hourOffset = 1; + bool showInnerClock = true; + bool temporaryDisableInnerClock = false; + unsigned long lastUnixTime = 0; + } analogClock; + struct { + uint16_t sleepTime = 80; + int8_t pixelStep = 1; + int8_t colorStep = 20; + int16_t currentColorIndex = 0; + int16_t currentPixelIndex = 0; + unsigned long lastMillis = 0; + } colorWheel1; + struct { + uint16_t sleepTime = 80; + int8_t colorStep = 20; + int16_t currentColorIndex = 0; + unsigned long lastMillis = 0; + } colorWheel2; + struct { + union { + uint8_t wrgb[4]; + uint32_t color = 0x00FF0000; + } color; + uint8_t maxPulses = 5; + uint8_t currentPulses = 0; + int8_t pulseDir = 10; + uint8_t pulseValue = 0; + unsigned long lastMillis = 0; + } pulse1; + } sceneData; +}; + + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::before() noexcept {} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::setup() noexcept { + pixels.begin(); + defaultScene_init(); +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::presentation() noexcept { + String desc(F("RGBW")); + present(_trgbwId, S_RGBW_LIGHT, desc.c_str()); + desc = F("Dimmer"); + present(_tdimmerId, S_DIMMER, desc.c_str()); + desc = F("PowerSwitch"); + present(_tpowerSwitchId, S_BINARY, desc.c_str()); + desc = F("Command"); + present(_tcommandId, S_INFO, desc.c_str()); +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept { + + // default scene + if (mode == 1 && sceneMode == 0) { + defaultScene_loop(currentUnixTime, currentMillis); + } else if (mode == 2) { + overrideScene_loop(currentUnixTime, currentMillis); + } + + if (lastSendTime == 0 || currentMillis - lastSendTime >= _msgSendInterval) { + + // RGBW Sensor + char rgbw[9] = "00000000"; + // WRGB => RGBW + String tmp((staticColor.color & 0xFF000000) >> 24 | ((staticColor.color & 0x00FFFFFF) << 8)); + memcpy(rgbw+(8-tmp.length()), tmp.c_str(), tmp.length()); + _sendValue(rgbw, _trgbwId, V_RGBW); + + //Dimmer + if (sceneMode == 0) { + _sendValue(brightness, _tdimmerId, V_STATUS); + } else { + uint16_t cb = max(staticColor.wrgb[0], max(staticColor.wrgb[1], max(staticColor.wrgb[2], staticColor.wrgb[3]))) * 100 / 255; + _sendValue(cb, _tdimmerId, V_STATUS); + } + + //Power Switch + _sendValue(mode == 0 ? 0 : 1, _tpowerSwitchId, V_STATUS); + + lastSendTime = currentMillis; + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> bool NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::process(const MyMessage& msg) noexcept { + bool retval = false; + + // RGBW Sensor + if (msg.sensor == _trgbwId) { + // Set Message + if (msg.getCommand() == C_SET) { + if (msg.type == V_STATUS) { + auto onOff = msg.getByte(); + if (onOff) { + enableStaticColor(); + } else { + enableDefaultScene(); + } + retval = true; + } else if (msg.type == V_PERCENTAGE) { + uint16_t cb = (uint16_t)max(staticColor.wrgb[0], max(staticColor.wrgb[1], max(staticColor.wrgb[2], staticColor.wrgb[3]))) * 100 / 255; + uint16_t nb = msg.getByte(); + for (auto i = 0; i < 4; i++) { + uint16_t newcolor = ((uint16_t)staticColor.wrgb[i] * nb) / cb; + if (newcolor > 255) { + newcolor = 255; + } + staticColor.wrgb[i] = newcolor; + } + setStaticColor(staticColor.color); + retval = true; + } else if (msg.type == V_RGBW) { + uint32_t color = strtoul(msg.data, NULL, 16); + // MySensors uses "RGBW" format, but the NeoPixel library uses "WRGB" format + setStaticColor((color & 0xFFFFFF00) >> 8 | ((color & 0xFF) << 24)); + retval = true; + } + // Request Message + } else if (msg.getCommand() == C_REQ) { + char rgbw[9] = "00000000"; + // WRGB => RGBW + String tmp((staticColor.color & 0xFF000000) >> 24 | ((staticColor.color & 0x00FFFFFF) << 8)); + memcpy(rgbw+(8-tmp.length()), tmp.c_str(), tmp.length()); + _sendValue(rgbw, _trgbwId, V_RGBW); + retval = true; + } + } + + // Dimmer Sensor + else if (msg.sensor == _tdimmerId) { + // Set Message + if (msg.getCommand() == C_SET) { + if (msg.type == V_PERCENTAGE) { + auto b = msg.getByte(); + if (sceneMode == 0) { + brightness = b; + sceneData.analogClock.lastUnixTime = 0; + } else { + uint16_t cb = max(staticColor.wrgb[0], max(staticColor.wrgb[1], max(staticColor.wrgb[2], staticColor.wrgb[3]))) * 100 / 255; + uint16_t nb = msg.getByte(); + for (auto i = 0; i < 4; i++) { + uint16_t newcolor = ((uint16_t)staticColor.wrgb[i] * nb) / cb; + if (newcolor > 255) { + newcolor = 255; + } + staticColor.wrgb[i] = newcolor; + } + setStaticColor(staticColor.color); + } + retval = true; + } + // Request Message + } else if (msg.getCommand() == C_REQ) { + if (sceneMode == 0) { + _sendValue(brightness, _tdimmerId, V_STATUS); + } else { + uint16_t cb = max(staticColor.wrgb[0], max(staticColor.wrgb[1], max(staticColor.wrgb[2], staticColor.wrgb[3]))) * 100 / 255; + _sendValue(cb, _tdimmerId, V_STATUS); + } + retval = true; + } + } + + // Power Switch + else if (msg.sensor == _tpowerSwitchId) { + // Set Message + if (msg.getCommand() == C_SET) { + if (msg.type == V_STATUS) { + auto v = msg.getByte(); + if (v == 0) { + powerOff(); + } else { + powerOn(); + } + retval = true; + } + // Request Message + } else if (msg.getCommand() == C_REQ) { + _sendValue(mode == 0 ? 0 : 1, _tpowerSwitchId, V_STATUS); + retval = true; + } + } + + // Command + else if (msg.sensor == _tcommandId) { + // Set Message + if (msg.getCommand() == C_SET) { + if (msg.type == V_TEXT) { + auto v = msg.getString(); + + Serial.print("Command: "); + Serial.println(v); + + auto cmd = strtok((char*)v, _configDelims); + if (cmd[0] == 'D') { // Set default Scene + auto id = atoi(cmd+1); + defaultScene_config(id); + if (mode == 1 && sceneMode == 0) { + defaultScene_init(); + } + } else if (cmd[0] == 'N') { // Notification + if (cmd[1] == 'C') { + returnToLastMode(); + } else if (cmd[1] == '\0') { + showNotification(); + } else { + auto id = atoi(cmd+1); + showNotification(id); + } + } + retval = true; + } + // Request Message + } else if (msg.getCommand() == C_REQ) { + retval = true; + } + } + + return retval; +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::enableDefaultScene(int id) { + sceneMode = 0; + mode = 1; + if (id >= 0) { + defaultScene = id; + } + defaultScene_init(); +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::setStaticColor(uint32_t color) { + sceneMode = 1; + mode = 1; + if (color == 0) { + staticColorOn = false; + for (unsigned i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, 0); + } + } else { + staticColorOn = true; + staticColor.color = color; + for (unsigned i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, staticColor.color); + } + } + pixels.show(); +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::enableStaticColor() noexcept { + sceneMode = 1; + mode = 1; + if (staticColorOn) { + for (unsigned i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, staticColor.color); + } + } else { + for (unsigned i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, 0); + } + } + pixels.show(); +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::showNotification(int id) noexcept { + if (mode < 2) { + lastMode = mode; + } + mode = 2; + if (id >= 0) { + overrideScene_config(id); + } + overrideScene_init(); +} + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::powerOff() noexcept { + mode = 0; + for (unsigned i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, 0); + } + pixels.show(); +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::powerOn() noexcept { + mode = 1; + if (sceneMode == 0) { + enableDefaultScene(); + } else { + enableStaticColor(); + } + pixels.show(); +} + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::returnToLastMode() noexcept { + if (lastMode == 0) { + powerOff(); + } else if (lastMode == 1) { + powerOn(); + } +} + + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::defaultScene_config(uint8_t id){ + if (id == 0) { + defaultScene = id; + analogClock_config(); + } else if (id == 1) { + defaultScene = id; + colorWheel1_config(); + } else if (id == 2) { + defaultScene = id; + colorWheel2_config(); + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::defaultScene_init() noexcept { + if (defaultScene == 0) { + analogClock_init(); + } else if (defaultScene == 1) { + colorWheel1_init(); + } else if (defaultScene == 2) { + colorWheel2_init(); + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::defaultScene_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept { + if (defaultScene == 0) { + analogClock_loop(currentUnixTime, currentMillis); + } else if (defaultScene == 1) { + colorWheel1_loop(currentUnixTime, currentMillis); + } else if (defaultScene == 2) { + colorWheel2_loop(currentUnixTime, currentMillis); + } +} + + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::overrideScene_config(uint8_t id){ + if (id == 0) { + overrideScene = id; + pulse1_config(); + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::overrideScene_init() noexcept { + if (overrideScene == 0) { + pulse1_init(); + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::overrideScene_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept { + if (overrideScene == 0) { + pulse1_loop(currentUnixTime, currentMillis); + } +} + +#include "SceneAnalogClock.h" +#include "SceneColorWheel.h" +#include "ScenePulse.h" + + + +#endif /* NOTIFICATIONLEDS_H_ */ diff --git a/SceneAnalogClock.h b/SceneAnalogClock.h new file mode 100644 index 0000000..4bb601a --- /dev/null +++ b/SceneAnalogClock.h @@ -0,0 +1,125 @@ +#ifndef SCENEANALOGCLOCK_H_ +#define SCENEANALOGCLOCK_H_ + +#include +#include +#include +#include +#include "NotificationLEDs.h" + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::analogClock_config() noexcept { + auto token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto offset = atoi(token); + sceneData.analogClock.hourOffset = offset; + } + token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + bool innerClock = atoi(token); + sceneData.analogClock.showInnerClock = innerClock; + } + sceneData.analogClock.temporaryDisableInnerClock = false; + sceneData.analogClock.lastUnixTime = 0; +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::analogClock_init() noexcept { + for (uint8_t i = 0; i < 12; i++) { + pixels.setPixelColor(i, 0); + } + if (sceneData.analogClock.showInnerClock && !sceneData.analogClock.temporaryDisableInnerClock) { + for (uint8_t i = 12; i < 16; i++) { + pixels.setPixelColor(i, 0); + } + } + pixels.show(); + sceneData.analogClock.lastUnixTime = 0; +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::analogClock_loop(unsigned long currentUnixTime, unsigned long) noexcept { + if (sceneData.analogClock.lastUnixTime != currentUnixTime) { + auto seconds = currentUnixTime % 60; + auto _tmp = currentUnixTime / 60; + auto minutes = _tmp % 60; + auto hours = (_tmp / 60 + sceneData.analogClock.hourOffset) % 12; + auto p_h = (11 - hours) % 12; + auto p_m = (11 - minutes/5) % 12; + auto p_m2 = minutes % 5; + auto p_s = (11 - seconds/5) % 12; + auto p_s2 = seconds % 5; + /*Serial.print("Time: "); + Serial.print(hours); + Serial.print(":"); + Serial.print(minutes); + Serial.print(":"); + Serial.println(seconds); + Serial.print("Pixels: "); + Serial.print(p_h); + Serial.print(":"); + Serial.print(p_m); + Serial.print(":"); + Serial.println(p_s);*/ + for (uint8_t i = 0; i < 12; i++) { + uint32_t c = 0; + if (i == p_h) { // hour => red + c |= ((uint32_t)255*(uint32_t)brightness/(uint32_t)100) << 16; + } + if (i == p_m) { // min => green + c |= ((uint32_t)255*(uint32_t)brightness/(uint32_t)100) << 8; + } + if (i == p_s) { // sec => blue + c |= (uint32_t)255*(uint32_t)brightness/(uint32_t)100; + } + if (c == 0) { + c = ((uint32_t)20*(uint32_t)brightness/(uint32_t)100) << 24; + } + pixels.setPixelColor(i, c); + } + if (sceneData.analogClock.showInnerClock && !sceneData.analogClock.temporaryDisableInnerClock) { + for (uint8_t i = 0; i < 4; i++) { + uint32_t c = 0; + if (i < p_s2) { + c |= (uint32_t)255*(uint32_t)brightness/(uint32_t)100; + } + if (i < p_m2) { + c |= ((uint32_t)255*(uint32_t)brightness/(uint32_t)100) << 8; + } + pixels.setPixelColor(15 - i, c); + } + } + pixels.show(); + sceneData.analogClock.lastUnixTime = currentUnixTime; + } +} + + +#endif /* SCENEANALOGCLOCK_H_ */ diff --git a/SceneColorWheel.h b/SceneColorWheel.h new file mode 100644 index 0000000..f7af58c --- /dev/null +++ b/SceneColorWheel.h @@ -0,0 +1,176 @@ +#ifndef SCENECOLORWHEEL_H_ +#define SCENECOLORWHEEL_H_ + +#include +#include +#include +#include +#include "NotificationLEDs.h" + + +void _colorWheel_mapIndex(uint16_t c, uint16_t& r, uint16_t& g, uint16_t& b) { + if (c < 255) { + r = 255 - c; + g = c; + b = 0; + } else if (c >= 255 && c < 510) { + r = 0; + g = 510 - c; + b = c - 255; + } else if (c >= 510 && c < 765) { + r = c - 510; + g = 0; + b = 765 - c; + } else { + r = g = b = 255; + } +} + +// mathematically correct modulo +#define MOD(a,b) ((((a)%(b))+(b))%(b)) + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::colorWheel1_config() noexcept { + auto token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto pixelStep = atoi(token); + sceneData.colorWheel1.pixelStep = pixelStep; + } + token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto colorStep = atoi(token); + sceneData.colorWheel1.colorStep = colorStep; + } + token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto sleepTime = atoi(token); + sceneData.colorWheel1.sleepTime = sleepTime; + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::colorWheel1_init() noexcept { + for (uint8_t i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, 0); + } + pixels.show(); + sceneData.colorWheel1.currentColorIndex = 0; + sceneData.colorWheel1.currentPixelIndex = 0; + sceneData.colorWheel1.lastMillis = 0; +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::colorWheel1_loop(unsigned long, unsigned long currentMillis) noexcept { + if (currentMillis - sceneData.colorWheel1.lastMillis >= sceneData.colorWheel1.sleepTime) { + uint16_t r, g, b; + _colorWheel_mapIndex(sceneData.colorWheel1.currentColorIndex, r, g, b); + r = r*(uint16_t)brightness/100; + g = g*(uint16_t)brightness/100; + b = b*(uint16_t)brightness/100; + pixels.setPixelColor(sceneData.colorWheel1.currentPixelIndex, r, g, b, 0); + pixels.setPixelColor(12, r, g, b, 0); + pixels.setPixelColor(13, r, g, b, 0); + pixels.setPixelColor(14, r, g, b, 0); + pixels.setPixelColor(15, r, g, b, 0); + pixels.show(); + sceneData.colorWheel1.currentColorIndex = MOD(sceneData.colorWheel1.currentColorIndex + sceneData.colorWheel1.colorStep, 765); + sceneData.colorWheel1.currentPixelIndex = MOD(sceneData.colorWheel1.currentPixelIndex + sceneData.colorWheel1.pixelStep, 12); + sceneData.colorWheel1.lastMillis = currentMillis; + } +} + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::colorWheel2_config() noexcept { + auto token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto colorStep = atoi(token); + sceneData.colorWheel2.colorStep = colorStep; + } + token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto sleepTime = atoi(token); + sceneData.colorWheel2.sleepTime = sleepTime; + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::colorWheel2_init() noexcept { + for (uint8_t i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, 0); + } + pixels.show(); + sceneData.colorWheel2.currentColorIndex = 0; + sceneData.colorWheel2.lastMillis = 0; +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::colorWheel2_loop(unsigned long, unsigned long currentMillis) noexcept { + if (currentMillis - sceneData.colorWheel2.lastMillis >= sceneData.colorWheel2.sleepTime) { + uint16_t r, g, b; + _colorWheel_mapIndex(sceneData.colorWheel2.currentColorIndex, r, g, b); + r = r*(uint16_t)brightness/100; + g = g*(uint16_t)brightness/100; + b = b*(uint16_t)brightness/100; + for (uint16_t i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, r, g, b, 0); + } + pixels.show(); + sceneData.colorWheel2.currentColorIndex = MOD(sceneData.colorWheel2.currentColorIndex + sceneData.colorWheel2.colorStep, 765); + sceneData.colorWheel2.lastMillis = currentMillis; + } +} + + +#endif /* SCENECOLORWHEEL_H_ */ diff --git a/ScenePulse.h b/ScenePulse.h new file mode 100644 index 0000000..519145d --- /dev/null +++ b/ScenePulse.h @@ -0,0 +1,103 @@ +#ifndef SCENEPULSE_H_ +#define SCENEPULSE_H_ + +#include +#include +#include +#include +#include "NotificationLEDs.h" + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::pulse1_config() noexcept { + auto token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto color = strtoul(token, NULL, 16); + sceneData.pulse1.color.color = color; + } + token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto maxPulses = atoi(token); + sceneData.pulse1.maxPulses = maxPulses; + } + token = strtok(NULL, _configDelims); + if (token && token[0] != ' ') { + auto pulseDir = atoi(token); + sceneData.pulse1.pulseDir = pulseDir; + } +} + + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::pulse1_init() noexcept { + for (uint8_t i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, 0); + } + pixels.show(); + sceneData.pulse1.pulseValue = 0; + sceneData.pulse1.lastMillis = 0; + sceneData.pulse1.currentPulses = 0; +} + + +template +T tmap(T x, T in_min, T in_max, T out_min, T out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +template< + uint8_t _tpin, + uint8_t _trgbwId, + uint8_t _tdimmerId, + uint8_t _tpowerSwitchId, + uint8_t _tcommandId, + uint16_t _tpixelCount, + unsigned long _msgSendInterval +> void NotificationLEDs<_tpin, _trgbwId, _tdimmerId, _tpowerSwitchId, _tcommandId, _tpixelCount, _msgSendInterval> +::pulse1_loop(unsigned long currentUnixTime, unsigned long currentMillis) noexcept { + if (currentMillis - sceneData.pulse1.lastMillis >= 50) { + auto color = sceneData.pulse1.color; + int16_t pulseValue = sceneData.pulse1.pulseValue; + uint16_t br = 127.5 * (-cos(tmap(pulseValue, 0, 255, 0, 2.0*M_PI))+1.0); + color.wrgb[0] = (uint16_t)color.wrgb[0]*br/255; + color.wrgb[1] = (uint16_t)color.wrgb[1]*br/255; + color.wrgb[2] = (uint16_t)color.wrgb[2]*br/255; + color.wrgb[3] = (uint16_t)color.wrgb[3]*br/255; + for (uint16_t i = 0; i < _tpixelCount; i++) { + pixels.setPixelColor(i, color.color); + } + pixels.show(); + pulseValue += sceneData.pulse1.pulseDir; + if (pulseValue < 0) { + sceneData.pulse1.pulseDir = -sceneData.pulse1.pulseDir; + pulseValue = sceneData.pulse1.pulseDir; + sceneData.pulse1.currentPulses++; + if (sceneData.pulse1.maxPulses > 0 && sceneData.pulse1.currentPulses > sceneData.pulse1.maxPulses) { + returnToLastMode(); + } + } else if (pulseValue > 255) { + sceneData.pulse1.pulseDir = -sceneData.pulse1.pulseDir; + pulseValue = 255 + sceneData.pulse1.pulseDir; + } + sceneData.pulse1.pulseValue = pulseValue; + sceneData.pulse1.lastMillis = currentMillis; + } +} + +#endif /* SCENEPULSE_H_ */ diff --git a/nodemanager_config.h b/nodemanager_config.h new file mode 100644 index 0000000..31f67c1 --- /dev/null +++ b/nodemanager_config.h @@ -0,0 +1,70 @@ +#ifndef config_h +#define config_h + +/********************************** + * Sketch configuration + */ + +#define SKETCH_NAME "Notification01" +#define SKETCH_VERSION "1.0" + +/********************************** + * MySensors node configuration + */ + +#define MY_NODE_ID 1 + +#define MY_MSG_ACK 1 +#define MY_MSG_RETRIES 3 +#define MY_MSG_RETRY_DELAY 1 + + +// Enable debug prints to serial monitor +#define MY_DEBUG +//#define MY_DEBUG_VERBOSE_RF24 +//#define MY_SPECIAL_DEBUG +#define MY_SPLASH_SCREEN_DISABLED + + +// Enable and select radio type attached +#define MY_RADIO_NRF24 + +#define MY_RF24_PA_LEVEL RF24_PA_MAX +#define MY_RF24_DATARATE RF24_250KBPS +#define MY_RF24_CHANNEL 82 +#define MY_RF24_BASE_RADIO_ID 0x00,0x30,0x08,0x19,0x82 +#define MY_RF24_ENABLE_XTEA +#define MY_RF24_XTEA_KEY { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F } +#define MY_MESSAGE_ENABLE_NONCE +#define MY_MESSAGE_ENABLE_HASH +#define MY_SMART_SLEEP_WAIT_DURATION_MS 60 + +#define MY_RF24_CE_PIN 9 +#define MY_RF24_CS_PIN 10 + + +/*********************************** + * NodeManager configuration + */ + +#define DEBUG 0 + +// if enabled, enable the capability to power on sensors with the arduino's pins to save battery while sleeping +#define POWER_MANAGER 0 +// if enabled, will load the battery manager library to allow the battery level to be reported automatically or on demand +#define BATTERY_MANAGER 0 +// if enabled, allow modifying the configuration remotely by interacting with the configuration child id +#define REMOTE_CONFIGURATION 1 +// if enabled, persist the remote configuration settings on EEPROM +#define PERSIST 1 +// if enabled, a battery sensor will be created at BATTERY_CHILD_ID and will report vcc voltage together with the battery level percentage +#define BATTERY_SENSOR 0 +// if enabled, send a SLEEPING and AWAKE service messages just before entering and just after leaving a sleep cycle and STARTED when starting/rebooting +#define SERVICE_MESSAGES 0 + +#define DISABLE_SLEEP_MODE + + + +#endif +