Browse Source

Migrated to AsyncWebServer, AsyncWebSocket and AsyncMqttClient

fastled
Xose Pérez 8 years ago
parent
commit
866f8138e7
10 changed files with 165 additions and 202 deletions
  1. +7
    -1
      code/html/custom.js
  2. +1
    -1
      code/html/fsversion
  3. +6
    -0
      code/html/index.html
  4. +27
    -13
      code/platformio.ini
  5. +2
    -0
      code/src/defaults.h
  6. +3
    -5
      code/src/main.ino
  7. +53
    -53
      code/src/mqtt.ino
  8. +1
    -1
      code/src/version.h
  9. +65
    -42
      code/src/web.ino
  10. +0
    -86
      code/src/webserver.ino

+ 7
- 1
code/html/custom.js View File

@ -40,6 +40,11 @@ function toggleMenu() {
function processData(data) {
// messages
if ("message" in data) {
window.alert(data.message);
}
// pre-process
if ("network" in data) {
data.network = data.network.toUpperCase();
@ -136,7 +141,8 @@ function init() {
$(".pure-menu-link").on('click', showPanel);
var host = window.location.hostname;
websock = new WebSocket('ws://' + host + ':81/');
//host = '192.168.1.115';
websock = new WebSocket('ws://' + host + '/ws');
websock.onopen = function(evt) {};
websock.onclose = function(evt) {};
websock.onerror = function(evt) {};


+ 1
- 1
code/html/fsversion View File

@ -1 +1 @@
0.9.8
1.0.0

+ 6
- 0
code/html/index.html View File

@ -167,6 +167,12 @@
</select>
</div>
<div class="pure-u-1">
<label class="form-label" for="httpPassword">Web interface password</label>
<div class="hint">Change the password for the 'admin' user to access this web interface.</div>
<input name="httpPassword" type="text" class="pure-u-1-4" tabindex="3">
</div>
</fieldset>
</div>
</div>


+ 27
- 13
code/platformio.ini View File

@ -1,10 +1,13 @@
[platformio]
env_default = sonoff-pow-debug
[common]
lib_install = 19,31,44,64,305,306,346,727
[env:sonoff-debug]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
@ -12,7 +15,7 @@ build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
[env:sonoff-debug-ota]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
@ -23,15 +26,26 @@ upload_flags = --auth=fibonacci --port 8266
[env:sonoff-pow-debug]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_POW
[env:sonoff-pow-debug-ota]
platform = espressif8266
framework = arduino
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_POW
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
[env:slampher-debug]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSLAMPHER
@ -39,7 +53,7 @@ build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSLAMPHER
[env:slampher-debug-ota]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSLAMPHER
@ -50,7 +64,7 @@ upload_flags = --auth=fibonacci --port 8266
[env:s20-debug]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
@ -58,7 +72,7 @@ build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
[env:s20-debug-ota]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
@ -69,7 +83,7 @@ upload_flags = --auth=fibonacci --port 8266
[env:node-debug]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = nodemcuv2
build_flags = -DNODEMCUV2 -DDEBUG_PORT=Serial
@ -77,7 +91,7 @@ build_flags = -DNODEMCUV2 -DDEBUG_PORT=Serial
[env:node-debug-ota]
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = nodemcuv2
build_flags = -DNODEMCUV2 -DDEBUG_PORT=Serial
@ -91,7 +105,7 @@ upload_flags = --auth=fibonacci --port 8266
topic = /home/cellar/airconditioner/ip
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
@ -103,7 +117,7 @@ upload_flags = --auth=fibonacci --port 8266
topic = /home/cellar/washer/ip
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
upload_speed = 115200
@ -115,7 +129,7 @@ build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF -DENABLE
topic = /home/studio/lamp/ip
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
@ -127,7 +141,7 @@ upload_flags = --auth=fibonacci --port 8266
topic = /home/living/lamp/ip
platform = espressif8266
framework = arduino
lib_install = 19,31,44,64,89,549,727
lib_install = ${common.lib_install}
extra_script = pio_hooks.py
board = esp01_1m
build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF


+ 2
- 0
code/src/defaults.h View File

@ -87,6 +87,8 @@
#define MQTT_PORT 1883
#define MQTT_TOPIC "/test/switch/{identifier}"
#define MQTT_RETAIN true
#define MQTT_QOS 0
#define MQTT_KEEPALIVE 30
#define MQTT_RECONNECT_DELAY 10000
#define MQTT_STATUS_TOPIC ""
#define MQTT_IP_TOPIC "/ip"


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

@ -28,7 +28,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
#include <NtpClientLib.h>
#include <WebSocketsServer.h>
#include <ESPAsyncWebServer.h>
#include <AsyncMqttClient.h>
#include "FS.h"
String getSetting(const String& key, String defaultValue = "");
@ -144,8 +145,7 @@ void setup() {
wifiSetup();
otaSetup();
mqttSetup();
webServerSetup();
webSocketSetup();
webSetup();
ntpSetup();
#if ENABLE_NOFUSS
@ -174,8 +174,6 @@ void loop() {
wifiLoop();
otaLoop();
mqttLoop();
webServerLoop();
webSocketLoop();
ntpLoop();
#if ENABLE_NOFUSS


+ 53
- 53
code/src/mqtt.ino View File

@ -7,12 +7,11 @@ Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <AsyncMqttClient.h>
AsyncMqttClient mqtt;
WiFiClient client;
PubSubClient mqtt(client);
boolean mqttStatus = false;
String mqttTopic;
bool isCallbackMessage = false;
@ -39,19 +38,48 @@ void mqttSend(char * topic, char * message) {
if (isCallbackMessage) return;
String path = mqttTopic + String(topic);
DEBUG_MSG("[MQTT] Sending %s %s\n", (char *) path.c_str(), message);
mqtt.publish(path.c_str(), message, MQTT_RETAIN);
mqtt.publish(path.c_str(), MQTT_QOS, MQTT_RETAIN, message);
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
void _mqttOnConnect(bool sessionPresent) {
DEBUG_MSG("[MQTT] Connected!\n");
// Send status via webSocket
webSocketSend((char *) "{\"mqttStatus\": true}");
// Build MQTT topics
buildTopics();
// 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 *) (digitalRead(RELAY_PIN) ? "1" : "0"));
// Subscribe to topic
DEBUG_MSG("[MQTT] Subscribing to %s\n", (char *) mqttTopic.c_str());
mqtt.subscribe(mqttTopic.c_str(), MQTT_QOS);
}
void _mqttOnDisconnect(AsyncMqttClientDisconnectReason reason) {
// Send status via webSocket
webSocketSend((char *) "{\"mqttStatus\": false}");
}
void _mqttOnMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
static bool isFirstMessage = true;
#ifdef DEBUG_PORT
char buffer[length+1];
memcpy(buffer, payload, length);
buffer[length] = 0;
DEBUG_MSG("[MQTT] Received %s %s\n", topic, buffer);
#endif
payload[len] = '\0';
DEBUG_MSG("[MQTT] Received %s %s\n", topic, payload);
// If relayMode is not SAME avoid responding to a retained message
if (isFirstMessage) {
@ -89,52 +117,31 @@ void mqttConnect() {
if (host.length() == 0) return;
DEBUG_MSG("[MQTT] Connecting to broker at %s", (char *) host.c_str());
mqtt.setServer(host.c_str(), port.toInt());
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: ", (char *) user.c_str());
mqtt.connect(getSetting("hostname", HOSTNAME).c_str(), user.c_str(), pass.c_str());
DEBUG_MSG(" as user %s.\n", (char *) user.c_str());
mqtt.setCredentials(user.c_str(), pass.c_str());
} else {
DEBUG_MSG(" anonymously: ");
mqtt.connect(getSetting("hostname", HOSTNAME).c_str());
DEBUG_MSG(" anonymously\n");
}
if (mqtt.connected()) {
mqtt.connect();
DEBUG_MSG("connected!\n");
buildTopics();
mqttStatus = true;
// Send status via webSocket
webSocketSend((char *) "{\"mqttStatus\": true}");
// 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 *) (digitalRead(RELAY_PIN) ? "1" : "0"));
// Subscribe to topic
DEBUG_MSG("[MQTT] Subscribing to %s\n", (char *) mqttTopic.c_str());
mqtt.subscribe(mqttTopic.c_str());
} else {
DEBUG_MSG("failed (rc=%d)\n", mqtt.state());
}
}
}
void mqttSetup() {
mqtt.setCallback(mqttCallback);
mqtt.onConnect(_mqttOnConnect);
mqtt.onDisconnect(_mqttOnDisconnect);
mqtt.onMessage(_mqttOnMessage);
}
void mqttLoop() {
@ -145,11 +152,6 @@ void mqttLoop() {
if (!mqtt.connected()) {
if (mqttStatus) {
webSocketSend((char *) "{\"mqttStatus\": false}");
mqttStatus = false;
}
unsigned long currPeriod = millis() / MQTT_RECONNECT_DELAY;
if (currPeriod != lastPeriod) {
lastPeriod = currPeriod;
@ -158,8 +160,6 @@ void mqttLoop() {
}
if (mqtt.connected()) mqtt.loop();
}
}

+ 1
- 1
code/src/version.h View File

@ -1,4 +1,4 @@
#define APP_NAME "Espurna"
#define APP_VERSION "0.9.9"
#define APP_VERSION "1.0.0"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"

code/src/websockets.ino → code/src/web.ino View File

@ -1,17 +1,22 @@
/*
RENTALITO
ESPurna
WEBSERVER MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <WebSocketsServer.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ESP8266mDNS.h>
#include "FS.h"
#include <Hash.h>
#include "AsyncJson.h"
#include <ArduinoJson.h>
WebSocketsServer webSocket = WebSocketsServer(81);
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
// -----------------------------------------------------------------------------
// WEBSOCKETS
@ -19,21 +24,22 @@ WebSocketsServer webSocket = WebSocketsServer(81);
bool webSocketSend(char * payload) {
//DEBUG_MSG("[WEBSOCKET] Broadcasting '%s'\n", payload);
webSocket.broadcastTXT(payload);
ws.textAll(payload);
}
bool webSocketSend(uint8_t num, char * payload) {
//DEBUG_MSG("[WEBSOCKET] Sending '%s' to #%d\n", payload, num);
webSocket.sendTXT(num, payload);
bool webSocketSend(uint32_t client_id, char * payload) {
//DEBUG_MSG("[WEBSOCKET] Sending '%s' to #%ld\n", payload, client_id);
ws.text(client_id, payload);
}
void webSocketParse(uint8_t num, uint8_t * payload, size_t length) {
void webSocketParse(uint32_t client_id, uint8_t * payload, size_t length) {
// Parse JSON input
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char *) payload);
if (!root.success()) {
DEBUG_MSG("[WEBSOCKET] Error parsing data\n");
ws.text(client_id, "{\"message\": \"Error parsing data!\"}");
return;
}
@ -62,8 +68,6 @@ void webSocketParse(uint8_t num, uint8_t * payload, size_t length) {
for (unsigned int i=0; i<config.size(); i++) {
yield();
String key = config[i]["name"];
String value = config[i]["value"];
@ -76,6 +80,11 @@ void webSocketParse(uint8_t num, uint8_t * payload, size_t length) {
#endif
// Do not change the password if empty
if (key == "httpPassword") {
if (value.length() == 0) continue;
}
if (key == "ssid") {
key = key + String(network);
}
@ -97,6 +106,7 @@ void webSocketParse(uint8_t num, uint8_t * payload, size_t length) {
saveSettings();
wifiConfigure();
buildTopics();
#if ENABLE_RF
rfBuildCodes();
@ -111,13 +121,19 @@ void webSocketParse(uint8_t num, uint8_t * payload, size_t length) {
mqttDisconnect();
}
ws.text(client_id, "{\"message\": \"Changes saved\"}");
} else {
ws.text(client_id, "{\"message\": \"No changes detected\"}");
}
}
}
void webSocketStart(uint8_t num) {
void webSocketStart(uint32_t client_id) {
char app[64];
sprintf(app, "%s %s", APP_NAME, APP_VERSION);
@ -178,42 +194,49 @@ void webSocketStart(uint8_t num) {
String output;
root.printTo(output);
webSocket.sendTXT(num, (char *) output.c_str());
ws.text(client_id, (char *) output.c_str());
}
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
DEBUG_MSG("[WEBSOCKET] #%u disconnected\n", num);
break;
case WStype_CONNECTED:
#if DEBUG_PORT
{
IPAddress ip = webSocket.remoteIP(num);
DEBUG_MSG("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
}
#endif
webSocketStart(num);
break;
case WStype_TEXT:
//DEBUG_MSG("[WEBSOCKET] #%u sent: %s\n", num, payload);
webSocketParse(num, payload, length);
break;
case WStype_BIN:
//DEBUG_MSG("[WEBSOCKET] #%u sent binary length: %u\n", num, length);
webSocketParse(num, payload, length);
break;
void webSocketEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
if (type == WS_EVT_CONNECT) {
#if DEBUG_PORT
{
IPAddress ip = server.remoteIP(client->id());
DEBUG_MSG("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n", client->id(), ip[0], ip[1], ip[2], ip[3], server->url());
}
#endif
webSocketStart(client->id());
} else if(type == WS_EVT_DISCONNECT) {
DEBUG_MSG("[WEBSOCKET] #%u disconnected\n", client->id());
} else if(type == WS_EVT_ERROR) {
DEBUG_MSG("[WEBSOCKET] #%u error(%u): %s\n", client->id(), *((uint16_t*)arg), (char*)data);
} else if(type == WS_EVT_PONG) {
DEBUG_MSG("[WEBSOCKET] #%u pong(%u): %s\n", client->id(), len, len ? (char*) data : "");
} else if(type == WS_EVT_DATA) {
webSocketParse(client->id(), data, len);
}
}
void webSocketSetup() {
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
// -----------------------------------------------------------------------------
// WEBSERVER
// -----------------------------------------------------------------------------
void webSetup() {
// Setup websocket plugin
ws.onEvent(webSocketEvent);
server.addHandler(&ws);
// Serve static files
server.serveStatic("/", SPIFFS, "/").setDefaultFile("/index.html");
// 404
server.onNotFound([](AsyncWebServerRequest *request){
request->send(404);
});
// Run server
server.begin();
void webSocketLoop() {
webSocket.loop();
}

+ 0
- 86
code/src/webserver.ino View File

@ -1,86 +0,0 @@
/*
ESPurna
WEBSERVER MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "FS.h"
ESP8266WebServer server(80);
// -----------------------------------------------------------------------------
// WEBSERVER
// -----------------------------------------------------------------------------
String getContentType(String filename) {
if (server.hasArg("download")) return "application/octet-stream";
else if (filename.endsWith(".htm")) return "text/html";
else if (filename.endsWith(".html")) return "text/html";
else if (filename.endsWith(".css")) return "text/css";
else if (filename.endsWith(".js")) return "application/javascript";
else if (filename.endsWith(".png")) return "image/png";
else if (filename.endsWith(".gif")) return "image/gif";
else if (filename.endsWith(".jpg")) return "image/jpeg";
else if (filename.endsWith(".ico")) return "image/x-icon";
else if (filename.endsWith(".xml")) return "text/xml";
else if (filename.endsWith(".pdf")) return "application/x-pdf";
else if (filename.endsWith(".zip")) return "application/x-zip";
else if (filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
bool handleFileRead(String path) {
DEBUG_MSG("[WEBSERVER] Request: %s\n", (char *) path.c_str());
if (path.endsWith("/")) path += "index.html";
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if (SPIFFS.exists(pathWithGz)) path = pathWithGz;
if (SPIFFS.exists(path)) {
File file = SPIFFS.open(path, "r");
size_t sent = server.streamFile(file, contentType);
size_t contentLength = file.size();
file.close();
return true;
}
return false;
}
void webServerSetup() {
// Anything else
server.onNotFound([]() {
// Hidden files
#ifndef DEBUG_PORT
if (server.uri().startsWith("/.")) {
server.send(403, "text/plain", "Forbidden");
return;
}
#endif
// Existing files in SPIFFS
if (!handleFileRead(server.uri())) {
server.send(404, "text/plain", "NotFound");
return;
}
});
// Run server
server.begin();
}
void webServerLoop() {
server.handleClient();
}

Loading…
Cancel
Save