Skip to content

Commit

Permalink
webui: remove jquery dependencies and clean-up websocket API
Browse files Browse the repository at this point in the history
Refactor WebUI:
- remove jquery dependency from the base custom.js and use vanilla JS
- remove jquery + jquery-datatables dependency from the RFM69 module
- replace jquery-datatables handlers with pure-css table + some basic cell filtering
  (may be incomplete, but tbh it is not worth additional 50Kb to the .bin size)
- introduce a common way to notify about the app errors, show small text notification
  at the top of the page instead of relying on user to find out about errors by using the Web Developer Tools
- replace <span name=...> with <span data-settings-key=...>
- replace <div> templates with <template>, disallowing modification
  without an explicit DOM clone
- run `eslint` on html/custom.js and `html-validate` on html/index.html,
  and fix issues detected by both tools

Streamline settings group handling in custom.js & index.html
- drop module-specific button-add-... in favour of button-add-settings-group
- only enforce data-settings-max requirement when the property actually exists
- re-create label for=... and input id=... when settings group is
  modified, so checkboxes refer to the correct element
- introduce additional data-... properties to generalize settings group additions
- introduce Enumerable object to track some common list elements for
  <select>, allow to re-create <option> list when messages come in
  different order

Minor fixes that also came with this:
- fix relay code incorrectly parsing the payload, causing no relay names
  to be displayed in the SWITCHES panel
- fix scheduler code accidentally combining keys b/c of the way C parses
  string literals on separate lines, without any commas in-between
- thermostat should not reference tmpUnit directly in the webui, replace with
  module-specific thermostatUnit that is handled on the device itself
- fix index.html initial setup invalid adminPass ids
- fix index.html layout when removing specific schedules
  • Loading branch information
mcspr committed Jul 18, 2021
1 parent 256e790 commit fa3deef
Show file tree
Hide file tree
Showing 45 changed files with 26,076 additions and 27,615 deletions.
12 changes: 11 additions & 1 deletion ci_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,26 @@ cd code

case "$1" in
("host")
cd test/ && pio test
# runs PIO unit tests, using the host compiler
# (see https://github.com/ThrowTheSwitch/Unity)
pushd test
pio test
popd
;;
("webui")
# TODO: both can only parse one file at a time
npx eslint html/custom.js
npx html-validate html/index.html
# checks whether the webui can be built
./build.sh -f environments
git --no-pager diff --stat
;;
("build")
# run generic build test with the specified environment as base
scripts/test_build.py -e $2
;;
("release")
# TODO: pending removal in favour of code/scripts/generate_release_sh.py
./build.sh -r
;;
(*)
Expand Down
18 changes: 14 additions & 4 deletions code/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
module.exports = {
"env": {
"commonjs": true,
"es2021": true,
"node": true
"browser": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
"ecmaVersion": 2021
},
"extends": [
"eslint:recommended"
],
"globals": {
"document": "readonly",
"navigator": "readonly",
"window": "readonly",
"iro": "readonly"
},
"rules": {
"no-invalid-this": "error",
"eqeqeq": "error",
"prefer-arrow-callback": "error"
}
};
12 changes: 12 additions & 0 deletions code/.htmlvalidate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"elements": [
"html5"
],
"extends": [
"html-validate:recommended"
],
"rules": {
"wcag/h32": "off",
"wcag/h71": "off"
}
}
2 changes: 1 addition & 1 deletion code/espurna/config/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
#endif

#ifndef CFG_VERSION
#define CFG_VERSION 7
#define CFG_VERSION 8
#endif
1 change: 0 additions & 1 deletion code/espurna/curtain_kingart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,6 @@ void _curtainMQTTCallback(unsigned int type, const char * topic, char * payload)
void _curtainWebSocketOnConnected(JsonObject& root) {
root["curtainType"] = getSetting("curtainType", "0");
root["curtainBoot"] = getSetting("curtainBoot", "0");
root["curtainConfig"] = 1;
}

//------------------------------------------------------------------------------
Expand Down
Binary file modified code/espurna/data/index.all.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.curtain.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.garland.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.light.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.lightfox.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.rfbridge.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.rfm69.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.sensor.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.small.html.gz
Binary file not shown.
Binary file modified code/espurna/data/index.thermostat.html.gz
Binary file not shown.
39 changes: 39 additions & 0 deletions code/espurna/gpio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "gpio_pin.h"
#include "mcp23s08_pin.h"

#include "ws.h"

