diff --git a/code/data/fsversion b/code/data/fsversion index 21e8796a..9084fa2f 100644 --- a/code/data/fsversion +++ b/code/data/fsversion @@ -1 +1 @@ -1.0.3 +1.1.0 diff --git a/code/data/index.html.gz b/code/data/index.html.gz index 59a3d111..6a84e34f 100644 Binary files a/code/data/index.html.gz and b/code/data/index.html.gz differ diff --git a/code/html/custom.css b/code/html/custom.css index 0d544a6a..c129c81b 100644 --- a/code/html/custom.css +++ b/code/html/custom.css @@ -61,3 +61,6 @@ div.hint { .module { display: none; } +#relayTemplate { + display: none; +} diff --git a/code/html/custom.js b/code/html/custom.js index 486ce000..5d6ef086 100644 --- a/code/html/custom.js +++ b/code/html/custom.js @@ -22,7 +22,8 @@ function doReconnect() { } function doToggle(element, value) { - websock.send(JSON.stringify({'action': value ? 'on' : 'off'})); + var relayID = parseInt(element.attr("data")); + websock.send(JSON.stringify({'action': value ? 'on' : 'off', 'relayID': relayID})); return false; } @@ -57,6 +58,31 @@ function toggleMenu() { $("#menuLink").toggleClass('active'); } +function createRelays(count) { + + var current = $("#relays > div").length; + if (current > 0) return; + + var template = $("#relayTemplate .pure-g")[0]; + for (var relayID=0; relayID 1) $(".relay_id", line).html(" " + relayID); + line.appendTo("#relays"); + $(":checkbox", line).iphoneStyle({ + onChange: doToggle, + resizeContainer: true, + resizeHandle: true, + checkedLabel: 'ON', + uncheckedLabel: 'OFF' + }); + + } + +} + function processData(data) { // title @@ -84,6 +110,26 @@ function processData(data) { return; } + // Relay status + if (key == "relayStatus") { + + var relays = data.relayStatus; + createRelays(relays.length); + + for (var relayID in relays) { + var element = $(".relayStatus[data=" + relayID + "]"); + if (element.length > 0) { + element + .prop("checked", relays[relayID]) + .iphoneStyle("refresh"); + } + } + + return; + + } + + // Messages if (key == "message") { window.alert(data.message); @@ -166,20 +212,6 @@ function init() { $(".button-apikey").on('click', doGenerateAPIKey); $(".pure-menu-link").on('click', showPanel); - $("input[name='relayStatus']") - .iphoneStyle({ - onChange: doToggle - }); - $("input[type='checkbox']") - .iphoneStyle({ - resizeContainer: true, - resizeHandle: true, - checkedLabel: 'ON', - uncheckedLabel: 'OFF' - }) - .iphoneStyle("refresh"); - - $.ajax({ 'method': 'GET', 'url': '/auth' diff --git a/code/html/fsversion b/code/html/fsversion index 21e8796a..9084fa2f 100644 --- a/code/html/fsversion +++ b/code/html/fsversion @@ -1 +1 @@ -1.0.3 +1.1.0 diff --git a/code/html/index.html b/code/html/index.html index 0bec6d50..00b8bfc7 100644 --- a/code/html/index.html +++ b/code/html/index.html @@ -132,11 +132,17 @@ -
-
-
+
+
+ +
+
+
+
+
+ @@ -176,6 +182,19 @@
Here you can define what will be the status of the relay after a reboot.
+
+ +
+ +
+
 
+
Define how the different relays should be synchronized.
+
+
diff --git a/code/platformio.custom.ini b/code/platformio.custom.ini index 3b434ed2..1dda5f93 100644 --- a/code/platformio.custom.ini +++ b/code/platformio.custom.ini @@ -65,6 +65,14 @@ build_flags = -g -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_POW [env:sonoff-pow-debug-ota] include = env:sonoff-pow-debug,ota +[env:sonoff-dual-debug] +include = common +board = esp12e +build_flags = -g -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_DUAL + +[env:sonoff-dual-debug-ota] +include = env:sonoff-dual-debug,ota + [env:slampher-debug] include = common board = esp01_1m @@ -81,6 +89,14 @@ build_flags = -g -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20 [env:s20-debug-ota] include = env:s20-debug,ota +[env:electrodragon-debug] +include = common +board = esp12e +build_flags = -g -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DESP_RELAY_BOARD + +[env:electrodragon-debug-ota] +include = env:electrodragon-debug,ota + # ------------------------------------------------------------------------------ [env:ac-device] diff --git a/code/platformio.ini b/code/platformio.ini index bbe389f0..95c215b4 100644 --- a/code/platformio.ini +++ b/code/platformio.ini @@ -32,7 +32,7 @@ board = nodemcuv2 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} extra_script = pio_hooks.py -build_flags = -g -DNODEMCUV2 -DDEBUG_PORT=Serial +build_flags = -g -DNODEMCUV2 -DDEBUG_PORT=Serial -DNOWSAUTH [env:node-debug-ota] platform = espressif8266 @@ -41,7 +41,7 @@ board = nodemcuv2 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} extra_script = pio_hooks.py -build_flags = -g -DNODEMCUV2 -DDEBUG_PORT=Serial +build_flags = -g -DNODEMCUV2 -DDEBUG_PORT=Serial -DNOWSAUTH upload_speed = 115200 upload_port = "192.168.4.1" upload_flags = --auth=fibonacci --port 8266 @@ -88,6 +88,27 @@ upload_speed = 115200 upload_port = "192.168.4.1" upload_flags = --auth=fibonacci --port 8266 +[env:sonoff-dual-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.1m256.ld -DSONOFF_DUAL + +[env:sonoff-dual-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.1m256.ld -DSONOFF_DUAL +upload_speed = 115200 +upload_port = "192.168.4.1" +upload_flags = --auth=fibonacci --port 8266 + [env:slampher-debug] platform = espressif8266 framework = arduino @@ -130,6 +151,27 @@ upload_speed = 115200 upload_port = "192.168.4.1" upload_flags = --auth=fibonacci --port 8266 +[env:electrodragon-debug] +platform = espressif8266 +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +extra_script = pio_hooks.py +build_flags = -g -DDEBUG_PORT=Serial -DDEBUG_PORT=Serial -DESP_RELAY_BOARD + +[env:electrodragon-debug-ota] +platform = espressif8266 +framework = arduino +board = esp12e +lib_deps = ${common.lib_deps} +lib_ignore = ${common.lib_ignore} +extra_script = pio_hooks.py +build_flags = -g -DDEBUG_PORT=Serial -DDEBUG_PORT=Serial -DESP_RELAY_BOARD +upload_speed = 115200 +upload_port = "192.168.4.1" +upload_flags = --auth=fibonacci --port 8266 + # ------------------------------------------------------------------------------ [env:ac-device] diff --git a/code/src/button.ino b/code/src/button.ino index bc79e8a0..53cafda5 100644 --- a/code/src/button.ino +++ b/code/src/button.ino @@ -7,14 +7,58 @@ Copyright (C) 2016 by Xose Pérez */ -#include - -DebounceEvent button1 = false; - // ----------------------------------------------------------------------------- // BUTTON // ----------------------------------------------------------------------------- +#ifdef SONOFF_DUAL + +void buttonSetup() {} + +void buttonLoop() { + + if (Serial.available() >= 4) { + + unsigned char value; + if (Serial.read() == 0xA0) { + if (Serial.read() == 0x04) { + value = Serial.read(); + if (Serial.read() == 0xA1) { + + // RELAYs and BUTTONs are synchonized in the SIL F330 + // The on-board BUTTON2 should toggle RELAY0 value + // Since we are not passing back RELAY2 value + // (in the relayStatus method) it will only be present + // here if it has actually been pressed + if ((value & 4) == 4) value = value ^ 1; + + // Otherwise check if any of the other two BUTTONs + // (in the header) has been pressent, but we should + // ensure that we only toggle one of them to avoid + // the synchronization going mad + // This loop is generic for any PSB-04 module + for (unsigned int i=0; i 0; + + // relayStatus returns true if the status has changed + if (relayStatus(i, status)) break; + + } + + } + } + } + + } + +} + +#else + +#include +DebounceEvent button1 = false; + void buttonSetup() { button1 = DebounceEvent(BUTTON_PIN); } @@ -26,3 +70,5 @@ void buttonLoop() { if (button1.getEvent() == EVENT_LONG_CLICK) ESP.reset(); } } + +#endif diff --git a/code/src/config/general.h b/code/src/config/general.h index bf859923..a1edee7f 100644 --- a/code/src/config/general.h +++ b/code/src/config/general.h @@ -15,6 +15,9 @@ // 0 means OFF, 1 ON and 2 whatever was before #define RELAY_MODE 1 +// 0 means ANY, 1 zero or one and 2 one and only one +#define RELAY_SYNC 0 + // ----------------------------------------------------------------------------- // WIFI & WEB // ----------------------------------------------------------------------------- @@ -45,7 +48,7 @@ #define MQTT_QOS 0 #define MQTT_KEEPALIVE 30 #define MQTT_RECONNECT_DELAY 10000 -#define MQTT_STATUS_TOPIC "" +#define MQTT_RELAY_TOPIC "/relay/%d" #define MQTT_IP_TOPIC "/ip" #define MQTT_VERSION_TOPIC "/version" #define MQTT_FSVERSION_TOPIC "/fsversion" diff --git a/code/src/config/hardware.h b/code/src/config/hardware.h index 34ef53a5..c1c13b6d 100644 --- a/code/src/config/hardware.h +++ b/code/src/config/hardware.h @@ -7,7 +7,7 @@ #define MANUFACTURER "NODEMCU" #define DEVICE "LOLIN" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 2 #define LED_PIN_INVERSE 0 @@ -20,7 +20,7 @@ #define MANUFACTURER "ITEAD" #define DEVICE "SONOFF" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 13 #define LED_PIN_INVERSE 0 @@ -29,7 +29,7 @@ #define MANUFACTURER "ITEAD" #define DEVICE "SONOFF_TH" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 13 #define LED_PIN_INVERSE 0 @@ -38,17 +38,29 @@ #define MANUFACTURER "ITEAD" #define DEVICE "SONOFF_POW" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 15 #define LED_PIN_INVERSE 1 #define ENABLE_POW 1 +#elif defined(SONOFF_DUAL) + + #define MANUFACTURER "ITEAD" + #define DEVICE "SONOFF_DUAL" + #define BUTTON_PIN 0 + #define RELAY1_PIN 12 + #define RELAY2_PIN 13 + #define LED_PIN 15 + #define LED_PIN_INVERSE 1 + #undef SERIAL_BAUDRATE + #define SERIAL_BAUDRATE 19230 + #elif defined(SLAMPHER) #define MANUFACTURER "ITEAD" #define DEVICE "SLAMPHER" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 13 #define LED_PIN_INVERSE 0 @@ -57,10 +69,20 @@ #define MANUFACTURER "ITEAD" #define DEVICE "S20" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 13 #define LED_PIN_INVERSE 0 +#elif defined(ESP_RELAY_BOARD) + + #define MANUFACTURER "ELECTRODRAGON" + #define DEVICE "ESP_RELAY_BOARD" + #define BUTTON_PIN 2 + #define RELAY1_PIN 12 + #define RELAY2_PIN 13 + #define LED_PIN 16 + #define LED_PIN_INVERSE 0 + // ----------------------------------------------------------------------------- // ESPurna board (still beta) // ----------------------------------------------------------------------------- @@ -70,7 +92,7 @@ #define MANUFACTURER "TINKERMAN" #define DEVICE "ESPURNA" #define BUTTON_PIN 0 - #define RELAY_PIN 12 + #define RELAY1_PIN 12 #define LED_PIN 13 #define LED_PIN_INVERSE 0 diff --git a/code/src/config/version.h b/code/src/config/version.h index b434af89..b11726cc 100644 --- a/code/src/config/version.h +++ b/code/src/config/version.h @@ -1,4 +1,4 @@ -#define APP_NAME "Espurna" -#define APP_VERSION "1.0.3" +#define APP_NAME "ESPurna" +#define APP_VERSION "1.1.0" #define APP_AUTHOR "xose.perez@gmail.com" #define APP_WEBSITE "http://tinkerman.cat" diff --git a/code/src/fauxmo.ino b/code/src/fauxmo.ino index 245432c0..3d89669a 100644 --- a/code/src/fauxmo.ino +++ b/code/src/fauxmo.ino @@ -23,10 +23,23 @@ void fauxmoConfigure() { void fauxmoSetup() { fauxmoConfigure(); - fauxmo.addDevice(getSetting("hostname", HOSTNAME).c_str()); - fauxmo.onMessage([](const char * name, bool state) { + unsigned int relays = relayCount(); + String hostname = getSetting("hostname", HOSTNAME); + if (relays == 1) { + fauxmo.addDevice(hostname.c_str()); + } else { + for (unsigned int i=0; i 1) { + id = name[strlen(name)-1] - '0'; + if (id >= relays) id = 0; + } + relayStatus(id, state); }); } diff --git a/code/src/main.ino b/code/src/main.ino index 4a9e1864..8b5593c6 100644 --- a/code/src/main.ino +++ b/code/src/main.ino @@ -64,7 +64,7 @@ void showStatus() { } void hardwareSetup() { - Serial.begin(115200); + Serial.begin(SERIAL_BAUDRATE); pinMode(LED_PIN, OUTPUT); SPIFFS.begin(); } @@ -105,24 +105,23 @@ void hardwareLoop() { void welcome() { delay(2000); - Serial.printf("%s %s\n", (char *) APP_NAME, (char *) APP_VERSION); - Serial.printf("%s\n%s\n\n", (char *) APP_AUTHOR, (char *) APP_WEBSITE); - //Serial.printf("Device: %s\n", (char *) getIdentifier().c_str()); - Serial.printf("ChipID: %06X\n", ESP.getChipId()); - Serial.printf("Last reset reason: %s\n", (char *) ESP.getResetReason().c_str()); - Serial.printf("Memory size: %d bytes\n", ESP.getFlashChipSize()); - Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap()); + DEBUG_MSG("%s %s\n", (char *) APP_NAME, (char *) APP_VERSION); + 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("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()); FSInfo fs_info; if (SPIFFS.info(fs_info)) { - Serial.printf("File system total size: %d bytes\n", fs_info.totalBytes); - Serial.printf(" used size : %d bytes\n", fs_info.usedBytes); - Serial.printf(" block size: %d bytes\n", fs_info.blockSize); - Serial.printf(" page size : %d bytes\n", fs_info.pageSize); - Serial.printf(" max files : %d\n", fs_info.maxOpenFiles); - Serial.printf(" max length: %d\n", fs_info.maxPathLength); + DEBUG_MSG("File system total size: %d bytes\n", fs_info.totalBytes); + DEBUG_MSG(" used size : %d bytes\n", fs_info.usedBytes); + DEBUG_MSG(" block size: %d bytes\n", fs_info.blockSize); + DEBUG_MSG(" page size : %d bytes\n", fs_info.pageSize); + DEBUG_MSG(" max files : %d\n", fs_info.maxOpenFiles); + DEBUG_MSG(" max length: %d\n", fs_info.maxPathLength); } - Serial.println(); - Serial.println(); + DEBUG_MSG("\n\n"); } @@ -174,12 +173,14 @@ void loop() { hardwareLoop(); buttonLoop(); - settingsLoop(); wifiLoop(); otaLoop(); mqttLoop(); ntpLoop(); + #ifndef SONOFF_DUAL + settingsLoop(); + #endif #if ENABLE_NOFUSS nofussLoop(); #endif diff --git a/code/src/mqtt.ino b/code/src/mqtt.ino index 73c53268..5c0cbf17 100644 --- a/code/src/mqtt.ino +++ b/code/src/mqtt.ino @@ -43,6 +43,8 @@ void mqttSend(char * topic, char * message) { void _mqttOnConnect(bool sessionPresent) { + char buffer[50]; + DEBUG_MSG("[MQTT] Connected!\n"); // Send status via webSocket @@ -54,16 +56,16 @@ void _mqttOnConnect(bool sessionPresent) { // Say hello and report our IP and VERSION mqttSend((char *) MQTT_IP_TOPIC, (char *) getIP().c_str()); mqttSend((char *) MQTT_VERSION_TOPIC, (char *) APP_VERSION); - char buffer[10]; getFSVersion(buffer); mqttSend((char *) MQTT_FSVERSION_TOPIC, buffer); // Publish current relay status - mqttSend((char *) MQTT_STATUS_TOPIC, (char *) (relayStatus(0) ? "1" : "0")); + relayMQTT(); - // Subscribe to topic - DEBUG_MSG("[MQTT] Subscribing to %s\n", (char *) mqttTopic.c_str()); - mqtt.subscribe(mqttTopic.c_str(), MQTT_QOS); + // Subscribe to relay topics + sprintf(buffer, "%s/relay/#", mqttTopic.c_str()); + DEBUG_MSG("[MQTT] Subscribing to %s\n", buffer); + mqtt.subscribe(buffer, MQTT_QOS); } @@ -78,8 +80,7 @@ void _mqttOnMessage(char* topic, char* payload, AsyncMqttClientMessageProperties static bool isFirstMessage = true; - payload[len] = '\0'; - DEBUG_MSG("[MQTT] Received %s %s\n", topic, payload); + DEBUG_MSG("[MQTT] Received %s %c\n", topic, payload[0]); // If relayMode is not SAME avoid responding to a retained message if (isFirstMessage) { @@ -88,17 +89,21 @@ void _mqttOnMessage(char* topic, char* payload, AsyncMqttClientMessageProperties if (relayMode != 2) return; } + // Get relay ID + unsigned int relayID = topic[strlen(topic)-1] - '0'; + if (relayID >= relayCount()) relayID = 0; + // Action to perform if ((char)payload[0] == '0') { isCallbackMessage = true; - relayStatus(0, false); + relayStatus(relayID, false); } if ((char)payload[0] == '1') { isCallbackMessage = true; - relayStatus(0, true); + relayStatus(relayID, true); } if ((char)payload[0] == '2') { - relayToggle(0); + relayToggle(relayID); } isCallbackMessage = false; diff --git a/code/src/relay.ino b/code/src/relay.ino index e72efdaf..62a8a6e4 100644 --- a/code/src/relay.ino +++ b/code/src/relay.ino @@ -8,56 +8,195 @@ Copyright (C) 2016 by Xose Pérez */ #include +#include +#include + +std::vector _relays; +bool recursive = false; +#ifdef SONOFF_DUAL + unsigned char dualRelayStatus = 0; +#endif + +#define RELAY_MODE_OFF 0 +#define RELAY_MODE_ON 1 +#define RELAY_MODE_SAME 2 + +#define RELAY_SYNC_ANY 0 +#define RELAY_SYNC_NONE_OR_ONE 1 +#define RELAY_SYNC_ONE 2 + // ----------------------------------------------------------------------------- // RELAY // ----------------------------------------------------------------------------- -void _relayOn(unsigned char id) { +void relayMQTT(unsigned char id) { + char buffer[10]; + sprintf(buffer, MQTT_RELAY_TOPIC, id); + mqttSend(buffer, (char *) (relayStatus(id) ? "1" : "0")); +} - if (!digitalRead(RELAY_PIN)) { - DEBUG_MSG("[RELAY] ON\n"); - digitalWrite(RELAY_PIN, HIGH); - EEPROM.write(0, 1); - EEPROM.commit(); - mqttSend((char *) MQTT_STATUS_TOPIC, (char *) "1"); +void relayMQTT() { + for (unsigned int i=0; i < _relays.size(); i++) { + relayMQTT(i); } +} - wsSend((char *) "{\"relayStatus\": true}"); - +String relayString() { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + JsonArray& relay = root.createNestedArray("relayStatus"); + for (unsigned char i=0; i 0); + #else + return (digitalRead(_relays[id]) == HIGH); + #endif } -void relayStatus(unsigned char id, bool status) { - status ? _relayOn(id) : _relayOff(id); +void relaySync(unsigned char id) { + + if (_relays.size() > 1) { + + recursive = true; + + byte relaySync = getSetting("relaySync", String(RELAY_SYNC)).toInt(); + bool status = relayStatus(id); + + // If NONE_OR_ONE or ONE and setting ON we should set OFF all the others + if (status) { + if (relaySync != RELAY_SYNC_ANY) { + for (unsigned short i=0; i<_relays.size(); i++) { + if (i != id) relayStatus(i, false); + } + } + + // If ONLY_ONE and setting OFF we should set ON the other one + } else { + if (relaySync == RELAY_SYNC_ONE) { + unsigned char i = (id + 1) % _relays.size(); + relayStatus(i, true); + } + } + + recursive = false; + + } + } -bool relayStatus(unsigned char id) { - return (digitalRead(RELAY_PIN) == HIGH); +bool relayStatus(unsigned char id, bool status) { + + bool changed = false; + + if (relayStatus(id) != status) { + + DEBUG_MSG("[RELAY] %d => %s\n", id, status ? "ON" : "OFF"); + changed = true; + + #ifdef SONOFF_DUAL + + dualRelayStatus ^= (1 << id); + Serial.flush(); + Serial.write(0xA0); + Serial.write(0x04); + Serial.write(dualRelayStatus); + Serial.write(0xA1); + Serial.flush(); + + #else + digitalWrite(_relays[id], status); + #endif + + if (!recursive) { + relaySync(id); + relaySave(); + } + + } + + relayMQTT(id); + if (!recursive) relayWS(); + return changed; } void relayToggle(unsigned char id) { relayStatus(id, !relayStatus(id)); } +unsigned char relayCount() { + return _relays.size(); +} + void relaySetup() { - pinMode(RELAY_PIN, OUTPUT); + + #ifdef SONOFF_DUAL + + // Two dummy relays for the dual + _relays.push_back(0); + _relays.push_back(0); + + #else + + #ifdef RELAY1_PIN + _relays.push_back(RELAY1_PIN); + #endif + #ifdef RELAY2_PIN + _relays.push_back(RELAY2_PIN); + #endif + #ifdef RELAY3_PIN + _relays.push_back(RELAY3_PIN); + #endif + #ifdef RELAY4_PIN + _relays.push_back(RELAY4_PIN); + #endif + + #endif + EEPROM.begin(4096); byte relayMode = getSetting("relayMode", String(RELAY_MODE)).toInt(); - if (relayMode == 0) relayStatus(0, false); - if (relayMode == 1) relayStatus(0, true); - if (relayMode == 2) relayStatus(0, EEPROM.read(0) == 1); + + for (unsigned int i=0; i < _relays.size(); i++) { + pinMode(_relays[i], OUTPUT); + if (relayMode == RELAY_MODE_OFF) relayStatus(i, false); + if (relayMode == RELAY_MODE_ON) relayStatus(i, true); + } + + if (relayMode == RELAY_MODE_SAME) relayRetrieve(); + } diff --git a/code/src/web.ino b/code/src/web.ino index 7cd8ac1e..d49546be 100644 --- a/code/src/web.ino +++ b/code/src/web.ino @@ -54,12 +54,18 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { if (root.containsKey("action")) { String action = root["action"]; + unsigned int relayID = 0; + if (root.containsKey("relayID")) { + String value = root["relayID"]; + relayID = value.toInt(); + } + DEBUG_MSG("[WEBSOCKET] Requested action: %s\n", action.c_str()); if (action.equals("reset")) ESP.reset(); if (action.equals("reconnect")) wifiDisconnect(); - if (action.equals("on")) relayStatus(0, true); - if (action.equals("off")) relayStatus(0, false); + if (action.equals("on")) relayStatus(relayID, true); + if (action.equals("off")) relayStatus(relayID, false); }; @@ -191,14 +197,24 @@ void _wsStart(uint32_t client_id) { root["hostname"] = getSetting("hostname", HOSTNAME); root["network"] = getNetwork(); root["ip"] = getIP(); + root["mqttStatus"] = mqttConnected(); root["mqttServer"] = getSetting("mqttServer", MQTT_SERVER); root["mqttPort"] = getSetting("mqttPort", String(MQTT_PORT)); root["mqttUser"] = getSetting("mqttUser"); root["mqttPassword"] = getSetting("mqttPassword"); root["mqttTopic"] = getSetting("mqttTopic", MQTT_TOPIC); - root["relayStatus"] = relayStatus(0); + + JsonArray& relay = root.createNestedArray("relayStatus"); + for (unsigned char relayID=0; relayID 1) { + root["multirelayVisible"] = 1; + root["relaySync"] = getSetting("relaySync", String(RELAY_SYNC)); + } + root["apiEnabled"] = getSetting("apiEnabled").toInt() == 1; root["apiKey"] = getSetting("apiKey"); @@ -340,24 +356,6 @@ void _onHome(AsyncWebServerRequest *request) { request->send(SPIFFS, "/index.html"); } -void _onRelayOn(AsyncWebServerRequest *request) { - - _logRequest(request); - - relayStatus(0, true); - request->send(200, "text/plain", "ON"); - -}; - -void _onRelayOff(AsyncWebServerRequest *request) { - - _logRequest(request); - - relayStatus(0, false); - request->send(200, "text/plain", "OFF"); - -}; - bool _apiAuth(AsyncWebServerRequest *request) { if (getSetting("apiEnabled").toInt() == 0) { @@ -383,9 +381,34 @@ bool _apiAuth(AsyncWebServerRequest *request) { } +void _onRelay(AsyncWebServerRequest *request) { + + _logRequest(request); + + if (!_apiAuth(request)) return; + + bool asJson = false; + if (request->hasHeader("Accept")) { + AsyncWebHeader* h = request->getHeader("Accept"); + asJson = h->value().equals("application/json"); + } + + String output; + if (asJson) { + output = relayString(); + request->send(200, "application/json", output); + } else { + for (unsigned int i=0; isend(200, "text/plain", output); + } + +}; + ArRequestHandlerFunction _onRelayStatusWrapper(unsigned int relayID) { - return [&](AsyncWebServerRequest *request) { + return [relayID](AsyncWebServerRequest *request) { _logRequest(request); @@ -394,6 +417,8 @@ ArRequestHandlerFunction _onRelayStatusWrapper(unsigned int relayID) { if (request->method() == HTTP_PUT) { if (request->hasParam("status", true)) { AsyncWebParameter* p = request->getParam("status", true); + wsSend((char *) String(relayID).c_str()); + wsSend((char *) p->value().c_str()); unsigned int value = p->value().toInt(); if (value == 2) { relayToggle(relayID); @@ -409,10 +434,10 @@ ArRequestHandlerFunction _onRelayStatusWrapper(unsigned int relayID) { asJson = h->value().equals("application/json"); } + String output; if (asJson) { - char buffer[20]; - sprintf(buffer, "{\"status\": %d}", relayStatus(relayID) ? 1 : 0); - request->send(200, "application/json", buffer); + output = String("{\"relayStatus\": ") + String(relayStatus(relayID) ? "1" : "0") + "}"; + request->send(200, "application/json", output); } else { request->send(200, "text/plain", relayStatus(relayID) ? "1" : "0"); } @@ -427,16 +452,18 @@ void webSetup() { ws.onEvent(_wsEvent); server.addHandler(&ws); - // Serve home (password protected) + // Serve home (basic authentication protection) server.on("/", HTTP_GET, _onHome); server.on("/index.html", HTTP_GET, _onHome); server.on("/auth", HTTP_GET, _onAuth); - // API entry points (non protected) - server.on("/relay/on", HTTP_GET, _onRelayOn); - server.on("/relay/off", HTTP_GET, _onRelayOff); - server.on("/relay/0/status", HTTP_GET + HTTP_PUT, _onRelayStatusWrapper(0)); - //server.on("/relay/1/status", HTTP_GET + HTTP_PUT, _onRelayStatusWrapper(1)); + // API entry points (protected with apikey) + for (unsigned int relayID=0; relayID