#pragma once #include "wled.h" #ifndef MULTI_RELAY_MAX_RELAYS #define MULTI_RELAY_MAX_RELAYS 4 #endif /* * This usermod handles multiple relay outputs. * These outputs complement built-in relay output in a way that the activation can be delayed. * They can also activate/deactivate in reverse logic independently. */ class MultiRelay : public Usermod { private: // pins int8_t _relayPin[MULTI_RELAY_MAX_RELAYS]; // delay (in seconds) before relay state changes uint16_t _relayDelay[MULTI_RELAY_MAX_RELAYS]; // activation mode (high/low) bool _relayMode[MULTI_RELAY_MAX_RELAYS]; // relay active state bool _relayActive[MULTI_RELAY_MAX_RELAYS]; // switch timer start time uint32_t _switchTimerStart = 0; // old brightness uint8_t _oldBrightness = 0; // usermod enabled bool enabled = false; // needs to be configured (no default config) // status of initialisation bool initDone = false; // strings to reduce flash memory usage (used more than twice) static const char _name[]; static const char _enabled[]; static const char _relay[]; static const char _delay[]; static const char _activeHigh[]; /** * switch relay on/off */ void switchRelay(uint8_t relay) { if (relay>=MULTI_RELAY_MAX_RELAYS || _relayPin[relay]<0) return; pinMode(_relayPin[relay], OUTPUT); bool mode = bri ? _relayMode[relay] : !_relayMode[relay]; digitalWrite(_relayPin[relay], mode); publishMqtt(mode ? "on" : "off", relay); } void publishMqtt(const char* state, int relay) { //Check if MQTT Connected, otherwise it will crash the 8266 if (WLED_MQTT_CONNECTED){ char subuf[64]; sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay); mqtt->publish(subuf, 0, true, state); } } /** * switch off the strip if the delay has elapsed */ void handleOffTimer() { bool activeRelays = false; for (uint8_t i=0; i 0 && millis() - _switchTimerStart > (_relayDelay[i]*1000)) { switchRelay(i); // toggle relay _relayActive[i] = false; } activeRelays = activeRelays || _relayActive[i]; } if (!activeRelays) _switchTimerStart = 0; } public: /** * constructor */ MultiRelay() { for (uint8_t i=0; i=0) _relayActive[i] = true; } } handleOffTimer(); } /** * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. */ void addToJsonInfo(JsonObject &root) { if (enabled) { uint8_t count = 0; for (uint8_t i=0; i=0) count++; JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); JsonArray infoArr = user.createNestedArray(F("Number of relays")); //name infoArr.add(String(count)); } } /** * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). * Values in the state object may be modified by connected clients */ void addToJsonState(JsonObject &root) { } /** * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). * Values in the state object may be modified by connected clients */ void readFromJsonState(JsonObject &root) { } /** * provide the changeable values */ void addToConfig(JsonObject &root) { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; for (uint8_t i=0; i()) { enabled = top[FPSTR(_enabled)].as(); // reading from cfg.json } else { // change from settings page String str = top[FPSTR(_enabled)]; // checkbox -> off or on enabled = (bool)(str!="off"); // off is guaranteed to be present } } for (uint8_t i=0; i())); if (top[parName+FPSTR(_activeHigh)] != nullptr) { if (top[parName+FPSTR(_activeHigh)].is()) { _relayMode[i] = top[parName+FPSTR(_activeHigh)].as(); // reading from cfg.json } else { // change from settings page String str = top[parName+FPSTR(_activeHigh)]; // checkbox -> off or on _relayMode[i] = (bool)(str!="off"); // off is guaranteed to be present } } _relayDelay[i] = min(600,max(0,abs(top[parName+FPSTR(_delay)].as()))); } if (!initDone) { // reading config prior to setup() DEBUG_PRINTLN(F("MultiRelay config loaded.")); } else { // deallocate all pins 1st for (uint8_t i=0; i=0) { pinManager.deallocatePin(oldPin[i]); } // allocate new pins for (uint8_t i=0; i=0 && pinManager.allocatePin(_relayPin[i],true)) { switchRelay(i); } else { _relayPin[i] = -1; } _relayActive[i] = false; } DEBUG_PRINTLN(F("MultiRelay config (re)loaded.")); } } /** * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ uint16_t getId() { return USERMOD_ID_MULTI_RELAY; } }; // strings to reduce flash memory usage (used more than twice) const char MultiRelay::_name[] PROGMEM = "MultiRelay"; const char MultiRelay::_enabled[] PROGMEM = "enabled"; const char MultiRelay::_relay[] PROGMEM = "relay"; const char MultiRelay::_delay[] PROGMEM = "delay-s"; const char MultiRelay::_activeHigh[] PROGMEM = "active-high";