Browse Source

LED modes

fastled
Xose Pérez 7 years ago
parent
commit
96202f7967
7 changed files with 3230 additions and 3113 deletions
  1. +6
    -9
      code/espurna/config/general.h
  2. +29
    -11
      code/espurna/config/hardware.h
  3. BIN
      code/espurna/data/index.html.gz
  4. +118
    -49
      code/espurna/led.ino
  5. +5
    -11
      code/espurna/relay.ino
  6. +3047
    -3031
      code/espurna/static/index.html.gz.h
  7. +25
    -2
      code/html/index.html

+ 6
- 9
code/espurna/config/general.h View File

@ -251,15 +251,12 @@ PROGMEM const char* const custom_reset_string[] = {
// LED // LED
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// All defined LEDs in the board can be managed through MQTT
// except the first one when LED_AUTO is set to 1.
// If LED_AUTO is set to 1 the board will use a defined LED to show wifi status.
#define LED_AUTO 1
// LED # to use as WIFI status indicator
#ifndef LED_WIFI
#define LED_WIFI 1
#endif
#define LED_MODE_MQTT 0 // LED will be managed from MQTT (OFF by default)
#define LED_MODE_WIFI 1 // LED will blink according to the WIFI status
#define LED_MODE_FOLLOW 2 // LED will follow state of linked relay (check RELAY#_LED)
#define LED_MODE_FOLLOW_INVERSE 3 // LED will follow the opposite state of linked relay (check RELAY#_LED)
#define LED_MODE_FINDME 4 // LED will be ON if all relays are OFF
#define LED_MODE_MIXED 5 // A mixed between WIFI and FINDME
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// WIFI // WIFI


+ 29
- 11
code/espurna/config/hardware.h View File

@ -13,9 +13,10 @@
// - BUTTON_SET_PULLUP: set pullup by software // - BUTTON_SET_PULLUP: set pullup by software
// RELAY#_PIN: GPIO for the n-th relay (1-based, up to 4 relays) // RELAY#_PIN: GPIO for the n-th relay (1-based, up to 4 relays)
// RELAY#_TYPE: Relay can be RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE or RELAY_TYPE_LATCHED // RELAY#_TYPE: Relay can be RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE or RELAY_TYPE_LATCHED
// RELAY#_LED: LED number that will be bind to the n-th relay (1-based)
// LED#_PIN: GPIO for the n-th LED (1-based, up to 4 LEDs) // LED#_PIN: GPIO for the n-th LED (1-based, up to 4 LEDs)
// LED#_PIN_INVERSE: LED has inversed logic (lit when pulled down) // LED#_PIN_INVERSE: LED has inversed logic (lit when pulled down)
// LED#_MODE: Check hardware.h for LED_MODE_%
// LED#_RELAY: Linked relay (1-based)
// //
// Besides, other hardware specific information should be stated here // Besides, other hardware specific information should be stated here
@ -100,11 +101,13 @@
#define RELAY1_TYPE RELAY_TYPE_INVERSE #define RELAY1_TYPE RELAY_TYPE_INVERSE
// LEDs // LEDs
#define LED1_PIN 5
#define LED1_PIN_INVERSE 0
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
// HLW8012 // HLW8012
#ifndef POWER_PROVIDER
#define POWER_PROVIDER POWER_PROVIDER_HLW8012 #define POWER_PROVIDER POWER_PROVIDER_HLW8012
#endif
#define HLW8012_SEL_PIN 2 #define HLW8012_SEL_PIN 2
#define HLW8012_CF1_PIN 13 #define HLW8012_CF1_PIN 13
#define HLW8012_CF_PIN 14 #define HLW8012_CF_PIN 14
@ -145,7 +148,9 @@
#define LED1_PIN_INVERSE 0 #define LED1_PIN_INVERSE 0
// HLW8012 // HLW8012
#ifndef POWER_PROVIDER
#define POWER_PROVIDER POWER_PROVIDER_HLW8012 #define POWER_PROVIDER POWER_PROVIDER_HLW8012
#endif
#define HLW8012_SEL_PIN 5 #define HLW8012_SEL_PIN 5
#define HLW8012_CF1_PIN 13 #define HLW8012_CF1_PIN 13
#define HLW8012_CF_PIN 14 #define HLW8012_CF_PIN 14
@ -1321,17 +1326,30 @@
#define RELAY4_DELAY_OFF 0 #define RELAY4_DELAY_OFF 0
#endif #endif
#ifndef RELAY1_LED
#define RELAY1_LED 0
#ifndef LED1_MODE
#define LED1_MODE LED_MODE_WIFI
#endif
#ifndef LED2_MODE
#define LED2_MODE LED_MODE_MQTT
#endif
#ifndef LED3_MODE
#define LED3_MODE LED_MODE_MQTT
#endif
#ifndef LED4_MODE
#define LED4_MODE LED_MODE_MQTT
#endif
#ifndef LED1_RELAY
#define LED1_RELAY 1
#endif #endif
#ifndef RELAY2_LED
#define RELAY2_LED 0
#ifndef LED2_RELAY
#define LED2_RELAY 2
#endif #endif
#ifndef RELAY3_LED
#define RELAY3_LED 0
#ifndef LED3_RELAY
#define LED3_RELAY 3
#endif #endif
#ifndef RELAY4_LED
#define RELAY4_LED 0
#ifndef LED4_RELAY
#define LED4_RELAY 4
#endif #endif
// Needed for ESP8285 boards under Windows using PlatformIO (?) // Needed for ESP8285 boards under Windows using PlatformIO (?)


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


+ 118
- 49
code/espurna/led.ino View File

@ -13,53 +13,60 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
typedef struct { typedef struct {
unsigned char pin; unsigned char pin;
bool reverse; bool reverse;
unsigned char mode;
unsigned char relay;
} led_t; } led_t;
std::vector<led_t> _leds; std::vector<led_t> _leds;
bool ledAuto;
bool ledStatus(unsigned char id) {
if (id >= _leds.size()) return false;
// -----------------------------------------------------------------------------
bool _ledStatus(unsigned char id) {
if (id >= _ledCount()) return false;
bool status = digitalRead(_leds[id].pin); bool status = digitalRead(_leds[id].pin);
return _leds[id].reverse ? !status : status; return _leds[id].reverse ? !status : status;
} }
bool ledStatus(unsigned char id, bool status) {
if (id >= _leds.size()) return false;
bool _ledStatus(unsigned char id, bool status) {
if (id >=_ledCount()) return false;
bool s = _leds[id].reverse ? !status : status; bool s = _leds[id].reverse ? !status : status;
digitalWrite(_leds[id].pin, _leds[id].reverse ? !status : status); digitalWrite(_leds[id].pin, _leds[id].reverse ? !status : status);
return status; return status;
} }
bool ledToggle(unsigned char id) {
if (id >= _leds.size()) return false;
return ledStatus(id, !ledStatus(id));
bool _ledToggle(unsigned char id) {
if (id >= _ledCount()) return false;
return _ledStatus(id, !_ledStatus(id));
} }
void ledBlink(unsigned char id, unsigned long delayOff, unsigned long delayOn) {
if (id >= _leds.size()) return;
unsigned char _ledMode(unsigned char id) {
if (id >= _ledCount()) return false;
return _leds[id].mode;
}
void _ledMode(unsigned char id, unsigned char mode) {
if (id >= _ledCount()) return;
_leds[id].mode = mode;
}
void _ledBlink(unsigned char id, unsigned long delayOff, unsigned long delayOn) {
if (id >= _ledCount()) return;
static unsigned long next = millis(); static unsigned long next = millis();
if (next < millis()) { if (next < millis()) {
next += (ledToggle(id) ? delayOn : delayOff);
next += (_ledToggle(id) ? delayOn : delayOff);
} }
} }
#if LED_WIFI
void showStatus() {
if (wifiConnected()) {
if (WiFi.getMode() == WIFI_AP) {
ledBlink(LED_WIFI - 1, 2500, 2500);
} else {
ledBlink(LED_WIFI - 1, 4900, 100);
}
} else {
ledBlink(LED_WIFI - 1, 500, 500);
}
#if WEB_SUPPORT
void _ledWebSocketOnSend(JsonObject& root) {
if (_ledCount() == 0) return;
root["ledVisible"] = 1;
root["ledMode0"] = _ledMode(0);
} }
#endif #endif
#if MQTT_SUPPORT #if MQTT_SUPPORT
void ledMQTTCallback(unsigned int type, const char * topic, const char * payload) {
void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) {
static bool isFirstMessage = true; static bool isFirstMessage = true;
@ -77,72 +84,134 @@ void ledMQTTCallback(unsigned int type, const char * topic, const char * payload
// Get led ID // Get led ID
unsigned int ledID = t.substring(strlen(MQTT_TOPIC_LED)+1).toInt(); unsigned int ledID = t.substring(strlen(MQTT_TOPIC_LED)+1).toInt();
if (ledID >= ledCount()) {
if (ledID >= _ledCount()) {
DEBUG_MSG_P(PSTR("[LED] Wrong ledID (%d)\n"), ledID); DEBUG_MSG_P(PSTR("[LED] Wrong ledID (%d)\n"), ledID);
return; return;
} }
// Check if LED is managed
if (_ledMode(ledID) != LED_MODE_MQTT) return;
// get value // get value
unsigned int value = (char)payload[0] - '0';
bool bitAuto = (value & 0x02) > 0;
bool bitState = (value & 0x01) > 0;
// Check ledAuto
if (ledID == 0) {
ledAuto = bitAuto ? bitState : false;
setSetting("ledAuto", String() + (ledAuto ? "1" : "0"));
if (bitAuto) return;
}
unsigned char value = relayParsePayload(payload);
// Action to perform // Action to perform
ledStatus(ledID, bitState);
if (value == 2) {
_ledToggle(ledID);
} else {
_ledStatus(ledID, value == 1);
}
} }
} }
#endif #endif
unsigned char ledCount() {
unsigned char _ledCount() {
return _leds.size(); return _leds.size();
} }
void ledConfigure() {
ledAuto = getSetting("ledAuto", String() + LED_AUTO).toInt() == 1;
void _ledConfigure() {
for (unsigned int i=0; i < _leds.size(); i++) {
_ledMode(i, getSetting("ledMode", i, _ledMode(i)).toInt());
}
} }
// -----------------------------------------------------------------------------
void ledSetup() { void ledSetup() {
#ifdef LED1_PIN #ifdef LED1_PIN
_leds.push_back((led_t) { LED1_PIN, LED1_PIN_INVERSE });
_leds.push_back((led_t) { LED1_PIN, LED1_PIN_INVERSE, LED1_MODE, LED1_RELAY });
#endif #endif
#ifdef LED2_PIN #ifdef LED2_PIN
_leds.push_back((led_t) { LED2_PIN, LED2_PIN_INVERSE });
_leds.push_back((led_t) { LED2_PIN, LED2_PIN_INVERSE, LED2_MODE, LED2_RELAY });
#endif #endif
#ifdef LED3_PIN #ifdef LED3_PIN
_leds.push_back((led_t) { LED3_PIN, LED3_PIN_INVERSE });
_leds.push_back((led_t) { LED3_PIN, LED3_PIN_INVERSE, LED3_MODE, LED3_RELAY });
#endif #endif
#ifdef LED4_PIN #ifdef LED4_PIN
_leds.push_back((led_t) { LED4_PIN, LED4_PIN_INVERSE });
_leds.push_back((led_t) { LED4_PIN, LED4_PIN_INVERSE, LED4_MODE, LED4_RELAY });
#endif #endif
for (unsigned int i=0; i < _leds.size(); i++) { for (unsigned int i=0; i < _leds.size(); i++) {
pinMode(_leds[i].pin, OUTPUT); pinMode(_leds[i].pin, OUTPUT);
ledStatus(i, false);
_ledStatus(i, false);
} }
ledConfigure();
_ledConfigure();
#if MQTT_SUPPORT #if MQTT_SUPPORT
mqttRegister(ledMQTTCallback);
mqttRegister(_ledMQTTCallback);
#endif
#if WEB_SUPPORT
wsOnSendRegister(_ledWebSocketOnSend);
wsOnAfterParseRegister(_ledConfigure);
#endif #endif
DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size()); DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size());
DEBUG_MSG_P(PSTR("[LED] Led auto indicator is %s\n"), ledAuto ? "ON" : "OFF" );
} }
void ledLoop() { void ledLoop() {
#if LED_WIFI
if (ledAuto) showStatus();
#endif
for (unsigned char i=0; i<_leds.size(); i++) {
if (_ledMode(i) == LED_MODE_WIFI) {
if (wifiConnected()) {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 900, 100);
} else {
_ledBlink(i, 4900, 100);
}
} else {
_ledBlink(i, 500, 500);
}
}
if (_ledMode(i) == LED_MODE_MIXED) {
if (wifiConnected()) {
if (relayStatus(_leds[i].relay-1)) {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 900, 100);
} else {
_ledBlink(i, 4900, 100);
}
} else {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 100, 900);
} else {
_ledBlink(i, 100, 4900);
}
}
} else {
_ledBlink(i, 500, 500);
}
}
if (_ledMode(i) == LED_MODE_FOLLOW) {
_ledStatus(i, relayStatus(_leds[i].relay-1));
}
if (_ledMode(i) == LED_MODE_FOLLOW_INVERSE) {
_ledStatus(i, !relayStatus(_leds[i].relay-1));
}
if (_ledMode(i) == LED_MODE_FINDME) {
bool status = true;
for (unsigned char k=0; k<relayCount(); k++) {
if (relayStatus(k)) {
status = false;
break;
}
}
_ledStatus(i, status);
}
}
} }

+ 5
- 11
code/espurna/relay.ino View File

@ -19,7 +19,6 @@ typedef struct {
unsigned char pin; // GPIO pin for the relay unsigned char pin; // GPIO pin for the relay
unsigned char type; unsigned char type;
unsigned char reset_pin; unsigned char reset_pin;
unsigned char led;
unsigned long delay_on; unsigned long delay_on;
unsigned long delay_off; unsigned long delay_off;
@ -370,7 +369,7 @@ void _relayWebSocketOnSend(JsonObject& root) {
if (relayCount() == 0) return; if (relayCount() == 0) return;
root["relayVisible"] = 1; root["relayVisible"] = 1;
// Statuses // Statuses
JsonArray& relay = root.createNestedArray("relayStatus"); JsonArray& relay = root.createNestedArray("relayStatus");
for (unsigned char relayID=0; relayID<relayCount(); relayID++) { for (unsigned char relayID=0; relayID<relayCount(); relayID++) {
@ -642,16 +641,16 @@ void relaySetup() {
#else #else
#ifdef RELAY1_PIN #ifdef RELAY1_PIN
_relays.push_back((relay_t) { RELAY1_PIN, RELAY1_TYPE, RELAY1_RESET_PIN, RELAY1_LED, RELAY1_DELAY_ON, RELAY1_DELAY_OFF });
_relays.push_back((relay_t) { RELAY1_PIN, RELAY1_TYPE, RELAY1_RESET_PIN, RELAY1_DELAY_ON, RELAY1_DELAY_OFF });
#endif #endif
#ifdef RELAY2_PIN #ifdef RELAY2_PIN
_relays.push_back((relay_t) { RELAY2_PIN, RELAY2_TYPE, RELAY2_RESET_PIN, RELAY2_LED, RELAY2_DELAY_ON, RELAY2_DELAY_OFF });
_relays.push_back((relay_t) { RELAY2_PIN, RELAY2_TYPE, RELAY2_RESET_PIN, RELAY2_DELAY_ON, RELAY2_DELAY_OFF });
#endif #endif
#ifdef RELAY3_PIN #ifdef RELAY3_PIN
_relays.push_back((relay_t) { RELAY3_PIN, RELAY3_TYPE, RELAY3_RESET_PIN, RELAY3_LED, RELAY3_DELAY_ON, RELAY3_DELAY_OFF });
_relays.push_back((relay_t) { RELAY3_PIN, RELAY3_TYPE, RELAY3_RESET_PIN, RELAY3_DELAY_ON, RELAY3_DELAY_OFF });
#endif #endif
#ifdef RELAY4_PIN #ifdef RELAY4_PIN
_relays.push_back((relay_t) { RELAY4_PIN, RELAY4_TYPE, RELAY4_RESET_PIN, RELAY4_LED, RELAY4_DELAY_ON, RELAY4_DELAY_OFF });
_relays.push_back((relay_t) { RELAY4_PIN, RELAY4_TYPE, RELAY4_RESET_PIN, RELAY4_DELAY_ON, RELAY4_DELAY_OFF });
#endif #endif
#endif #endif
@ -696,11 +695,6 @@ void relayLoop(void) {
// Call the provider to perform the action // Call the provider to perform the action
_relayProviderStatus(id, status); _relayProviderStatus(id, status);
// Change the binded LED if any
if (_relays[id].led > 0) {
ledStatus(_relays[id].led - 1, status);
}
// Send MQTT // Send MQTT
#if MQTT_SUPPORT #if MQTT_SUPPORT
relayMQTT(id); relayMQTT(id);


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


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

@ -306,14 +306,17 @@
<label class="pure-u-1 pure-u-md-1-4">Hostname</label> <label class="pure-u-1 pure-u-md-1-4">Hostname</label>
<input name="hostname" class="pure-u-1 pure-u-md-3-4" type="text" action="reboot" tabindex="1" /> <input name="hostname" class="pure-u-1 pure-u-md-3-4" type="text" action="reboot" tabindex="1" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">This name will identify this device in your network (http://&lt;hostname&gt;.local). For this setting to take effect you should restart the wifi interface clicking the "Reconnect" button.</div>
<div class="pure-u-1 pure-u-md-3-4 hint">
This name will identify this device in your network (http://&lt;hostname&gt;.local). For this setting to take effect you should restart the wifi interface clicking the "Reconnect" button.
</div>
</div> </div>
<div class="pure-g"> <div class="pure-g">
<label class="pure-u-1 pure-u-md-1-4">Double click delay</label> <label class="pure-u-1 pure-u-md-1-4">Double click delay</label>
<input name="btnDelay" class="pure-u-1 pure-u-md-3-4" type="number" action="reboot" min="0" step="100" max="1000" tabindex="6" /> <input name="btnDelay" class="pure-u-1 pure-u-md-3-4" type="number" action="reboot" min="0" step="100" max="1000" tabindex="6" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Delay in milliseconds to detect a double click (from 0 to 1000ms).<br />
<div class="pure-u-1 pure-u-md-3-4 hint">
Delay in milliseconds to detect a double click (from 0 to 1000ms).<br />
The lower this number the faster the device will respond to button clicks but the harder it will be to get a double click. The lower this number the faster the device will respond to button clicks but the harder it will be to get a double click.
Increase this number if you are having trouble to double click the button. Increase this number if you are having trouble to double click the button.
Set this value to 0 to disable double click. You won't be able to set the device in AP mode manually but your device will respond immediately to button clicks.<br /> Set this value to 0 to disable double click. You won't be able to set the device in AP mode manually but your device will respond immediately to button clicks.<br />
@ -321,6 +324,26 @@
</div> </div>
</div> </div>
<div class="pure-g module module-led">
<label class="pure-u-1 pure-u-md-1-4">LED mode</label>
<div class="pure-u-1 pure-u-md-3-4">
<select name="ledMode0" tabindex="7">
<option value="1">WiFi status</option>
<option value="0">MQTT managed</option>
<option value="4">Find me</option>
<option value="5">Mixed</option>
</select>
</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">
This setting defines the behaviour of the main LED in the board.<br />
When in "WiFi status" it will blink at 1Hz when trying to connecting. If successfully connected if will briefly lit every 5 seconds if in STA mode or every second if in AP mode.<br />
When in "MQTT managed" mode you will be able to set the LED state sending a message to "&lt;base_topic&gt;/led/0/set" with a payload of 0, 1 or 2 (to toggle it).<br />
When in "Find me" mode the LED will be ON when all relays are OFF. This is meant to locate switches at night.<br />
When in "Mixed" mode it will follow the WiFi status but will stay mostly on when relays are OFF, and mostly OFF when any of them is ON.
</div>
</div>
<div class="pure-g module module-alexa"> <div class="pure-g module module-alexa">
<div class="pure-u-1 pure-u-sm-1-4"><label>Alexa integration</label></div> <div class="pure-u-1 pure-u-sm-1-4"><label>Alexa integration</label></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="alexaEnabled" tabindex="13" /></div> <div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="alexaEnabled" tabindex="13" /></div>


Loading…
Cancel
Save