Files
espurna/code/espurna/gpio.cpp
Maxim Prokhorov fa3deeffbf webui: remove jquery dependencies and clean-up websocket API
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
2021-07-18 23:30:32 +03:00

195 lines
4.1 KiB
C++

/*
GPIO MODULE
Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include "espurna.h"
// --------------------------------------------------------------------------
#include <bitset>
#include <utility>
#include "gpio_pin.h"
#include "mcp23s08_pin.h"
#include "ws.h"
namespace settings {
namespace internal {
template <>
GpioType convert(const String& value) {
auto type = static_cast<GpioType>(value.toInt());
switch (type) {
case GpioType::Hardware:
case GpioType::Mcp23s08:
return type;
case GpioType::None:
break;
}
return GpioType::None;
}
} // namespace internal
} // namespace settings
namespace {
class GpioHardware : public GpioBase {
public:
constexpr static size_t Pins { 17ul };
using Mask = std::bitset<Pins>;
using Pin = GpioPin;
GpioHardware() {
// https://github.com/espressif/esptool/blob/f04d34bcab29ace798d2d3800ba87020cccbbfdd/esptool.py#L1060-L1070
// "One or the other efuse bit is set for ESP8285"
// https://github.com/espressif/ESP8266_RTOS_SDK/blob/3c055779e9793e5f082afff63a011d6615e73639/components/esp8266/include/esp8266/efuse_register.h#L20-L21
// "define EFUSE_IS_ESP8285 (1 << 4)"
const uint32_t efuse_blocks[4] {
READ_PERI_REG(0x3ff00050),
READ_PERI_REG(0x3ff00054),
READ_PERI_REG(0x3ff00058),
READ_PERI_REG(0x3ff0005c)
};
_esp8285 = (
(efuse_blocks[0] & (1 << 4))
|| (efuse_blocks[2] & (1 << 16))
);
}
const char* id() const override {
return "hardware";
}
size_t pins() const override {
return Pins;
}
bool lock(unsigned char index) const override {
return _lock[index];
}
void lock(unsigned char index, bool value) override {
_lock.set(index, value);
}
bool valid(unsigned char index) const override {
switch (index) {
case 0 ... 5:
return true;
case 9:
case 10:
return _esp8285;
case 12 ... 16:
return true;
}
return false;
}
BasePinPtr pin(unsigned char index) {
return std::make_unique<GpioPin>(index);
}
private:
bool _esp8285 { false };
Mask _lock;
};
} // namespace
String BasePin::description() const {
char buffer[64];
snprintf_P(buffer, sizeof(buffer), PSTR("%s @ GPIO%02u"), id(), pin());
return buffer;
}
BasePin::~BasePin() {
}
GpioBase& hardwareGpio() {
static GpioHardware gpio;
return gpio;
}
GpioBase* gpioBase(GpioType type) {
GpioBase* ptr { nullptr };
switch (type) {
case GpioType::Hardware:
ptr = &hardwareGpio();
break;
case GpioType::Mcp23s08:
#if MCP23S08_SUPPORT
ptr = &mcp23s08Gpio();
#endif
break;
case GpioType::None:
break;
}
return ptr;
}
BasePinPtr gpioRegister(GpioBase& base, unsigned char gpio) {
BasePinPtr result;
if (gpioLock(base, gpio)) {
result = std::move(base.pin(gpio));
}
return result;
}
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
}