Browse Source

Merge branch 'thingspeak' into dev

Conflicts:
	code/espurna/data/index.html.gz
	code/espurna/static/index.html.gz.h
i18n
Xose Pérez 7 years ago
parent
commit
207726b049
15 changed files with 3565 additions and 3150 deletions
  1. +2
    -1
      code/espurna/config/arduino.h
  2. +37
    -2
      code/espurna/config/general.h
  3. +4
    -0
      code/espurna/config/hardware.h
  4. BIN
      code/espurna/data/index.html.gz
  5. +1
    -1
      code/espurna/domoticz.ino
  6. +9
    -0
      code/espurna/espurna.ino
  7. +1
    -1
      code/espurna/influxdb.ino
  8. +6
    -47
      code/espurna/mqtt.ino
  9. +5
    -0
      code/espurna/relay.ino
  10. +8
    -0
      code/espurna/sensor.ino
  11. +3090
    -3079
      code/espurna/static/index.html.gz.h
  12. +260
    -0
      code/espurna/thinkspeak.ino
  13. +45
    -0
      code/espurna/utils.ino
  14. +34
    -15
      code/html/custom.js
  15. +63
    -4
      code/html/index.html

+ 2
- 1
code/espurna/config/arduino.h View File

@ -84,6 +84,7 @@
//#define SSDP_SUPPORT 1
//#define TELNET_SUPPORT 0
//#define TERMINAL_SUPPORT 0
//#define THINGSPEAK_SUPPORT 0
//#define WEB_SUPPORT 0
//--------------------------------------------------------------------------------
@ -105,4 +106,4 @@
//#define PMSX003_SUPPORT 1
//#define SHT3X_I2C_SUPPORT 1
//#define SI7021_SUPPORT 1
//#define V9261F_SUPPORT 1
//#define V9261F_SUPPORT 1

+ 37
- 2
code/espurna/config/general.h View File

