mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2025-12-13 19:12:10 +01:00
Merge pull request #59 from Noltari/github-warnings
Enable default warnings on Github CI
This commit is contained in:
commit
5fd255910a
15 changed files with 91 additions and 71 deletions
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
|
|
@ -123,7 +123,7 @@ jobs:
|
||||||
- name: Build ${{ matrix.name }}
|
- name: Build ${{ matrix.name }}
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
arduino-cli compile --clean --output-dir build --fqbn ${{ matrix.fqbn }} ./SomfyController
|
arduino-cli compile --clean --output-dir build --fqbn ${{ matrix.fqbn }} --warnings default ./SomfyController
|
||||||
|
|
||||||
- name: ${{ matrix.name }} Image
|
- name: ${{ matrix.name }} Image
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,10 @@ bool ConfigFile::seekRecordByIndex(uint16_t ndx) {
|
||||||
if(!this->file) {
|
if(!this->file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(((this->header.recordSize * ndx) + this->header.length) > this->file.size()) return false;
|
if(((this->header.recordSize * ndx) + this->header.length) > this->file.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
bool ConfigFile::readString(char *buff, size_t len) {
|
bool ConfigFile::readString(char *buff, size_t len) {
|
||||||
if(!this->file) return false;
|
if(!this->file) return false;
|
||||||
|
|
@ -369,7 +372,6 @@ bool ShadeConfigFile::getAppVersion(appver_t &ver) {
|
||||||
char app[15];
|
char app[15];
|
||||||
if(!LittleFS.exists("/appversion")) return false;
|
if(!LittleFS.exists("/appversion")) return false;
|
||||||
File f = LittleFS.open("/appversion", "r");
|
File f = LittleFS.open("/appversion", "r");
|
||||||
size_t fsize = f.size();
|
|
||||||
memset(app, 0x00, sizeof(app));
|
memset(app, 0x00, sizeof(app));
|
||||||
f.read((uint8_t *)app, sizeof(app) - 1);
|
f.read((uint8_t *)app, sizeof(app) - 1);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#define CFG_REC_END '\n'
|
#define CFG_REC_END '\n'
|
||||||
#define CFG_TOK_NONE 0x00
|
#define CFG_TOK_NONE 0x00
|
||||||
|
|
||||||
typedef struct config_header_t {
|
struct config_header_t {
|
||||||
uint8_t version = 1;
|
uint8_t version = 1;
|
||||||
uint16_t recordSize = 0;
|
uint16_t recordSize = 0;
|
||||||
uint16_t records = 0;
|
uint16_t records = 0;
|
||||||
|
|
@ -63,4 +63,4 @@ class ShadeConfigFile : public ConfigFile {
|
||||||
bool seekRecordById(uint8_t id);
|
bool seekRecordById(uint8_t id);
|
||||||
bool validate();
|
bool validate();
|
||||||
};
|
};
|
||||||
#endif;
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ bool BaseSettings::loadFile(const char *filename) {
|
||||||
data += c;
|
data += c;
|
||||||
}
|
}
|
||||||
DynamicJsonDocument doc(filesize);
|
DynamicJsonDocument doc(filesize);
|
||||||
DeserializationError err = deserializeJson(doc, data);
|
deserializeJson(doc, data);
|
||||||
JsonObject obj = doc.as<JsonObject>();
|
JsonObject obj = doc.as<JsonObject>();
|
||||||
this->fromJSON(obj);
|
this->fromJSON(obj);
|
||||||
file.close();
|
file.close();
|
||||||
|
|
@ -33,6 +33,7 @@ bool BaseSettings::saveFile(const char *filename) {
|
||||||
this->toJSON(obj);
|
this->toJSON(obj);
|
||||||
serializeJson(doc, file);
|
serializeJson(doc, file);
|
||||||
file.close();
|
file.close();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
bool BaseSettings::parseValueString(JsonObject &obj, const char *prop, char *pdest, size_t size) {
|
bool BaseSettings::parseValueString(JsonObject &obj, const char *prop, char *pdest, size_t size) {
|
||||||
if(obj.containsKey(prop)) strlcpy(pdest, obj[prop], size);
|
if(obj.containsKey(prop)) strlcpy(pdest, obj[prop], size);
|
||||||
|
|
@ -80,7 +81,7 @@ bool ConfigSettings::load() {
|
||||||
pref.end();
|
pref.end();
|
||||||
if(this->connType == conn_types::unset) {
|
if(this->connType == conn_types::unset) {
|
||||||
// We are doing this to convert the data from previous versions.
|
// We are doing this to convert the data from previous versions.
|
||||||
this->connType == conn_types::wifi;
|
this->connType = conn_types::wifi;
|
||||||
pref.begin("WIFI");
|
pref.begin("WIFI");
|
||||||
pref.getString("hostname", this->hostname, sizeof(this->hostname));
|
pref.getString("hostname", this->hostname, sizeof(this->hostname));
|
||||||
this->ssdpBroadcast = pref.getBool("ssdpBroadcast", true);
|
this->ssdpBroadcast = pref.getBool("ssdpBroadcast", true);
|
||||||
|
|
@ -112,7 +113,7 @@ bool ConfigSettings::fromJSON(JsonObject &obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void ConfigSettings::print() {
|
void ConfigSettings::print() {
|
||||||
Serial.printf("Connection Type: %d\n", this->connType);
|
Serial.printf("Connection Type: %u\n", (unsigned int) this->connType);
|
||||||
this->NTP.print();
|
this->NTP.print();
|
||||||
if(this->connType == conn_types::wifi || this->connType == conn_types::unset) this->WIFI.print();
|
if(this->connType == conn_types::wifi || this->connType == conn_types::unset) this->WIFI.print();
|
||||||
if(this->connType == conn_types::ethernet || this->connType == conn_types::ethernetpref) this->Ethernet.print();
|
if(this->connType == conn_types::ethernet || this->connType == conn_types::ethernetpref) this->Ethernet.print();
|
||||||
|
|
@ -272,8 +273,8 @@ String WifiSettings::mapEncryptionType(int type) {
|
||||||
return "WPA/WPA2/PSK";
|
return "WPA/WPA2/PSK";
|
||||||
case WIFI_AUTH_WPA2_ENTERPRISE:
|
case WIFI_AUTH_WPA2_ENTERPRISE:
|
||||||
return "WPA/Enterprise";
|
return "WPA/Enterprise";
|
||||||
return "Unknown";
|
|
||||||
}
|
}
|
||||||
|
return "Unknown";
|
||||||
}
|
}
|
||||||
void WifiSettings::print() {
|
void WifiSettings::print() {
|
||||||
Serial.println("WIFI Settings");
|
Serial.println("WIFI Settings");
|
||||||
|
|
@ -289,11 +290,6 @@ void WifiSettings::printNetworks() {
|
||||||
Serial.print(n);
|
Serial.print(n);
|
||||||
Serial.println(" Networks...");
|
Serial.println(" Networks...");
|
||||||
String network;
|
String network;
|
||||||
uint8_t encType;
|
|
||||||
int32_t RSSI;
|
|
||||||
uint8_t* BSSID;
|
|
||||||
int32_t channel;
|
|
||||||
bool isHidden;
|
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++) {
|
||||||
if(WiFi.SSID(i).compareTo(this->ssid) == 0) Serial.print("*");
|
if(WiFi.SSID(i).compareTo(this->ssid) == 0) Serial.print("*");
|
||||||
else Serial.print(" ");
|
else Serial.print(" ");
|
||||||
|
|
@ -306,7 +302,6 @@ void WifiSettings::printNetworks() {
|
||||||
Serial.print(WiFi.channel(i));
|
Serial.print(WiFi.channel(i));
|
||||||
Serial.print(" MAC:");
|
Serial.print(" MAC:");
|
||||||
Serial.print(WiFi.BSSIDstr(i));
|
Serial.print(WiFi.BSSIDstr(i));
|
||||||
if(isHidden) Serial.print(" [hidden]");
|
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
MQTT.cpp
10
MQTT.cpp
|
|
@ -35,7 +35,7 @@ void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
|
||||||
//Serial.println();
|
//Serial.println();
|
||||||
|
|
||||||
// We need to start at the last slash in the data
|
// We need to start at the last slash in the data
|
||||||
uint16_t ndx = strlen(topic) - 1;
|
int16_t ndx = strlen(topic) - 1;
|
||||||
// ------------------+
|
// ------------------+
|
||||||
// shades/1/target/set
|
// shades/1/target/set
|
||||||
while(ndx >= 0 && topic[ndx] != '/') ndx--; // Back off the set command
|
while(ndx >= 0 && topic[ndx] != '/') ndx--; // Back off the set command
|
||||||
|
|
@ -102,7 +102,7 @@ bool MQTTClass::connect() {
|
||||||
if(settings.MQTT.enabled) {
|
if(settings.MQTT.enabled) {
|
||||||
if(this->lastConnect + 10000 > millis()) return false;
|
if(this->lastConnect + 10000 > millis()) return false;
|
||||||
uint64_t mac = ESP.getEfuseMac();
|
uint64_t mac = ESP.getEfuseMac();
|
||||||
snprintf(this->clientId, sizeof(this->clientId), "client-%08lx%08lx", (uint32_t)((mac >> 32) & 0xFFFFFFFF), (uint32_t)(mac & 0xFFFFFFFF));
|
snprintf(this->clientId, sizeof(this->clientId), "client-%08x%08x", (uint32_t)((mac >> 32) & 0xFFFFFFFF), (uint32_t)(mac & 0xFFFFFFFF));
|
||||||
if(strlen(settings.MQTT.protocol) > 0 && strlen(settings.MQTT.hostname) > 0) {
|
if(strlen(settings.MQTT.protocol) > 0 && strlen(settings.MQTT.hostname) > 0) {
|
||||||
mqttClient.setServer(settings.MQTT.hostname, settings.MQTT.port);
|
mqttClient.setServer(settings.MQTT.hostname, settings.MQTT.port);
|
||||||
if(mqttClient.connect(this->clientId, settings.MQTT.username, settings.MQTT.password)) {
|
if(mqttClient.connect(this->clientId, settings.MQTT.username, settings.MQTT.password)) {
|
||||||
|
|
@ -138,7 +138,7 @@ bool MQTTClass::disconnect() {
|
||||||
}
|
}
|
||||||
bool MQTTClass::unsubscribe(const char *topic) {
|
bool MQTTClass::unsubscribe(const char *topic) {
|
||||||
if(mqttClient.connected()) {
|
if(mqttClient.connected()) {
|
||||||
char top[64];
|
char top[128];
|
||||||
if(strlen(settings.MQTT.rootTopic) > 0)
|
if(strlen(settings.MQTT.rootTopic) > 0)
|
||||||
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
||||||
else
|
else
|
||||||
|
|
@ -149,7 +149,7 @@ bool MQTTClass::unsubscribe(const char *topic) {
|
||||||
}
|
}
|
||||||
bool MQTTClass::subscribe(const char *topic) {
|
bool MQTTClass::subscribe(const char *topic) {
|
||||||
if(mqttClient.connected()) {
|
if(mqttClient.connected()) {
|
||||||
char top[64];
|
char top[128];
|
||||||
if(strlen(settings.MQTT.rootTopic) > 0)
|
if(strlen(settings.MQTT.rootTopic) > 0)
|
||||||
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
||||||
else
|
else
|
||||||
|
|
@ -162,7 +162,7 @@ bool MQTTClass::subscribe(const char *topic) {
|
||||||
}
|
}
|
||||||
bool MQTTClass::publish(const char *topic, const char *payload) {
|
bool MQTTClass::publish(const char *topic, const char *payload) {
|
||||||
if(mqttClient.connected()) {
|
if(mqttClient.connected()) {
|
||||||
char top[64];
|
char top[128];
|
||||||
if(strlen(settings.MQTT.rootTopic) > 0)
|
if(strlen(settings.MQTT.rootTopic) > 0)
|
||||||
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
14
Network.cpp
14
Network.cpp
|
|
@ -291,6 +291,8 @@ bool Network::connectWiFi() {
|
||||||
Serial.print(settings.WIFI.ssid);
|
Serial.print(settings.WIFI.ssid);
|
||||||
Serial.print(" could not be found");
|
Serial.print(" could not be found");
|
||||||
return false;
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
delay(500);
|
delay(500);
|
||||||
if(connectAttempts == 1) Serial.print("*");
|
if(connectAttempts == 1) Serial.print("*");
|
||||||
|
|
@ -314,11 +316,12 @@ bool Network::connect() {
|
||||||
return this->connectWiFi();
|
return this->connectWiFi();
|
||||||
}
|
}
|
||||||
int Network::getStrengthByMac(const char *macAddr) {
|
int Network::getStrengthByMac(const char *macAddr) {
|
||||||
int strength = -100;
|
|
||||||
int n = WiFi.scanNetworks(true);
|
int n = WiFi.scanNetworks(true);
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++) {
|
||||||
if(WiFi.BSSIDstr(i).compareTo(macAddr) == 0) return WiFi.RSSI(i);
|
if (WiFi.BSSIDstr(i).compareTo(macAddr) == 0)
|
||||||
|
return WiFi.RSSI(i);
|
||||||
}
|
}
|
||||||
|
return -100;
|
||||||
}
|
}
|
||||||
uint32_t Network::getChipId() {
|
uint32_t Network::getChipId() {
|
||||||
uint32_t chipId = 0;
|
uint32_t chipId = 0;
|
||||||
|
|
@ -341,11 +344,6 @@ int Network::getStrengthBySSID(const char *ssid) {
|
||||||
Serial.print(n);
|
Serial.print(n);
|
||||||
Serial.println(" Networks...");
|
Serial.println(" Networks...");
|
||||||
String network;
|
String network;
|
||||||
uint8_t encType;
|
|
||||||
int32_t RSSI;
|
|
||||||
uint8_t* BSSID;
|
|
||||||
int32_t channel;
|
|
||||||
bool isHidden;
|
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++) {
|
||||||
//WiFi.getNetworkInfo(i, network, encType, RSSI, BSSID, channel, isHidden);
|
//WiFi.getNetworkInfo(i, network, encType, RSSI, BSSID, channel, isHidden);
|
||||||
if(network.compareTo(this->ssid) == 0) Serial.print("*");
|
if(network.compareTo(this->ssid) == 0) Serial.print("*");
|
||||||
|
|
@ -359,7 +357,6 @@ int Network::getStrengthBySSID(const char *ssid) {
|
||||||
Serial.print(WiFi.channel(i));
|
Serial.print(WiFi.channel(i));
|
||||||
Serial.print(" MAC:");
|
Serial.print(" MAC:");
|
||||||
Serial.print(WiFi.BSSIDstr(i).c_str());
|
Serial.print(WiFi.BSSIDstr(i).c_str());
|
||||||
if(isHidden) Serial.print(" [hidden]");
|
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -416,6 +413,7 @@ bool Network::openSoftAP() {
|
||||||
}
|
}
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
bool Network::connected() {
|
bool Network::connected() {
|
||||||
if(this->connType == conn_types::unset) return false;
|
if(this->connType == conn_types::unset) return false;
|
||||||
|
|
|
||||||
10
SSDP.cpp
10
SSDP.cpp
|
|
@ -305,6 +305,8 @@ void SSDPClass::_parsePacket(ssdp_packet_t *pkt, AsyncUDPPacket &p) {
|
||||||
case AGENT:
|
case AGENT:
|
||||||
strcpy(pkt->agent, buffer);
|
strcpy(pkt->agent, buffer);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
keys = KEY;
|
keys = KEY;
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|
@ -683,7 +685,7 @@ void SSDPClass::_sendQueuedResponses() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void SSDPClass::_printPacket(ssdp_packet_t *pkt) {
|
void SSDPClass::_printPacket(ssdp_packet_t *pkt) {
|
||||||
Serial.printf("Rec: %d\n", pkt->recvd);
|
Serial.printf("Rec: %lu\n", pkt->recvd);
|
||||||
switch(pkt->method) {
|
switch(pkt->method) {
|
||||||
case NONE:
|
case NONE:
|
||||||
Serial.println("Method: NONE");
|
Serial.println("Method: NONE");
|
||||||
|
|
@ -728,13 +730,13 @@ void SSDPClass::_processRequest(AsyncUDPPacket &p) {
|
||||||
this->_printPacket(&pkt);
|
this->_printPacket(&pkt);
|
||||||
DEBUG_SSDP.println("--------------- ROOT ---------------------");
|
DEBUG_SSDP.println("--------------- ROOT ---------------------");
|
||||||
#endif
|
#endif
|
||||||
if(pkt.method == MULTICAST)
|
if(pkt.type == MULTICAST)
|
||||||
this->_addToSendQueue(IPAddress(SSDP_MULTICAST_ADDR), SSDP_PORT, dev, pkt.st, pkt.mx, false);
|
this->_addToSendQueue(IPAddress(SSDP_MULTICAST_ADDR), SSDP_PORT, dev, pkt.st, pkt.mx, false);
|
||||||
else
|
else
|
||||||
this->_sendResponse(p.remoteIP(), p.remotePort(), dev, pkt.st, false);
|
this->_sendResponse(p.remoteIP(), p.remotePort(), dev, pkt.st, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
UPNPDeviceType *dev;
|
UPNPDeviceType *dev = nullptr;
|
||||||
bool useUUID = false;
|
bool useUUID = false;
|
||||||
if(this->_startsWith("uuid:", pkt.st)) {
|
if(this->_startsWith("uuid:", pkt.st)) {
|
||||||
dev = this->findDeviceByUUID(pkt.st);
|
dev = this->findDeviceByUUID(pkt.st);
|
||||||
|
|
@ -746,7 +748,7 @@ void SSDPClass::_processRequest(AsyncUDPPacket &p) {
|
||||||
this->_printPacket(&pkt);
|
this->_printPacket(&pkt);
|
||||||
DEBUG_SSDP.println("-------------- ACCEPT --------------------");
|
DEBUG_SSDP.println("-------------- ACCEPT --------------------");
|
||||||
#endif
|
#endif
|
||||||
if(pkt.method == MULTICAST)
|
if(pkt.type == MULTICAST)
|
||||||
this->_addToSendQueue(IPAddress(SSDP_MULTICAST_ADDR), SSDP_PORT, dev, pkt.st, pkt.mx, useUUID);
|
this->_addToSendQueue(IPAddress(SSDP_MULTICAST_ADDR), SSDP_PORT, dev, pkt.st, pkt.mx, useUUID);
|
||||||
else {
|
else {
|
||||||
this->_sendResponse(p.remoteIP(), p.remotePort(), dev, pkt.st, useUUID);
|
this->_sendResponse(p.remoteIP(), p.remotePort(), dev, pkt.st, useUUID);
|
||||||
|
|
|
||||||
4
SSDP.h
4
SSDP.h
|
|
@ -38,7 +38,7 @@ typedef enum {
|
||||||
MULTICAST,
|
MULTICAST,
|
||||||
UNICAST
|
UNICAST
|
||||||
} ssdp_req_types_t;
|
} ssdp_req_types_t;
|
||||||
typedef struct ssdp_packet_t {
|
struct ssdp_packet_t {
|
||||||
bool pending;
|
bool pending;
|
||||||
unsigned long recvd;
|
unsigned long recvd;
|
||||||
ssdp_method_t method;
|
ssdp_method_t method;
|
||||||
|
|
@ -91,7 +91,7 @@ class UPNPDeviceType {
|
||||||
char *getUSN(const char *st);
|
char *getUSN(const char *st);
|
||||||
void setChipId(uint32_t chipId);
|
void setChipId(uint32_t chipId);
|
||||||
};
|
};
|
||||||
typedef struct ssdp_response_t {
|
struct ssdp_response_t {
|
||||||
bool waiting;
|
bool waiting;
|
||||||
IPAddress address;
|
IPAddress address;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,7 @@ void SocketEmitter::wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t
|
||||||
case WStype_PING:
|
case WStype_PING:
|
||||||
//Serial.printf("Ping from %u\n", num);
|
//Serial.printf("Ping from %u\n", num);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#define SOCK_MAX_ROOMS 1
|
#define SOCK_MAX_ROOMS 1
|
||||||
#define ROOM_EMIT_FRAME 0
|
#define ROOM_EMIT_FRAME 0
|
||||||
|
|
||||||
typedef struct room_t {
|
struct room_t {
|
||||||
uint8_t clients[5] = {255, 255, 255, 255};
|
uint8_t clients[5] = {255, 255, 255, 255};
|
||||||
uint8_t activeClients();
|
uint8_t activeClients();
|
||||||
bool isJoined(uint8_t num);
|
bool isJoined(uint8_t num);
|
||||||
|
|
|
||||||
29
Somfy.cpp
29
Somfy.cpp
|
|
@ -291,6 +291,8 @@ void somfy_frame_t::encodeFrame(byte *frame) {
|
||||||
case somfy_commands::Flag:
|
case somfy_commands::Flag:
|
||||||
frame[0] = 142;
|
frame[0] = 142;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -310,6 +312,8 @@ void somfy_frame_t::encodeFrame(byte *frame) {
|
||||||
frame[8] = 0;
|
frame[8] = 0;
|
||||||
frame[9] = 25;
|
frame[9] = 25;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byte checksum = 0;
|
byte checksum = 0;
|
||||||
|
|
@ -1039,6 +1043,8 @@ void SomfyShade::processWaitingFrame() {
|
||||||
Serial.println(" repeats");
|
Serial.println(" repeats");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1060,7 +1066,6 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
|
||||||
if(!hasRemote) return;
|
if(!hasRemote) return;
|
||||||
this->lastFrame.copy(frame);
|
this->lastFrame.copy(frame);
|
||||||
int8_t dir = 0;
|
int8_t dir = 0;
|
||||||
int8_t tiltDir = 0;
|
|
||||||
this->moveStart = this->tiltStart = millis();
|
this->moveStart = this->tiltStart = millis();
|
||||||
this->startPos = this->currentPos;
|
this->startPos = this->currentPos;
|
||||||
this->startTiltPos = this->currentTiltPos;
|
this->startTiltPos = this->currentTiltPos;
|
||||||
|
|
@ -1336,7 +1341,6 @@ void SomfyShade::sendTiltCommand(somfy_commands cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void SomfyShade::moveToTiltTarget(float target) {
|
void SomfyShade::moveToTiltTarget(float target) {
|
||||||
int8_t newDir = 0;
|
|
||||||
somfy_commands cmd = somfy_commands::My;
|
somfy_commands cmd = somfy_commands::My;
|
||||||
if(target < this->currentTiltPos)
|
if(target < this->currentTiltPos)
|
||||||
cmd = somfy_commands::Up;
|
cmd = somfy_commands::Up;
|
||||||
|
|
@ -1361,7 +1365,6 @@ void SomfyShade::moveToTiltTarget(float target) {
|
||||||
this->settingTiltPos = true;
|
this->settingTiltPos = true;
|
||||||
}
|
}
|
||||||
void SomfyShade::moveToTarget(float pos, float tilt) {
|
void SomfyShade::moveToTarget(float pos, float tilt) {
|
||||||
int8_t newDir = 0;
|
|
||||||
somfy_commands cmd = somfy_commands::My;
|
somfy_commands cmd = somfy_commands::My;
|
||||||
if(pos < this->currentPos)
|
if(pos < this->currentPos)
|
||||||
cmd = somfy_commands::Up;
|
cmd = somfy_commands::Up;
|
||||||
|
|
@ -1552,7 +1555,6 @@ void SomfyShadeController::publish() {
|
||||||
mqtt.publish("shades", arr);
|
mqtt.publish("shades", arr);
|
||||||
}
|
}
|
||||||
uint8_t SomfyShadeController::getNextShadeId() {
|
uint8_t SomfyShadeController::getNextShadeId() {
|
||||||
uint8_t nextId = 0;
|
|
||||||
// There is no shortcut for this since the deletion of
|
// There is no shortcut for this since the deletion of
|
||||||
// a shade in the middle makes all of this very difficult.
|
// a shade in the middle makes all of this very difficult.
|
||||||
for(uint8_t i = 1; i < SOMFY_MAX_SHADES - 1; i++) {
|
for(uint8_t i = 1; i < SOMFY_MAX_SHADES - 1; i++) {
|
||||||
|
|
@ -1792,7 +1794,7 @@ bool SomfyShadeController::toJSON(JsonArray &arr) {
|
||||||
}
|
}
|
||||||
void SomfyShadeController::loop() {
|
void SomfyShadeController::loop() {
|
||||||
this->transceiver.loop();
|
this->transceiver.loop();
|
||||||
for(uint8_t i; i < SOMFY_MAX_SHADES; i++) {
|
for(uint8_t i = 0; i < SOMFY_MAX_SHADES; i++) {
|
||||||
if(this->shades[i].getShadeId() != 255) this->shades[i].checkMovement();
|
if(this->shades[i].getShadeId() != 255) this->shades[i].checkMovement();
|
||||||
}
|
}
|
||||||
// Only commit the file once per second.
|
// Only commit the file once per second.
|
||||||
|
|
@ -1824,17 +1826,16 @@ static const uint32_t tempo_if_gap = 30415; // Gap between frames
|
||||||
|
|
||||||
|
|
||||||
static int16_t bitMin = SYMBOL * TOLERANCE_MIN;
|
static int16_t bitMin = SYMBOL * TOLERANCE_MIN;
|
||||||
static uint16_t timing_index = 0;
|
|
||||||
static somfy_rx_t somfy_rx;
|
static somfy_rx_t somfy_rx;
|
||||||
static somfy_rx_queue_t rx_queue;
|
static somfy_rx_queue_t rx_queue;
|
||||||
|
|
||||||
bool somfy_tx_queue_t::pop(somfy_tx_t *tx) {
|
bool somfy_tx_queue_t::pop(somfy_tx_t *tx) {
|
||||||
// Read the oldest index.
|
// Read the oldest index.
|
||||||
for(uint8_t i = MAX_TX_BUFFER - 1; i >= 0; i--) {
|
for(int8_t i = MAX_TX_BUFFER - 1; i >= 0; i--) {
|
||||||
if(this->index[i] < MAX_TX_BUFFER) {
|
if(this->index[i] < MAX_TX_BUFFER) {
|
||||||
uint8_t ndx = this->index[i];
|
uint8_t ndx = this->index[i];
|
||||||
memcpy(tx, &this->items[ndx], sizeof(somfy_tx_t));
|
memcpy(tx, &this->items[ndx], sizeof(somfy_tx_t));
|
||||||
memset(&this->items[ndx], 0x00, sizeof(somfy_tx_t));
|
this->items[ndx].clear();
|
||||||
this->length--;
|
this->length--;
|
||||||
this->index[i] = 255;
|
this->index[i] = 255;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1847,7 +1848,8 @@ bool somfy_tx_queue_t::push(uint32_t await, somfy_commands cmd, uint8_t repeats)
|
||||||
uint8_t ndx = this->index[MAX_TX_BUFFER - 1];
|
uint8_t ndx = this->index[MAX_TX_BUFFER - 1];
|
||||||
this->index[MAX_TX_BUFFER - 1] = 255;
|
this->index[MAX_TX_BUFFER - 1] = 255;
|
||||||
this->length = MAX_TX_BUFFER - 1;
|
this->length = MAX_TX_BUFFER - 1;
|
||||||
if(ndx < MAX_TX_BUFFER) memset(&this->items[ndx], 0x00, sizeof(somfy_tx_t));
|
if(ndx < MAX_TX_BUFFER)
|
||||||
|
this->items[ndx].clear();
|
||||||
}
|
}
|
||||||
// Place the command in the first empty slot. Empty slots are those
|
// Place the command in the first empty slot. Empty slots are those
|
||||||
// with a millis of 0. We will shift the indexes right so that this
|
// with a millis of 0. We will shift the indexes right so that this
|
||||||
|
|
@ -1870,7 +1872,8 @@ bool somfy_tx_queue_t::push(uint32_t await, somfy_commands cmd, uint8_t repeats)
|
||||||
}
|
}
|
||||||
void somfy_rx_queue_t::init() {
|
void somfy_rx_queue_t::init() {
|
||||||
Serial.println("Initializing RX Queue");
|
Serial.println("Initializing RX Queue");
|
||||||
memset(&this->items[0], 0x00, sizeof(somfy_rx_t) * MAX_RX_BUFFER);
|
for (uint8_t i = 0; i < MAX_RX_BUFFER; i++)
|
||||||
|
this->items[i].clear();
|
||||||
memset(&this->index[0], 0xFF, MAX_RX_BUFFER);
|
memset(&this->index[0], 0xFF, MAX_RX_BUFFER);
|
||||||
this->length = 0;
|
this->length = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1878,11 +1881,11 @@ void somfy_rx_queue_t::init() {
|
||||||
bool somfy_rx_queue_t::pop(somfy_rx_t *rx) {
|
bool somfy_rx_queue_t::pop(somfy_rx_t *rx) {
|
||||||
// Read off the data from the oldest index.
|
// Read off the data from the oldest index.
|
||||||
//Serial.println("Popping RX Queue");
|
//Serial.println("Popping RX Queue");
|
||||||
for(uint8_t i = MAX_RX_BUFFER - 1; i >= 0; i--) {
|
for(int8_t i = MAX_RX_BUFFER - 1; i >= 0; i--) {
|
||||||
if(this->index[i] < MAX_RX_BUFFER) {
|
if(this->index[i] < MAX_RX_BUFFER) {
|
||||||
uint8_t ndx = this->index[i];
|
uint8_t ndx = this->index[i];
|
||||||
memcpy(rx, &this->items[this->index[i]], sizeof(somfy_rx_t));
|
memcpy(rx, &this->items[this->index[i]], sizeof(somfy_rx_t));
|
||||||
memset(&this->items[ndx], 0x00, sizeof(somfy_rx_t));
|
this->items[ndx].clear();
|
||||||
this->length--;
|
this->length--;
|
||||||
this->index[i] = 255;
|
this->index[i] = 255;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -2124,7 +2127,7 @@ void Transceiver::emitFrame(somfy_frame_t *frame, somfy_rx_t *rx) {
|
||||||
evt.appendMessage(buf);
|
evt.appendMessage(buf);
|
||||||
snprintf(buf, sizeof(buf), "\"rcode\":%d,", frame->rollingCode);
|
snprintf(buf, sizeof(buf), "\"rcode\":%d,", frame->rollingCode);
|
||||||
evt.appendMessage(buf);
|
evt.appendMessage(buf);
|
||||||
snprintf(buf, sizeof(buf), "\"command\":\"%s\",", translateSomfyCommand(frame->cmd));
|
snprintf(buf, sizeof(buf), "\"command\":\"%s\",", translateSomfyCommand(frame->cmd).c_str());
|
||||||
evt.appendMessage(buf);
|
evt.appendMessage(buf);
|
||||||
snprintf(buf, sizeof(buf), "\"rssi\":%d,", frame->rssi);
|
snprintf(buf, sizeof(buf), "\"rssi\":%d,", frame->rssi);
|
||||||
evt.appendMessage(buf);
|
evt.appendMessage(buf);
|
||||||
|
|
|
||||||
41
Somfy.h
41
Somfy.h
|
|
@ -4,7 +4,7 @@
|
||||||
#define SOMFY_MAX_SHADES 32
|
#define SOMFY_MAX_SHADES 32
|
||||||
#define SOMFY_MAX_LINKED_REMOTES 7
|
#define SOMFY_MAX_LINKED_REMOTES 7
|
||||||
|
|
||||||
typedef struct appver_t {
|
struct appver_t {
|
||||||
uint8_t major;
|
uint8_t major;
|
||||||
uint8_t minor;
|
uint8_t minor;
|
||||||
uint8_t build;
|
uint8_t build;
|
||||||
|
|
@ -58,7 +58,18 @@ typedef enum {
|
||||||
complete = 2
|
complete = 2
|
||||||
} t_status;
|
} t_status;
|
||||||
|
|
||||||
typedef struct somfy_rx_t {
|
struct somfy_rx_t {
|
||||||
|
void clear() {
|
||||||
|
this->status = t_status::waiting_synchro;
|
||||||
|
this->bit_length = 56;
|
||||||
|
this->cpt_synchro_hw = 0;
|
||||||
|
this->cpt_bits = 0;
|
||||||
|
this->previous_bit = 0;
|
||||||
|
this->waiting_half_symbol = false;
|
||||||
|
memset(this->payload, 0, sizeof(this->payload));
|
||||||
|
memset(this->pulses, 0, sizeof(this->pulses));
|
||||||
|
this->pulseCount = 0;
|
||||||
|
}
|
||||||
t_status status;
|
t_status status;
|
||||||
uint8_t bit_length = 56;
|
uint8_t bit_length = 56;
|
||||||
uint8_t cpt_synchro_hw = 0;
|
uint8_t cpt_synchro_hw = 0;
|
||||||
|
|
@ -72,7 +83,7 @@ typedef struct somfy_rx_t {
|
||||||
// A simple FIFO queue to hold rx buffers. We are using
|
// A simple FIFO queue to hold rx buffers. We are using
|
||||||
// a byte index to make it so we don't have to reorganize
|
// a byte index to make it so we don't have to reorganize
|
||||||
// the storage each time we push or pop.
|
// the storage each time we push or pop.
|
||||||
typedef struct somfy_rx_queue_t {
|
struct somfy_rx_queue_t {
|
||||||
void init();
|
void init();
|
||||||
uint8_t length = 0;
|
uint8_t length = 0;
|
||||||
uint8_t index[MAX_RX_BUFFER];
|
uint8_t index[MAX_RX_BUFFER];
|
||||||
|
|
@ -80,14 +91,26 @@ typedef struct somfy_rx_queue_t {
|
||||||
//void push(somfy_rx_t *rx);
|
//void push(somfy_rx_t *rx);
|
||||||
bool pop(somfy_rx_t *rx);
|
bool pop(somfy_rx_t *rx);
|
||||||
};
|
};
|
||||||
typedef struct somfy_tx_t {
|
struct somfy_tx_t {
|
||||||
|
void clear() {
|
||||||
|
this->await = 0;
|
||||||
|
this->cmd = somfy_commands::Unknown0;
|
||||||
|
this->repeats = 0;
|
||||||
|
}
|
||||||
uint32_t await = 0;
|
uint32_t await = 0;
|
||||||
somfy_commands cmd;
|
somfy_commands cmd;
|
||||||
uint8_t repeats;
|
uint8_t repeats;
|
||||||
};
|
};
|
||||||
typedef struct somfy_tx_queue_t {
|
struct somfy_tx_queue_t {
|
||||||
somfy_tx_queue_t() { memset(this->index, 255, MAX_TX_BUFFER); memset(&this->items[0], 0x00, sizeof(somfy_tx_queue_t) * MAX_TX_BUFFER); }
|
somfy_tx_queue_t() {
|
||||||
void clear() { memset(&this->index[0], 255, MAX_TX_BUFFER); memset(&this->items[0], 0x00, sizeof(somfy_tx_queue_t) * MAX_TX_BUFFER); }
|
this->clear();
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
for (uint8_t i = 0; i < MAX_TX_BUFFER; i++) {
|
||||||
|
this->index[i] = 255;
|
||||||
|
this->items[i].clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
uint8_t length = 0;
|
uint8_t length = 0;
|
||||||
uint8_t index[MAX_TX_BUFFER];
|
uint8_t index[MAX_TX_BUFFER];
|
||||||
somfy_tx_t items[MAX_TX_BUFFER];
|
somfy_tx_t items[MAX_TX_BUFFER];
|
||||||
|
|
@ -98,7 +121,7 @@ typedef struct somfy_tx_queue_t {
|
||||||
enum class somfy_flags_t : byte {
|
enum class somfy_flags_t : byte {
|
||||||
Sun = 1
|
Sun = 1
|
||||||
};
|
};
|
||||||
typedef struct somfy_frame_t {
|
struct somfy_frame_t {
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
radio_proto proto = radio_proto::RTS;
|
radio_proto proto = radio_proto::RTS;
|
||||||
|
|
@ -209,7 +232,7 @@ class SomfyShade : public SomfyRemote {
|
||||||
void commitMyPosition();
|
void commitMyPosition();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct transceiver_config_t {
|
struct transceiver_config_t {
|
||||||
bool printBuffer = false;
|
bool printBuffer = false;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
uint8_t type = 56; // 56 or 80 bit protocol.
|
uint8_t type = 56; // 56 or 80 bit protocol.
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ char * Timestamp::formatISO(struct tm *dt, int tz) {
|
||||||
int tzHrs = floor(tz/100);
|
int tzHrs = floor(tz/100);
|
||||||
int tzMin = tz - (tzHrs * 100);
|
int tzMin = tz - (tzHrs * 100);
|
||||||
int ms = millis() % 1000;
|
int ms = millis() % 1000;
|
||||||
char isoTime[32];
|
|
||||||
snprintf(this->_timeBuffer, sizeof(this->_timeBuffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03d%s%02d%02d",
|
snprintf(this->_timeBuffer, sizeof(this->_timeBuffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03d%s%02d%02d",
|
||||||
dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec, ms, tzHrs < 0 ? "-" : "+", abs(tzHrs), abs(tzMin));
|
dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec, ms, tzHrs < 0 ? "-" : "+", abs(tzHrs), abs(tzMin));
|
||||||
return this->_timeBuffer;
|
return this->_timeBuffer;
|
||||||
|
|
|
||||||
10
Utils.h
10
Utils.h
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#define DEBUG_SOMFY Serial
|
#define DEBUG_SOMFY Serial
|
||||||
|
|
||||||
static void SETCHARPROP(char *prop, const char *value, size_t size) {strncpy(prop, value, size); prop[size - 1] = '\0';}
|
[[maybe_unused]] static void SETCHARPROP(char *prop, const char *value, size_t size) {strncpy(prop, value, size); prop[size - 1] = '\0';}
|
||||||
namespace util {
|
namespace util {
|
||||||
// Createa a custom to_string function. C++ can be annoying
|
// Createa a custom to_string function. C++ can be annoying
|
||||||
// with all the trailing 0s on number formats.
|
// with all the trailing 0s on number formats.
|
||||||
|
|
@ -36,13 +36,13 @@ static void _rtrim(char *str) {
|
||||||
int e = strlen(str) - 1;
|
int e = strlen(str) - 1;
|
||||||
while(e >= 0 && (str[e] == ' ' || str[e] == '\n' || str[e] == '\r' || str[e] == '\t' || str[e] == '"')) {str[e] = '\0'; e--;}
|
while(e >= 0 && (str[e] == ' ' || str[e] == '\n' || str[e] == '\r' || str[e] == '\t' || str[e] == '"')) {str[e] = '\0'; e--;}
|
||||||
}
|
}
|
||||||
static void _trim(char *str) { _ltrim(str); _rtrim(str); }
|
[[maybe_unused]] static void _trim(char *str) { _ltrim(str); _rtrim(str); }
|
||||||
typedef struct rebootDelay_t {
|
struct rebootDelay_t {
|
||||||
bool reboot = false;
|
bool reboot = false;
|
||||||
int rebootTime = 0;
|
int rebootTime = 0;
|
||||||
bool closed = false;
|
bool closed = false;
|
||||||
};
|
};
|
||||||
static bool toBoolean(const char *str, bool def) {
|
[[maybe_unused]] static bool toBoolean(const char *str, bool def) {
|
||||||
if(!str) return def;
|
if(!str) return def;
|
||||||
if(strlen(str) == 0) return def;
|
if(strlen(str) == 0) return def;
|
||||||
else if(str[0] == 't' || str[0] == 'T' || str[0] == '1') return true;
|
else if(str[0] == 't' || str[0] == 'T' || str[0] == '1') return true;
|
||||||
|
|
@ -51,7 +51,7 @@ static bool toBoolean(const char *str, bool def) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Timestamp {
|
class Timestamp {
|
||||||
char _timeBuffer[44];
|
char _timeBuffer[128];
|
||||||
public:
|
public:
|
||||||
time_t getUTC();
|
time_t getUTC();
|
||||||
time_t getUTC(time_t epoch);
|
time_t getUTC(time_t epoch);
|
||||||
|
|
|
||||||
11
Web.cpp
11
Web.cpp
|
|
@ -165,7 +165,7 @@ void Web::begin() {
|
||||||
Serial.print("Received:");
|
Serial.print("Received:");
|
||||||
Serial.println(apiServer.arg("plain"));
|
Serial.println(apiServer.arg("plain"));
|
||||||
// Send the command to the shade.
|
// Send the command to the shade.
|
||||||
if(target >= 0 && target <= 100)
|
if(target <= 100)
|
||||||
shade->moveToTarget(target);
|
shade->moveToTarget(target);
|
||||||
else
|
else
|
||||||
shade->sendCommand(command, repeat);
|
shade->sendCommand(command, repeat);
|
||||||
|
|
@ -250,7 +250,6 @@ void Web::begin() {
|
||||||
server.on("/", []() {
|
server.on("/", []() {
|
||||||
webServer.sendCacheHeaders(604800);
|
webServer.sendCacheHeaders(604800);
|
||||||
webServer.sendCORSHeaders();
|
webServer.sendCORSHeaders();
|
||||||
int statusCode = 200;
|
|
||||||
// Load the index html page from the data directory.
|
// Load the index html page from the data directory.
|
||||||
Serial.println("Loading file index.html");
|
Serial.println("Loading file index.html");
|
||||||
File file = LittleFS.open("/index.html", "r");
|
File file = LittleFS.open("/index.html", "r");
|
||||||
|
|
@ -481,7 +480,7 @@ void Web::begin() {
|
||||||
});
|
});
|
||||||
server.on("/addShade", []() {
|
server.on("/addShade", []() {
|
||||||
HTTPMethod method = server.method();
|
HTTPMethod method = server.method();
|
||||||
SomfyShade* shade;
|
SomfyShade* shade = nullptr;
|
||||||
if (method == HTTP_POST || method == HTTP_PUT) {
|
if (method == HTTP_POST || method == HTTP_PUT) {
|
||||||
Serial.println("Adding a shade");
|
Serial.println("Adding a shade");
|
||||||
DynamicJsonDocument doc(512);
|
DynamicJsonDocument doc(512);
|
||||||
|
|
@ -687,7 +686,7 @@ void Web::begin() {
|
||||||
Serial.print("Received:");
|
Serial.print("Received:");
|
||||||
Serial.println(server.arg("plain"));
|
Serial.println(server.arg("plain"));
|
||||||
// Send the command to the shade.
|
// Send the command to the shade.
|
||||||
if(target >= 0 && target <= 100)
|
if(target <= 100)
|
||||||
shade->moveToTiltTarget(target);
|
shade->moveToTiltTarget(target);
|
||||||
else
|
else
|
||||||
shade->sendTiltCommand(command);
|
shade->sendTiltCommand(command);
|
||||||
|
|
@ -754,7 +753,7 @@ void Web::begin() {
|
||||||
Serial.print("Received:");
|
Serial.print("Received:");
|
||||||
Serial.println(server.arg("plain"));
|
Serial.println(server.arg("plain"));
|
||||||
// Send the command to the shade.
|
// Send the command to the shade.
|
||||||
if(target >= 0 && target <= 100)
|
if(target <= 100)
|
||||||
shade->moveToTarget(target);
|
shade->moveToTarget(target);
|
||||||
else
|
else
|
||||||
shade->sendCommand(command, repeat);
|
shade->sendCommand(command, repeat);
|
||||||
|
|
@ -1320,7 +1319,6 @@ void Web::begin() {
|
||||||
});
|
});
|
||||||
server.on("/setgeneral", []() {
|
server.on("/setgeneral", []() {
|
||||||
webServer.sendCORSHeaders();
|
webServer.sendCORSHeaders();
|
||||||
int statusCode = 200;
|
|
||||||
DynamicJsonDocument doc(256);
|
DynamicJsonDocument doc(256);
|
||||||
DeserializationError err = deserializeJson(doc, server.arg("plain"));
|
DeserializationError err = deserializeJson(doc, server.arg("plain"));
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -1399,7 +1397,6 @@ void Web::begin() {
|
||||||
});
|
});
|
||||||
server.on("/connectwifi", []() {
|
server.on("/connectwifi", []() {
|
||||||
webServer.sendCORSHeaders();
|
webServer.sendCORSHeaders();
|
||||||
int statusCode = 200;
|
|
||||||
Serial.println("Settings WIFI connection...");
|
Serial.println("Settings WIFI connection...");
|
||||||
DynamicJsonDocument doc(512);
|
DynamicJsonDocument doc(512);
|
||||||
DeserializationError err = deserializeJson(doc, server.arg("plain"));
|
DeserializationError err = deserializeJson(doc, server.arg("plain"));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue