Browse Source

Adding double and long click support, double to SoftAP mode, long to reset board, single click toggles relay

fastled
Xose Pérez 8 years ago
parent
commit
7850a2ae22
4 changed files with 137 additions and 70 deletions
  1. +4
    -4
      README.md
  2. +43
    -10
      code/lib/DebounceEvent/DebounceEvent.cpp
  3. +15
    -4
      code/lib/DebounceEvent/DebounceEvent.h
  4. +75
    -52
      code/src/code.ino

+ 4
- 4
README.md View File

@ -15,7 +15,8 @@ You can read about this board and firmware in [my blog][2].
* Flashing firmware Over-The-Air (OTA)
* Up to 3 configurable WIFI networks
* MQTT support with configurable host and topic
* Manual switch ON/OFF with button
* Manual switch ON/OFF with button (single click the button)
* AP mode backup (double click the button)
* Support for custom RF module (check blog post)
* Visual status of the connection via the LED
@ -60,14 +61,13 @@ It configures the hardware (button, LED, relay), the SPIFFS memory access, the
WIFI, the WebServer and MQTT connection.
Obviously the default values for WIFI network and MQTT will probably not match
your requirements. Either it connects to a WiFi or not, it will set up a Soft AP
named "SONOFF_XXXX", where XXXX are the las 2 bytes of the radio MAC. Connect with
your requirements. The device will start in Soft AP creating a WIFI SSID named "SONOFF_XXXXXX", where XXXXXX are the last 3 bytes of the radio MAC. Connect with
phone, PC, laptop, whatever to that network, password is "fibonacci". Once connected
browse to 192.168.4.1 and you will be presented a configuration page where you will
be able to define up to 3 possible WIFI networks and the MQTT configuration parameters.
It will then try to connect to the first WIFI network. If fail it will try the second
in 30 seconds, and so on. Once connected it will try to connect the MQTT server.
in 30 seconds, and so on. Once connected it will try to connect the MQTT server. If there are no configured networks or none of the configured ones is reachable it defaults to SoftAP mode. You can also switch to SoftAP mode by double clicking the on board button.
The device will publish the relay state to the given topic and it will subscribe to
the same topic plus "/set" for remote switching. So if your topic is "/home/living/switch"


+ 43
- 10
code/lib/DebounceEvent/DebounceEvent.cpp View File