@ -321,7 +321,7 @@ PROGMEM const char* const custom_reset_string[] = {
#endif
// This is not working at the moment!!
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core staging version.
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0
#define WEB_SSL_ENABLED 0 // Use HTTPS web interface
#define WEB_MODE_NORMAL 0
@ -420,7 +420,7 @@ PROGMEM const char* const custom_reset_string[] = {
// MQTT OVER SSL
// Using MQTT over SSL works pretty well but generates problems with the web interface.
// It could be a good idea to use it in conjuntion with WEB_SUPPORT=0.
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core staging version.
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0.
//
// You can use it with MQTT_USE_ASYNC=1 (AsyncMqttClient library)
// but you might experience hiccups on the web interface, so my recommendation is:
@ -627,6 +627,41 @@ PROGMEM const char* const custom_reset_string[] = {
#define INFLUXDB_USERNAME "" // Default username
#define INFLUXDB_PASSWORD "" // Default password
// -----------------------------------------------------------------------------
// THINGSPEAK
// -----------------------------------------------------------------------------
#ifndef THINGSPEAK_SUPPORT
#define THINGSPEAK_SUPPORT 0 // Enable Thingspeak support by default (???Kb)
#endif
#define THINGSPEAK_ENABLED 0 // Thingspeak disabled by default
#define THINGSPEAK_APIKEY "" // Default API KEY
#define THINGSPEAK_USE_ASYNC 1 // Use AsyncClient instead of WiFiClientSecure
// THINGSPEAK OVER SSL
// Using THINGSPEAK over SSL works well but generates problems with the web interface,
// so you should compile it with WEB_SUPPORT to 0.
// When THINGSPEAK_USE_ASYNC is 1, requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0.
#define THINGSPEAK_USE_SSL 0 // Use secure connection
#define THINGSPEAK_FINGERPRINT "78 60 18 44 81 35 BF DF 77 84 D4 0A 22 0D 9B 4E 6C DC 57 2C"
#define THINGSPEAK_HOST "api.thingspeak.com"
#if THINGSPEAK_USE_SSL
#define THINGSPEAK_PORT 443
#else
#define THINGSPEAK_PORT 80
#endif
#define THINGSPEAK_URL "/update"
#define THINGSPEAK_MIN_INTERVAL 15000 // Minimum interval between POSTs (in millis)
#ifndef ASYNC_TCP_SSL_ENABLED
#if THINGSPEAK_USE_SSL && THINGSPEAK_USE_ASYNC
#undef THINGSPEAK_SUPPORT // Thingspeak in ASYNC mode requires ASYNC_TCP_SSL_ENABLED
#endif
#endif
// -----------------------------------------------------------------------------
// NTP
// -----------------------------------------------------------------------------


+ 4
- 0
code/espurna/config/hardware.h View File

@ -70,6 +70,10 @@
#define MANUFACTURER "WEMOS"
#define DEVICE "D1_TARPUNA_SHIELD"
// Relays
#define RELAY1_PIN 12
#define RELAY1_TYPE RELAY_TYPE_NORMAL
// -----------------------------------------------------------------------------
// ESPurna
// -----------------------------------------------------------------------------


BIN
code/espurna/data/index.html.gz View File


+ 1
- 1
code/espurna/domoticz.ino View File

@ -97,7 +97,7 @@ void _domoticzWebSocketOnSend(JsonObject& root) {
root["dczTopicIn"] = getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC);
root["dczTopicOut"] = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC);
JsonArray& relays = root.createNestedArray("dczRelayIdx");
JsonArray& relays = root.createNestedArray("dczRelays");
for (byte i=0; i<relayCount(); i++) {
relays.add(domoticzIdx(i));
}


+ 9
- 0
code/espurna/espurna.ino View File

@ -188,6 +188,9 @@ void welcome() {
#if TERMINAL_SUPPORT
DEBUG_MSG_P(PSTR(" TERMINAL"));
#endif
#if THINGSPEAK_SUPPORT
DEBUG_MSG_P(PSTR(" THINGSPEAK"));
#endif
#if WEB_SUPPORT
DEBUG_MSG_P(PSTR(" WEB"));
#endif
@ -357,6 +360,9 @@ void setup() {
#if INFLUXDB_SUPPORT
idbSetup();
#endif
#if THINGSPEAK_SUPPORT
tspkSetup();
#endif
#if RF_SUPPORT
rfSetup();
#endif
@ -427,6 +433,9 @@ void loop() {
#if SENSOR_SUPPORT
sensorLoop();
#endif
#if THINGSPEAK_SUPPORT
tspkLoop();
#endif
// Power saving delay
delay(_loopDelay);


+ 1
- 1
code/espurna/influxdb.ino View File

@ -1,6 +1,6 @@
/*
I2C MODULE
INFLUXDB MODULE
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>


+ 6
- 47
code/espurna/mqtt.ino View File

@ -319,47 +319,6 @@ void _mqttOnMessage(char* topic, char* payload, unsigned int len) {
}
#if MQTT_USE_ASYNC
bool mqttFormatFP(const char * fingerprint, unsigned char * bytearray) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (strlen(fingerprint) != 59) return false;
DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint);
// walk the fingerprint
for (unsigned int i=0; i<20; i++) {
bytearray[i] = strtol(fingerprint + 3*i, NULL, 16);
}
return true;
}
#else
bool mqttFormatFP(const char * fingerprint, char * destination) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (strlen(fingerprint) != 59) return false;
DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint);
// copy it
strncpy(destination, fingerprint, 59);
// walk the fingerprint replacing ':' for ' '
for (unsigned char i = 0; i<59; i++) {
if (destination[i] == ':') destination[i] = ' ';
}
return true;
}
#endif
void mqttEnabled(bool status) {
_mqtt_enabled = status;
setSetting("mqttEnabled", status ? 1 : 0);
@ -423,7 +382,7 @@ void mqttConnect() {
if (secure) {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
unsigned char fp[20] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (sslFingerPrintArray(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
_mqtt.addServerFingerprint(fp);
} else {
DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n"));
@ -450,7 +409,7 @@ void mqttConnect() {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
if (_mqtt_client_secure.connect(host, port)) {
char fp[60] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (sslFingerPrintChar(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (_mqtt_client_secure.verify(fp, host)) {
_mqtt.setClient(_mqtt_client_secure);
} else {
@ -549,8 +508,10 @@ void mqttSetBrokerIfNone(IPAddress ip, unsigned int port) {
void mqttSetup() {
DEBUG_MSG_P(PSTR("[MQTT] MQTT_USE_ASYNC = %d\n"), MQTT_USE_ASYNC);
DEBUG_MSG_P(PSTR("[MQTT] MQTT_AUTOCONNECT = %d\n"), MQTT_AUTOCONNECT);
DEBUG_MSG_P(PSTR("[MQTT] Async %s, Autoconnect %s\n"),
MQTT_USE_ASYNC ? "ENABLED" : "DISABLED",
MQTT_AUTOCONNECT ? "ENABLED" : "DISABLED"
);
#if MQTT_USE_ASYNC
@ -592,8 +553,6 @@ void mqttSetup() {
#else // not MQTT_USE_ASYNC
DEBUG_MSG_P(PSTR("[MQTT] Using SYNC MQTT library\n"));
_mqtt.setCallback([](char* topic, byte* payload, unsigned int length) {
_mqttOnMessage(topic, (char *) payload, length);
});


+ 5
- 0
code/espurna/relay.ino View File

@ -747,6 +747,11 @@ void relayLoop(void) {
relayInfluxDB(id);
#endif
#if THINGSPEAK_SUPPORT
tspkEnqueueRelay(id, status);
tspkFlush();
#endif
// Flag relay-based LEDs to update status
ledUpdate(true);


+ 8
- 0
code/espurna/sensor.ino View File

@ -687,6 +687,10 @@ void sensorLoop() {
}
#endif // INFLUXDB_SUPPORT
#if THINGSPEAK_SUPPORT
tspkEnqueueMeasurement(i, buffer);
#endif
#if DOMOTICZ_SUPPORT
{
char key[15];
@ -723,6 +727,10 @@ void sensorLoop() {
wsSend(_sensorWebSocketSendData);
#endif
#if THINGSPEAK_SUPPORT
if (report_count == 0) tspkFlush();
#endif
}
}


+ 3090
- 3079
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 260
- 0
code/espurna/thinkspeak.ino View File

@ -0,0 +1,260 @@
/*
THINGSPEAK MODULE
Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if THINGSPEAK_SUPPORT
#if THINGSPEAK_USE_ASYNC
#include <ESPAsyncTCP.h>
AsyncClient * _tspk_client;
#else
#include <ESP8266WiFi.h>
#endif
const char THINGSPEAK_REQUEST_TEMPLATE[] PROGMEM =
"POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: ESPurna\r\n"
"Connection: close\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %d\r\n\r\n"
"%s\r\n";
bool _tspk_enabled = false;
char * _tspk_queue[8] = {NULL};
bool _tspk_flush = false;
unsigned long _tspk_last_flush = 0;
// -----------------------------------------------------------------------------
void _tspkWebSocketOnSend(JsonObject& root) {
root["tspkVisible"] = 1;
root["tspkEnabled"] = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
root["tspkKey"] = getSetting("tspkKey");
JsonArray& relays = root.createNestedArray("tspkRelays");
for (byte i=0; i<relayCount(); i++) {
relays.add(getSetting("tspkRelay", i, 0).toInt());
}
#if SENSOR_SUPPORT
JsonArray& list = root.createNestedArray("tspkMagnitudes");
for (byte i=0; i<magnitudeCount(); i++) {
JsonObject& element = list.createNestedObject();
element["name"] = magnitudeName(i);
element["type"] = magnitudeType(i);
element["index"] = magnitudeIndex(i);
element["idx"] = getSetting("tspkMagnitude", i, 0).toInt();
}
#endif
}
void _tspkConfigure() {
_tspk_enabled = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
if (_tspk_enabled && (getSetting("tspkKey").length() == 0)) {
_tspk_enabled = false;
setSetting("tspkEnabled", 0);
}
}
#if THINGSPEAK_USE_ASYNC
void _tspkPost(String data) {
if (_tspk_client == NULL) {
_tspk_client = new AsyncClient();
}
_tspk_client->onDisconnect([](void *s, AsyncClient *c) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Disconnected\n"));
_tspk_client->free();
delete _tspk_client;
_tspk_client = NULL;
}, 0);
_tspk_client->onTimeout([](void *s, AsyncClient *c, uint32_t time) {
_tspk_client->close(true);
}, 0);
_tspk_client->onData([](void * arg, AsyncClient * c, void * response, size_t len) {
char * b = (char *) response;
b[len] = 0;
char * p = strstr((char *)response, "\r\n\r\n");
unsigned int code = (p != NULL) ? atoi(&p[4]) : 0;
DEBUG_MSG_P(PSTR("[THINGSPEAK] Response value: %d\n"), code);
_tspk_client->close(true);
}, NULL);
_tspk_client->onConnect([data](void * arg, AsyncClient * client) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connected to %s:%d\n"), THINGSPEAK_HOST, THINGSPEAK_PORT);
#if THINGSPEAK_USE_SSL
uint8_t fp[20] = {0};
sslFingerPrintArray(THINGSPEAK_FINGERPRINT, fp);
SSL * ssl = _tspk_client->getSSL();
if (ssl_match_fingerprint(ssl, fp) != SSL_OK) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Warning: certificate doesn't match\n"));
}
#endif
DEBUG_MSG_P(PSTR("[THINGSPEAK] POST %s\n"), data.c_str());
char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()];
snprintf_P(buffer, sizeof(buffer),
THINGSPEAK_REQUEST_TEMPLATE,
THINGSPEAK_URL,
THINGSPEAK_HOST,
data.length(),
data.c_str()
);
client->write(buffer);
}, NULL);
#if ASYNC_TCP_SSL_ENABLED
bool connected = _tspk_client->connect(THINGSPEAK_HOST, THINGSPEAK_PORT, THINGSPEAK_USE_SSL);
#else
bool connected = _tspk_client->connect(THINGSPEAK_HOST, THINGSPEAK_PORT);
#endif
if (!connected) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connection failed\n"));
_tspk_client->close(true);
}
}
#else // THINGSPEAK_USE_ASYNC
void _tspkPost(String data) {
#if THINGSPEAK_USE_SSL
WiFiClientSecure _tspk_client;
#else
WiFiClient _tspk_client;
#endif
if (_tspk_client.connect(THINGSPEAK_HOST, THINGSPEAK_PORT)) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connected to %s:%d\n"), THINGSPEAK_HOST, THINGSPEAK_PORT);
if (!_tspk_client.verify(THINGSPEAK_FINGERPRINT, THINGSPEAK_HOST)) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Warning: certificate doesn't match\n"));
}
DEBUG_MSG_P(PSTR("[THINGSPEAK] POST %s\n"), data.c_str());
char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()];
snprintf_P(buffer, sizeof(buffer),
THINGSPEAK_REQUEST_TEMPLATE,
THINGSPEAK_URL,
THINGSPEAK_HOST,
data.length(),
data.c_str()
);
_tspk_client.print(buffer);
nice_delay(100);
String response = _tspk_client.readString();
int pos = response.indexOf("\r\n\r\n");
unsigned int code = (pos > 0) ? response.substring(pos + 4).toInt() : 0;
DEBUG_MSG_P(PSTR("[THINGSPEAK] Response value: %d\n"), code);
_tspk_client.stop();
return;
}
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connection failed\n"));
}
#endif // THINGSPEAK_USE_ASYNC
bool _tspkEnqueue(unsigned char index, char * payload) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Enqueuing field #%d with value %s\n"), index, payload);
--index;
if (_tspk_queue[index] != NULL) free(_tspk_queue[index]);
_tspk_queue[index] = strdup(payload);
}
void _tspkFlush() {
String data;
// Walk the fields
for (unsigned char id=0; id<8; id++) {
if (_tspk_queue[id] != NULL) {
if (data.length() > 0) data = data + String("&");
data = data + String("field") + String(id+1) + String("=") + String(_tspk_queue[id]);
free(_tspk_queue[id]);
_tspk_queue[id] = NULL;
}
}
// POST data if any
if (data.length() > 0) {
data = data + String("&api_key=") + getSetting("tspkKey");
_tspkPost(data);
_tspk_last_flush = millis();
}
}
// -----------------------------------------------------------------------------
bool tspkEnqueueRelay(unsigned char index, unsigned char status) {
if (!_tspk_enabled) return true;
unsigned char id = getSetting("tspkRelay", index, 0).toInt();
if (id > 0) {
char payload[3];
itoa(status ? 1 : 0, payload, 10);
_tspkEnqueue(id, payload);
}
}
bool tspkEnqueueMeasurement(unsigned char index, char * payload) {
if (!_tspk_enabled) return true;
unsigned char id = getSetting("tspkMagnitude", index, 0).toInt();
if (id > 0) {
_tspkEnqueue(id, payload);
}
}
void tspkFlush() {
_tspk_flush = true;
}
bool tspkEnabled() {
return _tspk_enabled;
}
void tspkSetup() {
_tspkConfigure();
#if WEB_SUPPORT
wsOnSendRegister(_tspkWebSocketOnSend);
wsOnAfterParseRegister(_tspkConfigure);
#endif
DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"),
THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED",
THINGSPEAK_USE_SSL ? "ENABLED" : "DISABLED"
);
}
void tspkLoop() {
if (!_tspk_enabled) return;
if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return;
if (_tspk_flush && (millis() - _tspk_last_flush > THINGSPEAK_MIN_INTERVAL)) {
_tspkFlush();
_tspk_flush = false;
}
}
#endif

+ 45
- 0
code/espurna/utils.ino View File

@ -201,6 +201,51 @@ void heartbeat() {
}
// -----------------------------------------------------------------------------
// SSL
// -----------------------------------------------------------------------------
#if ASYNC_TCP_SSL_ENABLED
bool sslCheckFingerPrint(const char * fingerprint) {
return (strlen(fingerprint) == 59);
}
bool sslFingerPrintArray(const char * fingerprint, unsigned char * bytearray) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (!sslCheckFingerPrint(fingerprint)) return false;
// walk the fingerprint
for (unsigned int i=0; i<20; i++) {
bytearray[i] = strtol(fingerprint + 3*i, NULL, 16);
}
return true;
}
bool sslFingerPrintChar(const char * fingerprint, char * destination) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (!sslCheckFingerPrint(fingerprint)) return false;
// copy it
strncpy(destination, fingerprint, 59);
// walk the fingerprint replacing ':' for ' '
for (unsigned char i = 0; i<59; i++) {
if (destination[i] == ':') destination[i] = ' ';
}
return true;
}
#endif
// -----------------------------------------------------------------------------
// Reset
// -----------------------------------------------------------------------------
unsigned char resetReason() {


+ 34
- 15
code/html/custom.js View File

@ -102,7 +102,8 @@ var is_group = [
"ssid", "pass", "gw", "mask", "ip", "dns",
"relayBoot", "relayPulse", "relayTime",
"mqttGroup", "mqttGroupInv",
"dczRelayIdx",
"dczRelayIdx", "dczMagnitude",
"tspkRelay", "tspkMagnitude",
"ledMode",
"adminPass"
];
@ -394,36 +395,36 @@ function toggleMenu() {
}
// -----------------------------------------------------------------------------
// Domoticz
// Relays & magnitudes mapping
// -----------------------------------------------------------------------------
function createRelayIdxs(data) {
function createRelayList(data, container, template) {
var current = $("#domoticzRelays > div").length;
var current = $("#" + container + " > div").length;
if (current > 0) return;
var template = $("#relayIdxTemplate .pure-g")[0];
var template = $("#" + template + " .pure-g")[0];
for (var i=0; i<data.length; i++) {
var line = $(template).clone();
$("label", line).html("Switch #" + i);
$("input", line).attr("name", "dczRelayIdx" + i).attr("tabindex", 40 + i).val(data[i]);
line.appendTo("#domoticzRelays");
$("input", line).attr("tabindex", 40 + i).val(data[i]);
line.appendTo("#" + container);
}
}
function createMagnitudeIdxs(data) {
function createMagnitudeList(data, container, template) {
var current = $("#domoticzMagnitudes > div").length;
var current = $("#" + container + " > div").length;
if (current > 0) return;
var template = $("#magnitudeIdxTemplate .pure-g")[0];
var template = $("#" + template + " .pure-g")[0];
for (var i=0; i<data.length; i++) {
var line = $(template).clone();
$("label", line).html(magnitudeType(data[i].type) + " #" + parseInt(data[i].index));
$("div.hint", line).html(data[i].name);
$("input", line).attr("name", "dczMagnitude" + i).attr("tabindex", 40 + i).val(data[i].idx);
line.appendTo("#domoticzMagnitudes");
$("input", line).attr("tabindex", 40 + i).val(data[i].idx);
line.appendTo("#" + container);
}
}
@ -683,6 +684,8 @@ function rfbSend() {
function processData(data) {
console.log(data);
// title
if ("app_name" in data) {
var title = data.app_name;
@ -842,14 +845,30 @@ function processData(data) {
// ---------------------------------------------------------------------
// Domoticz - Relays
if (key == "dczRelayIdx") {
createRelayIdxs(data[key]);
if (key == "dczRelays") {
createRelayList(data[key], "dczRelays", "dczRelayTemplate");
return;
}
// Domoticz - Magnitudes
if (key == "dczMagnitudes") {
createMagnitudeIdxs(data[key]);
createMagnitudeList(data[key], "dczMagnitudes", "dczMagnitudeTemplate");
return;
}
// ---------------------------------------------------------------------
// Thingspeak
// ---------------------------------------------------------------------
// Thingspeak - Relays
if (key == "tspkRelays") {
createRelayList(data[key], "tspkRelays", "tspkRelayTemplate");
return;
}
// Thingspeak - Magnitudes
if (key == "tspkMagnitudes") {
createMagnitudeList(data[key], "tspkMagnitudes", "tspkMagnitudeTemplate");
return;
}


+ 63
- 4
code/html/index.html View File

@ -116,6 +116,10 @@
<a href="#" class="pure-menu-link" data="panel-idb">INFLUXDB</a>
</li>
<li class="pure-menu-item module module-tspk">
<a href="#" class="pure-menu-link" data="panel-thingspeak">THINGSPEAK</a>
</li>
<li class="pure-menu-item module module-rfb">
<a href="#" class="pure-menu-link" data="panel-rfb">RFBRIDGE</a>
</li>
@ -738,9 +742,49 @@
<div class="pure-u-1 hint">Set IDX to 0 to disable notifications from that component.</div>
</div>
<div id="domoticzRelays"></div>
<div id="dczRelays"></div>
<div id="domoticzMagnitudes"></div>
<div id="dczMagnitudes"></div>
</fieldset>
</div>
</div>
<div class="panel" id="panel-thingspeak">
<div class="header">
<h1>THINGSPEAK</h1>
<h2>
Send your sensors data to Thinkgspeak.
</h2>
</div>
<div class="page">
<fieldset>
<legend>General</legend>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Enable Thingspeak</label></div>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="tspkEnabled" tabindex="30" /></div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Thingspeak API Key</label>
<input class="pure-u-1 pure-u-lg-3-4" name="tspkKey" type="text" tabindex="31" />
</div>
<legend>Sensors &amp; actuators</legend>
<div class="pure-g">
<div class="pure-u-1 hint">Enter the field number to send each data to, 0 disable notifications from that component.</div>
</div>
<div id="tspkRelays"></div>
<div id="tspkMagnitudes"></div>
</fieldset>
</div>
@ -1028,14 +1072,14 @@
</div>
</div>
<div id="relayIdxTemplate" class="template">
<div id="dczRelayTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Switch</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24 dczRelayIdx" name="dczRelayIdx" type="number" min="0" tabindex="0" data="0" /></div>
</div>
</div>
<div id="magnitudeIdxTemplate" class="template">
<div id="dczMagnitudeTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Magnitude</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24 center" name="dczMagnitude" type="number" min="0" tabindex="0" data="0" /></div>
@ -1043,6 +1087,21 @@
</div>
</div>
<div id="tspkRelayTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Switch</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24" name="tspkRelay" type="number" min="0" max="8" tabindex="0" data="0" /></div>
</div>
</div>
<div id="tspkMagnitudeTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Magnitude</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24 center" name="tspkMagnitude" type="number" min="0" max="8" tabindex="0" data="0" /></div>
<div class="pure-u-1 pure-u-lg-1-2 hint center"></div>
</div>
</div>
<div id="colorRGBTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Color</label>


Loading…
Cancel
Save