Browse Source

Compact WS data

* send all ws config at once on start
* reduce ws json overhead by creating message buffer manually
* use k:[values] instead of k1:value1, k2:value2 etc. for lists
sensors
Max Prokhorov 5 years ago
parent
commit
868d153fa4
12 changed files with 367 additions and 235 deletions
  1. +4
    -0
      code/espurna/config/prototypes.h
  2. +21
    -28
      code/espurna/debug.ino
  3. +6
    -9
      code/espurna/domoticz.ino
  4. +17
    -14
      code/espurna/light.ino
  5. +0
    -1
      code/espurna/ntp.ino
  6. +46
    -33
      code/espurna/relay.ino
  7. +13
    -9
      code/espurna/rfbridge.ino
  8. +33
    -18
      code/espurna/scheduler.ino
  9. +48
    -11
      code/espurna/sensor.ino
  10. +2
    -9
      code/espurna/thinkspeak.ino
  11. +120
    -64
      code/espurna/ws.ino
  12. +57
    -39
      code/html/custom.js

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

@ -184,6 +184,8 @@ void webRequestRegister(web_request_callback_f callback);
#if WEB_SUPPORT
typedef std::function<void(JsonObject&)> ws_on_send_callback_f;
void wsOnSendRegister(ws_on_send_callback_f callback);
void wsSend(uint32_t, JsonObject& root);
void wsSend(JsonObject& root);
void wsSend(ws_on_send_callback_f sender);
typedef std::function<void(uint32_t, const char *, JsonObject&)> ws_on_action_callback_f;
@ -191,6 +193,8 @@ void webRequestRegister(web_request_callback_f callback);
typedef std::function<bool(const char *, JsonVariant&)> ws_on_receive_callback_f;
void wsOnReceiveRegister(ws_on_receive_callback_f callback);
bool wsDebugSend(const char*);
#else
#define ws_on_send_callback_f void *
#define ws_on_action_callback_f void *


+ 21
- 28
code/espurna/debug.ino View File

@ -8,6 +8,8 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
#if DEBUG_SUPPORT
constexpr const uint8_t TIMESTAMP_LENGTH = 10;
#if DEBUG_UDP_SUPPORT
#include <WiFiUdp.h>
WiFiUDP _udp_debug;
@ -18,20 +20,30 @@ char _udp_syslog_header[40] = {0};
void _debugSend(char * message) {
size_t msg_len = strlen(message);
bool pause = false;
#if DEBUG_ADD_TIMESTAMP
static bool add_timestamp = true;
char timestamp[10] = {0};
if (add_timestamp) snprintf_P(timestamp, sizeof(timestamp), PSTR("[%06lu] "), millis() % 1000000);
add_timestamp = (message[strlen(message)-1] == 10) || (message[strlen(message)-1] == 13);
size_t offset = 0;
char buffer[TIMESTAMP_LENGTH + msg_len];
if (add_timestamp) {
snprintf_P(buffer, TIMESTAMP_LENGTH, PSTR("[%06lu] "), millis() % 1000000);
offset = TIMESTAMP_LENGTH - 1;
}
memcpy(buffer + offset, message, msg_len);
buffer[msg_len + offset] = '\0';
add_timestamp = (message[msg_len - 1] == 10) || (message[msg_len - 1] == 13);
#else
char* buffer = message;
#endif
#if DEBUG_SERIAL_SUPPORT
#if DEBUG_ADD_TIMESTAMP
DEBUG_PORT.printf(timestamp);
#endif
DEBUG_PORT.printf(message);
DEBUG_PORT.print(buffer);
#endif
#if DEBUG_UDP_SUPPORT
@ -51,31 +63,12 @@ void _debugSend(char * message) {
#endif
#if DEBUG_TELNET_SUPPORT
#if DEBUG_ADD_TIMESTAMP
_telnetWrite(timestamp, strlen(timestamp));
#endif
_telnetWrite(message, strlen(message));
_telnetWrite(buffer, strlen(buffer));
pause = true;
#endif
#if DEBUG_WEB_SUPPORT
if (wsConnected() && (getFreeHeap() > 10000)) {
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(1) + strlen(message) + 17);
JsonObject &root = jsonBuffer.createObject();
#if DEBUG_ADD_TIMESTAMP
char buffer[strlen(timestamp) + strlen(message) + 1];
snprintf_P(buffer, sizeof(buffer), "%s%s", timestamp, message);
root.set("weblog", buffer);
#else
root.set("weblog", message);
#endif
String out;
root.printTo(out);
jsonBuffer.clear();
wsSend(out.c_str());
pause = true;
}
wsDebugSend(buffer);
#endif
if (pause) optimistic_yield(100);


+ 6
- 9
code/espurna/domoticz.ino View File

@ -171,7 +171,7 @@ bool _domoticzWebSocketOnReceive(const char * key, JsonVariant& value) {
void _domoticzWebSocketOnSend(JsonObject& root) {
root["dczVisible"] = 1;
unsigned char visible = 0;
root["dczEnabled"] = getSetting("dczEnabled", DOMOTICZ_ENABLED).toInt() == 1;
root["dczTopicIn"] = getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC);
root["dczTopicOut"] = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC);
@ -180,18 +180,15 @@ void _domoticzWebSocketOnSend(JsonObject& root) {
for (unsigned char i=0; i<relayCount(); i++) {
relays.add(domoticzIdx(i));
}
visible = (relayCount() > 0);
#if SENSOR_SUPPORT
JsonArray& list = root.createNestedArray("dczMagnitudes");
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("dczMagnitude", i, 0).toInt();
}
_sensorWebSocketMagnitudes(root, "dcz");
visible = visible || (magnitudeCount() > 0);
#endif
root["dczVisible"] = visible;
}
#endif // WEB_SUPPORT