namespace settings {
namespace internal {

Expand Down Expand Up @@ -151,5 +153,42 @@ BasePinPtr gpioRegister(unsigned char gpio) {
return gpioRegister(hardwareGpio(), gpio);
}

#if WEB_SUPPORT

void _gpioWebSocketOnVisible(JsonObject& root) {
JsonObject& config = root.createNestedObject("gpioConfig");

constexpr GpioType known_types[] {
GpioType::Hardware,
#if MCP23S08_SUPPORT
GpioType::Mcp23s08,
#endif
};

JsonArray& types = config.createNestedArray("types");

for (auto& type : known_types) {
auto* base = gpioBase(type);
if (base) {
JsonArray& entry = types.createNestedArray();
entry.add(base->id());
entry.add(static_cast<int>(type));

JsonArray& pins = config.createNestedArray(base->id());
for (unsigned char pin = 0; pin < base->pins(); ++pin) {
if (base->valid(pin)) {
pins.add(pin);
}
}
}
}
}

#endif

void gpioSetup() {
#if WEB_SUPPORT
wsRegister()
.onVisible(_gpioWebSocketOnVisible);
#endif
}
58 changes: 26 additions & 32 deletions code/espurna/relay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1183,20 +1183,26 @@ bool _relayWebSocketOnKeyCheck(const char * key, JsonVariant& value) {

void _relayWebSocketUpdate(JsonObject& root) {
JsonObject& state = root.createNestedObject("relayState");
state["size"] = relayCount();

JsonArray& status = state.createNestedArray("status");
JsonArray& lock = state.createNestedArray("lock");
static const char* const keys[] PROGMEM {
"status", "lock"
};
JsonArray& schema = state.createNestedArray("schema");
schema.copyFrom(keys, sizeof(keys) / sizeof(*keys));

// Note: we use byte instead of bool to ever so slightly compress json output
auto relays = relayCount();
for (decltype(relays) id = 0; id < relays; ++id) {
status.add(_relays[id].target_status ? 1 : 0);
lock.add(static_cast<uint8_t>(_relays[id].lock));
// Byte instead of bool in case payload has lot of relays
JsonArray& relays = state.createNestedArray("states");

size_t Relays { relayCount() };
for (decltype(Relays) id = 0; id < Relays; ++id) {
JsonArray& relay = relays.createNestedArray();
relay.add(_relays[id].target_status ? 1 : 0);
relay.add(static_cast<uint8_t>(_relays[id].lock));
}
}

void _relayWebSocketRelayConfig(JsonArray& relay, size_t id) {
relay.add(_relays[id].provider->id());
relay.add(static_cast<uint8_t>(getSetting({"relayProv", id}, relay::build::provider(id))));
relay.add(getSetting({"relayName", id}));
relay.add(getSetting({"relayBoot", id}, relay::build::bootMode(id)));
Expand Down Expand Up @@ -1225,7 +1231,8 @@ void _relayWebSocketSendRelays(JsonObject& root) {
config["start"] = 0;

{
static const char* const schema_keys[] PROGMEM = {
static const char* const keys[] PROGMEM = {
"relayDesc",
"relayProv",
"relayName",
"relayBoot",
Expand All @@ -1240,19 +1247,13 @@ void _relayWebSocketSendRelays(JsonObject& root) {
};

JsonArray& schema = config.createNestedArray("schema");
schema.copyFrom(schema_keys, sizeof(schema_keys) / sizeof(*schema_keys));
schema.copyFrom(keys, sizeof(keys) / sizeof(*keys));
}

{
JsonArray& cfg = config.createNestedArray("cfg");
JsonArray& desc = config.createNestedArray("desc");

for (size_t id = 0; id < relayCount(); ++id) {
desc.add(_relays[id].provider->id());

JsonArray& relay = cfg.createNestedArray();
_relayWebSocketRelayConfig(relay, id);
}
JsonArray& relays = config.createNestedArray("relays");
for (size_t id = 0; id < relayCount(); ++id) {
JsonArray& relay = relays.createNestedArray();
_relayWebSocketRelayConfig(relay, id);
}
}

Expand All @@ -1272,21 +1273,14 @@ void _relayWebSocketOnConnected(JsonObject& root) {
_relayWebSocketSendRelays(root);
}

void _relayWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {

if (strcmp(action, "relay") != 0) return;

if (data.containsKey("status")) {

unsigned int relayID = 0;
if (data.containsKey("id") && data.is<int>("id")) {
relayID = data["id"];
void _relayWebSocketOnAction(uint32_t client_id, const char* action, JsonObject& data) {
if (strcmp(action, "relay") == 0) {
if (!data.is<size_t>("id") || !data.is<String>("status")) {
return;
}

_relayHandlePayload(relayID, data["status"].as<const char*>());

_relayHandlePayload(data["id"].as<size_t>(), data["status"].as<String>().c_str());
}

}

void relaySetupWS() {
Expand Down
9 changes: 4 additions & 5 deletions code/espurna/rfbridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,15 +344,14 @@ void _rfbWebSocketOnVisible(JsonObject& root) {

void _rfbWebSocketSendCodeArray(JsonObject& root, size_t start, size_t size) {
JsonObject& rfb = root.createNestedObject("rfb");
rfb["size"] = size;
rfb["start"] = start;

JsonArray& on = rfb.createNestedArray("on");
JsonArray& off = rfb.createNestedArray("off");
JsonArray& codes = rfb.createNestedArray("codes");

for (auto id = start; id < (start + size); ++id) {
on.add(rfbRetrieve(id, true));
off.add(rfbRetrieve(id, false));
JsonArray& pair = codes.createNestedArray();
pair.add(rfbRetrieve(id, false));
pair.add(rfbRetrieve(id, true));
}
}

Expand Down
Loading

0 comments on commit fa3deef

Please sign in to comment.