mirror of
https://github.com/xoseperez/espurna.git
synced 2026-03-23 16:47:08 +01:00
merge dev branch
This commit is contained in:
1
code/.gitignore
vendored
1
code/.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
.pioenvs
|
||||
.piolibdeps
|
||||
.vscode/c_cpp_properties.json
|
||||
core_version.h
|
||||
|
||||
51
code/core_version.py
Normal file
51
code/core_version.py
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/bin/python
|
||||
|
||||
import json
|
||||
import commands
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
|
||||
def core_version(env):
|
||||
|
||||
# Get the core folder
|
||||
fwdir = env["FRAMEWORK_ARDUINOESP8266_DIR"]
|
||||
|
||||
# Get the core version
|
||||
with open(fwdir + '/package.json') as data_file:
|
||||
data = json.load(data_file)
|
||||
core_version = data["version"].upper().replace(".", "_").replace("-", "_")
|
||||
print "CORE VERSION: %s" % core_version
|
||||
|
||||
# Get git version
|
||||
pr = subprocess.Popen(
|
||||
"git --git-dir .git rev-parse --short=8 HEAD 2>/dev/null || echo ffffffff",
|
||||
cwd = fwdir,
|
||||
shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE )
|
||||
(out, error) = pr.communicate()
|
||||
git_version = str(out).replace('\n', "")
|
||||
print "GIT VERSION: %s" % git_version
|
||||
|
||||
#env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_RELEASE=" + core_version)
|
||||
#env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_RELEASE_" + core_version)
|
||||
#env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_GIT_VER=" + git_version)
|
||||
|
||||
with open('espurna/config/core_version.h', 'w') as the_file:
|
||||
the_file.write('#define ARDUINO_ESP8266_RELEASE "%s"\n' % core_version)
|
||||
the_file.write('#define ARDUINO_ESP8266_RELEASE_%s\n' % core_version)
|
||||
the_file.write('#define ARDUINO_ESP8266_GIT_VER "%s"\n' % git_version)
|
||||
|
||||
#env.Append(
|
||||
# CFLAGS = [
|
||||
# str("-DARDUINO_ESP8266_RELEASE=" + core_version),
|
||||
# str("-DARDUINO_ESP8266_RELEASE_" + core_version),
|
||||
# str("-DARDUINO_ESP8266_GIT_VER=" + git_version)
|
||||
# ]
|
||||
#)
|
||||
|
||||
#print " -DARDUINO_ESP8266_RELEASE=" + core_version +
|
||||
# " -DARDUINO_ESP8266_RELEASE_" + core_version +
|
||||
# " -DARDUINO_ESP8266_GIT_VER=" + git_version
|
||||
|
||||
Import('env')
|
||||
core_version(env)
|
||||
@@ -20,6 +20,15 @@ bool _alexa_change = false;
|
||||
unsigned int _alexa_device_id = 0;
|
||||
bool _alexa_state = false;
|
||||
|
||||
#if WEB_SUPPORT
|
||||
void _alexaWSSend(JsonObject& root) {
|
||||
root["alexaVisible"] = 1;
|
||||
root["alexaEnabled"] = getSetting("alexaEnabled", ALEXA_ENABLED).toInt() == 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void alexaConfigure() {
|
||||
alexa.enable(getSetting("alexaEnabled", ALEXA_ENABLED).toInt() == 1);
|
||||
}
|
||||
@@ -29,8 +38,14 @@ void alexaSetup() {
|
||||
// Backwards compatibility
|
||||
moveSetting("fauxmoEnabled", "alexaEnabled");
|
||||
|
||||
// Load & cache settings
|
||||
alexaConfigure();
|
||||
|
||||
#if WEB_SUPPORT
|
||||
// Websockets
|
||||
wsRegister(_alexaWSSend);
|
||||
#endif
|
||||
|
||||
unsigned int relays = relayCount();
|
||||
String hostname = getSetting("hostname");
|
||||
if (relays == 1) {
|
||||
|
||||
@@ -12,6 +12,13 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
// ANALOG
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void _analogWSSend(JsonObject& root) {
|
||||
root["analogVisible"] = 1;
|
||||
root["analogValue"] = getAnalog();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
unsigned int getAnalog() {
|
||||
return analogRead(ANALOG_PIN);
|
||||
}
|
||||
@@ -21,9 +28,15 @@ void analogSetup() {
|
||||
pinMode(ANALOG_PIN, INPUT);
|
||||
|
||||
#if WEB_SUPPORT
|
||||
|
||||
// Websocket register
|
||||
wsRegister(_analogWSSend);
|
||||
|
||||
// API register
|
||||
apiRegister(ANALOG_TOPIC, ANALOG_TOPIC, [](char * buffer, size_t len) {
|
||||
snprintf_P(buffer, len, PSTR("%d"), getAnalog());
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
DEBUG_MSG_P(PSTR("[ANALOG] Monitoring analog values\n"));
|
||||
@@ -51,14 +64,12 @@ void analogLoop() {
|
||||
|
||||
// Send to InfluxDB
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSend(MQTT_TOPIC_ANALOG, analog);
|
||||
idbSend(MQTT_TOPIC_ANALOG, analog);
|
||||
#endif
|
||||
|
||||
// Update websocket clients
|
||||
#if WEB_SUPPORT
|
||||
char buffer[100];
|
||||
snprintf_P(buffer, sizeof(buffer), PSTR("{\"analogVisible\": 1, \"analogValue\": %d}"), analog);
|
||||
wsSend(buffer);
|
||||
wsSend(_analogWSSend);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
181
code/espurna/api.ino
Normal file
181
code/espurna/api.ino
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
|
||||
API MODULE
|
||||
|
||||
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
*/
|
||||
|
||||
#if WEB_SUPPORT
|
||||
|
||||
#include <ESPAsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <vector>
|
||||
|
||||
typedef struct {
|
||||
char * url;
|
||||
char * key;
|
||||
api_get_callback_f getFn = NULL;
|
||||
api_put_callback_f putFn = NULL;
|
||||
} web_api_t;
|
||||
std::vector<web_api_t> _apis;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// API
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool _authAPI(AsyncWebServerRequest *request) {
|
||||
|
||||
if (getSetting("apiEnabled", API_ENABLED).toInt() == 0) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSERVER] HTTP API is not enabled\n"));
|
||||
request->send(403);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!request->hasParam("apikey", (request->method() == HTTP_PUT))) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSERVER] Missing apikey parameter\n"));
|
||||
request->send(403);
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncWebParameter* p = request->getParam("apikey", (request->method() == HTTP_PUT));
|
||||
if (!p->value().equals(getSetting("apiKey"))) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSERVER] Wrong apikey parameter\n"));
|
||||
request->send(403);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool _asJson(AsyncWebServerRequest *request) {
|
||||
bool asJson = false;
|
||||
if (request->hasHeader("Accept")) {
|
||||
AsyncWebHeader* h = request->getHeader("Accept");
|
||||
asJson = h->value().equals("application/json");
|
||||
}
|
||||
return asJson;
|
||||
}
|
||||
|
||||
ArRequestHandlerFunction _bindAPI(unsigned int apiID) {
|
||||
|
||||
return [apiID](AsyncWebServerRequest *request) {
|
||||
|
||||
webLog(request);
|
||||
if (!_authAPI(request)) return;
|
||||
|
||||
web_api_t api = _apis[apiID];
|
||||
|
||||
// Check if its a PUT
|
||||
if (api.putFn != NULL) {
|
||||
if (request->hasParam("value", request->method() == HTTP_PUT)) {
|
||||
AsyncWebParameter* p = request->getParam("value", request->method() == HTTP_PUT);
|
||||
(api.putFn)((p->value()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Get response from callback
|
||||
char value[API_BUFFER_SIZE];
|
||||
(api.getFn)(value, API_BUFFER_SIZE);
|
||||
|
||||
// The response will be a 404 NOT FOUND if the resource is not available
|
||||
if (!value) {
|
||||
DEBUG_MSG_P(PSTR("[API] Sending 404 response\n"));
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
DEBUG_MSG_P(PSTR("[API] Sending response '%s'\n"), value);
|
||||
|
||||
// Format response according to the Accept header
|
||||
if (_asJson(request)) {
|
||||
char buffer[64];
|
||||
snprintf_P(buffer, sizeof(buffer), PSTR("{ \"%s\": %s }"), api.key, value);
|
||||
request->send(200, "application/json", buffer);
|
||||
} else {
|
||||
request->send(200, "text/plain", value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void _onAPIs(AsyncWebServerRequest *request) {
|
||||
|
||||
webLog(request);
|
||||
if (!_authAPI(request)) return;
|
||||
|
||||
bool asJson = _asJson(request);
|
||||
|
||||
String output;
|
||||
if (asJson) {
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
for (unsigned int i=0; i < _apis.size(); i++) {
|
||||
root[_apis[i].key] = _apis[i].url;
|
||||
}
|
||||
root.printTo(output);
|
||||
request->send(200, "application/json", output);
|
||||
|
||||
} else {
|
||||
for (unsigned int i=0; i < _apis.size(); i++) {
|
||||
output += _apis[i].key + String(" -> ") + _apis[i].url + String("\n");
|
||||
}
|
||||
request->send(200, "text/plain", output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _onRPC(AsyncWebServerRequest *request) {
|
||||
|
||||
webLog(request);
|
||||
if (!_authAPI(request)) return;
|
||||
|
||||
//bool asJson = _asJson(request);
|
||||
int response = 404;
|
||||
|
||||
if (request->hasParam("action")) {
|
||||
|
||||
AsyncWebParameter* p = request->getParam("action");
|
||||
String action = p->value();
|
||||
DEBUG_MSG_P(PSTR("[RPC] Action: %s\n"), action.c_str());
|
||||
|
||||
if (action.equals("reset")) {
|
||||
response = 200;
|
||||
deferredReset(100, CUSTOM_RESET_RPC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
request->send(response);
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void apiRegister(const char * url, const char * key, api_get_callback_f getFn, api_put_callback_f putFn) {
|
||||
|
||||
// Store it
|
||||
web_api_t api;
|
||||
char buffer[40];
|
||||
snprintf_P(buffer, sizeof(buffer), PSTR("/api/%s"), url);
|
||||
api.url = strdup(buffer);
|
||||
api.key = strdup(key);
|
||||
api.getFn = getFn;
|
||||
api.putFn = putFn;
|
||||
_apis.push_back(api);
|
||||
|
||||
// Bind call
|
||||
unsigned int methods = HTTP_GET;
|
||||
if (putFn != NULL) methods += HTTP_PUT;
|
||||
webServer()->on(buffer, methods, _bindAPI(_apis.size() - 1));
|
||||
|
||||
}
|
||||
|
||||
void apiSetup() {
|
||||
webServer()->on("/apis", HTTP_GET, _onAPIs);
|
||||
webServer()->on("/rpc", HTTP_GET, _onRPC);
|
||||
}
|
||||
|
||||
#endif // WEB_SUPPORT
|
||||
@@ -104,15 +104,13 @@ void buttonEvent(unsigned int id, unsigned char event) {
|
||||
}
|
||||
if (action == BUTTON_MODE_AP) createAP();
|
||||
if (action == BUTTON_MODE_RESET) {
|
||||
customReset(CUSTOM_RESET_HARDWARE);
|
||||
ESP.restart();
|
||||
deferredReset(100, CUSTOM_RESET_HARDWARE);
|
||||
}
|
||||
if (action == BUTTON_MODE_PULSE) relayPulseToggle();
|
||||
if (action == BUTTON_MODE_FACTORY) {
|
||||
DEBUG_MSG_P(PSTR("\n\nFACTORY RESET\n\n"));
|
||||
settingsFactoryReset();
|
||||
customReset(CUSTOM_RESET_FACTORY);
|
||||
ESP.restart();
|
||||
deferredReset(100, CUSTOM_RESET_FACTORY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
#include "sensors.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
#ifdef USE_CORE_VERSION_H
|
||||
#include "core_version.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
If you want to modify the stock configuration but you don't want to touch
|
||||
the repo files you can either define USE_CUSTOM_H or remove the
|
||||
the repo files you can either define USE_CUSTOM_H or remove the
|
||||
"#ifdef USE_CUSTOM_H" & "#endif" lines and add a "custom.h"
|
||||
file to this same folder.
|
||||
Check https://bitbucket.org/xoseperez/espurna/issues/104/general_customh
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
//#define I2C_SUPPORT 1
|
||||
//#define INFLUXDB_SUPPORT 0
|
||||
//#define IR_SUPPORT 1
|
||||
//#define LLMNR_SUPPORT 1
|
||||
//#define MDNS_SUPPORT 0
|
||||
//#define NOFUSS_SUPPORT 1
|
||||
//#define NTP_SUPPORT 0
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#define ADMIN_PASS "fibonacci" // Default password (WEB, OTA, WIFI)
|
||||
#define DEVICE_NAME MANUFACTURER "_" DEVICE // Concatenate both to get a unique device name
|
||||
#define LOOP_DELAY_TIME 10 // Delay for this millis in the main loop [0-250]
|
||||
|
||||
#define ARRAYINIT(type, name, ...) \
|
||||
type name[] = {__VA_ARGS__};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TELNET
|
||||
@@ -59,10 +63,9 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// General debug options and macros
|
||||
#define DEBUG_MESSAGE_MAX_LENGTH 80
|
||||
#define DEBUG_FORMAT_MAX_LENGTH 80
|
||||
#define DEBUG_SUPPORT DEBUG_SERIAL_SUPPORT || DEBUG_UDP_SUPPORT || DEBUG_TELNET_SUPPORT
|
||||
|
||||
|
||||
#if DEBUG_SUPPORT
|
||||
#define DEBUG_MSG(...) debugSend(__VA_ARGS__)
|
||||
#define DEBUG_MSG_P(...) debugSend_P(__VA_ARGS__)
|
||||
@@ -82,11 +85,15 @@
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CRASH
|
||||
// SYSTEM CHECK
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define CRASH_SAFE_TIME 60000 // The system is considered stable after these many millis
|
||||
#define CRASH_COUNT_MAX 5 // After this many crashes on boot
|
||||
#ifndef SYSTEM_CHECK_ENABLED
|
||||
#define SYSTEM_CHECK_ENABLED 1 // Enable crash check by default
|
||||
#endif
|
||||
|
||||
#define SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis
|
||||
#define SYSTEM_CHECK_MAX 5 // After this many crashes on boot
|
||||
// the system is flagged as unstable
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -263,6 +270,7 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
#define WIFI_RECONNECT_INTERVAL 180000 // If could not connect to WIFI, retry after this time in ms
|
||||
#define WIFI_MAX_NETWORKS 5 // Max number of WIFI connection configurations
|
||||
#define WIFI_AP_MODE AP_MODE_ALONE
|
||||
#define WIFI_SLEEP_ENABLED 1 // Enable WiFi light sleep
|
||||
|
||||
// Optional hardcoded configuration (up to 2 different networks)
|
||||
//#define WIFI1_SSID "..."
|
||||
@@ -317,13 +325,17 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
#define API_REAL_TIME_VALUES 0 // Show filtered/median values by default (0 => median, 1 => real time)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MDNS
|
||||
// MDNS & LLMNR
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifndef MDNS_SUPPORT
|
||||
#define MDNS_SUPPORT 1 // Publish services using mDNS by default
|
||||
#endif
|
||||
|
||||
#ifndef LLMNR_SUPPORT
|
||||
#define LLMNR_SUPPORT 0 // Publish device using LLMNR protocol by default - requires 2.4.0
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SPIFFS
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -475,7 +487,7 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
|
||||
// Available light providers (do not change)
|
||||
#define LIGHT_PROVIDER_NONE 0
|
||||
#define LIGHT_PROVIDER_MY9192 1 // works with MY9231 also (Sonoff B1)
|
||||
#define LIGHT_PROVIDER_MY92XX 1 // works with MY9291 and MY9231
|
||||
#define LIGHT_PROVIDER_DIMMER 2
|
||||
|
||||
// LIGHT_PROVIDER_DIMMER can have from 1 to 5 different channels.
|
||||
@@ -500,7 +512,7 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
|
||||
#ifndef LIGHT_MAX_PWM
|
||||
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX
|
||||
#define LIGHT_MAX_PWM 255
|
||||
#endif
|
||||
|
||||
@@ -664,6 +676,7 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
#define DOMOTICZ_ENABLED 0 // Disable domoticz by default
|
||||
#define DOMOTICZ_IN_TOPIC "domoticz/in" // Default subscription topic
|
||||
#define DOMOTICZ_OUT_TOPIC "domoticz/out" // Default publication topic
|
||||
#define DOMOTICZ_SKIP_TIME 2 // Avoid recursion skipping messages to same IDX within 2 seconds
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// HOME ASSISTANT
|
||||
@@ -673,6 +686,7 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
#define HOMEASSISTANT_SUPPORT 1 // Build with home assistant support
|
||||
#endif
|
||||
|
||||
#define HOMEASSISTANT_ENABLED 0 // Integration not enabled by default
|
||||
#define HOMEASSISTANT_PREFIX "homeassistant" // Default MQTT prefix
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -321,7 +321,6 @@
|
||||
#define RELAY_PROVIDER RELAY_PROVIDER_DUAL
|
||||
#define DUMMY_RELAY_COUNT 2
|
||||
#define DEBUG_SERIAL_SUPPORT 0
|
||||
#define TERMINAL_SUPPORT 0
|
||||
|
||||
// Buttons
|
||||
#define BUTTON3_RELAY 1
|
||||
@@ -464,7 +463,7 @@
|
||||
#define LED1_PIN 13
|
||||
#define LED1_PIN_INVERSE 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 1
|
||||
#define LIGHT_CH1_PIN 12
|
||||
#define LIGHT_CH1_INVERSE 0
|
||||
@@ -497,12 +496,17 @@
|
||||
#define MANUFACTURER "ITEAD"
|
||||
#define DEVICE "SONOFF_B1"
|
||||
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY9192
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX
|
||||
#define DUMMY_RELAY_COUNT 1
|
||||
#define MY9291_DI_PIN 12
|
||||
#define MY9291_DCKI_PIN 14
|
||||
#define MY9291_COMMAND MY9291_COMMAND_DEFAULT
|
||||
#define MY9291_CHANNELS 5
|
||||
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 5
|
||||
#define MY92XX_MODEL MY92XX_MODEL_MY9231
|
||||
#define MY92XX_CHIPS 2
|
||||
#define MY92XX_DI_PIN 12
|
||||
#define MY92XX_DCKI_PIN 14
|
||||
#define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT
|
||||
#define MY92XX_MAPPING 4, 3, 5, 0, 1
|
||||
|
||||
#elif defined(ITEAD_SONOFF_LED)
|
||||
|
||||
@@ -517,7 +521,7 @@
|
||||
#define LED1_PIN 13
|
||||
#define LED1_PIN_INVERSE 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 2
|
||||
#define LIGHT_CH1_PIN 12 // Cold white
|
||||
#define LIGHT_CH2_PIN 14 // Warm white
|
||||
@@ -531,12 +535,12 @@
|
||||
#define DEVICE "SONOFF_T1_1CH"
|
||||
|
||||
// Buttons
|
||||
#define BUTTON1_PIN 9
|
||||
#define BUTTON1_PIN 0
|
||||
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
|
||||
#define BUTTON1_RELAY 1
|
||||
|
||||
// Relays
|
||||
#define RELAY1_PIN 5
|
||||
#define RELAY1_PIN 12
|
||||
#define RELAY1_TYPE RELAY_TYPE_NORMAL
|
||||
|
||||
// LEDs
|
||||
@@ -551,7 +555,7 @@
|
||||
|
||||
// Buttons
|
||||
#define BUTTON1_PIN 0
|
||||
#define BUTTON2_PIN 10
|
||||
#define BUTTON2_PIN 9
|
||||
|
||||
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
|
||||
#define BUTTON2_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
|
||||
@@ -561,7 +565,7 @@
|
||||
|
||||
// Relays
|
||||
#define RELAY1_PIN 12
|
||||
#define RELAY2_PIN 4
|
||||
#define RELAY2_PIN 5
|
||||
|
||||
#define RELAY1_TYPE RELAY_TYPE_NORMAL
|
||||
#define RELAY2_TYPE RELAY_TYPE_NORMAL
|
||||
@@ -700,12 +704,17 @@
|
||||
#define MANUFACTURER "AITHINKER"
|
||||
#define DEVICE "AI_LIGHT"
|
||||
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY9192
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX
|
||||
#define DUMMY_RELAY_COUNT 1
|
||||
#define MY9291_DI_PIN 13
|
||||
#define MY9291_DCKI_PIN 15
|
||||
#define MY9291_COMMAND MY9291_COMMAND_DEFAULT
|
||||
#define MY9291_CHANNELS 4
|
||||
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 4
|
||||
#define MY92XX_MODEL MY92XX_MODEL_MY9291
|
||||
#define MY92XX_CHIPS 1
|
||||
#define MY92XX_DI_PIN 13
|
||||
#define MY92XX_DCKI_PIN 15
|
||||
#define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT
|
||||
#define MY92XX_MAPPING 0, 1, 2, 3
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// LED Controller
|
||||
@@ -724,7 +733,7 @@
|
||||
#define LED1_PIN 2
|
||||
#define LED1_PIN_INVERSE 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 4
|
||||
#define LIGHT_CH1_PIN 14 // RED
|
||||
#define LIGHT_CH2_PIN 5 // GREEN
|
||||
@@ -755,7 +764,7 @@
|
||||
#define LED1_PIN 2
|
||||
#define LED1_PIN_INVERSE 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 4
|
||||
#define LIGHT_CH1_PIN 5 // RED
|
||||
#define LIGHT_CH2_PIN 12 // GREEN
|
||||
@@ -788,7 +797,7 @@
|
||||
#define LED1_PIN 5
|
||||
#define LED1_PIN_INVERSE 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 5
|
||||
#define LIGHT_CH1_PIN 15 // RED
|
||||
#define LIGHT_CH2_PIN 13 // GREEN
|
||||
@@ -810,7 +819,7 @@
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
|
||||
#define DUMMY_RELAY_COUNT 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 4
|
||||
#define LIGHT_CH1_PIN 12 // RED
|
||||
#define LIGHT_CH2_PIN 14 // GREEN
|
||||
@@ -1047,7 +1056,7 @@
|
||||
#define LED1_PIN 5
|
||||
#define LED1_PIN_INVERSE 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 2
|
||||
#define LIGHT_CH1_PIN 0
|
||||
#define LIGHT_CH2_PIN 2
|
||||
@@ -1067,7 +1076,7 @@
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
|
||||
#define DUMMY_RELAY_COUNT 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 5
|
||||
#define LIGHT_CH1_PIN 14 // RED
|
||||
#define LIGHT_CH2_PIN 12 // GREEN
|
||||
@@ -1087,14 +1096,17 @@
|
||||
#define MANUFACTURER "ARILUX"
|
||||
#define DEVICE "E27"
|
||||
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY9192
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY92XX
|
||||
#define DUMMY_RELAY_COUNT 1
|
||||
|
||||
// Channels
|
||||
#define MY9291_CHANNELS 4
|
||||
#define MY9291_DI_PIN 13
|
||||
#define MY9291_DCKI_PIN 15
|
||||
#define MY9291_COMMAND MY9291_COMMAND_DEFAULT
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 4
|
||||
#define MY92XX_MODEL MY92XX_MODEL_MY9291
|
||||
#define MY92XX_CHIPS 1
|
||||
#define MY92XX_DI_PIN 13
|
||||
#define MY92XX_DCKI_PIN 15
|
||||
#define MY92XX_COMMAND MY92XX_COMMAND_DEFAULT
|
||||
#define MY92XX_MAPPING 0, 1, 2, 3
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// XENON SM-PW701U
|
||||
@@ -1133,7 +1145,7 @@
|
||||
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
|
||||
#define DUMMY_RELAY_COUNT 1
|
||||
|
||||
// Channels
|
||||
// Light
|
||||
#define LIGHT_CHANNELS 4
|
||||
#define LIGHT_CH1_PIN 13 // RED
|
||||
#define LIGHT_CH2_PIN 12 // GREEN
|
||||
|
||||
@@ -2,22 +2,32 @@
|
||||
#include <NtpClientLib.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncMqttClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <functional>
|
||||
#include <FastLED.h>
|
||||
|
||||
typedef std::function<void(char *, size_t)> apiGetCallbackFunction;
|
||||
typedef std::function<void(const char *)> apiPutCallbackFunction;
|
||||
void apiRegister(const char * url, const char * key, apiGetCallbackFunction getFn, apiPutCallbackFunction putFn = NULL);
|
||||
AsyncWebServer * webServer();
|
||||
|
||||
void mqttRegister(void (*callback)(unsigned int, const char *, const char *));
|
||||
typedef std::function<void(char *, size_t)> api_get_callback_f;
|
||||
typedef std::function<void(const char *)> api_put_callback_f;
|
||||
void apiRegister(const char * url, const char * key, api_get_callback_f getFn, api_put_callback_f putFn = NULL);
|
||||
|
||||
typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f;
|
||||
void mqttRegister(mqtt_callback_f callback);
|
||||
String mqttSubtopic(char * topic);
|
||||
|
||||
typedef std::function<void(JsonObject&)> ws_callback_f;
|
||||
void wsRegister(ws_callback_f sender, ws_callback_f receiver = NULL);
|
||||
void wsSend(ws_callback_f sender);
|
||||
|
||||
template<typename T> bool setSetting(const String& key, T value);
|
||||
template<typename T> bool setSetting(const String& key, unsigned int index, T value);
|
||||
template<typename T> String getSetting(const String& key, T defaultValue);
|
||||
template<typename T> String getSetting(const String& key, unsigned int index, T defaultValue);
|
||||
|
||||
template<typename T> void domoticzSend(const char * key, T value);
|
||||
template<typename T> void domoticzSend(const char * key, T nvalue, const char * svalue);
|
||||
|
||||
template<typename T> bool influxDBSend(const char * topic, T payload);
|
||||
template<typename T> bool idbSend(const char * topic, T payload);
|
||||
|
||||
char * ltrim(char * s);
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
#define DHT_UPDATE_INTERVAL 60000
|
||||
#endif
|
||||
|
||||
#define DHT_TIMING 11
|
||||
#define DHT_TEMPERATURE_TOPIC "temperature"
|
||||
#define DHT_HUMIDITY_TOPIC "humidity"
|
||||
#define DHT_TEMPERATURE_DECIMALS 1 // Decimals for temperature values
|
||||
|
||||
#define HUMIDITY_NORMAL 0
|
||||
#define HUMIDITY_COMFORTABLE 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define APP_NAME "ESPURNA"
|
||||
#define APP_VERSION "1.9.9"
|
||||
#define APP_VERSION "1.9.10b"
|
||||
#define APP_AUTHOR "xose.perez@gmail.com"
|
||||
#define APP_WEBSITE "http://tinkerman.cat"
|
||||
|
||||
@@ -26,6 +26,13 @@ void ICACHE_RAM_ATTR _counterISR() {
|
||||
}
|
||||
}
|
||||
|
||||
#if WEB_SUPPORT
|
||||
void _counterWSSend(JsonObject& root) {
|
||||
root["counterVisible"] = 1;
|
||||
root["counterValue"] = getCounter();
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long getCounter() {
|
||||
return _counterValue;
|
||||
}
|
||||
@@ -36,9 +43,15 @@ void counterSetup() {
|
||||
attachInterrupt(COUNTER_PIN, _counterISR, COUNTER_INTERRUPT_MODE);
|
||||
|
||||
#if WEB_SUPPORT
|
||||
|
||||
// Websockets
|
||||
wsRegister(_counterWSSend);
|
||||
|
||||
// API
|
||||
apiRegister(COUNTER_TOPIC, COUNTER_TOPIC, [](char * buffer, size_t len) {
|
||||
snprintf_P(buffer, len, PSTR("%d"), getCounter());
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
DEBUG_MSG_P(PSTR("[COUNTER] Counter on GPIO %d\n"), COUNTER_PIN);
|
||||
@@ -62,9 +75,7 @@ void counterLoop() {
|
||||
|
||||
// Update websocket clients
|
||||
#if WEB_SUPPORT
|
||||
char buffer[100];
|
||||
snprintf_P(buffer, sizeof(buffer), PSTR("{\"counterVisible\": 1, \"counterValue\": %d}"), _counterValue);
|
||||
wsSend(buffer);
|
||||
wsSend(_counterWSSend);
|
||||
#endif
|
||||
|
||||
// Do we have to report?
|
||||
@@ -80,7 +91,7 @@ void counterLoop() {
|
||||
|
||||
// Send to InfluxDB
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSend(COUNTER_TOPIC, _counterValue);
|
||||
idbSend(COUNTER_TOPIC, _counterValue);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -18,73 +18,75 @@ WiFiUDP udpDebug;
|
||||
|
||||
void debugSend(const char * format, ...) {
|
||||
|
||||
char buffer[DEBUG_MESSAGE_MAX_LENGTH+1];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int len = ets_vsnprintf(buffer, DEBUG_MESSAGE_MAX_LENGTH, format, args);
|
||||
char test[1];
|
||||
int len = ets_vsnprintf(test, 1, format, args) + 1;
|
||||
char * buffer = new char[len];
|
||||
ets_vsnprintf(buffer, len, format, args);
|
||||
va_end(args);
|
||||
|
||||
#if DEBUG_SERIAL_SUPPORT
|
||||
DEBUG_PORT.printf(buffer);
|
||||
if (len > DEBUG_MESSAGE_MAX_LENGTH) {
|
||||
DEBUG_PORT.printf(" (...)\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG_UDP_SUPPORT
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
if (systemCheck()) {
|
||||
#endif
|
||||
udpDebug.beginPacket(DEBUG_UDP_IP, DEBUG_UDP_PORT);
|
||||
udpDebug.write(buffer);
|
||||
if (len > DEBUG_MESSAGE_MAX_LENGTH) {
|
||||
udpDebug.write(" (...)\n");
|
||||
}
|
||||
udpDebug.endPacket();
|
||||
delay(1);
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DEBUG_TELNET_SUPPORT
|
||||
_telnetWrite(buffer, strlen(buffer));
|
||||
#endif
|
||||
|
||||
free(buffer);
|
||||
|
||||
}
|
||||
|
||||
void debugSend_P(PGM_P format, ...) {
|
||||
|
||||
char f[DEBUG_MESSAGE_MAX_LENGTH+1];
|
||||
memcpy_P(f, format, DEBUG_MESSAGE_MAX_LENGTH);
|
||||
|
||||
char buffer[DEBUG_MESSAGE_MAX_LENGTH+1];
|
||||
char f[DEBUG_FORMAT_MAX_LENGTH+1];
|
||||
memcpy_P(f, format, DEBUG_FORMAT_MAX_LENGTH);
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int len = ets_vsnprintf(buffer, DEBUG_MESSAGE_MAX_LENGTH, f, args);
|
||||
char test[1];
|
||||
int len = ets_vsnprintf(test, 1, f, args) + 1;
|
||||
char * buffer = new char[len];
|
||||
ets_vsnprintf(buffer, len, f, args);
|
||||
va_end(args);
|
||||
|
||||
#if DEBUG_SERIAL_SUPPORT
|
||||
DEBUG_PORT.printf(buffer);
|
||||
if (len > DEBUG_MESSAGE_MAX_LENGTH) {
|
||||
DEBUG_PORT.printf(" (...)\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG_UDP_SUPPORT
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
if (systemCheck()) {
|
||||
#endif
|
||||
udpDebug.beginPacket(DEBUG_UDP_IP, DEBUG_UDP_PORT);
|
||||
udpDebug.write(buffer);
|
||||
if (len > DEBUG_MESSAGE_MAX_LENGTH) {
|
||||
udpDebug.write(" (...)\n");
|
||||
}
|
||||
udpDebug.endPacket();
|
||||
delay(1);
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DEBUG_TELNET_SUPPORT
|
||||
_telnetWrite(buffer, strlen(buffer));
|
||||
#endif
|
||||
|
||||
free(buffer);
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -136,7 +136,8 @@ int readDHT() {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
double getDHTTemperature(bool celsius) {
|
||||
return celsius ? _dhtTemperature : _dhtTemperature * 1.8 + 32;
|
||||
double value = celsius ? _dhtTemperature : _dhtTemperature * 1.8 + 32;
|
||||
return roundTo(value, DHT_TEMPERATURE_DECIMALS);
|
||||
}
|
||||
|
||||
double getDHTTemperature() {
|
||||
@@ -208,8 +209,8 @@ void dhtLoop() {
|
||||
#endif
|
||||
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature);
|
||||
influxDBSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
|
||||
idbSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature);
|
||||
idbSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
|
||||
#endif
|
||||
|
||||
// Update websocket clients
|
||||
|
||||
@@ -11,6 +11,9 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
bool _dcz_enabled = false;
|
||||
unsigned long _dcz_skip_time = 0;
|
||||
unsigned long _dcz_last_idx = 0;
|
||||
unsigned long _dcz_last_time = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
@@ -25,6 +28,13 @@ int _domoticzRelay(unsigned int idx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool _domoticzSkip(unsigned long idx) {
|
||||
if (idx == _dcz_last_idx && (millis() - _dcz_last_time < _dcz_skip_time)) return true;
|
||||
_dcz_last_idx = idx;
|
||||
_dcz_last_time = millis();
|
||||
return false;
|
||||
}
|
||||
|
||||
void _domoticzMqtt(unsigned int type, const char * topic, const char * payload) {
|
||||
|
||||
String dczTopicOut = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC);
|
||||
@@ -52,9 +62,14 @@ void _domoticzMqtt(unsigned int type, const char * topic, const char * payload)
|
||||
unsigned long idx = root["idx"];
|
||||
int relayID = _domoticzRelay(idx);
|
||||
if (relayID >= 0) {
|
||||
|
||||
// Skip message if recursive
|
||||
if (_domoticzSkip(idx)) return;
|
||||
|
||||
unsigned long value = root["nvalue"];
|
||||
DEBUG_MSG_P(PSTR("[DOMOTICZ] Received value %d for IDX %d\n"), value, idx);
|
||||
relayStatus(relayID, value == 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -71,9 +86,14 @@ template<typename T> void domoticzSend(const char * key, T nvalue, const char *
|
||||
if (!_dcz_enabled) return;
|
||||
unsigned int idx = getSetting(key).toInt();
|
||||
if (idx > 0) {
|
||||
|
||||
// Skip message if recursive
|
||||
if (_domoticzSkip(idx)) return;
|
||||
|
||||
char payload[128];
|
||||
snprintf(payload, sizeof(payload), "{\"idx\": %d, \"nvalue\": %s, \"svalue\": \"%s\"}", idx, String(nvalue).c_str(), svalue);
|
||||
mqttSendRaw(getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC).c_str(), payload);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +116,7 @@ int domoticzIdx(unsigned int relayID) {
|
||||
|
||||
void domoticzConfigure() {
|
||||
_dcz_enabled = getSetting("dczEnabled", DOMOTICZ_ENABLED).toInt() == 1;
|
||||
_dcz_skip_time = 1000 * getSetting("dczSkip", DOMOTICZ_SKIP_TIME).toInt();
|
||||
}
|
||||
|
||||
void domoticzSetup() {
|
||||
|
||||
@@ -119,7 +119,7 @@ void dsLoop() {
|
||||
#endif
|
||||
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSend(getSetting("dsTmpTopic", DS18B20_TEMPERATURE_TOPIC).c_str(), _dsTemperatureStr);
|
||||
idbSend(getSetting("dsTmpTopic", DS18B20_TEMPERATURE_TOPIC).c_str(), _dsTemperatureStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "config/all.h"
|
||||
#include <EEPROM.h>
|
||||
#include <FastLED.h> // W.T.H. is this include ALSO needed here ?!?!!
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// METHODS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
unsigned long _loopDelay = 0;
|
||||
|
||||
void hardwareSetup() {
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@@ -49,18 +50,11 @@ void hardwareSetup() {
|
||||
pinMode(16, OUTPUT);
|
||||
digitalWrite(16, HIGH); //Defualt CT input (pin B, solder jumper B)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void hardwareLoop() {
|
||||
|
||||
// System check
|
||||
static bool checked = false;
|
||||
if (!checked && (millis() > CRASH_SAFE_TIME)) {
|
||||
// Check system as stable
|
||||
systemCheck(true);
|
||||
checked = true;
|
||||
}
|
||||
|
||||
// Heartbeat
|
||||
static unsigned long last_uptime = 0;
|
||||
if ((millis() - last_uptime > HEARTBEAT_INTERVAL) || (last_uptime == 0)) {
|
||||
@@ -87,7 +81,8 @@ void welcome() {
|
||||
DEBUG_MSG_P(PSTR("[INIT] CPU chip ID: 0x%06X\n"), ESP.getChipId());
|
||||
DEBUG_MSG_P(PSTR("[INIT] CPU frequency: %d MHz\n"), ESP.getCpuFreqMHz());
|
||||
DEBUG_MSG_P(PSTR("[INIT] SDK version: %s\n"), ESP.getSdkVersion());
|
||||
DEBUG_MSG_P(PSTR("[INIT] Core version: %s\n"), ESP.getCoreVersion().c_str());
|
||||
DEBUG_MSG_P(PSTR("[INIT] Core version: %s\n"), getCoreVersion().c_str());
|
||||
DEBUG_MSG_P(PSTR("[INIT] Core revision: %s\n"), getCoreRevision().c_str());
|
||||
DEBUG_MSG_P(PSTR("\n"));
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -173,6 +168,9 @@ void welcome() {
|
||||
#if INFLUXDB_SUPPORT
|
||||
DEBUG_MSG_P(PSTR(" INFLUXDB"));
|
||||
#endif
|
||||
#if LLMNR_SUPPORT
|
||||
DEBUG_MSG_P(PSTR(" LLMNR"));
|
||||
#endif
|
||||
#if MDNS_SUPPORT
|
||||
DEBUG_MSG_P(PSTR(" MDNS"));
|
||||
#endif
|
||||
@@ -202,10 +200,10 @@ void welcome() {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
unsigned char custom_reset = customReset();
|
||||
if (custom_reset > 0) {
|
||||
unsigned char reason = resetReason();
|
||||
if (reason > 0) {
|
||||
char buffer[32];
|
||||
strcpy_P(buffer, custom_reset_string[custom_reset-1]);
|
||||
strcpy_P(buffer, custom_reset_string[reason-1]);
|
||||
DEBUG_MSG_P(PSTR("[INIT] Last reset reason: %s\n"), buffer);
|
||||
} else {
|
||||
DEBUG_MSG_P(PSTR("[INIT] Last reset reason: %s\n"), (char *) ESP.getResetReason().c_str());
|
||||
@@ -215,6 +213,8 @@ void welcome() {
|
||||
#if ADC_VCC_ENABLED
|
||||
DEBUG_MSG_P(PSTR("[INIT] Power: %d mV\n"), ESP.getVcc());
|
||||
#endif
|
||||
|
||||
DEBUG_MSG_P(PSTR("[INIT] Power saving delay value: %lu ms\n"), _loopDelay);
|
||||
DEBUG_MSG_P(PSTR("\n"));
|
||||
|
||||
}
|
||||
@@ -225,10 +225,9 @@ void setup() {
|
||||
hardwareSetup();
|
||||
|
||||
// Question system stability
|
||||
systemCheck(false);
|
||||
|
||||
// Show welcome message and system configuration
|
||||
welcome();
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
systemCheck(false);
|
||||
#endif
|
||||
|
||||
// Init persistance and terminal features
|
||||
settingsSetup();
|
||||
@@ -236,6 +235,13 @@ void setup() {
|
||||
setSetting("hostname", getIdentifier());
|
||||
}
|
||||
|
||||
// Cache loop delay value to speed things (recommended max 250ms)
|
||||
_loopDelay = atol(getSetting("loopDelay", LOOP_DELAY_TIME).c_str());
|
||||
|
||||
// Show welcome message and system configuration
|
||||
welcome();
|
||||
|
||||
// Basic modules, will always run
|
||||
wifiSetup();
|
||||
otaSetup();
|
||||
#if TELNET_SUPPORT
|
||||
@@ -243,10 +249,15 @@ void setup() {
|
||||
#endif
|
||||
|
||||
// Do not run the next services if system is flagged stable
|
||||
if (!systemCheck()) return;
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
if (!systemCheck()) return;
|
||||
#endif
|
||||
|
||||
// Init webserver required before any module that uses API
|
||||
#if WEB_SUPPORT
|
||||
webSetup();
|
||||
wsSetup();
|
||||
apiSetup();
|
||||
#endif
|
||||
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
@@ -260,7 +271,6 @@ void setup() {
|
||||
#ifdef ITEAD_SONOFF_RFBRIDGE
|
||||
rfbSetup();
|
||||
#endif
|
||||
|
||||
#if POWER_PROVIDER != POWER_PROVIDER_NONE
|
||||
powerSetup();
|
||||
#endif
|
||||
@@ -277,7 +287,7 @@ void setup() {
|
||||
nofussSetup();
|
||||
#endif
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSetup();
|
||||
idbSetup();
|
||||
#endif
|
||||
#if DS18B20_SUPPORT
|
||||
dsSetup();
|
||||
@@ -300,6 +310,12 @@ void setup() {
|
||||
#if DOMOTICZ_SUPPORT
|
||||
domoticzSetup();
|
||||
#endif
|
||||
#if HOMEASSISTANT_SUPPORT
|
||||
haSetup();
|
||||
#endif
|
||||
#if LLMNR_SUPPORT
|
||||
llmnrSetup();
|
||||
#endif
|
||||
|
||||
// Prepare configuration for version 2.0
|
||||
hwUpwardsCompatibility();
|
||||
@@ -315,23 +331,23 @@ void loop() {
|
||||
wifiLoop();
|
||||
otaLoop();
|
||||
|
||||
// Do not run the next services if system is flagged stable
|
||||
if (!systemCheck()) return;
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
systemCheckLoop();
|
||||
// Do not run the next services if system is flagged stable
|
||||
if (!systemCheck()) return;
|
||||
#endif
|
||||
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
lightLoop();
|
||||
#endif
|
||||
|
||||
|
||||
buttonLoop();
|
||||
relayLoop();
|
||||
buttonLoop();
|
||||
ledLoop();
|
||||
mqttLoop();
|
||||
|
||||
#ifdef ITEAD_SONOFF_RFBRIDGE
|
||||
rfbLoop();
|
||||
#endif
|
||||
|
||||
#if POWER_PROVIDER != POWER_PROVIDER_NONE
|
||||
powerLoop();
|
||||
#endif
|
||||
@@ -363,4 +379,7 @@ void loop() {
|
||||
irLoop();
|
||||
#endif
|
||||
|
||||
// Power saving delay
|
||||
delay(_loopDelay);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ the migration to future version 2 will be straigh forward.
|
||||
|
||||
*/
|
||||
|
||||
#include <my92xx.h>
|
||||
|
||||
void hwUpwardsCompatibility() {
|
||||
|
||||
unsigned int board = getSetting("board", 0).toInt();
|
||||
@@ -222,7 +224,9 @@ void hwUpwardsCompatibility() {
|
||||
|
||||
setSetting("board", 20);
|
||||
setSetting("relayProvider", RELAY_PROVIDER_LIGHT);
|
||||
setSetting("lightProvider", LIGHT_PROVIDER_MY9192);
|
||||
setSetting("lightProvider", LIGHT_PROVIDER_MY92XX);
|
||||
setSetting("myModel", MY92XX_MODEL_MY9291);
|
||||
setSetting("myChips", 1);
|
||||
setSetting("myDIGPIO", 13);
|
||||
setSetting("myDCKIGPIO", 15);
|
||||
setSetting("relays", 1);
|
||||
@@ -349,7 +353,9 @@ void hwUpwardsCompatibility() {
|
||||
|
||||
setSetting("board", 28);
|
||||
setSetting("relayProvider", RELAY_PROVIDER_LIGHT);
|
||||
setSetting("lightProvider", LIGHT_PROVIDER_MY9192);
|
||||
setSetting("lightProvider", LIGHT_PROVIDER_MY92XX);
|
||||
setSetting("myModel", MY92XX_MODEL_MY9231);
|
||||
setSetting("myChips", 2);
|
||||
setSetting("myDIGPIO", 12);
|
||||
setSetting("myDCKIGPIO", 14);
|
||||
setSetting("relays", 1);
|
||||
@@ -561,7 +567,9 @@ void hwUpwardsCompatibility() {
|
||||
|
||||
setSetting("board", 46);
|
||||
setSetting("relayProvider", RELAY_PROVIDER_LIGHT);
|
||||
setSetting("lightProvider", LIGHT_PROVIDER_MY9192);
|
||||
setSetting("lightProvider", LIGHT_PROVIDER_MY92XX);
|
||||
setSetting("myModel", MY92XX_MODEL_MY9291);
|
||||
setSetting("myChips", 1);
|
||||
setSetting("myDIGPIO", 13);
|
||||
setSetting("myDCKIGPIO", 15);
|
||||
setSetting("relays", 1);
|
||||
|
||||
@@ -10,6 +10,8 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
bool _haEnabled = false;
|
||||
|
||||
void haSend(bool add) {
|
||||
|
||||
DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n"));
|
||||
@@ -29,6 +31,9 @@ void haSend(bool add) {
|
||||
root["command_topic"] = getTopic(MQTT_TOPIC_RELAY, 0, true);
|
||||
root["payload_on"] = String("1");
|
||||
root["payload_off"] = String("0");
|
||||
root["availability_topic"] = getTopic(MQTT_TOPIC_STATUS, false);
|
||||
root["payload_available"] = String("1");
|
||||
root["payload_not_available"] = String("0");
|
||||
}
|
||||
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
@@ -63,8 +68,21 @@ void haSend(bool add) {
|
||||
"/config";
|
||||
|
||||
mqttSendRaw(topic.c_str(), output.c_str());
|
||||
mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true);
|
||||
|
||||
}
|
||||
|
||||
void haConfigure() {
|
||||
bool enabled = getSetting("haEnabled", HOMEASSISTANT_ENABLED).toInt() == 1;
|
||||
if (enabled != _haEnabled) haSend(enabled);
|
||||
_haEnabled = enabled;
|
||||
}
|
||||
|
||||
void haSetup() {
|
||||
haConfigure();
|
||||
mqttRegister([](unsigned int type, const char * topic, const char * payload) {
|
||||
if (type == MQTT_CONNECT_EVENT) haSend(_haEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
#endif // HOMEASSISTANT_SUPPORT
|
||||
|
||||
@@ -11,18 +11,33 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
#include "ESPAsyncTCP.h"
|
||||
#include "SyncClient.h"
|
||||
|
||||
bool _influxdb_enabled = false;
|
||||
SyncClient _influx_client;
|
||||
bool _idb_enabled = false;
|
||||
SyncClient _idb_client;
|
||||
|
||||
template<typename T> bool influxDBSend(const char * topic, T payload) {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
if (!_influxdb_enabled) return true;
|
||||
#if WEB_SUPPORT
|
||||
void _idbWSSend(JsonObject& root) {
|
||||
root["idbVisible"] = 1;
|
||||
root["idbHost"] = getSetting("idbHost");
|
||||
root["idbPort"] = getSetting("idbPort", INFLUXDB_PORT).toInt();
|
||||
root["idbDatabase"] = getSetting("idbDatabase");
|
||||
root["idbUsername"] = getSetting("idbUsername");
|
||||
root["idbPassword"] = getSetting("idbPassword");
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<typename T> bool idbSend(const char * topic, T payload) {
|
||||
|
||||
if (!_idb_enabled) return true;
|
||||
if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return true;
|
||||
|
||||
DEBUG_MSG("[INFLUXDB] Sending\n");
|
||||
|
||||
_influx_client.setTimeout(2);
|
||||
if (!_influx_client.connect(getSetting("idbHost").c_str(), getSetting("idbPort", INFLUXDB_PORT).toInt())) {
|
||||
_idb_client.setTimeout(2);
|
||||
if (!_idb_client.connect(getSetting("idbHost").c_str(), getSetting("idbPort", INFLUXDB_PORT).toInt())) {
|
||||
DEBUG_MSG("[INFLUXDB] Connection failed\n");
|
||||
return false;
|
||||
}
|
||||
@@ -37,29 +52,33 @@ template<typename T> bool influxDBSend(const char * topic, T payload) {
|
||||
getSetting("idbHost").c_str(), getSetting("idbPort", INFLUXDB_PORT).toInt(),
|
||||
strlen(data), data);
|
||||
|
||||
if (_influx_client.printf(request) > 0) {
|
||||
while (_influx_client.connected() && _influx_client.available() == 0) delay(1);
|
||||
while (_influx_client.available()) _influx_client.read();
|
||||
if (_influx_client.connected()) _influx_client.stop();
|
||||
if (_idb_client.printf(request) > 0) {
|
||||
while (_idb_client.connected() && _idb_client.available() == 0) delay(1);
|
||||
while (_idb_client.available()) _idb_client.read();
|
||||
if (_idb_client.connected()) _idb_client.stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
_influx_client.stop();
|
||||
_idb_client.stop();
|
||||
DEBUG_MSG("[INFLUXDB] Sent failed\n");
|
||||
while (_influx_client.connected()) delay(0);
|
||||
while (_idb_client.connected()) delay(0);
|
||||
return false;
|
||||
|
||||
}
|
||||
bool influxdbEnabled() {
|
||||
return _influxdb_enabled;
|
||||
|
||||
bool idbEnabled() {
|
||||
return _idb_enabled;
|
||||
}
|
||||
|
||||
void influxDBConfigure() {
|
||||
_influxdb_enabled = getSetting("idbHost").length() > 0;
|
||||
void idbConfigure() {
|
||||
_idb_enabled = getSetting("idbHost").length() > 0;
|
||||
}
|
||||
|
||||
void influxDBSetup() {
|
||||
influxDBConfigure();
|
||||
void idbSetup() {
|
||||
idbConfigure();
|
||||
#if WEB_SUPPORT
|
||||
wsRegister(_idbWSSend);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,9 +31,9 @@ std::vector<channel_t> _channels;
|
||||
bool _lightState = false;
|
||||
unsigned int _brightness = LIGHT_MAX_BRIGHTNESS;
|
||||
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
|
||||
#include <my9291.h>
|
||||
my9291 * _my9291;
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX
|
||||
#include <my92xx.h>
|
||||
my92xx * _my92xx;
|
||||
#endif
|
||||
|
||||
// Gamma Correction lookup table (8 bit)
|
||||
@@ -387,24 +387,15 @@ void _lightProviderUpdate() {
|
||||
digitalWrite(LIGHT_ENABLE_PIN, _lightState);
|
||||
#endif
|
||||
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX
|
||||
|
||||
if (_lightState) {
|
||||
|
||||
unsigned int red = _toPWM(0);
|
||||
unsigned int green = _toPWM(1);
|
||||
unsigned int blue = _toPWM(2);
|
||||
unsigned int white = _toPWM(3);
|
||||
unsigned int warm = _toPWM(4);
|
||||
_my9291->setColor((my9291_color_t) { red, green, blue, white, warm });
|
||||
_my9291->setState(true);
|
||||
|
||||
} else {
|
||||
|
||||
_my9291->setColor((my9291_color_t) { 0, 0, 0, 0, 0 });
|
||||
_my9291->setState(false);
|
||||
ARRAYINIT(unsigned char, channels, MY92XX_MAPPING);
|
||||
|
||||
for (unsigned char i=0; i<_channels.size(); i++) {
|
||||
_my92xx->setChannel(channels[i], _toPWM(i));
|
||||
}
|
||||
_my92xx->setState(_lightState);
|
||||
_my92xx->update();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -803,10 +794,10 @@ void lightSetup() {
|
||||
pinMode(LIGHT_ENABLE_PIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
|
||||
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX
|
||||
|
||||
_my9291 = new my9291(MY9291_DI_PIN, MY9291_DCKI_PIN, MY9291_COMMAND, MY9291_CHANNELS);
|
||||
for (unsigned char i=0; i<MY9291_CHANNELS; i++) {
|
||||
_my92xx = new my92xx(MY92XX_MODEL, MY92XX_CHIPS, MY92XX_DI_PIN, MY92XX_DCKI_PIN, MY92XX_COMMAND);
|
||||
for (unsigned char i=0; i<LIGHT_CHANNELS; i++) {
|
||||
_channels.push_back((channel_t) {0, false, 0});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ Not currently Implemented :
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
18
code/espurna/llmnr.ino
Normal file
18
code/espurna/llmnr.ino
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
|
||||
LLMNR MODULE
|
||||
|
||||
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
*/
|
||||
|
||||
#if LLMNR_SUPPORT
|
||||
|
||||
#include <ESP8266LLMNR.h>
|
||||
|
||||
void llmnrSetup() {
|
||||
LLMNR.begin(getSetting("hostname").c_str());
|
||||
DEBUG_MSG_P(PSTR("[LLMNR] Configured\n"));
|
||||
}
|
||||
|
||||
#endif // LLMNR_SUPPORT
|
||||
@@ -44,7 +44,7 @@ char *_mqtt_will;
|
||||
unsigned long _mqtt_connected_at = 0;
|
||||
#endif
|
||||
|
||||
std::vector<void (*)(unsigned int, const char *, const char *)> _mqtt_callbacks;
|
||||
std::vector<mqtt_callback_f> _mqtt_callbacks;
|
||||
|
||||
typedef struct {
|
||||
char * topic;
|
||||
@@ -180,7 +180,19 @@ void mqttSubscribe(const char * topic) {
|
||||
mqttSubscribeRaw(path.c_str());
|
||||
}
|
||||
|
||||
void mqttRegister(void (*callback)(unsigned int, const char *, const char *)) {
|
||||
void mqttUnsubscribeRaw(const char * topic) {
|
||||
if (_mqtt.connected() && (strlen(topic) > 0)) {
|
||||
#if MQTT_USE_ASYNC
|
||||
unsigned int packetId = _mqtt.unsubscribe(topic);
|
||||
DEBUG_MSG_P(PSTR("[MQTT] Unsubscribing to %s (PID %d)\n"), topic, packetId);
|
||||
#else
|
||||
_mqtt.unsubscribe(topic);
|
||||
DEBUG_MSG_P(PSTR("[MQTT] Unsubscribing to %s\n"), topic);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void mqttRegister(mqtt_callback_f callback) {
|
||||
_mqtt_callbacks.push_back(callback);
|
||||
}
|
||||
|
||||
@@ -190,7 +202,6 @@ void mqttRegister(void (*callback)(unsigned int, const char *, const char *)) {
|
||||
|
||||
void _mqttCallback(unsigned int type, const char * topic, const char * payload) {
|
||||
|
||||
|
||||
if (type == MQTT_CONNECT_EVENT) {
|
||||
|
||||
mqttSubscribe(MQTT_TOPIC_ACTION);
|
||||
@@ -205,8 +216,7 @@ void _mqttCallback(unsigned int type, const char * topic, const char * payload)
|
||||
// Actions
|
||||
if (t.equals(MQTT_TOPIC_ACTION)) {
|
||||
if (strcmp(payload, MQTT_ACTION_RESET) == 0) {
|
||||
customReset(CUSTOM_RESET_MQTT);
|
||||
ESP.restart();
|
||||
deferredReset(100, CUSTOM_RESET_MQTT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,9 +236,12 @@ void _mqttOnConnect() {
|
||||
// Send first Heartbeat
|
||||
heartbeat();
|
||||
|
||||
// Clean subscriptions
|
||||
mqttUnsubscribeRaw("#");
|
||||
|
||||
// Send connect event to subscribers
|
||||
for (unsigned char i = 0; i < _mqtt_callbacks.size(); i++) {
|
||||
(*_mqtt_callbacks[i])(MQTT_CONNECT_EVENT, NULL, NULL);
|
||||
(_mqtt_callbacks[i])(MQTT_CONNECT_EVENT, NULL, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -239,7 +252,7 @@ void _mqttOnDisconnect() {
|
||||
|
||||
// Send disconnect event to subscribers
|
||||
for (unsigned char i = 0; i < _mqtt_callbacks.size(); i++) {
|
||||
(*_mqtt_callbacks[i])(MQTT_DISCONNECT_EVENT, NULL, NULL);
|
||||
(_mqtt_callbacks[i])(MQTT_DISCONNECT_EVENT, NULL, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -261,7 +274,7 @@ void _mqttOnMessage(char* topic, char* payload, unsigned int len) {
|
||||
|
||||
// Send message event to subscribers
|
||||
for (unsigned char i = 0; i < _mqtt_callbacks.size(); i++) {
|
||||
(*_mqtt_callbacks[i])(MQTT_MESSAGE_EVENT, topic, message);
|
||||
(_mqtt_callbacks[i])(MQTT_MESSAGE_EVENT, topic, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,12 +30,11 @@ void otaSetup() {
|
||||
});
|
||||
|
||||
ArduinoOTA.onEnd([]() {
|
||||
customReset(CUSTOM_RESET_OTA);
|
||||
DEBUG_MSG_P(PSTR("\n[OTA] End\n"));
|
||||
#if WEB_SUPPORT
|
||||
wsSend_P(PSTR("{\"action\": \"reload\"}"));
|
||||
#endif
|
||||
delay(100);
|
||||
deferredReset(100, CUSTOM_RESET_OTA);
|
||||
});
|
||||
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
|
||||
@@ -234,16 +234,16 @@ void _powerReport() {
|
||||
#endif
|
||||
|
||||
#if INFLUXDB_SUPPORT
|
||||
if (influxdbEnabled()) {
|
||||
influxDBSend(MQTT_TOPIC_CURRENT, buf_current);
|
||||
influxDBSend(MQTT_TOPIC_POWER_APPARENT, String((int) _power_apparent).c_str());
|
||||
influxDBSend(MQTT_TOPIC_ENERGY_DELTA, buf_energy_delta);
|
||||
influxDBSend(MQTT_TOPIC_ENERGY_TOTAL, buf_energy_total);
|
||||
if (idbEnabled()) {
|
||||
idbSend(MQTT_TOPIC_CURRENT, buf_current);
|
||||
idbSend(MQTT_TOPIC_POWER_APPARENT, String((int) _power_apparent).c_str());
|
||||
idbSend(MQTT_TOPIC_ENERGY_DELTA, buf_energy_delta);
|
||||
idbSend(MQTT_TOPIC_ENERGY_TOTAL, buf_energy_total);
|
||||
#if POWER_HAS_ACTIVE
|
||||
influxDBSend(MQTT_TOPIC_POWER_ACTIVE, String((int) _power_active).c_str());
|
||||
influxDBSend(MQTT_TOPIC_POWER_REACTIVE, String((int) _power_reactive).c_str());
|
||||
influxDBSend(MQTT_TOPIC_VOLTAGE, String((int) _power_voltage).c_str());
|
||||
influxDBSend(MQTT_TOPIC_POWER_FACTOR, String((int) 100 * _power_factor).c_str());
|
||||
idbSend(MQTT_TOPIC_POWER_ACTIVE, String((int) _power_active).c_str());
|
||||
idbSend(MQTT_TOPIC_POWER_REACTIVE, String((int) _power_reactive).c_str());
|
||||
idbSend(MQTT_TOPIC_VOLTAGE, String((int) _power_voltage).c_str());
|
||||
idbSend(MQTT_TOPIC_POWER_FACTOR, String((int) 100 * _power_factor).c_str());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -493,7 +493,7 @@ void relayInfluxDB(unsigned char id) {
|
||||
if (id >= _relays.size()) return;
|
||||
char buffer[10];
|
||||
snprintf_P(buffer, sizeof(buffer), PSTR("%s,id=%d"), MQTT_TOPIC_RELAY, id);
|
||||
influxDBSend(buffer, relayStatus(id) ? "1" : "0");
|
||||
idbSend(buffer, relayStatus(id) ? "1" : "0");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ void settingsSetup() {
|
||||
Embedis::hardware( F("WIFI"), [](Embedis* e) {
|
||||
StreamString s;
|
||||
WiFi.printDiag(s);
|
||||
e->response(s);
|
||||
DEBUG_MSG(s.c_str());
|
||||
}, 0);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -126,58 +126,57 @@ void settingsSetup() {
|
||||
Embedis::command( F("RESET.WIFI"), [](Embedis* e) {
|
||||
wifiConfigure();
|
||||
wifiDisconnect();
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("RESET.MQTT"), [](Embedis* e) {
|
||||
mqttConfigure();
|
||||
mqttDisconnect();
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("INFO"), [](Embedis* e) {
|
||||
welcome();
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("UPTIME"), [](Embedis* e) {
|
||||
e->stream->printf("Uptime: %d seconds\n", getUptime());
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Uptime: %d seconds\n"), getUptime());
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("RESET"), [](Embedis* e) {
|
||||
e->response(Embedis::OK);
|
||||
customReset(CUSTOM_RESET_TERMINAL);
|
||||
ESP.restart();
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
deferredReset(100, CUSTOM_RESET_TERMINAL);
|
||||
});
|
||||
|
||||
Embedis::command( F("ERASE.CONFIG"), [](Embedis* e) {
|
||||
e->response(Embedis::OK);
|
||||
customReset(CUSTOM_RESET_TERMINAL);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
resetReason(CUSTOM_RESET_TERMINAL);
|
||||
ESP.eraseConfig();
|
||||
*((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494
|
||||
});
|
||||
|
||||
#if NOFUSS_SUPPORT
|
||||
Embedis::command( F("NOFUSS"), [](Embedis* e) {
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
nofussRun();
|
||||
});
|
||||
#endif
|
||||
|
||||
Embedis::command( F("FACTORY.RESET"), [](Embedis* e) {
|
||||
settingsFactoryReset();
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("HEAP"), [](Embedis* e) {
|
||||
e->stream->printf("Free HEAP: %d bytes\n", ESP.getFreeHeap());
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Free HEAP: %d bytes\n"), ESP.getFreeHeap());
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("RELAY"), [](Embedis* e) {
|
||||
if (e->argc < 2) {
|
||||
return e->response(Embedis::ARGS_ERROR);
|
||||
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
|
||||
}
|
||||
int id = String(e->argv[1]).toInt();
|
||||
if (e->argc > 2) {
|
||||
@@ -188,8 +187,8 @@ void settingsSetup() {
|
||||
relayStatus(id, value == 1);
|
||||
}
|
||||
}
|
||||
e->stream->printf("Status: %s\n", relayStatus(id) ? "true" : "false");
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Status: %s\n"), relayStatus(id) ? "true" : "false");
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
@@ -202,8 +201,8 @@ void settingsSetup() {
|
||||
lightColor(color.c_str());
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
e->stream->printf("Color: %s\n", lightColor().c_str());
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str());
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("BRIGHTNESS"), [](Embedis* e) {
|
||||
@@ -211,8 +210,8 @@ void settingsSetup() {
|
||||
lightBrightness(String(e->argv[1]).toInt());
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
e->stream->printf("Brightness: %d\n", lightBrightness());
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Brightness: %d\n"), lightBrightness());
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("MIRED"), [](Embedis* e) {
|
||||
@@ -221,8 +220,8 @@ void settingsSetup() {
|
||||
lightColor(color.c_str());
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
e->stream->printf("Color: %s\n", lightColor().c_str());
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str());
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("KELVIN"), [](Embedis* e) {
|
||||
@@ -231,15 +230,15 @@ void settingsSetup() {
|
||||
lightColor(color.c_str());
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
e->stream->printf("Color: %s\n", lightColor().c_str());
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str());
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Embedis::command( F("CHANNEL"), [](Embedis* e) {
|
||||
if (e->argc < 2) {
|
||||
return e->response(Embedis::ARGS_ERROR);
|
||||
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
|
||||
}
|
||||
int id = String(e->argv[1]).toInt();
|
||||
if (e->argc > 2) {
|
||||
@@ -247,17 +246,17 @@ void settingsSetup() {
|
||||
lightChannel(id, value);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
e->stream->printf("Channel #%d: %d\n", id, lightChannel(id));
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Channel #%d: %d\n"), id, lightChannel(id));
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
Embedis::command( F("EEPROM"), [](Embedis* e) {
|
||||
unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - settingsSize();
|
||||
e->stream->printf("Number of keys: %d\n", settingsKeyCount());
|
||||
e->stream->printf("Free EEPROM: %d bytes (%d%%)\n", freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE);
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("Number of keys: %d\n"), settingsKeyCount());
|
||||
DEBUG_MSG_P(PSTR("Free EEPROM: %d bytes (%d%%)\n"), freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
Embedis::command( F("DUMP"), [](Embedis* e) {
|
||||
@@ -265,25 +264,24 @@ void settingsSetup() {
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
String key = settingsKeyName(i);
|
||||
String value = getSetting(key);
|
||||
e->stream->printf("+%s => %s\n", key.c_str(), value.c_str());
|
||||
DEBUG_MSG_P(PSTR("+%s => %s\n"), key.c_str(), value.c_str());
|
||||
}
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
|
||||
#if DEBUG_SUPPORT
|
||||
Embedis::command( F("CRASH"), [](Embedis* e) {
|
||||
debugDumpCrashInfo();
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("+OK\n"));
|
||||
});
|
||||
#endif
|
||||
|
||||
Embedis::command( F("DUMP.RAW"), [](Embedis* e) {
|
||||
for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) {
|
||||
if (i % 16 == 0) e->stream->printf("\n[%04X] ", i);
|
||||
e->stream->printf("%02X ", EEPROM.read(i));
|
||||
if (i % 16 == 0) DEBUG_MSG_P(PSTR("\n[%04X] "), i);
|
||||
DEBUG_MSG_P(PSTR("%02X "), EEPROM.read(i));
|
||||
}
|
||||
e->stream->printf("\n");
|
||||
e->response(Embedis::OK);
|
||||
DEBUG_MSG_P(PSTR("\n+OK\n"));
|
||||
});
|
||||
|
||||
DEBUG_MSG_P(PSTR("[SETTINGS] EEPROM size: %d bytes\n"), SPI_FLASH_SEC_SIZE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,12 +6,33 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
*/
|
||||
|
||||
#include <Ticker.h>
|
||||
Ticker _defer_reset;
|
||||
|
||||
String getIdentifier() {
|
||||
char buffer[20];
|
||||
snprintf_P(buffer, sizeof(buffer), PSTR("%s_%06X"), DEVICE, ESP.getChipId());
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
String getCoreVersion() {
|
||||
String version = ESP.getCoreVersion();
|
||||
#ifdef ARDUINO_ESP8266_RELEASE
|
||||
if (version.equals("00000000")) {
|
||||
version = String(ARDUINO_ESP8266_RELEASE);
|
||||
}
|
||||
#endif
|
||||
return version;
|
||||
}
|
||||
|
||||
String getCoreRevision() {
|
||||
#ifdef ARDUINO_ESP8266_GIT_VER
|
||||
return String(ARDUINO_ESP8266_GIT_VER);
|
||||
#else
|
||||
return String("");
|
||||
#endif
|
||||
}
|
||||
|
||||
String buildTime() {
|
||||
|
||||
const char time_now[] = __TIME__; // hh:mm:ss
|
||||
@@ -96,13 +117,13 @@ void heartbeat() {
|
||||
#if (HEARTBEAT_REPORT_UPTIME)
|
||||
mqttSend(MQTT_TOPIC_UPTIME, String(uptime_seconds).c_str());
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSend(MQTT_TOPIC_UPTIME, String(uptime_seconds).c_str());
|
||||
idbSend(MQTT_TOPIC_UPTIME, String(uptime_seconds).c_str());
|
||||
#endif
|
||||
#endif
|
||||
#if (HEARTBEAT_REPORT_FREEHEAP)
|
||||
mqttSend(MQTT_TOPIC_FREEHEAP, String(free_heap).c_str());
|
||||
#if INFLUXDB_SUPPORT
|
||||
influxDBSend(MQTT_TOPIC_FREEHEAP, String(free_heap).c_str());
|
||||
idbSend(MQTT_TOPIC_FREEHEAP, String(free_heap).c_str());
|
||||
#endif
|
||||
#endif
|
||||
#if (HEARTBEAT_REPORT_RELAY)
|
||||
@@ -120,30 +141,53 @@ void heartbeat() {
|
||||
mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true);
|
||||
#endif
|
||||
|
||||
// Send info to websocket clients
|
||||
{
|
||||
char buffer[200];
|
||||
snprintf_P(
|
||||
buffer,
|
||||
sizeof(buffer) - 1,
|
||||
PSTR("{\"time\": \"%s\", \"uptime\": %lu, \"heap\": %lu}"),
|
||||
ntpDateTime().c_str(), uptime_seconds, free_heap
|
||||
);
|
||||
wsSend(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void customReset(unsigned char status) {
|
||||
EEPROM.write(EEPROM_CUSTOM_RESET, status);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
unsigned char customReset() {
|
||||
unsigned char resetReason() {
|
||||
static unsigned char status = 255;
|
||||
if (status == 255) {
|
||||
status = EEPROM.read(EEPROM_CUSTOM_RESET);
|
||||
if (status > 0) customReset(0);
|
||||
if (status > 0) resetReason(0);
|
||||
if (status > CUSTOM_RESET_MAX) status = 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void resetReason(unsigned char reason) {
|
||||
EEPROM.write(EEPROM_CUSTOM_RESET, reason);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void reset(unsigned char reason) {
|
||||
resetReason(reason);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void deferredReset(unsigned long delay, unsigned char reason) {
|
||||
_defer_reset.once_ms(delay, reset, reason);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
|
||||
// Call this method on boot with start=true to increase the crash counter
|
||||
// Call it again once the system is stable to decrease the counter
|
||||
// If the counter reaches CRASH_COUNT_MAX then the system is flagged as unstable
|
||||
// If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable
|
||||
// setting _systemOK = false;
|
||||
//
|
||||
// An unstable system will only have serial access, WiFi in AP mode and OTA
|
||||
@@ -156,7 +200,7 @@ void systemCheck(bool stable) {
|
||||
value = 0;
|
||||
DEBUG_MSG_P(PSTR("[MAIN] System OK\n"));
|
||||
} else {
|
||||
if (++value > CRASH_COUNT_MAX) {
|
||||
if (++value > SYSTEM_CHECK_MAX) {
|
||||
_systemStable = false;
|
||||
value = 0;
|
||||
DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n"));
|
||||
@@ -170,6 +214,17 @@ bool systemCheck() {
|
||||
return _systemStable;
|
||||
}
|
||||
|
||||
void systemCheckLoop() {
|
||||
static bool checked = false;
|
||||
if (!checked && (millis() > SYSTEM_CHECK_TIME)) {
|
||||
// Check system as stable
|
||||
systemCheck(true);
|
||||
checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
char * ltrim(char * s) {
|
||||
|
||||
1023
code/espurna/web.ino
1023
code/espurna/web.ino
File diff suppressed because it is too large
Load Diff
@@ -66,7 +66,9 @@ void wifiConfigure() {
|
||||
jw.cleanNetworks();
|
||||
|
||||
// If system is flagged unstable we do not init wifi networks
|
||||
if (!systemCheck()) return;
|
||||
#if SYSTEM_CHECK_ENABLED
|
||||
if (!systemCheck()) return;
|
||||
#endif
|
||||
|
||||
int i;
|
||||
for (i = 0; i< WIFI_MAX_NETWORKS; i++) {
|
||||
@@ -172,6 +174,10 @@ void wifiInject() {
|
||||
|
||||
void wifiSetup() {
|
||||
|
||||
#if WIFI_SLEEP_ENABLED
|
||||
wifi_set_sleep_type(LIGHT_SLEEP_T);
|
||||
#endif
|
||||
|
||||
wifiInject();
|
||||
wifiConfigure();
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ class WebSocketIncommingBuffer {
|
||||
public:
|
||||
WebSocketIncommingBuffer(AwsMessageHandler cb, bool terminate_string = true, bool cb_on_fragments = false) :
|
||||
_cb(cb),
|
||||
_cb_on_fragments(cb_on_fragments),
|
||||
_terminate_string(terminate_string),
|
||||
_cb_on_fragments(cb_on_fragments),
|
||||
_buffer(0)
|
||||
{}
|
||||
|
||||
@@ -30,19 +30,24 @@ class WebSocketIncommingBuffer {
|
||||
|
||||
void data_event(AsyncWebSocketClient *client, AwsFrameInfo *info, uint8_t *data, size_t len) {
|
||||
|
||||
if((info->final || _cb_on_fragments) &&
|
||||
!_terminate_string && info->index == 0 && info->len == len) {
|
||||
if ((info->final || _cb_on_fragments)
|
||||
&& !_terminate_string
|
||||
&& info->index == 0
|
||||
&& info->len == len) {
|
||||
|
||||
/* The whole message is in a single frame and we got all of it's
|
||||
data therefore we can parse it without copying the data first.*/
|
||||
_cb(client, data, len);
|
||||
} else {
|
||||
if (info->len > MAX_WS_MSG_SIZE) return;
|
||||
/* Check if previous fragment was discarded because it was too long. */
|
||||
if (!_cb_on_fragments && info->num > 0 && !_buffer) return;
|
||||
|
||||
if (!_buffer) {
|
||||
_buffer = new std::vector<uint8_t>();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (info->len > MAX_WS_MSG_SIZE) return;
|
||||
|
||||
/* Check if previous fragment was discarded because it was too long. */
|
||||
//if (!_cb_on_fragments && info->num > 0 && !_buffer) return;
|
||||
|
||||
if (!_buffer) _buffer = new std::vector<uint8_t>();
|
||||
|
||||
if (info->index == 0) {
|
||||
//New frame => preallocate memory
|
||||
if (_cb_on_fragments) {
|
||||
@@ -59,16 +64,17 @@ class WebSocketIncommingBuffer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//assert(_buffer->size() == info->index);
|
||||
_buffer->insert(_buffer->end(), data, data+len);
|
||||
if (info->index + len == info->len &&
|
||||
(info->final || _cb_on_fragments)) {
|
||||
if (info->index + len == info->len
|
||||
&& (info->final || _cb_on_fragments)) {
|
||||
|
||||
// Frame/message complete
|
||||
if (_terminate_string) {
|
||||
_buffer->push_back(0);
|
||||
}
|
||||
if (_terminate_string) _buffer->push_back(0);
|
||||
_cb(client, _buffer->data(), _buffer->size());
|
||||
_buffer->clear();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
755
code/espurna/ws.ino
Normal file
755
code/espurna/ws.ino
Normal file
@@ -0,0 +1,755 @@
|
||||
/*
|
||||
|
||||
WEBSOCKET MODULE
|
||||
|
||||
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
*/
|
||||
|
||||
#if WEB_SUPPORT
|
||||
|
||||
#include <ESPAsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ticker.h>
|
||||
#include <vector>
|
||||
#include "ws.h"
|
||||
|
||||
AsyncWebSocket _ws("/ws");
|
||||
Ticker _web_defer;
|
||||
|
||||
std::vector<ws_callback_f> _ws_sender_callbacks;
|
||||
std::vector<ws_callback_f> _ws_receiver_callbacks;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void _wsMQTTCallback(unsigned int type, const char * topic, const char * payload) {
|
||||
|
||||
if (type == MQTT_CONNECT_EVENT) {
|
||||
wsSend_P(PSTR("{\"mqttStatus\": true}"));
|
||||
}
|
||||
|
||||
if (type == MQTT_DISCONNECT_EVENT) {
|
||||
wsSend_P(PSTR("{\"mqttStatus\": false}"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
|
||||
|
||||
//DEBUG_MSG_P(PSTR("[WEBSOCKET] Parsing: %s\n"), length ? (char*) payload : "");
|
||||
|
||||
// Get client ID
|
||||
uint32_t client_id = client->id();
|
||||
|
||||
// Parse JSON input
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.parseObject((char *) payload);
|
||||
if (!root.success()) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] Error parsing data\n"));
|
||||
wsSend_P(client_id, PSTR("{\"message\": 3}"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check actions
|
||||
if (root.containsKey("action")) {
|
||||
|
||||
String action = root["action"];
|
||||
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] Requested action: %s\n"), action.c_str());
|
||||
|
||||
if (action.equals("reset")) {
|
||||
deferredReset(100, CUSTOM_RESET_WEB);
|
||||
}
|
||||
|
||||
#ifdef ITEAD_SONOFF_RFBRIDGE
|
||||
if (action.equals("rfblearn") && root.containsKey("data")) {
|
||||
JsonObject& data = root["data"];
|
||||
rfbLearn(data["id"], data["status"]);
|
||||
}
|
||||
if (action.equals("rfbforget") && root.containsKey("data")) {
|
||||
JsonObject& data = root["data"];
|
||||
rfbForget(data["id"], data["status"]);
|
||||
}
|
||||
if (action.equals("rfbsend") && root.containsKey("data")) {
|
||||
JsonObject& data = root["data"];
|
||||
rfbStore(data["id"], data["status"], data["data"].as<const char*>());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (action.equals("restore") && root.containsKey("data")) {
|
||||
|
||||
JsonObject& data = root["data"];
|
||||
if (!data.containsKey("app") || (data["app"] != APP_NAME)) {
|
||||
wsSend_P(client_id, PSTR("{\"message\": 4}"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) {
|
||||
EEPROM.write(i, 0xFF);
|
||||
}
|
||||
|
||||
for (auto element : data) {
|
||||
if (strcmp(element.key, "app") == 0) continue;
|
||||
if (strcmp(element.key, "version") == 0) continue;
|
||||
setSetting(element.key, element.value.as<char*>());
|
||||
}
|
||||
|
||||
saveSettings();
|
||||
|
||||
wsSend_P(client_id, PSTR("{\"message\": 5}"));
|
||||
|
||||
}
|
||||
|
||||
if (action.equals("reconnect")) {
|
||||
|
||||
// Let the HTTP request return and disconnect after 100ms
|
||||
_web_defer.once_ms(100, wifiDisconnect);
|
||||
|
||||
}
|
||||
|
||||
if (action.equals("relay") && root.containsKey("data")) {
|
||||
|
||||
JsonObject& data = root["data"];
|
||||
|
||||
if (data.containsKey("status")) {
|
||||
|
||||
unsigned char value = relayParsePayload(data["status"]);
|
||||
|
||||
if (value == 3) {
|
||||
|
||||
relayWS();
|
||||
|
||||
} else if (value < 3) {
|
||||
|
||||
unsigned int relayID = 0;
|
||||
if (data.containsKey("id")) {
|
||||
String value = data["id"];
|
||||
relayID = value.toInt();
|
||||
}
|
||||
|
||||
// Action to perform
|
||||
if (value == 0) {
|
||||
relayStatus(relayID, false);
|
||||
} else if (value == 1) {
|
||||
relayStatus(relayID, true);
|
||||
} else if (value == 2) {
|
||||
relayToggle(relayID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
|
||||
if (lightHasColor()) {
|
||||
|
||||
if (action.equals("rgb") && root.containsKey("data")) {
|
||||
lightColor((const char *) root["data"], true);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
|
||||
if (action.equals("brightness") && root.containsKey("data")) {
|
||||
lightBrightness(root["data"]);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
|
||||
if (action.equals("hsv") && root.containsKey("data")) {
|
||||
lightColor((const char *) root["data"], false);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (action.equals("channel") && root.containsKey("data")) {
|
||||
JsonObject& data = root["data"];
|
||||
if (data.containsKey("id") && data.containsKey("value")) {
|
||||
lightChannel(data["id"], data["value"]);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
|
||||
if (action.equals("anim_mode") && root.containsKey("data")) {
|
||||
lightAnimMode(root["data"]);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
if (action.equals("anim_speed") && root.containsKey("data")) {
|
||||
lightAnimSpeed(root["data"]);
|
||||
lightUpdate(true, true);
|
||||
}
|
||||
#endif //LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
|
||||
|
||||
#endif //LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
|
||||
};
|
||||
|
||||
// Check config
|
||||
if (root.containsKey("config") && root["config"].is<JsonArray&>()) {
|
||||
|
||||
JsonArray& config = root["config"];
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] Parsing configuration data\n"));
|
||||
|
||||
unsigned char webMode = WEB_MODE_NORMAL;
|
||||
|
||||
bool save = false;
|
||||
bool changed = false;
|
||||
bool changedMQTT = false;
|
||||
bool changedNTP = false;
|
||||
|
||||
unsigned int network = 0;
|
||||
unsigned int dczRelayIdx = 0;
|
||||
String adminPass;
|
||||
|
||||
for (unsigned int i=0; i<config.size(); i++) {
|
||||
|
||||
String key = config[i]["name"];
|
||||
String value = config[i]["value"];
|
||||
|
||||
// Skip firmware filename
|
||||
if (key.equals("filename")) continue;
|
||||
|
||||
#if POWER_PROVIDER != POWER_PROVIDER_NONE
|
||||
|
||||
if (key == "pwrExpectedP") {
|
||||
powerCalibrate(POWER_MAGNITUDE_ACTIVE, value.toFloat());
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "pwrExpectedV") {
|
||||
powerCalibrate(POWER_MAGNITUDE_VOLTAGE, value.toFloat());
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "pwrExpectedC") {
|
||||
powerCalibrate(POWER_MAGNITUDE_CURRENT, value.toFloat());
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "pwrExpectedF") {
|
||||
powerCalibrate(POWER_MAGNITUDE_POWER_FACTOR, value.toFloat());
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "pwrResetCalibration") {
|
||||
if (value.toInt() == 1) {
|
||||
powerResetCalibration();
|
||||
changed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if DOMOTICZ_SUPPORT
|
||||
|
||||
if (key == "dczRelayIdx") {
|
||||
if (dczRelayIdx >= relayCount()) continue;
|
||||
key = key + String(dczRelayIdx);
|
||||
++dczRelayIdx;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (key.startsWith("dcz")) continue;
|
||||
|
||||
#endif
|
||||
|
||||
// Web portions
|
||||
if (key == "webPort") {
|
||||
if ((value.toInt() == 0) || (value.toInt() == 80)) {
|
||||
save = changed = true;
|
||||
delSetting(key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (key == "webMode") {
|
||||
webMode = value.toInt();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check password
|
||||
if (key == "adminPass1") {
|
||||
adminPass = value;
|
||||
continue;
|
||||
}
|
||||
if (key == "adminPass2") {
|
||||
if (!value.equals(adminPass)) {
|
||||
wsSend_P(client_id, PSTR("{\"message\": 7}"));
|
||||
return;
|
||||
}
|
||||
if (value.length() == 0) continue;
|
||||
wsSend_P(client_id, PSTR("{\"action\": \"reload\"}"));
|
||||
key = String("adminPass");
|
||||
}
|
||||
|
||||
if (key == "ssid") {
|
||||
key = key + String(network);
|
||||
}
|
||||
if (key == "pass") {
|
||||
key = key + String(network);
|
||||
}
|
||||
if (key == "ip") {
|
||||
key = key + String(network);
|
||||
}
|
||||
if (key == "gw") {
|
||||
key = key + String(network);
|
||||
}
|
||||
if (key == "mask") {
|
||||
key = key + String(network);
|
||||
}
|
||||
if (key == "dns") {
|
||||
key = key + String(network);
|
||||
++network;
|
||||
}
|
||||
|
||||
if (value != getSetting(key)) {
|
||||
//DEBUG_MSG_P(PSTR("[WEBSOCKET] Storing %s = %s\n", key.c_str(), value.c_str()));
|
||||
setSetting(key, value);
|
||||
save = changed = true;
|
||||
if (key.startsWith("mqtt")) changedMQTT = true;
|
||||
#if NTP_SUPPORT
|
||||
if (key.startsWith("ntp")) changedNTP = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (webMode == WEB_MODE_NORMAL) {
|
||||
|
||||
// Clean wifi networks
|
||||
int i = 0;
|
||||
while (i < network) {
|
||||
if (!hasSetting("ssid", i)) {
|
||||
delSetting("ssid", i);
|
||||
break;
|
||||
}
|
||||
if (!hasSetting("pass", i)) delSetting("pass", i);
|
||||
if (!hasSetting("ip", i)) delSetting("ip", i);
|
||||
if (!hasSetting("gw", i)) delSetting("gw", i);
|
||||
if (!hasSetting("mask", i)) delSetting("mask", i);
|
||||
if (!hasSetting("dns", i)) delSetting("dns", i);
|
||||
++i;
|
||||
}
|
||||
while (i < WIFI_MAX_NETWORKS) {
|
||||
if (hasSetting("ssid", i)) {
|
||||
save = changed = true;
|
||||
}
|
||||
delSetting("ssid", i);
|
||||
delSetting("pass", i);
|
||||
delSetting("ip", i);
|
||||
delSetting("gw", i);
|
||||
delSetting("mask", i);
|
||||
delSetting("dns", i);
|
||||
++i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save settings
|
||||
if (save) {
|
||||
|
||||
wsConfigure();
|
||||
saveSettings();
|
||||
wifiConfigure();
|
||||
otaConfigure();
|
||||
if (changedMQTT) {
|
||||
mqttConfigure();
|
||||
mqttDisconnect();
|
||||
}
|
||||
|
||||
#if ALEXA_SUPPORT
|
||||
alexaConfigure();
|
||||
#endif
|
||||
#if INFLUXDB_SUPPORT
|
||||
idbConfigure();
|
||||
#endif
|
||||
#if DOMOTICZ_SUPPORT
|
||||
domoticzConfigure();
|
||||
#endif
|
||||
#if NOFUSS_SUPPORT
|
||||
nofussConfigure();
|
||||
#endif
|
||||
#if RF_SUPPORT
|
||||
rfBuildCodes();
|
||||
#endif
|
||||
#if POWER_PROVIDER != POWER_PROVIDER_NONE
|
||||
powerConfigure();
|
||||
#endif
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
#if LIGHT_SAVE_ENABLED == 0
|
||||
lightSave();
|
||||
#endif
|
||||
#endif
|
||||
#if NTP_SUPPORT
|
||||
if (changedNTP) ntpConfigure();
|
||||
#endif
|
||||
#if HOMEASSISTANT_SUPPORT
|
||||
haConfigure();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
wsSend_P(client_id, PSTR("{\"message\": 8}"));
|
||||
} else {
|
||||
wsSend_P(client_id, PSTR("{\"message\": 9}"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _wsStart(uint32_t client_id) {
|
||||
|
||||
char chipid[7];
|
||||
snprintf_P(chipid, sizeof(chipid), PSTR("%06X"), ESP.getChipId());
|
||||
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
|
||||
bool changePassword = false;
|
||||
#if WEB_FORCE_PASS_CHANGE
|
||||
String adminPass = getSetting("adminPass", ADMIN_PASS);
|
||||
if (adminPass.equals(ADMIN_PASS)) changePassword = true;
|
||||
#endif
|
||||
|
||||
if (changePassword) {
|
||||
|
||||
root["webMode"] = WEB_MODE_PASSWORD;
|
||||
|
||||
} else {
|
||||
|
||||
root["webMode"] = WEB_MODE_NORMAL;
|
||||
|
||||
root["app_name"] = APP_NAME;
|
||||
root["app_version"] = APP_VERSION;
|
||||
root["app_build"] = buildTime();
|
||||
root["manufacturer"] = MANUFACTURER;
|
||||
root["chipid"] = chipid;
|
||||
root["mac"] = WiFi.macAddress();
|
||||
root["device"] = DEVICE;
|
||||
root["hostname"] = getSetting("hostname");
|
||||
root["network"] = getNetwork();
|
||||
root["deviceip"] = getIP();
|
||||
root["time"] = ntpDateTime();
|
||||
root["uptime"] = getUptime();
|
||||
root["heap"] = ESP.getFreeHeap();
|
||||
root["sketch_size"] = ESP.getSketchSize();
|
||||
root["free_size"] = ESP.getFreeSketchSpace();
|
||||
|
||||
#if NTP_SUPPORT
|
||||
root["ntpVisible"] = 1;
|
||||
root["ntpStatus"] = ntpConnected();
|
||||
root["ntpServer1"] = getSetting("ntpServer1", NTP_SERVER);
|
||||
root["ntpServer2"] = getSetting("ntpServer2");
|
||||
root["ntpServer3"] = getSetting("ntpServer3");
|
||||
root["ntpOffset"] = getSetting("ntpOffset", NTP_TIME_OFFSET).toInt();
|
||||
root["ntpDST"] = getSetting("ntpDST", NTP_DAY_LIGHT).toInt() == 1;
|
||||
#endif
|
||||
|
||||
root["mqttStatus"] = mqttConnected();
|
||||
root["mqttEnabled"] = mqttEnabled();
|
||||
root["mqttServer"] = getSetting("mqttServer", MQTT_SERVER);
|
||||
root["mqttPort"] = getSetting("mqttPort", MQTT_PORT);
|
||||
root["mqttUser"] = getSetting("mqttUser");
|
||||
root["mqttPassword"] = getSetting("mqttPassword");
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
root["mqttsslVisible"] = 1;
|
||||
root["mqttUseSSL"] = getSetting("mqttUseSSL", 0).toInt() == 1;
|
||||
root["mqttFP"] = getSetting("mqttFP");
|
||||
#endif
|
||||
root["mqttTopic"] = getSetting("mqttTopic", MQTT_TOPIC);
|
||||
root["mqttUseJson"] = getSetting("mqttUseJson", MQTT_USE_JSON).toInt() == 1;
|
||||
|
||||
JsonArray& relay = root.createNestedArray("relayStatus");
|
||||
for (unsigned char relayID=0; relayID<relayCount(); relayID++) {
|
||||
relay.add(relayStatus(relayID));
|
||||
}
|
||||
|
||||
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
|
||||
root["colorVisible"] = 1;
|
||||
root["useColor"] = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1;
|
||||
root["useWhite"] = getSetting("useWhite", LIGHT_USE_WHITE).toInt() == 1;
|
||||
root["useGamma"] = getSetting("useGamma", LIGHT_USE_GAMMA).toInt() == 1;
|
||||
root["useCSS"] = getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1;
|
||||
bool useRGB = getSetting("useRGB", LIGHT_USE_RGB).toInt() == 1;
|
||||
root["useRGB"] = useRGB;
|
||||
if (lightHasColor()) {
|
||||
if (useRGB) {
|
||||
root["rgb"] = lightColor(true);
|
||||
root["brightness"] = lightBrightness();
|
||||
} else {
|
||||
root["hsv"] = lightColor(false);
|
||||
}
|
||||
#ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
|
||||
root["anim_mode"] = lightAnimMode();
|
||||
root["anim_speed"] = lightAnimSpeed();
|
||||
#endif // LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
|
||||
}
|
||||
JsonArray& channels = root.createNestedArray("channels");
|
||||
for (unsigned char id=0; id < lightChannels(); id++) {
|
||||
channels.add(lightChannel(id));
|
||||
}
|
||||
#endif
|
||||
|
||||
root["relayMode"] = getSetting("relayMode", RELAY_MODE);
|
||||
root["relayPulseMode"] = getSetting("relayPulseMode", RELAY_PULSE_MODE);
|
||||
root["relayPulseTime"] = getSetting("relayPulseTime", RELAY_PULSE_TIME).toFloat();
|
||||
if (relayCount() > 1) {
|
||||
root["multirelayVisible"] = 1;
|
||||
root["relaySync"] = getSetting("relaySync", RELAY_SYNC);
|
||||
}
|
||||
|
||||
root["btnDelay"] = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY).toInt();
|
||||
|
||||
root["webPort"] = getSetting("webPort", WEB_PORT).toInt();
|
||||
|
||||
root["apiEnabled"] = getSetting("apiEnabled", API_ENABLED).toInt() == 1;
|
||||
root["apiKey"] = getSetting("apiKey");
|
||||
root["apiRealTime"] = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
|
||||
|
||||
root["tmpUnits"] = getSetting("tmpUnits", TMP_UNITS).toInt();
|
||||
root["tmpCorrection"] = getSetting("tmpCorrection", TMP_CORRECTION).toFloat();
|
||||
|
||||
#if HOMEASSISTANT_SUPPORT
|
||||
root["haVisible"] = 1;
|
||||
root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX);
|
||||
#endif // HOMEASSISTANT_SUPPORT
|
||||
|
||||
#if DOMOTICZ_SUPPORT
|
||||
|
||||
root["dczVisible"] = 1;
|
||||
root["dczEnabled"] = getSetting("dczEnabled", DOMOTICZ_ENABLED).toInt() == 1;
|
||||
root["dczSkip"] = getSetting("dczSkip", DOMOTICZ_SKIP_TIME);
|
||||
root["dczTopicIn"] = getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC);
|
||||
root["dczTopicOut"] = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC);
|
||||
|
||||
JsonArray& dczRelayIdx = root.createNestedArray("dczRelayIdx");
|
||||
for (byte i=0; i<relayCount(); i++) {
|
||||
dczRelayIdx.add(domoticzIdx(i));
|
||||
}
|
||||
|
||||
#if DHT_SUPPORT
|
||||
root["dczTmpIdx"] = getSetting("dczTmpIdx").toInt();
|
||||
root["dczHumIdx"] = getSetting("dczHumIdx").toInt();
|
||||
#endif
|
||||
|
||||
#if DS18B20_SUPPORT
|
||||
root["dczTmpIdx"] = getSetting("dczTmpIdx").toInt();
|
||||
#endif
|
||||
|
||||
#if ANALOG_SUPPORT
|
||||
root["dczAnaIdx"] = getSetting("dczAnaIdx").toInt();
|
||||
#endif
|
||||
|
||||
#if POWER_PROVIDER != POWER_PROVIDER_NONE
|
||||
root["dczPowIdx"] = getSetting("dczPowIdx").toInt();
|
||||
root["dczEnergyIdx"] = getSetting("dczEnergyIdx").toInt();
|
||||
root["dczCurrentIdx"] = getSetting("dczCurrentIdx").toInt();
|
||||
#if POWER_HAS_ACTIVE
|
||||
root["dczVoltIdx"] = getSetting("dczVoltIdx").toInt();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if DS18B20_SUPPORT
|
||||
root["dsVisible"] = 1;
|
||||
root["dsTmp"] = getDSTemperatureStr();
|
||||
#endif
|
||||
|
||||
#if DHT_SUPPORT
|
||||
root["dhtVisible"] = 1;
|
||||
root["dhtTmp"] = getDHTTemperature();
|
||||
root["dhtHum"] = getDHTHumidity();
|
||||
#endif
|
||||
|
||||
#if RF_SUPPORT
|
||||
root["rfVisible"] = 1;
|
||||
root["rfChannel"] = getSetting("rfChannel", RF_CHANNEL);
|
||||
root["rfDevice"] = getSetting("rfDevice", RF_DEVICE);
|
||||
#endif
|
||||
|
||||
#if POWER_PROVIDER != POWER_PROVIDER_NONE
|
||||
root["pwrVisible"] = 1;
|
||||
root["pwrCurrent"] = getCurrent();
|
||||
root["pwrVoltage"] = getVoltage();
|
||||
root["pwrApparent"] = getApparentPower();
|
||||
root["pwrEnergy"] = getPowerEnergy();
|
||||
root["pwrReadEvery"] = powerReadInterval();
|
||||
root["pwrReportEvery"] = powerReportInterval();
|
||||
#if POWER_HAS_ACTIVE
|
||||
root["pwrActive"] = getActivePower();
|
||||
root["pwrReactive"] = getReactivePower();
|
||||
root["pwrFactor"] = int(100 * getPowerFactor());
|
||||
#endif
|
||||
#if (POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG) || (POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121)
|
||||
root["emonVisible"] = 1;
|
||||
#endif
|
||||
#if POWER_PROVIDER == POWER_PROVIDER_HLW8012
|
||||
root["hlwVisible"] = 1;
|
||||
#endif
|
||||
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
|
||||
root["v9261fVisible"] = 1;
|
||||
#endif
|
||||
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
|
||||
root["ech1560fVisible"] = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if NOFUSS_SUPPORT
|
||||
root["nofussVisible"] = 1;
|
||||
root["nofussEnabled"] = getSetting("nofussEnabled", NOFUSS_ENABLED).toInt() == 1;
|
||||
root["nofussServer"] = getSetting("nofussServer", NOFUSS_SERVER);
|
||||
#endif
|
||||
|
||||
#ifdef ITEAD_SONOFF_RFBRIDGE
|
||||
root["rfbVisible"] = 1;
|
||||
root["rfbCount"] = relayCount();
|
||||
JsonArray& rfb = root.createNestedArray("rfb");
|
||||
for (byte id=0; id<relayCount(); id++) {
|
||||
for (byte status=0; status<2; status++) {
|
||||
JsonObject& node = rfb.createNestedObject();
|
||||
node["id"] = id;
|
||||
node["status"] = status;
|
||||
node["data"] = rfbRetrieve(id, status == 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TELNET_SUPPORT
|
||||
root["telnetVisible"] = 1;
|
||||
root["telnetSTA"] = getSetting("telnetSTA", TELNET_STA).toInt() == 1;
|
||||
#endif
|
||||
|
||||
root["maxNetworks"] = WIFI_MAX_NETWORKS;
|
||||
JsonArray& wifi = root.createNestedArray("wifi");
|
||||
for (byte i=0; i<WIFI_MAX_NETWORKS; i++) {
|
||||
if (getSetting("ssid" + String(i)).length() == 0) break;
|
||||
JsonObject& network = wifi.createNestedObject();
|
||||
network["ssid"] = getSetting("ssid" + String(i));
|
||||
network["pass"] = getSetting("pass" + String(i));
|
||||
network["ip"] = getSetting("ip" + String(i));
|
||||
network["gw"] = getSetting("gw" + String(i));
|
||||
network["mask"] = getSetting("mask" + String(i));
|
||||
network["dns"] = getSetting("dns" + String(i));
|
||||
}
|
||||
|
||||
// Module setters
|
||||
for (unsigned char i = 0; i < _ws_sender_callbacks.size(); i++) {
|
||||
(_ws_sender_callbacks[i])(root);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
String output;
|
||||
root.printTo(output);
|
||||
wsSend(client_id, (char *) output.c_str());
|
||||
|
||||
}
|
||||
|
||||
void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
|
||||
|
||||
if (type == WS_EVT_CONNECT) {
|
||||
IPAddress ip = client->remoteIP();
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n"), client->id(), ip[0], ip[1], ip[2], ip[3], server->url());
|
||||
_wsStart(client->id());
|
||||
client->_tempObject = new WebSocketIncommingBuffer(&_wsParse, true);
|
||||
wifiReconnectCheck();
|
||||
|
||||
} else if(type == WS_EVT_DISCONNECT) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u disconnected\n"), client->id());
|
||||
if (client->_tempObject) {
|
||||
delete (WebSocketIncommingBuffer *) client->_tempObject;
|
||||
}
|
||||
wifiReconnectCheck();
|
||||
|
||||
} else if(type == WS_EVT_ERROR) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u error(%u): %s\n"), client->id(), *((uint16_t*)arg), (char*)data);
|
||||
|
||||
} else if(type == WS_EVT_PONG) {
|
||||
DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u pong(%u): %s\n"), client->id(), len, len ? (char*) data : "");
|
||||
|
||||
} else if(type == WS_EVT_DATA) {
|
||||
//DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u data(%u): %s\n"), client->id(), len, len ? (char*) data : "");
|
||||
WebSocketIncommingBuffer *buffer = (WebSocketIncommingBuffer *)client->_tempObject;
|
||||
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||
buffer->data_event(client, info, data, len);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Piblic API
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool wsConnected() {
|
||||
return (_ws.count() > 0);
|
||||
}
|
||||
|
||||
void wsRegister(ws_callback_f sender, ws_callback_f receiver) {
|
||||
_ws_sender_callbacks.push_back(sender);
|
||||
if (receiver) _ws_receiver_callbacks.push_back(receiver);
|
||||
}
|
||||
|
||||
void wsSend(ws_callback_f sender) {
|
||||
if (_ws.count() > 0) {
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
sender(root);
|
||||
String output;
|
||||
root.printTo(output);
|
||||
wsSend((char *) output.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void wsSend(const char * payload) {
|
||||
if (_ws.count() > 0) {
|
||||
_ws.textAll(payload);
|
||||
}
|
||||
}
|
||||
|
||||
void wsSend_P(PGM_P payload) {
|
||||
if (_ws.count() > 0) {
|
||||
char buffer[strlen_P(payload)];
|
||||
strcpy_P(buffer, payload);
|
||||
_ws.textAll(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void wsSend(uint32_t client_id, const char * payload) {
|
||||
_ws.text(client_id, payload);
|
||||
}
|
||||
|
||||
void wsSend_P(uint32_t client_id, PGM_P payload) {
|
||||
char buffer[strlen_P(payload)];
|
||||
strcpy_P(buffer, payload);
|
||||
_ws.text(client_id, buffer);
|
||||
}
|
||||
|
||||
void wsConfigure() {
|
||||
_ws.setAuthentication(WEB_USERNAME, (const char *) getSetting("adminPass", ADMIN_PASS).c_str());
|
||||
}
|
||||
|
||||
void wsSetup() {
|
||||
_ws.onEvent(_wsEvent);
|
||||
wsConfigure();
|
||||
webServer()->addHandler(&_ws);
|
||||
mqttRegister(_wsMQTTCallback);
|
||||
}
|
||||
|
||||
#endif // WEB_SUPPORT
|
||||
@@ -21,7 +21,6 @@ function initMessages() {
|
||||
messages[03] = "Error parsing data!";
|
||||
messages[04] = "The file does not look like a valid configuration backup or is corrupted";
|
||||
messages[05] = "Changes saved. You should reboot your board now";
|
||||
messages[06] = "Home Assistant auto-discovery message sent";
|
||||
messages[07] = "Passwords do not match!";
|
||||
messages[08] = "Changes saved";
|
||||
messages[09] = "No changes detected";
|
||||
@@ -91,24 +90,6 @@ function generateAPIKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function forgetCredentials() {
|
||||
$.ajax({
|
||||
'method': 'GET',
|
||||
'url': '/',
|
||||
'async': false,
|
||||
'username': "logmeout",
|
||||
'password': "123456",
|
||||
'headers': { "Authorization": "Basic xxx" }
|
||||
}).done(function(data) {
|
||||
return false;
|
||||
// If we don't get an error, we actually got an error as we expect an 401!
|
||||
}).fail(function(){
|
||||
// We expect to get an 401 Unauthorized error! In this case we are successfully
|
||||
// logged out and we redirect the user.
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function getJson(str) {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
@@ -626,14 +607,12 @@ function processData(data) {
|
||||
password = data.webMode == 1;
|
||||
$("#layout").toggle(data.webMode == 0);
|
||||
$("#password").toggle(data.webMode == 1);
|
||||
$("#credentials").hide();
|
||||
}
|
||||
|
||||
// Actions
|
||||
if (key == "action") {
|
||||
|
||||
if (data.action == "reload") {
|
||||
if (password) forgetCredentials();
|
||||
doReload(1000);
|
||||
}
|
||||
|
||||
@@ -954,24 +933,11 @@ function init() {
|
||||
$(".button-add-network").on('click', function() {
|
||||
$("div.more", addNetwork()).toggle();
|
||||
});
|
||||
$(".button-ha-add").on('click', function() {
|
||||
websock.send(JSON.stringify({'action': 'ha_add', 'data': $("input[name='haPrefix']").val()}));
|
||||
});
|
||||
$(".button-ha-del").on('click', function() {
|
||||
websock.send(JSON.stringify({'action': 'ha_del', 'data': $("input[name='haPrefix']").val()}));
|
||||
});
|
||||
|
||||
$(document).on('change', 'input', hasChanged);
|
||||
$(document).on('change', 'select', hasChanged);
|
||||
|
||||
$.ajax({
|
||||
'method': 'GET',
|
||||
'url': window.location.href + 'auth'
|
||||
}).done(function(data) {
|
||||
connect();
|
||||
}).fail(function(){
|
||||
$("#credentials").show();
|
||||
});
|
||||
connect();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
|
||||
<body>
|
||||
|
||||
<div id="credentials" class="webmode">
|
||||
Wrong credentials
|
||||
</div>
|
||||
|
||||
<div id="password" class="webmode">
|
||||
|
||||
<div class="content">
|
||||
@@ -416,24 +412,25 @@
|
||||
</div>
|
||||
|
||||
<div class="pure-g module module-ha">
|
||||
<label class="pure-u-1 pure-u-md-1-4" for="haPrefix">Home Assistant Prefix</label>
|
||||
<input class="pure-u-1 pure-u-md-1-4" name="haPrefix" type="text" tabindex="13" />
|
||||
<div class="pure-u-1-2 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-ha-add">Add</button></div>
|
||||
<div class="pure-u-1-2 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-ha-del">Delete</button></div>
|
||||
<div class="pure-u-0 pure-u-md-1-4"> </div>
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><label for="haEnabled">Home Assistant</label></div>
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="haEnabled" tabindex="13" /></div>
|
||||
<div class="pure-u-0 pure-u-md-1-2"> </div>
|
||||
<div class="pure-u-0 pure-u-md-1-4"> </div>
|
||||
<div class="pure-u-1 pure-u-md-3-4 hint">
|
||||
Home Assistant auto-discovery feature.<br />
|
||||
Add should immediately add the device to your HA console. Messages are retained so the device should be there even after a HA reboot<br />
|
||||
To remove the device click on the Del button (retained message will be deleted) and reboot HA.<br />
|
||||
Home Assistant auto-discovery feature. Enable and save to add the device to your HA console.
|
||||
You might want to disable CSS style (above) so Home Assistant can parse the color.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g module module-ha">
|
||||
<label class="pure-u-1 pure-u-md-1-4" for="haPrefix">Home Assistant Prefix</label>
|
||||
<input class="pure-u-1 pure-u-md-1-4" name="haPrefix" type="text" tabindex="14" />
|
||||
</div>
|
||||
|
||||
<div class="pure-g module module-ds module-dht">
|
||||
<label class="pure-u-1 pure-u-sm-1-4" for="tmpUnits">Temperature units</label>
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="14" value="0"> Celsius (°C)</input></div>
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="15" value="1"> Fahrenheit (°F)</input></div>
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="15" value="0"> Celsius (°C)</input></div>
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><input type="radio" name="tmpUnits" tabindex="16" value="1"> Fahrenheit (°F)</input></div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g module module-ds module-dht">
|
||||
@@ -719,6 +716,12 @@
|
||||
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="dczEnabled" tabindex="30" /></div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<label class="pure-u-1 pure-u-sm-1-4" for="dczSkip">Anti-recursion time</label>
|
||||
<div class="pure-u-1 pure-u-sm-1-8"><input class="pure-u-sm-23-24" name="dczSkip" type="number" min="0" max="10" tabindex="31" /></div>
|
||||
<div class="pure-u-1 pure-u-sm-5-8 hint center">Skips in/out messages from the same IDX within this time in seconds</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<label class="pure-u-1 pure-u-md-1-4" for="dczTopicIn">Domoticz IN Topic</label>
|
||||
<input class="pure-u-1 pure-u-md-3-4" name="dczTopicIn" type="text" tabindex="31" />
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
[platformio]
|
||||
env_default = nodemcu-lolin
|
||||
env_default = wemos-d1mini-relayshield
|
||||
src_dir = espurna
|
||||
data_dir = espurna/data
|
||||
|
||||
[common]
|
||||
platform = espressif8266
|
||||
#platform = espressif8266_stage
|
||||
#platform = espressif8266
|
||||
platform = espressif8266_stage
|
||||
build_flags = -g -DMQTT_MAX_PACKET_SIZE=400 ${env.ESPURNA_FLAGS}
|
||||
debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
|
||||
build_flags_512k = ${common.build_flags} -Wl,-Tesp8266.flash.512k0.ld
|
||||
build_flags_1m = ${common.build_flags} -Wl,-Tesp8266.flash.1m0.ld
|
||||
#https://github.com/me-no-dev/ESPAsyncTCP#9b0cc37 // 2.3.0 compatible
|
||||
#https://github.com/me-no-dev/ESPAsyncTCP#289a681 // 2.4.0-rc2 compatible
|
||||
lib_deps =
|
||||
https://github.com/xoseperez/Time
|
||||
ArduinoJson
|
||||
https://github.com/me-no-dev/ESPAsyncTCP#9b0cc37
|
||||
https://github.com/me-no-dev/ESPAsyncTCP#a57560d
|
||||
https://github.com/me-no-dev/ESPAsyncWebServer#313f337
|
||||
https://github.com/marvinroger/async-mqtt-client#v0.8.1
|
||||
PubSubClient
|
||||
@@ -31,11 +29,13 @@ lib_deps =
|
||||
https://bitbucket.org/xoseperez/nofuss.git#0.2.5
|
||||
https://bitbucket.org/xoseperez/emonliteesp.git#0.2.0
|
||||
https://bitbucket.org/xoseperez/debounceevent.git#2.0.1
|
||||
https://github.com/xoseperez/my9291#2.0.0
|
||||
https://github.com/xoseperez/my92xx#3.0.0
|
||||
https://github.com/xoseperez/RemoteSwitch-arduino-library.git
|
||||
https://github.com/FastLED/FastLED#v3.1.6
|
||||
https://github.com/markszabo/IRremoteESP8266#v2.2.0
|
||||
lib_ignore =
|
||||
#extra_scripts = post:core_version.py
|
||||
extra_scripts =
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
@@ -48,6 +48,7 @@ lib_ignore = ${common.lib_ignore}
|
||||
build_flags = ${common.build_flags} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH
|
||||
upload_speed = 460800
|
||||
monitor_baud = 115200
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:wemos-d1mini-relayshield-ssl]
|
||||
platform = espressif8266_stage
|
||||
@@ -229,6 +230,29 @@ upload_port = "192.168.4.1"
|
||||
upload_flags = --auth=fibonacci --port 8266
|
||||
monitor_baud = 115200
|
||||
|
||||
[env:itead-sonoff-th]
|
||||
platform = ${common.platform}
|
||||
framework = arduino
|
||||
board = esp01_1m
|
||||
board_flash_mode = dout
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TH
|
||||
monitor_baud = 115200
|
||||
|
||||
[env:itead-sonoff-th-ota]
|
||||
platform = ${common.platform}
|
||||
framework = arduino
|
||||
board = esp01_1m
|
||||
board_flash_mode = dout
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TH
|
||||
upload_speed = 115200
|
||||
upload_port = "192.168.4.1"
|
||||
upload_flags = --auth=fibonacci --port 8266
|
||||
monitor_baud = 115200
|
||||
|
||||
[env:itead-sonoff-pow]
|
||||
platform = ${common.platform}
|
||||
framework = arduino
|
||||
|
||||
Reference in New Issue
Block a user