Browse Source

Merge branch 'master' into inching

Conflicts:
	code/src/config/general.h
	code/src/relay.ino
	code/src/web.ino
fastled
Xose Pérez 7 years ago
parent
commit
92600611a5
19 changed files with 403 additions and 108 deletions
  1. +6
    -0
      CHANGELOG.md
  2. +9
    -7
      code/lib/DebounceEvent/DebounceEvent.cpp
  3. +1
    -0
      code/lib/DebounceEvent/DebounceEvent.h
  4. +21
    -0
      code/platformio.ini
  5. +18
    -1
      code/src/config/general.h
  6. +42
    -24
      code/src/config/hardware.h
  7. +4
    -4
      code/src/emon.ino
  8. +1
    -1
      code/src/fauxmo.ino
  9. +109
    -11
      code/src/led.ino
  10. +7
    -3
      code/src/main.ino
  11. +9
    -5
      code/src/mqtt.ino
  12. +1
    -1
      code/src/nofuss.ino
  13. +6
    -6
      code/src/pow.ino
  14. +32
    -16
      code/src/relay.ino
  15. +2
    -2
      code/src/rf.ino
  16. +49
    -8
      code/src/settings.ino
  17. +12
    -12
      code/src/web.ino
  18. +14
    -0
      code/src/wifi.ino
  19. +60
    -7
      docs/Hardware.md

+ 6
- 0
CHANGELOG.md View File

@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added last-modified header to static contents
- Added support for multi-button boards (SONOFF_4CH)
- Added support for WorkChoice ecoPlug (ECOPLUG). Thanks to David Myers
- Added support for Sonoff SV
- Added DNS captive portal for AP mode
- Force password changing if it's the default one
- Comment out hardware selection in hardware.h if using Arduino IDE
@ -15,6 +17,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Using unreleased AsyncMqttClient with stability improvements
- Better decoupling between MQTT and relays/websockets
### Fixed
- Issue #14 MQTT Connection with Username an Password not working
- Issue #11 Compile error when building sonoff-dual-debug
## [1.1.0] 2016-12-06
### Added
- Added support for DS18B20 temperature sensor. Thanks to Francesco Boscarino


+ 9
- 7
code/lib/DebounceEvent/DebounceEvent.cpp View File

