Browse Source

Preliminary support for Thingspeak REST API over SSL

i18n
Xose Pérez 6 years ago
parent
commit
ad05448603
8 changed files with 3332 additions and 3100 deletions
  1. +13
    -0
      code/espurna/config/general.h
  2. BIN
      code/espurna/data/index.html.gz
  3. +1
    -1
      code/espurna/domoticz.ino
  4. +1
    -1
      code/espurna/influxdb.ino
  5. +3090
    -3079
      code/espurna/static/index.html.gz.h
  6. +132
    -0
      code/espurna/thinkspeak.ino
  7. +32
    -15
      code/html/custom.js
  8. +63
    -4
      code/html/index.html

+ 13
- 0
code/espurna/config/general.h View File

@ -612,6 +612,19 @@ PROGMEM const char* const custom_reset_string[] = {
#define INFLUXDB_USERNAME "" // Default username #define INFLUXDB_USERNAME "" // Default username
#define INFLUXDB_PASSWORD "" // Default password #define INFLUXDB_PASSWORD "" // Default password
// -----------------------------------------------------------------------------
// THINGSPEAK
// -----------------------------------------------------------------------------
#ifndef THINGSPEAK_SUPPORT
#define THINGSPEAK_SUPPORT 1 // Enable Thingspeak support by default (???Kb)
#endif
#define THINGSPEAK_ENABLED 0 // Thingspeak disabled by default
#define THINGSPEAK_HOST "api.thingspeak.com"
#define THINGSPEAK_URL "/update"
#define THINGSPEAK_APIKEY "" // Default API KEY
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// NTP // NTP
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


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["dczTopicIn"] = getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC);
root["dczTopicOut"] = getSetting("dczTopicOut", DOMOTICZ_OUT_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++) { for (byte i=0; i<relayCount(); i++) {
relays.add(domoticzIdx(i)); relays.add(domoticzIdx(i));
} }


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

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


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


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