+ 17
- 14
code/espurna/light.ino View File

@ -669,7 +669,7 @@ void _lightComms(unsigned char mask) {
// Report color to WS clients (using current brightness setting)
#if WEB_SUPPORT
wsSend(_lightWebSocketOnSend);
wsSend(_lightWebSocketStatus);
#endif
// Report channels to local broker
@ -824,23 +824,13 @@ bool _lightWebSocketOnReceive(const char * key, JsonVariant& value) {
return false;
}
void _lightWebSocketOnSend(JsonObject& root) {
root["colorVisible"] = 1;
root["mqttGroupColor"] = getSetting("mqttGroupColor");
root["useColor"] = _light_has_color;
root["useWhite"] = _light_use_white;
root["useGamma"] = _light_use_gamma;
root["useTransitions"] = _light_use_transitions;
root["lightTime"] = _light_transition_time;
root["useCSS"] = getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1;
bool useRGB = getSetting("useRGB", LIGHT_USE_RGB).toInt() == 1;
root["useRGB"] = useRGB;
void _lightWebSocketStatus(JsonObject& root) {
if (_light_has_color) {
if (_light_use_cct) {
root["useCCT"] = _light_use_cct;
root["mireds"] = _light_mireds;
}
if (useRGB) {
if (getSetting("useRGB", LIGHT_USE_RGB).toInt() == 1) {
root["rgb"] = lightColor(true);
} else {
root["hsv"] = lightColor(false);
@ -850,7 +840,20 @@ void _lightWebSocketOnSend(JsonObject& root) {
for (unsigned char id=0; id < _light_channel.size(); id++) {
channels.add(lightChannel(id));
}
root["brightness"] = lightBrightness();
}
void _lightWebSocketOnSend(JsonObject& root) {
root["colorVisible"] = 1;
root["mqttGroupColor"] = getSetting("mqttGroupColor");
root["useColor"] = _light_has_color;
root["useWhite"] = _light_use_white;
root["useGamma"] = _light_use_gamma;
root["useTransitions"] = _light_use_transitions;
root["useCSS"] = getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1;
root["useRGB"] = getSetting("useRGB", LIGHT_USE_RGB).toInt() == 1;
root["lightTime"] = _light_transition_time;
_lightWebSocketStatus(root);
}
void _lightWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {


+ 0
- 1
code/espurna/ntp.ino View File

@ -34,7 +34,6 @@ void _ntpWebSocketOnSend(JsonObject& root) {
root["ntpOffset"] = getSetting("ntpOffset", NTP_TIME_OFFSET).toInt();
root["ntpDST"] = getSetting("ntpDST", NTP_DAY_LIGHT).toInt() == 1;
root["ntpRegion"] = getSetting("ntpRegion", NTP_DST_REGION).toInt();
if (ntpSynced()) root["now"] = now();
}
#endif


+ 46
- 33
code/espurna/relay.ino View File

@ -581,65 +581,78 @@ bool _relayWebSocketOnReceive(const char * key, JsonVariant& value) {
void _relayWebSocketUpdate(JsonObject& root) {
JsonArray& relay = root.createNestedArray("relayStatus");
for (unsigned char i=0; i<relayCount(); i++) {
relay.add(_relays[i].target_status);
relay.add<uint8_t>(_relays[i].target_status);
}
}
void _relayWebSocketSendRelay(unsigned char i) {
String _relayFriendlyName(unsigned char i) {
String res = String("GPIO") + String(_relays[i].pin);
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
JsonArray& config = root.createNestedArray("relayConfig");
JsonObject& line = config.createNestedObject();
line["id"] = i;
if (GPIO_NONE == _relays[i].pin) {
#if (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT)
uint8_t physical = _relays.size() - DUMMY_RELAY_COUNT;
if (i >= physical) {
if (DUMMY_RELAY_COUNT == lightChannels()) {
line["gpio"] = String("CH") + String(i-physical);
res = String("CH") + String(i-physical);
} else if (DUMMY_RELAY_COUNT == (lightChannels() + 1u)) {
if (physical == i) {
line["gpio"] = String("Light");
res = String("Light");
} else {
line["gpio"] = String("CH") + String(i-1-physical);
res = String("CH") + String(i-1-physical);
}
} else {
line["gpio"] = String("Light");
res = String("Light");
}
} else {
line["gpio"] = String("?");
res = String("?");
}
#else
line["gpio"] = String("SW") + String(i);
res = String("SW") + String(i);
#endif
} else {
line["gpio"] = String("GPIO") + String(_relays[i].pin);
}
line["type"] = _relays[i].type;
line["reset"] = _relays[i].reset_pin;
line["boot"] = getSetting("relayBoot", i, RELAY_BOOT_MODE).toInt();
line["pulse"] = _relays[i].pulse;
line["pulse_ms"] = _relays[i].pulse_ms / 1000.0;
#if MQTT_SUPPORT
line["group"] = getSetting("mqttGroup", i, "");
line["group_inv"] = getSetting("mqttGroupInv", i, 0).toInt();
line["on_disc"] = getSetting("relayOnDisc", i, 0).toInt();
#endif
String output;
root.printTo(output);
jsonBuffer.clear();
wsSend((char *) output.c_str());
return res;
}
void _relayWebSocketSendRelays() {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
JsonObject& relays = root.createNestedObject("relayConfig");
relays["size"] = relayCount();
relays["start"] = 0;
JsonArray& gpio = relays.createNestedArray("gpio");
JsonArray& type = relays.createNestedArray("type");
JsonArray& reset = relays.createNestedArray("reset");
JsonArray& boot = relays.createNestedArray("boot");
JsonArray& pulse = relays.createNestedArray("pulse");
JsonArray& pulse_time = relays.createNestedArray("pulse_time");
#if MQTT_SUPPORT
JsonArray& group = relays.createNestedArray("group");
JsonArray& group_inverse = relays.createNestedArray("group_inv");
JsonArray& on_disconnect = relays.createNestedArray("on_disc");
#endif
for (unsigned char i=0; i<relayCount(); i++) {
_relayWebSocketSendRelay(i);
gpio.add(_relayFriendlyName(i));
type.add(_relays[i].type);
reset.add(_relays[i].reset_pin);
boot.add(getSetting("relayBoot", i, RELAY_BOOT_MODE).toInt());
pulse.add(_relays[i].pulse);
pulse_time.add(_relays[i].pulse_ms / 1000.0);
#if MQTT_SUPPORT
group.add(getSetting("mqttGroup", i, ""));
group_inverse.add(getSetting("mqttGroupInv", i, 0).toInt() == 1);
on_disconnect.add(getSetting("relayOnDisc", i, 0).toInt());
#endif
}
wsSend(root);
}
void _relayWebSocketOnStart(JsonObject& root) {


+ 13
- 9
code/espurna/rfbridge.ino View File

@ -88,17 +88,21 @@ static bool _rfbToChar(byte * in, char * out, int n = RF_MESSAGE_SIZE) {
#if WEB_SUPPORT
void _rfbWebSocketSendCode(unsigned char id, bool status, const char * code) {
char wsb[192]; // (32 * 5): 46 bytes for json , 116 bytes raw code, reserve
snprintf_P(wsb, sizeof(wsb), PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%s\"}]}"), id, status ? 1 : 0, code);
wsSend(wsb);
}
void _rfbWebSocketSendCodes() {
for (unsigned char id=0; id<relayCount(); id++) {
_rfbWebSocketSendCode(id, true, rfbRetrieve(id, true).c_str());
_rfbWebSocketSendCode(id, false, rfbRetrieve(id, false).c_str());
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["size"] = relayCount();
JsonArray& on = root.createNestedArray("on");
JsonArray& off = root.createNestedArray("off");
for (byte id=0; id<relayCount(); id++) {
on.add(rfbRetrieve(id, true));
off.add(rfbRetrieve(id, false));
}
wsSend(rfb);
}
void _rfbWebSocketOnSend(JsonObject& root) {


+ 33
- 18
code/espurna/scheduler.ino View File

@ -21,26 +21,41 @@ bool _schWebSocketOnReceive(const char * key, JsonVariant& value) {
void _schWebSocketOnSend(JsonObject &root){
if (relayCount() > 0) {
root["schVisible"] = 1;
root["maxSchedules"] = SCHEDULER_MAX_SCHEDULES;
JsonArray &sch = root.createNestedArray("schedule");
for (byte i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) {
if (!hasSetting("schSwitch", i)) break;
JsonObject &scheduler = sch.createNestedObject();
scheduler["schEnabled"] = getSetting("schEnabled", i, 1).toInt() == 1;
scheduler["schSwitch"] = getSetting("schSwitch", i, 0).toInt();
scheduler["schAction"] = getSetting("schAction", i, 0).toInt();
scheduler["schType"] = getSetting("schType", i, 0).toInt();
scheduler["schHour"] = getSetting("schHour", i, 0).toInt();
scheduler["schMinute"] = getSetting("schMinute", i, 0).toInt();
scheduler["schUTC"] = getSetting("schUTC", i, 0).toInt() == 1;
scheduler["schWDs"] = getSetting("schWDs", i, "");
}
if (!relayCount()) return;
root["schVisible"] = 1;
root["maxSchedules"] = SCHEDULER_MAX_SCHEDULES;
JsonObject &schedules = root.createNestedObject("schedules");
uint8_t size = 0;
JsonArray& enabled = schedules.createNestedArray("schEnabled");
JsonArray& switch_ = schedules.createNestedArray("schSwitch");
JsonArray& action = schedules.createNestedArray("schAction");
JsonArray& type = schedules.createNestedArray("schType");
JsonArray& hour = schedules.createNestedArray("schHour");
JsonArray& minute = schedules.createNestedArray("schMinute");
JsonArray& utc = schedules.createNestedArray("schUTC");
JsonArray& weekdays = schedules.createNestedArray("schWDs");
for (byte i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) {
if (!hasSetting("schSwitch", i)) break;
++size;
enabled.add<uint8_t>(getSetting("schEnabled", i, 1).toInt() == 1);
utc.add<uint8_t>(getSetting("schUTC", i, 0).toInt() == 1);
switch_.add(getSetting("schSwitch", i, 0).toInt());
action.add(getSetting("schAction", i, 0).toInt());
type.add(getSetting("schType", i, 0).toInt());
hour.add(getSetting("schHour", i, 0).toInt());
minute.add(getSetting("schMinute", i, 0).toInt());
weekdays.add(getSetting("schWDs", i, ""));
}
schedules["size"] = size;
schedules["start"] = 0;
}
#endif // WEB_SUPPORT


+ 48
- 11
code/espurna/sensor.ino View File

@ -102,6 +102,32 @@ double _magnitudeProcess(unsigned char type, double value) {
#if WEB_SUPPORT
template<typename T>
void _sensorWebSocketMagnitudes(JsonObject& root, T prefix) {
// ws produces flat list <prefix>Magnitudes
String ws_name = String(prefix);
ws_name.concat("Magnitudes");
// config uses <prefix>Magnitude<index> (cut 's')
String conf_name = ws_name.substring(0, ws_name.length() - 1);
JsonObject& list = root.createNestedObject(ws_name);
list["size"] = magnitudeCount();
JsonArray& name = list.createNestedArray("name");
JsonArray& type = list.createNestedArray("type");
JsonArray& index = list.createNestedArray("index");
JsonArray& idx = list.createNestedArray("idx");
for (unsigned char i=0; i<magnitudeCount(); ++i) {
name.add(magnitudeName(i));
type.add(magnitudeType(i));
index.add(magnitudeIndex(i));
idx.add(getSetting(conf_name, i, 0).toInt());
}
}
bool _sensorWebSocketOnReceive(const char * key, JsonVariant& value) {
if (strncmp(key, "pwr", 3) == 0) return true;
if (strncmp(key, "sns", 3) == 0) return true;
@ -118,27 +144,36 @@ void _sensorWebSocketSendData(JsonObject& root) {
bool hasHumidity = false;
bool hasMICS = false;
JsonArray& list = root.createNestedArray("magnitudes");
for (unsigned char i=0; i<_magnitudes.size(); i++) {
JsonObject& magnitudes = root.createNestedObject("magnitudes");
uint8_t size = 0;
JsonArray& index = magnitudes.createNestedArray("index");
JsonArray& type = magnitudes.createNestedArray("type");
JsonArray& value = magnitudes.createNestedArray("value");
JsonArray& units = magnitudes.createNestedArray("units");
JsonArray& error = magnitudes.createNestedArray("error");
JsonArray& description = magnitudes.createNestedArray("description");
for (unsigned char i=0; i<magnitudeCount(); i++) {
sensor_magnitude_t magnitude = _magnitudes[i];
if (magnitude.type == MAGNITUDE_EVENT) continue;
++size;
unsigned char decimals = _magnitudeDecimals(magnitude.type);
dtostrf(magnitude.current, 1-sizeof(buffer), decimals, buffer);
JsonObject& element = list.createNestedObject();
element["index"] = int(magnitude.global);
element["type"] = int(magnitude.type);
element["value"] = String(buffer);
element["units"] = magnitudeUnits(magnitude.type);
element["error"] = magnitude.sensor->error();
index.add<uint8_t>(magnitude.global);
type.add<uint8_t>(magnitude.type);
value.add(buffer);
units.add(magnitudeUnits(magnitude.type));
error.add(magnitude.sensor->error());
if (magnitude.type == MAGNITUDE_ENERGY) {
if (_sensor_energy_reset_ts.length() == 0) _sensorResetTS();
element["description"] = magnitude.sensor->slot(magnitude.local) + String(" (since ") + _sensor_energy_reset_ts + String(")");
description.add(magnitude.sensor->slot(magnitude.local) + String(" (since ") + _sensor_energy_reset_ts + String(")"));
} else {
element["description"] = magnitude.sensor->slot(magnitude.local);
description.add(magnitude.sensor->slot(magnitude.local));
}
if (magnitude.type == MAGNITUDE_TEMPERATURE) hasTemperature = true;
@ -148,6 +183,8 @@ void _sensorWebSocketSendData(JsonObject& root) {
#endif
}
magnitudes["size"] = size;
if (hasTemperature) root["temperatureVisible"] = 1;
if (hasHumidity) root["humidityVisible"] = 1;
if (hasMICS) root["micsVisible"] = 1;
@ -210,7 +247,7 @@ void _sensorWebSocketStart(JsonObject& root) {
}
if (_magnitudes.size() > 0) {
if (magnitudeCount()) {
root["snsVisible"] = 1;
//root["apiRealTime"] = _sensor_realtime;
root["pwrUnits"] = _sensor_power_units;


+ 2
- 9
code/espurna/thinkspeak.ino View File

@ -75,15 +75,8 @@ void _tspkWebSocketOnSend(JsonObject& root) {
if (relayCount() > 0) visible = 1;
#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();
}
if (magnitudeCount() > 0) visible = 1;
_sensorWebSocketMagnitudes(root, "tspk");
visible = visible || (magnitudeCount() > 0);
#endif
root["tspkVisible"] = visible;


+ 120
- 64
code/espurna/ws.ino View File

@ -73,6 +73,22 @@ bool _wsAuth(AsyncWebSocketClient * client) {
}
#if DEBUG_WEB_SUPPORT
bool wsDebugSend(const char* message) {
if (!wsConnected()) return false;
if (getFreeHeap() < (strlen(message) * 3)) return false;
DynamicJsonBuffer jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
root.set("weblog", message);
wsSend(root);
return true;
}
#endif
// -----------------------------------------------------------------------------
#if MQTT_SUPPORT
@ -289,6 +305,20 @@ void _wsUpdate(JsonObject& root) {
#endif
}
void _wsDoUpdate(bool reset = false) {
static unsigned long last = 0;
if (reset) {
last = 0;
return;
}
if (millis() - last > WS_UPDATE_INTERVAL) {
last = millis();
wsSend(_wsUpdate);
}
}
bool _wsOnReceive(const char * key, JsonVariant& value) {
if (strncmp(key, "ws", 2) == 0) return true;
if (strncmp(key, "admin", 5) == 0) return true;
@ -298,69 +328,94 @@ bool _wsOnReceive(const char * key, JsonVariant& value) {
}
void _wsOnStart(JsonObject& root) {
char chipid[7];
snprintf_P(chipid, sizeof(chipid), PSTR("%06X"), ESP.getChipId());
uint8_t * bssid = WiFi.BSSID();
char bssid_str[20];
snprintf_P(bssid_str, sizeof(bssid_str),
PSTR("%02X:%02X:%02X:%02X:%02X:%02X"),
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]
);
root["webMode"] = WEB_MODE_NORMAL;
root["app_name"] = APP_NAME;
root["app_version"] = APP_VERSION;
root["app_build"] = buildTime();
#if defined(APP_REVISION)
root["app_revision"] = APP_REVISION;
#endif
root["manufacturer"] = MANUFACTURER;
root["chipid"] = String(chipid);
root["mac"] = WiFi.macAddress();
root["bssid"] = String(bssid_str);
root["channel"] = WiFi.channel();
root["device"] = DEVICE;
root["hostname"] = getSetting("hostname");
root["network"] = getNetwork();
root["deviceip"] = getIP();
root["sketch_size"] = ESP.getSketchSize();
root["free_size"] = ESP.getFreeSketchSpace();
root["sdk"] = ESP.getSdkVersion();
root["core"] = getCoreVersion();
root["btnDelay"] = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY).toInt();
root["webPort"] = getSetting("webPort", WEB_PORT).toInt();
root["wsAuth"] = getSetting("wsAuth", WS_AUTHENTICATION).toInt() == 1;
#if TERMINAL_SUPPORT
root["cmdVisible"] = 1;
#endif
root["hbMode"] = getSetting("hbMode", HEARTBEAT_MODE).toInt();
root["hbInterval"] = getSetting("hbInterval", HEARTBEAT_INTERVAL).toInt();
_wsDoUpdate(true);
}
void wsSend(JsonObject& root) {
size_t len = root.measureLength();
AsyncWebSocketMessageBuffer* buffer = _ws.makeBuffer(len);
if (buffer) {
root.printTo(reinterpret_cast<char*>(buffer->get()), len + 1);
_ws.textAll(buffer);
}
}
void wsSend(uint32_t client_id, JsonObject& root) {
AsyncWebSocketClient* client = _ws.client(client_id);
if (client == nullptr) return;
size_t len = root.measureLength();
AsyncWebSocketMessageBuffer* buffer = _ws.makeBuffer(len);
if (buffer) {
root.printTo(reinterpret_cast<char*>(buffer->get()), len + 1);
client->text(buffer);
}
}
void _wsStart(uint32_t client_id) {
#if USE_PASSWORD && WEB_FORCE_PASS_CHANGE
bool changePassword = getAdminPass().equals(ADMIN_PASS);
#else
bool changePassword = false;
#endif
if (changePassword) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
if (changePassword) {
root["webMode"] = WEB_MODE_PASSWORD;
} else {
char chipid[7];
snprintf_P(chipid, sizeof(chipid), PSTR("%06X"), ESP.getChipId());
uint8_t * bssid = WiFi.BSSID();
char bssid_str[20];
snprintf_P(bssid_str, sizeof(bssid_str),
PSTR("%02X:%02X:%02X:%02X:%02X:%02X"),
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]
);
root["webMode"] = WEB_MODE_NORMAL;
root["app_name"] = APP_NAME;
root["app_version"] = APP_VERSION;
root["app_build"] = buildTime();
#if defined(APP_REVISION)
root["app_revision"] = APP_REVISION;
#endif
root["manufacturer"] = MANUFACTURER;
root["chipid"] = String(chipid);
root["mac"] = WiFi.macAddress();
root["bssid"] = String(bssid_str);
root["channel"] = WiFi.channel();
root["device"] = DEVICE;
root["hostname"] = getSetting("hostname");
root["network"] = getNetwork();
root["deviceip"] = getIP();
root["sketch_size"] = ESP.getSketchSize();
root["free_size"] = ESP.getFreeSketchSpace();
root["sdk"] = ESP.getSdkVersion();
root["core"] = getCoreVersion();
_wsUpdate(root);
root["btnDelay"] = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY).toInt();
root["webPort"] = getSetting("webPort", WEB_PORT).toInt();
root["wsAuth"] = getSetting("wsAuth", WS_AUTHENTICATION).toInt() == 1;
#if TERMINAL_SUPPORT
root["cmdVisible"] = 1;
#endif
root["hbMode"] = getSetting("hbMode", HEARTBEAT_MODE).toInt();
root["hbInterval"] = getSetting("hbInterval", HEARTBEAT_INTERVAL).toInt();
wsSend(root);
return;
}
}
void _wsStart(uint32_t client_id) {
for (unsigned char i = 0; i < _ws_on_send_callbacks.size(); i++) {
wsSend(client_id, _ws_on_send_callbacks[i]);
for (auto callback : _ws_on_send_callbacks) {
callback(root);
}
wsSend(client_id, root);
}
void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
@ -408,12 +463,8 @@ void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTy
}
void _wsLoop() {
static unsigned long last = 0;
if (!wsConnected()) return;
if (millis() - last > WS_UPDATE_INTERVAL) {
last = millis();
wsSend(_wsUpdate);
}
_wsDoUpdate();
}
// -----------------------------------------------------------------------------
@ -441,10 +492,8 @@ void wsSend(ws_on_send_callback_f callback) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
callback(root);
String output;
root.printTo(output);
jsonBuffer.clear();
_ws.textAll((char *) output.c_str());
wsSend(root);
}
}
@ -463,13 +512,20 @@ void wsSend_P(PGM_P payload) {
}
void wsSend(uint32_t client_id, ws_on_send_callback_f callback) {
AsyncWebSocketClient* client = _ws.client(client_id);
if (client == nullptr) return;
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
callback(root);
String output;
root.printTo(output);
jsonBuffer.clear();
_ws.text(client_id, (char *) output.c_str());
size_t len = root.measureLength();
AsyncWebSocketMessageBuffer* buffer = _ws.makeBuffer(len);
if (buffer) {
root.printTo(reinterpret_cast<char*>(buffer->get()), len + 1);
client->text(buffer);
}
}
void wsSend(uint32_t client_id, const char * payload) {


+ 57
- 39
code/html/custom.js View File

@ -767,12 +767,13 @@ function createMagnitudeList(data, container, template_name) {
if (current > 0) { return; }
var template = $("#" + template_name + " .pure-g")[0];
for (var i in data) {
var magnitude = data[i];
var size = data.size;
for (var i=0; i<size; ++i) {
var line = $(template).clone();
$("label", line).html(magnitudeType(magnitude.type) + " #" + parseInt(magnitude.index, 10));
$("div.hint", line).html(magnitude.name);
$("input", line).attr("tabindex", 40 + i).val(magnitude.idx);
$("label", line).html(magnitudeType(data.type[i]) + " #" + parseInt(data.index[i], 10));
$("div.hint", line).html(data.name[i]);
$("input", line).attr("tabindex", 40 + i).val(data.idx[i]);
line.appendTo("#" + container);
}
@ -934,24 +935,34 @@ function createCheckboxes() {
function initRelayConfig(data) {
var current = $("#relayConfig > div").length / 6; // there are 6 divs per each relay
var current = $("#relayConfig > legend").length; // there is a legend per relay
if (current > 0) { return; }
var size = data.size;
var start = data.start;
var template = $("#relayConfigTemplate").children();
for (var i in data) {
var relay = data[i];
if (current > relay.id) continue;
for (var i=start; i<size; ++i) {
var line = $(template).clone();
$("span.gpio", line).html(relay.gpio);
$("span.id", line).html(relay.id);
$("select[name='relayBoot']", line).val(relay.boot);
$("select[name='relayPulse']", line).val(relay.pulse);
$("input[name='relayTime']", line).val(relay.pulse_ms);
$("input[name='mqttGroup']", line).val(relay.group);
$("select[name='mqttGroupInv']", line).val(relay.group_inv);
$("select[name='relayOnDisc']", line).val(relay.on_disc);
line.appendTo("#relayConfig");
$("span.id", line).html(i);
$("span.gpio", line).html(data.gpio[i]);
$("select[name='relayBoot']", line).val(data.boot[i]);
$("select[name='relayPulse']", line).val(data.pulse[i]);
$("input[name='relayTime']", line).val(data.pulse_time[i]);
if ("group" in data) {
$("input[name='mqttGroup']", line).val(data.group[i]);
}
if ("group_inv" in data) {
$("input[name='mqttGroupInv']", line).val(data.group_inv[i]);
}
if ("on_disc" in data) {
$("input[name='relayOnDisc']", line).val(data.on_disc[i]);
}
line.appendTo("#relayConfig");
}
}
@ -963,17 +974,19 @@ function initRelayConfig(data) {
<!-- removeIf(!sensor)-->
function initMagnitudes(data) {
// check if already initialized
// check if already initialized (each magnitude is inside div.pure-g)
var done = $("#magnitudes > div").length;
if (done > 0) { return; }
var size = data.size;
// add templates
var template = $("#magnitudeTemplate").children();
for (var i in data) {
var magnitude = data[i];
for (var i=0; i<size; ++i) {
var line = $(template).clone();
$("label", line).html(magnitudeType(magnitude.type) + " #" + parseInt(magnitude.index, 10));
$("div.hint", line).html(magnitude.description);
$("label", line).html(magnitudeType(data.type[i]) + " #" + parseInt(data.index[i], 10));
$("div.hint", line).html(data.description[i]);
$("input", line).attr("data", i);
line.appendTo("#magnitudes");
}
@ -1202,11 +1215,17 @@ function processData(data) {
}
if ("rfb" === key) {
var nodes = data.rfb;
for (i in nodes) {
var node = nodes[i];
$("input[name='rfbcode'][data-id='" + node.id + "'][data-status='" + node.status + "']").val(node.data);
var rfb = data.rfb;
var size = data.size;
var on = rfb[0];
var off = rfb[1];
for (var i=0; i<size; ++i) {
$("input[name='rfbcode'][data-id='" + i + "'][data-status='1']").val(on[i]);
$("input[name='rfbcode'][data-id='" + i + "'][data-status='0']").val(off[i]);
}
return;
}
<!-- endRemoveIf(!rfbridge)-->
@ -1321,15 +1340,13 @@ function processData(data) {
if ("magnitudes" === key) {
initMagnitudes(value);
for (i in value) {
var magnitude = value[i];
var error = magnitude.error || 0;
for (var i=0; i<value.size; ++i) {
var error = value.error[i] || 0;
var text = (0 === error) ?
magnitude.value + magnitude.units :
value.value[i] + value.units[i] :
magnitudeError(error);
var element = $("input[name='magnitude'][data='" + i + "']");
element.val(text);
$("div.hint", element.parent().parent()).html(magnitude.description);
}
return;
}
@ -1378,13 +1395,13 @@ function processData(data) {
return;
}
if ("schedule" === key) {
for (i in value) {
var schedule = value[i];
var sch_line = addSchedule({ data: {schType: schedule["schType"] }});
if ("schedules" === key) {
for (var i=0; i<value.size; ++i) {
var sch_line = addSchedule({ data: {schType: value.schType[i] }});
Object.keys(schedule).forEach(function(key) {
var sch_value = schedule[key];
Object.keys(value).forEach(function(key) {
if ("size" == key) return;
var sch_value = value[key][i];
$("input[name='" + key + "']", sch_line).val(sch_value);
$("select[name='" + key + "']", sch_line).prop("value", sch_value);
$("input[type='checkbox'][name='" + key + "']", sch_line).prop("checked", sch_value);
@ -1459,6 +1476,7 @@ function processData(data) {
// Web log
if ("weblog" === key) {
websock.send("{}");
$("#weblog").append(new Text(value));
$("#weblog").scrollTop($("#weblog")[0].scrollHeight - $("#weblog").height());
return;


Loading…
Cancel
Save