@ -45,7 +45,6 @@ DebounceEvent::DebounceEvent(uint8_t pin, uint8_t defaultStatus, unsigned long d
bool DebounceEvent::loop() {
// holds whether status has changed or not
static bool pending = false;
bool changed = false;
_event = EVENT_NONE;
@ -57,7 +56,7 @@ bool DebounceEvent::loop() {
if (newStatus != _status) {
changed = true;
pending = false;
_clicked = false;
_status = newStatus;
// released
@ -69,9 +68,13 @@ bool DebounceEvent::loop() {
} else if (millis() - _last_start < DOUBLE_CLICK_DELAY ) {
_event = EVENT_DOUBLE_CLICK;
} else {
// We are not setting the event type here because we still don't
// know what kind of event it will be (it might be a double click).
// Instead we are setting the _clicked variable to check later
_clicked = true;
changed = false;
pending = true;
//_event = EVENT_SINGLE_CLICK;
}
// pressed
@ -86,8 +89,8 @@ bool DebounceEvent::loop() {
}
}
if (pending && (millis() - _this_start > DOUBLE_CLICK_DELAY) && (!changed) && (_status == _defaultStatus)) {
pending = false;
if (_clicked && (millis() - _this_start > DOUBLE_CLICK_DELAY) && (!changed) && (_status == _defaultStatus)) {
_clicked = false;
changed = true;
_event = EVENT_SINGLE_CLICK;
}
@ -99,7 +102,6 @@ bool DebounceEvent::loop() {
}
}
return changed;
}


+ 1
- 0
code/lib/DebounceEvent/DebounceEvent.h View File

@ -42,6 +42,7 @@ class DebounceEvent {
uint8_t _pin;
uint8_t _status;
uint8_t _event;
bool _clicked = false;
unsigned long _this_start;
unsigned long _last_start;
uint8_t _defaultStatus;


+ 21
- 0
code/platformio.ini View File

@ -219,3 +219,24 @@ build_flags = -g -DDEBUG_PORT=Serial -DDEBUG_PORT=Serial -DESP_RELAY_BOARD -DENA
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
[env:ecoplug-debug]
platform = espressif8266
framework = arduino
board = esp01_1m
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
extra_script = pio_hooks.py
build_flags = -g -Wl,-Tesp8266.flash.1m128.ld -DDEBUG_PORT=Serial -DECOPLUG
[env:ecoplug-debug-ota]
platform = espressif8266
framework = arduino
board = esp01_1m
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
extra_script = pio_hooks.py
build_flags = -g -Wl,-Tesp8266.flash.1m128.ld -DDEBUG_PORT=Serial -DECOPLUG
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266

+ 18
- 1
code/src/config/general.h View File

@ -37,6 +37,15 @@
// 0 means no inching, 1 means normally off, 2 normally on
#define RELAY_INCHING RELAY_INCHING_NONE
//--------------------------------------------------------------------------------
// 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 first defined LED to show wifi status.
#define LED_AUTO 1
// -----------------------------------------------------------------------------
// WIFI & WEB
// -----------------------------------------------------------------------------
@ -47,6 +56,7 @@
#define HTTP_USERNAME "admin"
#define WS_BUFFER_SIZE 5
#define WS_TIMEOUT 1800000
#define DNS_PORT 53
// -----------------------------------------------------------------------------
// OTA & NOFUSS
@ -67,7 +77,8 @@
#define MQTT_QOS 0
#define MQTT_KEEPALIVE 30
#define MQTT_RECONNECT_DELAY 10000
#define MQTT_RELAY_TOPIC "/relay/%d"
#define MQTT_RELAY_TOPIC "/relay"
#define MQTT_LED_TOPIC "/led"
#define MQTT_IP_TOPIC "/ip"
#define MQTT_VERSION_TOPIC "/version"
#define MQTT_FSVERSION_TOPIC "/fsversion"
@ -77,6 +88,12 @@
#define MQTT_DISCONNECT_EVENT 1
#define MQTT_MESSAGE_EVENT 2
// Custom get and set postfixes
// Use something like "/status" or "/set", with trailing slash
#define MQTT_USE_GETTER ""
#define MQTT_USE_SETTER ""
// -----------------------------------------------------------------------------
// NTP
// -----------------------------------------------------------------------------


+ 42
- 24
code/src/config/hardware.h View File

@ -10,12 +10,21 @@
//#define SONOFF_POW
//#define SONOFF_DUAL
//#define SONOFF_4CH
//#define SONOFF_SV
//#define SLAMPHER
//#define S20
//#define ESP_RELAY_BOARD
//#define ECOPLUG
//#define ESPURNA
//#define ENABLE_DHT 1
//#define ENABLE_DS18B20 1
//#define ENABLE_EMON 1
//#define ENABLE_HLW8018 1
//#define ENABLE_RF 1
//#define ENABLE_FAUXMO 1
//#define ENABLE_NOFUSS 1
// -----------------------------------------------------------------------------
// NODEMCUv2 development board
// -----------------------------------------------------------------------------
@ -26,8 +35,8 @@
#define DEVICE "LOLIN"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 2
#define LED_PIN_INVERSE 0
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
// -----------------------------------------------------------------------------
// Itead Studio boards
@ -39,8 +48,8 @@
#define DEVICE "SONOFF"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 13
#define LED_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(SONOFF_TH)
@ -48,8 +57,8 @@
#define DEVICE "SONOFF_TH"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 13
#define LED_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(SONOFF_TOUCH)
@ -57,8 +66,8 @@
#define DEVICE "SONOFF_TOUCH"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 13
#define LED_PIN_INVERSE 1
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(SONOFF_POW)
@ -66,8 +75,8 @@
#define DEVICE "SONOFF_POW"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 15
#define LED_PIN_INVERSE 1
#define LED1_PIN 15
#define LED1_PIN_INVERSE 0
#define ENABLE_POW 1
#elif defined(SONOFF_DUAL)
@ -75,8 +84,8 @@
#define MANUFACTURER "ITEAD"
#define DEVICE "SONOFF_DUAL"
#define BUTTON1_PIN 0
#define LED_PIN 13
#define LED_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#undef SERIAL_BAUDRATE
#define SERIAL_BAUDRATE 19230
@ -92,8 +101,17 @@
#define RELAY2_PIN 5
#define RELAY3_PIN 4
#define RELAY4_PIN 15
#define LED_PIN 13
#define LED_PIN_INVERSE 1
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(SONOFF_SV)
#define MANUFACTURER "ITEAD"
#define DEVICE "SONOFF_SV"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(SLAMPHER)
@ -101,8 +119,8 @@
#define DEVICE "SLAMPHER"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 13
#define LED_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(S20)
@ -110,8 +128,8 @@
#define DEVICE "S20"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 13
#define LED_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
#elif defined(ITEAD_1CH_INCHING)
@ -136,8 +154,8 @@
#define BUTTON2_PIN 2
#define RELAY1_PIN 12
#define RELAY2_PIN 13
#define LED_PIN 16
#define LED_PIN_INVERSE 1
#define LED1_PIN 16
#define LED1_PIN_INVERSE 0
// -----------------------------------------------------------------------------
// WorkChoice ecoPlug
@ -149,8 +167,8 @@
#define DEVICE "ECOPLUG"
#define BUTTON1_PIN 13
#define RELAY_PIN 15
#define LED_PIN 2
#define LED_PIN_INVERSE 1
#define LED1_PIN 2
#define LED1_PIN_INVERSE 0
// -----------------------------------------------------------------------------
// ESPurna board (still beta)
@ -162,8 +180,8 @@
#define DEVICE "ESPURNA"
#define BUTTON1_PIN 0
#define RELAY1_PIN 12
#define LED_PIN 13
#define LED_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 0
// -----------------------------------------------------------------------------
// Unknown hardware


+ 4
- 4
code/src/emon.ino View File

@ -39,10 +39,10 @@ void powerMonitorSetup() {
// backwards compatibility
String tmp;
tmp = getSetting("pwMainsVoltage", String() + EMON_MAINS_VOLTAGE);
tmp = getSetting("pwMainsVoltage", EMON_MAINS_VOLTAGE);
setSetting("emonMains", tmp);
delSetting("pwMainsVoltage");
tmp = getSetting("pwCurrentRatio", String() + EMON_CURRENT_RATIO);
tmp = getSetting("pwCurrentRatio", EMON_CURRENT_RATIO);
setSetting("emonRatio", tmp);
delSetting("pwCurrentRatio");
@ -50,7 +50,7 @@ void powerMonitorSetup() {
currentCallback,
EMON_ADC_BITS,
EMON_REFERENCE_VOLTAGE,
getSetting("emonRatio", String(EMON_CURRENT_RATIO)).toFloat()
getSetting("emonRatio", EMON_CURRENT_RATIO).toFloat()
);
emon.setPrecision(EMON_CURRENT_PRECISION);
}
@ -91,7 +91,7 @@ void powerMonitorLoop() {
sum += current;
++measurements;
float mainsVoltage = getSetting("emonMains", String(EMON_MAINS_VOLTAGE)).toFloat();
float mainsVoltage = getSetting("emonMains", EMON_MAINS_VOLTAGE).toFloat();
//DEBUG_MSG("[ENERGY] Power now: %dW\n", int(current * mainsVoltage));


+ 1
- 1
code/src/fauxmo.ino View File

@ -18,7 +18,7 @@ fauxmoESP fauxmo;
// -----------------------------------------------------------------------------
void fauxmoConfigure() {
fauxmo.enable(getSetting("fauxmoEnabled", String(FAUXMO_ENABLED)).toInt() == 1);
fauxmo.enable(getSetting("fauxmoEnabled", FAUXMO_ENABLED).toInt() == 1);
}
void fauxmoSetup() {


+ 109
- 11
code/src/led.ino View File

@ -11,36 +11,134 @@ Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
// LED
// -----------------------------------------------------------------------------
#ifdef LED_PIN
#ifdef LED1_PIN
void blink(unsigned long delayOff, unsigned long delayOn) {
typedef struct {
unsigned char pin;
bool reverse;
} led_t;
std::vector<led_t> _leds;
bool ledAuto;
bool ledStatus(unsigned char id) {
if (id <= _leds.size()) return false;
bool status = digitalRead(_leds[id].pin);
return _leds[id].reverse ? !status : status;
}
bool ledStatus(unsigned char id, bool status) {
if (id <= _leds.size()) return false;
bool s = _leds[id].reverse ? !status : status;
digitalWrite(_leds[id].pin, _leds[id].reverse ? !status : status);
return status;
}
bool ledToggle(unsigned char id) {
if (id <= _leds.size()) return false;
return ledStatus(id, !ledStatus(id));
}
void ledBlink(unsigned char id, unsigned long delayOff, unsigned long delayOn) {
if (id <= _leds.size()) return;
static unsigned long next = millis();
static bool status = HIGH;
if (next < millis()) {
status = !status;
digitalWrite(LED_PIN, LED_PIN_INVERSE ? !status : status);
next += ((status) ? delayOff : delayOn);
next += (ledToggle(id) ? delayOn : delayOff);
}
}
void showStatus() {
if (wifiConnected()) {
if (WiFi.getMode() == WIFI_AP) {
blink(2000, 2000);
ledBlink(0, 2000, 2000);
} else {
blink(5000, 500);
ledBlink(0, 5000, 500);
}
} else {
blink(500, 500);
ledBlink(0, 500, 500);
}
}
void ledMQTTCallback(unsigned int type, const char * topic, const char * payload) {
static bool isFirstMessage = true;
String mqttSetter = getSetting("mqttSetter", MQTT_USE_SETTER);
if (type == MQTT_CONNECT_EVENT) {
char buffer[strlen(MQTT_LED_TOPIC) + mqttSetter.length() + 3];
sprintf(buffer, "%s/+%s", MQTT_LED_TOPIC, mqttSetter.c_str());
mqttSubscribe(buffer);
}
if (type == MQTT_MESSAGE_EVENT) {
// Match topic
String t = String(topic);
if (!t.startsWith(MQTT_LED_TOPIC)) return;
if (!t.endsWith(mqttSetter)) return;
// Get led ID
unsigned int ledID = topic[strlen(MQTT_LED_TOPIC)+1] - '0';
if (ledID >= ledCount()) ledID = 0;
// 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;
}
// Action to perform
ledStatus(ledID, bitState);
}
}
unsigned char ledCount() {
return _leds.size();
}
void ledConfigure() {
ledAuto = getSetting("ledAuto", String() + LED_AUTO).toInt() == 1;
}
void ledSetup() {
pinMode(LED_PIN, OUTPUT);
#ifdef LED1_PIN
_leds.push_back((led_t) { LED1_PIN, LED1_PIN_INVERSE });
#endif
#ifdef LED2_PIN
_leds.push_back((led_t) { LED2_PIN, LED2_PIN_INVERSE });
#endif
#ifdef LED3_PIN
_leds.push_back((led_t) { LED3_PIN, LED3_PIN_INVERSE });
#endif
#ifdef LED4_PIN
_leds.push_back((led_t) { LED4_PIN, LED4_PIN_INVERSE });
#endif
for (unsigned int i=0; i < _leds.size(); i++) {
pinMode(_leds[i].pin, OUTPUT);
ledStatus(i, false);
}
ledConfigure();
mqttRegister(ledMQTTCallback);
DEBUG_MSG("[LED] Number of leds: %d\n", _leds.size());
}
void ledLoop() {
showStatus();
if (ledAuto) showStatus();
}
#else


+ 7
- 3
code/src/main.ino View File

@ -29,8 +29,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <ESPAsyncWebServer.h>
#include <AsyncMqttClient.h>
#include "FS.h"
String getSetting(const String& key, String defaultValue = "");
bool relayStatus(unsigned char id, bool status, bool report = true);
void mqttRegister(void (*callback)(unsigned int, const char *, const char *));
template<typename T> bool setSetting(const String& key, T value);
template<typename T> String getSetting(const String& key, T defaultValue);
// -----------------------------------------------------------------------------
// METHODS
@ -85,9 +86,12 @@ void welcome() {
DEBUG_MSG("%s\n%s\n\n", (char *) APP_AUTHOR, (char *) APP_WEBSITE);
//DEBUG_MSG("Device: %s\n", (char *) getIdentifier().c_str());
DEBUG_MSG("ChipID: %06X\n", ESP.getChipId());
DEBUG_MSG("CPU frequency: %d MHz\n", ESP.getCpuFreqMHz());
DEBUG_MSG("Last reset reason: %s\n", (char *) ESP.getResetReason().c_str());
DEBUG_MSG("Memory size: %d bytes\n", ESP.getFlashChipSize());
DEBUG_MSG("Free heap: %d bytes\n", ESP.getFreeHeap());
DEBUG_MSG("Firmware size: %d bytes\n", ESP.getSketchSize());
DEBUG_MSG("Free firmware space: %d bytes\n", ESP.getFreeSketchSpace());
FSInfo fs_info;
if (SPIFFS.info(fs_info)) {
DEBUG_MSG("File system total size: %d bytes\n", fs_info.totalBytes);
@ -108,7 +112,7 @@ void setup() {
settingsSetup();
if (getSetting("hostname").length() == 0) {
setSetting("hostname", String() + getIdentifier());
setSetting("hostname", getIdentifier());
saveSettings();
}


+ 9
- 5
code/src/mqtt.ino View File

@ -57,6 +57,7 @@ void _mqttOnConnect(bool sessionPresent) {
// Build MQTT topics
buildTopics();
mqtt.setWill((mqttTopic + MQTT_HEARTBEAT_TOPIC).c_str(), MQTT_QOS, MQTT_RETAIN, (char *) "0");
// Say hello and report our IP and VERSION
mqttSend((char *) MQTT_IP_TOPIC, (char *) getIP().c_str());
@ -100,7 +101,7 @@ void mqttConnect() {
if (!mqtt.connected()) {
String host = getSetting("mqttServer", MQTT_SERVER);
String port = getSetting("mqttPort", String(MQTT_PORT));
String port = getSetting("mqttPort", MQTT_PORT);
String user = getSetting("mqttUser");
String pass = getSetting("mqttPassword");
@ -112,12 +113,15 @@ void mqttConnect() {
mqtt
.setKeepAlive(MQTT_KEEPALIVE)
.setCleanSession(false)
//.setWill("topic/online", 2, true, "no")
.setClientId(getSetting("hostname", HOSTNAME).c_str());
if ((user != "") & (pass != "")) {
DEBUG_MSG(" as user %s.\n", (char *) user.c_str());
mqtt.setCredentials(user.c_str(), pass.c_str());
if ((user != "") && (pass != "")) {
DEBUG_MSG(" as user '%s'.\n", (char *) user.c_str());
char username[user.length()+1];
user.toCharArray(username, user.length()+1);
char password[pass.length()+1];
pass.toCharArray(password, pass.length()+1);
mqtt.setCredentials(username, password);
} else {
DEBUG_MSG(" anonymously\n");
}


+ 1
- 1
code/src/nofuss.ino View File

@ -74,7 +74,7 @@ void nofussLoop() {
static unsigned long last_check = 0;
if (!wifiConnected()) return;
unsigned long interval = getSetting("nofussInterval", String(NOFUSS_INTERVAL)).toInt();
unsigned long interval = getSetting("nofussInterval", NOFUSS_INTERVAL).toInt();
if ((last_check > 0) && ((millis() - last_check) < interval)) return;
last_check = millis();
NoFUSSClient.handle();


+ 6
- 6
code/src/pow.ino View File

@ -41,18 +41,18 @@ void powDettachInterrupts() {
}
void powSaveCalibration() {
setSetting("powPowerMult", String() + hlw8012.getPowerMultiplier());
setSetting("powCurrentMult", String() + hlw8012.getCurrentMultiplier());
setSetting("powVoltageMult", String() + hlw8012.getVoltageMultiplier());
setSetting("powPowerMult", hlw8012.getPowerMultiplier());
setSetting("powCurrentMult", hlw8012.getCurrentMultiplier());
setSetting("powVoltageMult", hlw8012.getVoltageMultiplier());
}
void powRetrieveCalibration() {
double value;
value = getSetting("powPowerMult", "0").toFloat();
value = getSetting("powPowerMult", 0).toFloat();
if (value > 0) hlw8012.setPowerMultiplier((int) value);
value = getSetting("powCurrentMult", "0").toFloat();
value = getSetting("powCurrentMult", 0).toFloat();
if (value > 0) hlw8012.setCurrentMultiplier((int) value);
value = getSetting("powVoltageMult", "0").toFloat();
value = getSetting("powVoltageMult", 0).toFloat();
if (value > 0) hlw8012.setVoltageMultiplier((int) value);
}


+ 32
- 16
code/src/relay.ino View File

@ -24,8 +24,10 @@ Ticker inching;
// -----------------------------------------------------------------------------
void relayMQTT(unsigned char id) {
char buffer[10];
sprintf(buffer, MQTT_RELAY_TOPIC, id);
if (id >= _relays.size()) return;
String mqttGetter = getSetting("mqttGetter", MQTT_USE_GETTER);
char buffer[strlen(MQTT_RELAY_TOPIC) + mqttGetter.length() + 3];
sprintf(buffer, "%s/%d%s", MQTT_RELAY_TOPIC, id, mqttGetter.c_str());
mqttSend(buffer, (char *) (relayStatus(id) ? "1" : "0"));
}
@ -54,8 +56,10 @@ void relayWS() {
bool relayStatus(unsigned char id) {
#ifdef SONOFF_DUAL
if (id >= 2) return false;
return ((dualRelayStatus & (1 << id)) > 0);
#else
if (id >= _relays.size()) return false;
return (digitalRead(_relays[id]) == HIGH);
#endif
}
@ -87,6 +91,8 @@ void relayInching(unsigned char id) {
bool relayStatus(unsigned char id, bool status, bool report) {
if (id >= _relays.size()) return false;
bool changed = false;
if (relayStatus(id) != status) {
@ -122,13 +128,17 @@ bool relayStatus(unsigned char id, bool status, bool report) {
}
bool relayStatus(unsigned char id, bool status) {
return relayStatus(id, status, true);
}
void relaySync(unsigned char id) {
if (_relays.size() > 1) {
recursive = true;
byte relaySync = getSetting("relaySync", String(RELAY_SYNC)).toInt();
byte relaySync = getSetting("relaySync", RELAY_SYNC).toInt();
bool status = relayStatus(id);
// If RELAY_SYNC_SAME all relays should have the same state
@ -182,6 +192,7 @@ void relayRetrieve() {
}
void relayToggle(unsigned char id) {
if (id >= _relays.size()) return;
relayStatus(id, !relayStatus(id));
}
@ -193,36 +204,41 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo
static bool isFirstMessage = true;
String mqttSetter = getSetting("mqttSetter", MQTT_USE_SETTER);
String mqttGetter = getSetting("mqttGetter", MQTT_USE_GETTER);
bool sameSetGet = mqttGetter.compareTo(mqttSetter) == 0;
if (type == MQTT_CONNECT_EVENT) {
relayMQTT();
mqttSubscribe("/relay/#");
char buffer[strlen(MQTT_RELAY_TOPIC) + mqttSetter.length() + 3];
sprintf(buffer, "%s/+%s", MQTT_RELAY_TOPIC, mqttSetter.c_str());
mqttSubscribe(buffer);
}
if (type == MQTT_MESSAGE_EVENT) {
// Match topic
if (memcmp("/relay/", topic, 7) != 0) return;
String t = String(topic);
if (!t.startsWith(MQTT_RELAY_TOPIC)) return;
if (!t.endsWith(mqttSetter)) return;
// If relayMode is not SAME avoid responding to a retained message
if (isFirstMessage) {
if (sameSetGet && isFirstMessage) {
isFirstMessage = false;
byte relayMode = getSetting("relayMode", String(RELAY_MODE)).toInt();
byte relayMode = getSetting("relayMode", RELAY_MODE).toInt();
if (relayMode != RELAY_MODE_SAME) return;
}
// Get relay ID
unsigned int relayID = topic[strlen(topic)-1] - '0';
unsigned int relayID = topic[strlen(MQTT_RELAY_TOPIC)+1] - '0';
if (relayID >= relayCount()) relayID = 0;
// Action to perform
if ((char)payload[0] == '0') {
relayStatus(relayID, false, false);
}
if ((char)payload[0] == '1') {
relayStatus(relayID, true, false);
}
if ((char)payload[0] == '2') {
unsigned int value = (char)payload[0] - '0';
if (value == 2) {
relayToggle(relayID);
} else {
relayStatus(relayID, value > 0, !sameSetGet);
}
}
@ -255,7 +271,7 @@ void relaySetup() {
#endif
EEPROM.begin(4096);
byte relayMode = getSetting("relayMode", String(RELAY_MODE)).toInt();
byte relayMode = getSetting("relayMode", RELAY_MODE).toInt();
for (unsigned int i=0; i < _relays.size(); i++) {
pinMode(_relays[i], OUTPUT);


+ 2
- 2
code/src/rf.ino View File

@ -33,7 +33,7 @@ void rfBuildCodes() {
unsigned long code = 0;
// channel
unsigned int channel = getSetting("rfChannel", String(RF_CHANNEL)).toInt();
unsigned int channel = getSetting("rfChannel", RF_CHANNEL).toInt();
for (byte i = 0; i < 5; i++) {
code *= 3;
if (channel & 1) code += 1;
@ -41,7 +41,7 @@ void rfBuildCodes() {
}
// device
unsigned int device = getSetting("rfDevice", String(RF_DEVICE)).toInt();
unsigned int device = getSetting("rfDevice", RF_DEVICE).toInt();
for (byte i = 0; i < 5; i++) {
code *= 3;
if (device != i) code += 2;


+ 49
- 8
code/src/settings.ino View File

@ -20,6 +20,21 @@ Embedis embedis(Serial);
// Settings
// -----------------------------------------------------------------------------
unsigned long settingsSize() {
bool zero = false;
unsigned long size = 0;
for (unsigned int i = SPI_FLASH_SEC_SIZE; i>0; i--) {
size++;
if (EEPROM.read(i) == 0) {
if (zero) break;
zero = true;
} else {
zero = false;
}
}
return size-2;
}
void settingsSetup() {
EEPROM.begin(SPI_FLASH_SEC_SIZE);
@ -35,24 +50,46 @@ void settingsSetup() {
#endif
);
Embedis::hardware( F("wifi"), [](Embedis* e) {
Embedis::hardware( F("WIFI"), [](Embedis* e) {
StreamString s;
WiFi.printDiag(s);
e->response(s);
}, 0);
Embedis::command( F("reconnect"), [](Embedis* e) {
Embedis::command( F("RECONNECT"), [](Embedis* e) {
wifiConfigure();
wifiDisconnect();
e->response(Embedis::OK);
});
Embedis::command( F("reset"), [](Embedis* e) {
Embedis::command( F("RESET"), [](Embedis* e) {
e->response(Embedis::OK);
ESP.reset();
});
DEBUG_MSG("[SETTINGS] Initialized\n");
Embedis::command( F("EEPROM.DUMP"), [](Embedis* e) {
for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) {
if (i % 16 == 0) Serial.printf("\n[%04X] ", i);
Serial.printf("%02X ", EEPROM.read(i));
}
Serial.printf("\n");
e->response(Embedis::OK);
});
Embedis::command( F("EEPROM.ERASE"), [](Embedis* e) {
for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) {
EEPROM.write(i, 0xFF);
}
EEPROM.commit();
e->response(Embedis::OK);
});
Embedis::command( F("SETTINGS.SIZE"), [](Embedis* e) {
e->response(String(settingsSize()));
});
DEBUG_MSG("[SETTINGS] EEPROM size: %d bytes\n", SPI_FLASH_SEC_SIZE);
DEBUG_MSG("[SETTINGS] Settings size: %d bytes\n", settingsSize());
}
@ -60,14 +97,18 @@ void settingsLoop() {
embedis.process();
}
String getSetting(const String& key, String defaultValue) {
template<typename T> String getSetting(const String& key, T defaultValue) {
String value;
if (!Embedis::get(key, value)) value = defaultValue;
if (!Embedis::get(key, value)) value = String(defaultValue);
return value;
}
bool setSetting(const String& key, String& value) {
return Embedis::set(key, value);
String getSetting(const String& key) {
return getSetting(key, "");
}
template<typename T> bool setSetting(const String& key, T value) {
return Embedis::set(key, String(value));
}
bool delSetting(const String& key) {


+ 12
- 12
code/src/web.ino View File

@ -155,12 +155,12 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) {
// Checkboxes
if (apiEnabled != (getSetting("apiEnabled").toInt() == 1)) {
setSetting("apiEnabled", String() + (apiEnabled ? 1 : 0));
setSetting("apiEnabled", apiEnabled);
dirty = true;
}
#if ENABLE_FAUXMO
if (fauxmoEnabled != (getSetting("fauxmoEnabled").toInt() == 1)) {
setSetting("fauxmoEnabled", String() + (fauxmoEnabled ? 1 : 0));
setSetting("fauxmoEnabled", fauxmoEnabled);
dirty = true;
}
#endif
@ -229,7 +229,7 @@ void _wsStart(uint32_t client_id) {
root["mqttStatus"] = mqttConnected();
root["mqttServer"] = getSetting("mqttServer", MQTT_SERVER);
root["mqttPort"] = getSetting("mqttPort", String(MQTT_PORT));
root["mqttPort"] = getSetting("mqttPort", MQTT_PORT);
root["mqttUser"] = getSetting("mqttUser");
root["mqttPassword"] = getSetting("mqttPassword");
root["mqttTopic"] = getSetting("mqttTopic", MQTT_TOPIC);
@ -238,12 +238,12 @@ void _wsStart(uint32_t client_id) {
for (unsigned char relayID=0; relayID<relayCount(); relayID++) {
relay.add(relayStatus(relayID));
}
root["relayMode"] = getSetting("relayMode", String(RELAY_MODE));
root["relayInch"] = getSetting("relayInch", String(RELAY_INCHING));
root["relayInchTime"] = getSetting("relayInchTime", String(RELAY_INCHING_TIME));
root["relayMode"] = getSetting("relayMode", RELAY_MODE);
root["relayInch"] = getSetting("relayInch", RELAY_INCHING);
root["relayInchTime"] = getSetting("relayInchTime", RELAY_INCHING_TIME);
if (relayCount() > 1) {
root["multirelayVisible"] = 1;
root["relaySync"] = getSetting("relaySync", String(RELAY_SYNC));
root["relaySync"] = getSetting("relaySync", RELAY_SYNC);
}
root["apiEnabled"] = getSetting("apiEnabled").toInt() == 1;
@ -251,7 +251,7 @@ void _wsStart(uint32_t client_id) {
#if ENABLE_FAUXMO
root["fauxmoVisible"] = 1;
root["fauxmoEnabled"] = getSetting("fauxmoEnabled", String(FAUXMO_ENABLED)).toInt() == 1;
root["fauxmoEnabled"] = getSetting("fauxmoEnabled", FAUXMO_ENABLED).toInt() == 1;
#endif
#if ENABLE_DS18B20
@ -267,15 +267,15 @@ void _wsStart(uint32_t client_id) {
#if ENABLE_RF
root["rfVisible"] = 1;
root["rfChannel"] = getSetting("rfChannel", String(RF_CHANNEL));
root["rfDevice"] = getSetting("rfDevice", String(RF_DEVICE));
root["rfChannel"] = getSetting("rfChannel", RF_CHANNEL);
root["rfDevice"] = getSetting("rfDevice", RF_DEVICE);
#endif
#if ENABLE_EMON
root["emonVisible"] = 1;
root["emonPower"] = getPower();
root["emonMains"] = getSetting("emonMains", String(EMON_MAINS_VOLTAGE));
root["emonRatio"] = getSetting("emonRatio", String(EMON_CURRENT_RATIO));
root["emonMains"] = getSetting("emonMains", EMON_MAINS_VOLTAGE);
root["emonRatio"] = getSetting("emonRatio", EMON_CURRENT_RATIO);
#endif
#if ENABLE_POW


+ 14
- 0
code/src/wifi.ino View File

@ -8,6 +8,9 @@ Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include "JustWifi.h"
#include <DNSServer.h>
DNSServer dnsServer;
// -----------------------------------------------------------------------------
// WIFI
@ -147,10 +150,21 @@ void wifiSetup() {
}
// Configure captive portal
if (code == MESSAGE_ACCESSPOINT_CREATED) {
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
}
if (code == MESSAGE_DISCONNECTED) {
dnsServer.stop();
}
});
}
void wifiLoop() {
jw.loop();
if (WiFi.getMode() == WIFI_AP) {
dnsServer.processNextRequest();
}
}

+ 60
- 7
docs/Hardware.md View File

@ -9,16 +9,20 @@ This is the official list of supported hardware for the ESPurna firmware. The ha
* [IteadStudio Sonoff TH](#iteadstudio-sonoff-th)
* [IteadStudio Sonoff POW](#iteadstudio-sonoff-pow)
* [IteadStudio Sonoff DUAL](#iteadstudio-sonoff-dual)
* [IteadStudio Sonoff TOUCH](#iteadstudio-sonoff-touch)
* [IteadStudio Sonoff 4CH](#iteadstudio-sonoff-4ch)
* [IteadStudio Sonoff SV](#iteadstudio-sonoff-sv)
* [IteadStudio Slampher](#iteadstudio-slampher)
* [IteadStudio S20](#iteadstudio-s20)
* [Electrodragon ESP Relay Board](#electrodragon-esp-relay-board)
* [WorkChoice EcoPlug](#workchoice-ecoplug)
## IteadStudio Sonoff
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|https://www.itead.cc/sonoff-wifi-wireless-switch.html|
|Web page|[https://www.itead.cc/sonoff-wifi-wireless-switch.html](https://www.itead.cc/sonoff-wifi-wireless-switch.html)|
|Build flag|SONOFF|
The [IteadStudio Sonoff][1] has an ESP8266 on board with a 8Mbit flash memory chip, a mains to 3V3 transformer and a relay (GPIO12). It also features a button (GPIO0), an LED (GPIO13) and an unpopulated header you can use to reprogram it.
@ -57,7 +61,7 @@ My recommendation is to **temporary shortcut the bottom pad of the unpopulated R
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|https://www.itead.cc/sonoff-th.html|
|Web page|[https://www.itead.cc/sonoff-th.html](https://www.itead.cc/sonoff-th.html)|
|Build flag|SONOFF_TH|
### Flashing
@ -73,7 +77,7 @@ As in the Sonoff the button is connected to GPIO0, so to enter flash mode press
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|https://www.itead.cc/sonoff-pow.html|
|Web page|[https://www.itead.cc/sonoff-pow.html](https://www.itead.cc/sonoff-pow.html)|
|Build flag|SONOFF_POW|
### Flashing
@ -87,7 +91,7 @@ Same as for the [Sonoff TH](#iteadstudio-sonoff-th) above.
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|https://www.itead.cc/sonoff-dual.html|
|Web page|[https://www.itead.cc/sonoff-dual.html](https://www.itead.cc/sonoff-dual.html)|
|Build flag|SONOFF_DUAL|
### Flashing
@ -100,12 +104,48 @@ In the picture above you have a location of an available and easily accessible G
Once flashed use OTA to update the firmware or the filesystem.
## IteadStudio Sonoff TOUCH
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|[https://www.itead.cc/sonoff-touch.html](https://www.itead.cc/sonoff-touch.html)|
|Build flag|SONOFF_TOUCH|
### Flashing
*TODO*
## IteadStudio Sonoff 4CH
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|[https://www.itead.cc/sonoff-4ch.html](https://www.itead.cc/sonoff-4ch.html)|
|Build flag|SONOFF_4CH|
### Flashing
*TODO*
## IteadStudio Sonoff SV
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|[https://www.itead.cc/sonoff-sv.html](https://www.itead.cc/sonoff-sv.html)|
|Build flag|SONOFF_SV|
### Flashing
*TODO*
## IteadStudio Slampher
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|https://www.itead.cc/slampher.html|
|Web page|[https://www.itead.cc/slampher.html](https://www.itead.cc/slampher.html)|
|Build flag|SLAMPHER|
### Flashing
@ -124,7 +164,7 @@ My recommendation is to **temporary shortcut the right pad of the unpopulated R2
|Property|Value|
|---|---|
|Manufacturer|Itead Studio|
|Web page|https://www.itead.cc/smart-socket.html|
|Web page|[https://www.itead.cc/smart-socket.html](https://www.itead.cc/smart-socket.html)|
|Build flag|S20|
### Flashing
@ -140,7 +180,7 @@ Solder a 4 pin male or female header and connect it to your USB-to-UART bridge.
|Property|Value|
|---|---|
|Manufacturer|Electrodragon|
|Web page|http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/|
|Web page|[http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/](http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/)|
|Build flag|ESP_RELAY_BOARD|
### Flashing
@ -154,6 +194,19 @@ The Electrodragon ESP Relay Board is pretty easy to flash IF you do not follow t
* The TX pin in the header should go to your programmer RX pin
* The button labeled BTN2 is connected to GPIO0, so hold it down while powering the board, I've had better results keeping it down until the flashing starts
## WorkChoice EcoPlug
|Property|Value|
|---|---|
|Manufacturer|WorkChoice|
|Web page (non-official)|[http://thegreatgeekery.blogspot.com.es/2016/02/ecoplug-wifi-switch-hacking.html](http://thegreatgeekery.blogspot.com.es/2016/02/ecoplug-wifi-switch-hacking.html)|
|Build flag|ECOPLUG|
### Flashing
*TODO*
[1]: https://www.itead.cc/sonoff-wifi-wireless-switch.html
[2]: https://www.itead.cc/sonoff-rf.html


Loading…
Cancel
Save