@ -0,0 +1,132 @@
/*
THINGSPEAK MODULE
Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if THINGSPEAK_SUPPORT
#include <ESP8266WiFi.h>
bool _tspk_enabled = false;
WiFiClientSecure _tspk_client;
char * _tspk_queue[0];
// -----------------------------------------------------------------------------
void _tspkWebSocketOnSend(JsonObject& root) {
root["tspkVisible"] = 1;
root["tspkEnabled"] = getSetting("idbEnabled", THINGSPEAK_ENABLED).toInt() == 1;
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);
}
}
bool _tspkPost(String data) {
if (_tspk_client.connect(THINGSPEAK_HOST, 443)) {
_tspk_client.println("POST " + String(THINGSPEAK_URL) + " HTTP/1.1");
_tspk_client.println("Host: " + String(THINGSPEAK_HOST));
//_tspk_client.println("User-Agent: ESPurna");
_tspk_client.println("Connection: close");
_tspk_client.println("Content-Type: application/x-www-form-urlencoded;");
_tspk_client.print("Content-Length: ");
_tspk_client.println(data.length());
_tspk_client.println();
_tspk_client.println(data);
delay(10);
String response = _tspk_client.readString();
int bodypos = response.indexOf("\r\n\r\n") + 4;
Serial.println(response.substring(bodypos));
return true;
}
return false;
}
// -----------------------------------------------------------------------------
bool tspkSendRelay(unsigned char index, unsigned char status, bool enqueue) {
if (!_tspk_enabled) return true;
unsigned char id = getSetting("tspkRelay", index, 0).toInt();
if (id > 0) {
--id;
char payload[3];
itoa(status ? 1 : 0, payload, 10);
if (_tspk_queue[id]) free(_tspk_queue[id]);
_tspk_queue[id] = strdup(payload);
if (!enqueue) tspkFlush();
}
}
bool tspkSendMeasurement(unsigned char index, char * payload, bool enqueue) {
if (!_tspk_enabled) return true;
unsigned char id = getSetting("tspkMagnitude", index, 0).toInt();
if (id > 0) {
--id;
if (_tspk_queue[id]) free(_tspk_queue[id]);
_tspk_queue[id] = strdup(payload);
if (!enqueue) tspkFlush();
}
}
bool tspkFlush() {
if (!_tspk_enabled) return true;
if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return true;
String data;
// Walk the fields
for (unsigned char id=0; id<8; id++) {
if (_tspk_queue[id]) {
if (data.length() > 0) data = data + String("&");
data = data + String("field") + String(id+1) + String("=") + String(_tspk_queue[id]);
free(_tspk_queue[id]);
}
}
// POST data if any
if (data.length() > 0) {
data = data + String("&api_key=") + getSetting("tspkKey");
_tspkPost(data);
}
}
bool tspkEnabled() {
return _tspk_enabled;
}
void tspkSetup() {
_tspkConfigure();
#if WEB_SUPPORT
wsOnSendRegister(_tspkWebSocketOnSend);
wsOnAfterParseRegister(_tspkConfigure);
#endif
}
#endif

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

@ -102,7 +102,8 @@ var is_group = [
"ssid", "pass", "gw", "mask", "ip", "dns", "ssid", "pass", "gw", "mask", "ip", "dns",
"relayBoot", "relayPulse", "relayTime", "relayBoot", "relayPulse", "relayTime",
"mqttGroup", "mqttGroupInv", "mqttGroup", "mqttGroupInv",
"dczRelayIdx",
"dczRelayIdx", "dczMagnitude",
"tspkRelay", "tspkMagnitude",
"ledMode", "ledMode",
"adminPass" "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; if (current > 0) return;
var template = $("#relayIdxTemplate .pure-g")[0];
var template = $("#" + template + " .pure-g")[0];
for (var i=0; i<data.length; i++) { for (var i=0; i<data.length; i++) {
var line = $(template).clone(); var line = $(template).clone();
$("label", line).html("Switch #" + i); $("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; if (current > 0) return;
var template = $("#magnitudeIdxTemplate .pure-g")[0];
var template = $("#" + template + " .pure-g")[0];
for (var i=0; i<data.length; i++) { for (var i=0; i<data.length; i++) {
var line = $(template).clone(); var line = $(template).clone();
$("label", line).html(magnitudeType(data[i].type) + " #" + parseInt(data[i].index)); $("label", line).html(magnitudeType(data[i].type) + " #" + parseInt(data[i].index));
$("div.hint", line).html(data[i].name); $("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);
} }
} }
@ -842,14 +843,30 @@ function processData(data) {
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Domoticz - Relays // Domoticz - Relays
if (key == "dczRelayIdx") {
createRelayIdxs(data[key]);
if (key == "dczRelays") {
createRelayList(data[key], "dczRelays", "dczRelayTemplate");
return; return;
} }
// Domoticz - Magnitudes // Domoticz - Magnitudes
if (key == "dczMagnitudes") { 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; return;
} }


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

@ -116,6 +116,10 @@
<a href="#" class="pure-menu-link" data="panel-idb">INFLUXDB</a> <a href="#" class="pure-menu-link" data="panel-idb">INFLUXDB</a>
</li> </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"> <li class="pure-menu-item module module-rfb">
<a href="#" class="pure-menu-link" data="panel-rfb">RFBRIDGE</a> <a href="#" class="pure-menu-link" data="panel-rfb">RFBRIDGE</a>
</li> </li>
@ -738,9 +742,49 @@
<div class="pure-u-1 hint">Set IDX to 0 to disable notifications from that component.</div> <div class="pure-u-1 hint">Set IDX to 0 to disable notifications from that component.</div>
</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> </fieldset>
</div> </div>
@ -1028,14 +1072,14 @@
</div> </div>
</div> </div>
<div id="relayIdxTemplate" class="template">
<div id="dczRelayTemplate" class="template">
<div class="pure-g"> <div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Switch</label> <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 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> </div>
<div id="magnitudeIdxTemplate" class="template">
<div id="dczMagnitudeTemplate" class="template">
<div class="pure-g"> <div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Magnitude</label> <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> <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> </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 id="colorRGBTemplate" class="template">
<div class="pure-g"> <div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Color</label> <label class="pure-u-1 pure-u-lg-1-4">Color</label>


Loading…
Cancel
Save