@ -41,34 +41,63 @@ DebounceEvent::DebounceEvent(uint8_t pin, callback_t callback, uint8_t defaultSt
bool DebounceEvent::loop() {
// holds whether status has changed or not
static bool pending = false;
bool changed = false;
_event = EVENT_NONE;
if (digitalRead(_pin) != _status) {
// Debounce
delay(_delay);
uint8_t newStatus = digitalRead(_pin);
if (newStatus != _status) {
changed = true;
pending = false;
_status = newStatus;
// raise events if callback defined
if (_callback) {
// raise change event
_callback(_pin, EVENT_CHANGED);
// released
if (_status == _defaultStatus) {
if (_status == _defaultStatus) {
// raise released event
_callback(_pin, EVENT_RELEASED);
// get event
if (millis() - _this_start > LONG_CLICK_DELAY) {
_event = EVENT_LONG_CLICK;
} else if (millis() - _last_start < DOUBLE_CLICK_DELAY ) {
_event = EVENT_DOUBLE_CLICK;
} else {
// raise pressed event
_callback(_pin, EVENT_PRESSED);
Serial.println("deferring");
changed = false;
pending = true;
//_event = EVENT_SINGLE_CLICK;
}
// pressed
} else {
_last_start = _this_start;
_this_start = millis();
_event = EVENT_PRESSED;
}
}
}
if (pending && (millis() - _this_start > DOUBLE_CLICK_DELAY) && (!changed) && (_status == _defaultStatus)) {
Serial.println("catched");
pending = false;
changed = true;
_event = EVENT_SINGLE_CLICK;
}
if (changed) {
if (_callback) {
_callback(_pin, EVENT_CHANGED);
_callback(_pin, _event);
}
}
return changed;
}
@ -76,3 +105,7 @@ bool DebounceEvent::loop() {
bool DebounceEvent::pressed() {
return (_status != _defaultStatus);
}
uint8_t DebounceEvent::getEvent() {
return _event;
}

+ 15
- 4
code/lib/DebounceEvent/DebounceEvent.h View File

@ -21,10 +21,17 @@
#ifndef _DEBOUNCE_EVENT_h
#define _DEBOUNCE_EVENT_h
#define DEBOUNCE_DELAY 100
#define EVENT_CHANGED 0
#define EVENT_PRESSED 1
#define EVENT_RELEASED 2
#define DEBOUNCE_DELAY 50
#define LONG_CLICK_DELAY 1000
#define DOUBLE_CLICK_DELAY 500
#define EVENT_NONE 0
#define EVENT_CHANGED 1
#define EVENT_PRESSED 2
#define EVENT_RELEASED 3
#define EVENT_SINGLE_CLICK 3
#define EVENT_DOUBLE_CLICK 4
#define EVENT_LONG_CLICK 5
typedef void(*callback_t)(uint8_t pin, uint8_t event);
@ -34,6 +41,9 @@ class DebounceEvent {
uint8_t _pin;
uint8_t _status;
uint8_t _event;
unsigned long _this_start;
unsigned long _last_start;
uint8_t _defaultStatus;
unsigned long _delay;
callback_t _callback;
@ -43,6 +53,7 @@ class DebounceEvent {
DebounceEvent(uint8_t pin, callback_t callback = false, uint8_t defaultStatus = HIGH, unsigned long delay = DEBOUNCE_DELAY);
bool pressed();
bool loop();
uint8_t getEvent();
};


+ 75
- 52
code/src/code.ino View File

@ -43,21 +43,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define ENABLE_WEBSERVER 1
#define ENABLE_ENERGYMONITOR 1
#define APP_NAME "Espurna 0.9"
#define APP_NAME "Espurna 0.9.1"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"
#define MODEL "SONOFF"
#define BUTTON_PIN 0
#define RELAY_PIN 12
#define LED_PIN 13
#define LED_PIN 13ter
#define ADMIN_PASS "fibonacci"
#define CONFIG_PATH "/.config"
#define WIFI_CONNECT_TIMEOUT 5000
#define WIFI_RECONNECT_DELAY 5000
#define MQTT_RECONNECT_DELAY 10000
#define NETWORK_BUFFER 3
#define BUFFER_SIZE 1024
#define STATUS_UPDATE_INTERVAL 10000
@ -65,10 +62,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RF_CHANNEL 31
#define RF_DEVICE 1
#define MQTT_RECONNECT_DELAY 10000
#define MQTT_RETAIN true
#define MQTT_TOPIC "/test/switch/{identifier}"
#define MQTT_PORT 1883
#define NETWORK_BUFFER 3
#define WIFI_CONNECT_TIMEOUT 5000
#define WIFI_RECONNECT_DELAY 5000
#define WIFI_STATUS_CONNECTING 0
#define WIFI_STATUS_CONNECTED 1
#define WIFI_STATUS_AP 2
#define CURRENT_PIN A0
#define REFERENCE_VOLTAGE 1.0
#define MAINS_VOLTAGE 230.0
@ -84,7 +89,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
char identifier[20] = {0};
byte network = 0;
byte status = WIFI_STATUS_CONNECTING;
String configSSID[NETWORK_BUFFER];
String configPASS[NETWORK_BUFFER];
@ -214,26 +219,22 @@ void toggleRelay() {
char * getIdentifier() {
if (identifier[0] == 0) {
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String name = MODEL + String("_") + String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
name.toUpperCase();
byte length = std::min(20, (int) name.length() + 1);
name.toCharArray(identifier, length);
sprintf(identifier, "%s_%06X", MODEL, ESP.getChipId());
}
return identifier;
}
void wifiSetup(bool force) {
void wifiSetupAP() {
// Set WIFI module to Mixed Mode
WiFi.mode(WIFI_AP_STA);
// Set WIFI module AP mode
WiFi.mode(WIFI_AP);
#ifdef DEBUG
WiFi.printDiag(Serial);
#endif
// SoftAP mode
WiFi.softAP(getIdentifier(), ADMIN_PASS);
status = WIFI_STATUS_AP;
#ifdef DEBUG
Serial.print("[AP Mode] SSID: ");
Serial.print(getIdentifier());
@ -243,45 +244,66 @@ void wifiSetup(bool force) {
Serial.println(WiFi.softAPIP());
#endif
// STA mode
}
void wifiSetupSTA(bool force) {
byte network = 0;
if (force || (WiFi.status() != WL_CONNECTED)) {
if (configSSID[network].length() > 0) {
#if ENABLE_MQTT
if (mqtt.connected()) mqtt.disconnect();
#endif
// Set WIFI module to STA mode
WiFi.mode(WIFI_STA);
#ifdef DEBUG
WiFi.printDiag(Serial);
#endif
#if ENABLE_RF
RemoteReceiver::disable();
#endif
#if ENABLE_MQTT
if (mqtt.connected()) mqtt.disconnect();
#endif
#if ENABLE_RF
RemoteReceiver::disable();
#endif
char ssid[configSSID[network].length()+1];
char pass[configPASS[network].length()+1];
configSSID[network].toCharArray(ssid, configSSID[network].length()+1);
configPASS[network].toCharArray(pass, configPASS[network].length()+1);
WiFi.begin(ssid, pass);
while (network < 3) {
#ifdef DEBUG
Serial.println("Connecting to WIFI " + configSSID[network]);
#endif
if (configSSID[network].length() > 0) {
char ssid[configSSID[network].length()+1];
char pass[configPASS[network].length()+1];
configSSID[network].toCharArray(ssid, configSSID[network].length()+1);
configPASS[network].toCharArray(pass, configPASS[network].length()+1);
WiFi.begin(ssid, pass);
#ifdef DEBUG
Serial.println("Connecting to WIFI " + configSSID[network]);
#endif
// Wait
unsigned long timeout = millis() + WIFI_CONNECT_TIMEOUT;
while (timeout > millis()) {
showStatus();
if (WiFi.status() == WL_CONNECTED) break;
delay(100);
}
// Wait
unsigned long timeout = millis() + WIFI_CONNECT_TIMEOUT;
while (timeout > millis()) {
showStatus();
if (WiFi.status() == WL_CONNECTED) break;
delay(100);
}
#if ENABLE_RF
RemoteReceiver::enable();
#endif
if (WiFi.status() == WL_CONNECTED) break;
network++;
}
#if ENABLE_RF
RemoteReceiver::enable();
#endif
}
if (WiFi.status() == WL_CONNECTED) {
WiFi.setAutoConnect(true);
status = WIFI_STATUS_CONNECTED;
#ifdef DEBUG
Serial.print("[STA Mode] SSID: ");
Serial.print(WiFi.SSID());
@ -289,22 +311,22 @@ void wifiSetup(bool force) {
Serial.println(WiFi.localIP());
#endif
} else {
network = (network + 1) % NETWORK_BUFFER;
#ifdef DEBUG
Serial.println("[STA Mode] NOT CONNECTED");
#endif
wifiSetupAP();
}
}
void wifiLoop() {
static unsigned long timeout = millis();
if (WiFi.status() != WL_CONNECTED) {
if (timeout < millis()) {
wifiSetup(false);
timeout = millis() + WIFI_RECONNECT_DELAY;
}
// Trying to reconnect in case of disconnection
if ((status == WIFI_STATUS_CONNECTED) && (WiFi.status() != WL_CONNECTED)) {
status = WIFI_STATUS_CONNECTING;
wifiSetupSTA(false);
}
}
// -----------------------------------------------------------------------------
@ -459,8 +481,7 @@ void wifiLoop() {
#if ENABLE_RF
rfBuildCodes();
#endif
network = 0;
wifiSetup(true);
wifiSetupSTA(true);
}
@ -963,7 +984,9 @@ void showStatus() {
void hardwareLoop() {
if (button1.loop()) {
if (!button1.pressed()) toggleRelay();
if (button1.getEvent() == EVENT_SINGLE_CLICK) toggleRelay();
if (button1.getEvent() == EVENT_DOUBLE_CLICK) wifiSetupAP();
if (button1.getEvent() == EVENT_LONG_CLICK) ESP.restart();
}
showStatus();
}
@ -994,7 +1017,7 @@ void setup() {
OTASetup();
#endif
loadConfig();
wifiSetup(false);
wifiSetupSTA(false);
#if ENABLE_WEBSERVER
webServerSetup();
#endif


Loading…
Cancel
Save