From ea39872d4a4e3d444e2bdf927076972087feadc1 Mon Sep 17 00:00:00 2001 From: cjkas Date: Tue, 13 Oct 2026 20:37:36 +0200 Subject: [PATCH] refactor: move config parsing into SomfyJson.cpp validateJSON and fromJSON for shades, rooms, groups and the radio move out of Somfy.cpp unchanged. Keeping every ArduinoJson parser in one file shares its inlined helpers, which saves 2.8 KB of flash. Co-Authored-By: Claude Opus 5.5 --- src/Somfy.cpp | 226 -------------------------------------------- src/SomfyJson.cpp | 235 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+), 226 deletions(-) create mode 100644 src/SomfyJson.cpp diff --git a/src/Somfy.cpp b/src/Somfy.cpp index 7a75559..324c981 100644 --- a/src/Somfy.cpp +++ b/src/Somfy.cpp @@ -1949,204 +1949,6 @@ bool SomfyShade::usesPin(uint8_t pin) { } return false; } -int8_t SomfyShade::validateJSON(JsonObject &obj) { - int8_t ret = 0; - shade_types type = this->shadeType; - if(!obj["shadeType"].isNull()) { - if(obj["shadeType"].is()) { - if(strncmp(obj["shadeType"].as(), "roller", 7) == 0) - type = shade_types::roller; - else if(strncmp(obj["shadeType"].as(), "ldrapery", 9) == 0) - type = shade_types::ldrapery; - else if(strncmp(obj["shadeType"].as(), "rdrapery", 9) == 0) - type = shade_types::rdrapery; - else if(strncmp(obj["shadeType"].as(), "cdrapery", 9) == 0) - type = shade_types::cdrapery; - else if(strncmp(obj["shadeType"].as(), "garage1", 7) == 0) - type = shade_types::garage1; - else if(strncmp(obj["shadeType"].as(), "garage3", 7) == 0) - type = shade_types::garage3; - else if(strncmp(obj["shadeType"].as(), "blind", 5) == 0) - type = shade_types::blind; - else if(strncmp(obj["shadeType"].as(), "awning", 7) == 0) - type = shade_types::awning; - else if(strncmp(obj["shadeType"].as(), "shutter", 8) == 0) - type = shade_types::shutter; - else if(strncmp(obj["shadeType"].as(), "drycontact2", 12) == 0) - type = shade_types::drycontact2; - else if(strncmp(obj["shadeType"].as(), "drycontact", 11) == 0) - type = shade_types::drycontact; - } - else { - this->shadeType = static_cast(obj["shadeType"].as()); - } - } - if(!obj["proto"].isNull()) { - radio_proto proto = this->proto; - if(proto == radio_proto::GP_Relay || proto == radio_proto::GP_Remote) { - // Check to see if we are using the up and or down - // GPIOs anywhere else. - uint8_t upPin = !obj["gpioUp"].isNull() ? obj["gpioUp"].as() : this->gpioUp; - uint8_t downPin = !obj["gpioDown"].isNull() ? obj["gpioDown"].as() : this->gpioDown; - uint8_t myPin = !obj["gpioMy"].isNull() ? obj["gpioMy"].as() : this->gpioMy; - if(type == shade_types::drycontact || - ((type == shade_types::garage1 || type == shade_types::lgate1 || type == shade_types::cgate1 || type == shade_types::rgate1) - && proto == radio_proto::GP_Remote)) upPin = myPin = 255; - else if(type == shade_types::drycontact2) myPin = 255; - if(proto == radio_proto::GP_Relay) myPin = 255; - if(somfy.transceiver.config.enabled) { - if((upPin != 255 && somfy.transceiver.usesPin(upPin)) || - (downPin != 255 && somfy.transceiver.usesPin(downPin)) || - (myPin != 255 && somfy.transceiver.usesPin(myPin))) - ret = -10; - } -#ifndef CONFIG_IDF_TARGET_ESP32C6 - if(settings.connType == conn_types_t::ethernet || settings.connType == conn_types_t::ethernetpref) { - if((upPin != 255 && settings.Ethernet.usesPin(upPin)) || - (downPin != 255 && somfy.transceiver.usesPin(downPin)) || - (myPin != 255 && somfy.transceiver.usesPin(myPin))) - ret = -11; - } -#endif - if(ret == 0) { - for(uint8_t i = 0; i < SOMFY_MAX_SHADES; i++) { - SomfyShade *shade = &somfy.shades[i]; - if(shade->getShadeId() == this->getShadeId() || shade->getShadeId() == 255) continue; - if((upPin != 255 && shade->usesPin(upPin)) || - (downPin != 255 && shade->usesPin(downPin)) || - (myPin != 255 && shade->usesPin(myPin))){ - ret = -12; - break; - } - } - } - } - } - return ret; -} -int8_t SomfyShade::fromJSON(JsonObject &obj) { - int8_t err = this->validateJSON(obj); - if(err == 0) { - if(!obj["name"].isNull()) strlcpy(this->name, obj["name"], sizeof(this->name)); - if(!obj["roomId"].isNull()) this->roomId = obj["roomId"]; - if(!obj["upTime"].isNull()) this->upTime = obj["upTime"]; - if(!obj["downTime"].isNull()) this->downTime = obj["downTime"]; - if(!obj["remoteAddress"].isNull()) this->setRemoteAddress(obj["remoteAddress"]); - if(!obj["tiltTime"].isNull()) this->tiltTime = obj["tiltTime"]; - if(!obj["stepSize"].isNull()) this->stepSize = obj["stepSize"]; - if(!obj["hasTilt"].isNull()) this->tiltType = static_cast(obj["hasTilt"]) ? tilt_types::none : tilt_types::tiltmotor; - if(!obj["bitLength"].isNull()) this->bitLength = obj["bitLength"]; - if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); - if(!obj["sunSensor"].isNull()) this->setSunSensor(obj["sunSensor"]); - if(!obj["simMy"].isNull()) this->setSimMy(obj["simMy"]); - if(!obj["light"].isNull()) this->setLight(obj["light"]); - if(!obj["gpioFlags"].isNull()) this->gpioFlags = obj["gpioFlags"]; - if(!obj["gpioLLTrigger"].isNull()) { - if(obj["gpioLLTrigger"].as()) - this->gpioFlags |= (uint8_t)gpio_flags_t::LowLevelTrigger; - else - this->gpioFlags &= ~(uint8_t)gpio_flags_t::LowLevelTrigger; - } - - if(!obj["shadeType"].isNull()) { - if(obj["shadeType"].is()) { - if(strncmp(obj["shadeType"].as(), "roller", 7) == 0) - this->shadeType = shade_types::roller; - else if(strncmp(obj["shadeType"].as(), "ldrapery", 9) == 0) - this->shadeType = shade_types::ldrapery; - else if(strncmp(obj["shadeType"].as(), "rdrapery", 9) == 0) - this->shadeType = shade_types::rdrapery; - else if(strncmp(obj["shadeType"].as(), "cdrapery", 9) == 0) - this->shadeType = shade_types::cdrapery; - else if(strncmp(obj["shadeType"].as(), "garage1", 7) == 0) - this->shadeType = shade_types::garage1; - else if(strncmp(obj["shadeType"].as(), "garage3", 7) == 0) - this->shadeType = shade_types::garage3; - else if(strncmp(obj["shadeType"].as(), "blind", 5) == 0) - this->shadeType = shade_types::blind; - else if(strncmp(obj["shadeType"].as(), "awning", 7) == 0) - this->shadeType = shade_types::awning; - else if(strncmp(obj["shadeType"].as(), "shutter", 8) == 0) - this->shadeType = shade_types::shutter; - else if(strncmp(obj["shadeType"].as(), "drycontact2", 12) == 0) - this->shadeType = shade_types::drycontact2; - else if(strncmp(obj["shadeType"].as(), "drycontact", 11) == 0) - this->shadeType = shade_types::drycontact; - } - else { - this->shadeType = static_cast(obj["shadeType"].as()); - } - } - if(!obj["flipCommands"].isNull()) this->flipCommands = obj["flipCommands"].as(); - if(!obj["flipPosition"].isNull()) this->flipPosition = obj["flipPosition"].as(); - if(!obj["repeats"].isNull()) this->repeats = obj["repeats"]; - if(!obj["tiltType"].isNull()) { - if(obj["tiltType"].is()) { - if(strncmp(obj["tiltType"].as(), "none", 4) == 0) - this->tiltType = tilt_types::none; - else if(strncmp(obj["tiltType"].as(), "tiltmotor", 9) == 0) - this->tiltType = tilt_types::tiltmotor; - else if(strncmp(obj["tiltType"].as(), "integ", 5) == 0) - this->tiltType = tilt_types::integrated; - else if(strncmp(obj["tiltType"].as(), "tiltonly", 8) == 0) - this->tiltType = tilt_types::tiltonly; - } - else { - this->tiltType = static_cast(obj["tiltType"].as()); - } - } - if(!obj["linkedAddresses"].isNull()) { - uint32_t linkedAddresses[SOMFY_MAX_LINKED_REMOTES]; - memset(linkedAddresses, 0x00, sizeof(linkedAddresses)); - JsonArray arr = obj["linkedAddresses"]; - uint8_t i = 0; - for(uint32_t addr : arr) { - linkedAddresses[i++] = addr; - } - for(uint8_t j = 0; j < SOMFY_MAX_LINKED_REMOTES; j++) { - this->linkedRemotes[j].setRemoteAddress(linkedAddresses[j]); - } - } - if(!obj["flags"].isNull()) this->flags = obj["flags"]; - if(this->proto == radio_proto::GP_Remote || this->proto == radio_proto::GP_Relay) { - if(!obj["gpioUp"].isNull()) this->gpioUp = obj["gpioUp"]; - if(!obj["gpioDown"].isNull()) this->gpioDown = obj["gpioDown"]; - pinMode(this->gpioUp, OUTPUT); - pinMode(this->gpioDown, OUTPUT); - } - if(this->proto == radio_proto::GP_Remote) { - if(!obj["gpioMy"].isNull()) this->gpioMy = obj["gpioMy"]; - pinMode(this->gpioMy, OUTPUT); - } - } - return err; -} -bool SomfyRoom::fromJSON(JsonObject &obj) { - if(!obj["name"].isNull()) strlcpy(this->name, obj["name"], sizeof(this->name)); - if(!obj["sortOrder"].isNull()) this->sortOrder = obj["sortOrder"]; - return true; -} -bool SomfyGroup::fromJSON(JsonObject &obj) { - if(!obj["name"].isNull()) strlcpy(this->name, obj["name"], sizeof(this->name)); - if(!obj["roomId"].isNull()) this->roomId = obj["roomId"]; - if(!obj["remoteAddress"].isNull()) this->setRemoteAddress(obj["remoteAddress"]); - if(!obj["bitLength"].isNull()) this->bitLength = obj["bitLength"]; - if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); - if(!obj["flipCommands"].isNull()) this->flipCommands = obj["flipCommands"].as(); - - //if(!obj["sunSensor"].isNull()) this->hasSunSensor() = obj["sunSensor"]; This is calculated - if(!obj["repeats"].isNull()) this->repeats = obj["repeats"]; - if(!obj["linkedShades"].isNull()) { - uint8_t linkedShades[SOMFY_MAX_GROUPED_SHADES]; - memset(linkedShades, 0x00, sizeof(linkedShades)); - JsonArray arr = obj["linkedShades"]; - uint8_t i = 0; - for(uint8_t shadeId : arr) { - linkedShades[i++] = shadeId; - } - } - return true; -} void SomfyRemote::setRemoteAddress(uint32_t address) { this->m_remoteAddress = address; this->m_rollingCodeSynced = false; snprintf(this->m_remotePrefId, sizeof(this->m_remotePrefId), "_%lu", (unsigned long)this->m_remoteAddress); } uint32_t SomfyRemote::getRemoteAddress() { return this->m_remoteAddress; } @@ -2615,31 +2417,3 @@ SomfyLinkedRemote::SomfyLinkedRemote() {} -bool Transceiver::fromJSON(JsonObject& obj) { - if (!obj["config"].isNull()) { - JsonObject objConfig = obj["config"]; - // Parse into a copy so the radio task never sees a half updated config. - transceiver_config_t cfg = this->config; - cfg.fromJSON(objConfig); - this->setConfig(cfg); - } - return true; -} -void transceiver_config_t::fromJSON(JsonObject& obj) { - //Serial.print("Deserialize Radio JSON "); - if(!obj["type"].isNull()) this->type = obj["type"]; - if(!obj["CSNPin"].isNull()) this->CSNPin = obj["CSNPin"]; - if(!obj["MISOPin"].isNull()) this->MISOPin = obj["MISOPin"]; - if(!obj["MOSIPin"].isNull()) this->MOSIPin = obj["MOSIPin"]; - if(!obj["RXPin"].isNull()) this->RXPin = obj["RXPin"]; - if(!obj["SCKPin"].isNull()) this->SCKPin = obj["SCKPin"]; - if(!obj["TXPin"].isNull()) this->TXPin = obj["TXPin"]; - if(!obj["rxBandwidth"].isNull()) this->rxBandwidth = obj["rxBandwidth"]; // float - if(!obj["frequency"].isNull()) this->frequency = obj["frequency"]; // float - if(!obj["deviation"].isNull()) this->deviation = obj["deviation"]; // float - if(!obj["enabled"].isNull()) this->enabled = obj["enabled"]; - if(!obj["txPower"].isNull()) this->txPower = obj["txPower"]; - if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); - if(!obj["noiseDetection"].isNull()) this->noiseDetection = obj["noiseDetection"]; - ESP_LOGD(TAG, "SCK:%u MISO:%u MOSI:%u CSN:%u RX:%u TX:%u", this->SCKPin, this->MISOPin, this->MOSIPin, this->CSNPin, this->RXPin, this->TXPin); -} diff --git a/src/SomfyJson.cpp b/src/SomfyJson.cpp new file mode 100644 index 0000000..7ca7c30 --- /dev/null +++ b/src/SomfyJson.cpp @@ -0,0 +1,235 @@ +#include "esp_log.h" +#include "ConfigSettings.h" +#include "Somfy.h" + +static const char *TAG = "Somfy"; + +extern SomfyShadeController somfy; +extern ConfigSettings settings; + +int8_t SomfyShade::validateJSON(JsonObject &obj) { + int8_t ret = 0; + shade_types type = this->shadeType; + if(!obj["shadeType"].isNull()) { + if(obj["shadeType"].is()) { + if(strncmp(obj["shadeType"].as(), "roller", 7) == 0) + type = shade_types::roller; + else if(strncmp(obj["shadeType"].as(), "ldrapery", 9) == 0) + type = shade_types::ldrapery; + else if(strncmp(obj["shadeType"].as(), "rdrapery", 9) == 0) + type = shade_types::rdrapery; + else if(strncmp(obj["shadeType"].as(), "cdrapery", 9) == 0) + type = shade_types::cdrapery; + else if(strncmp(obj["shadeType"].as(), "garage1", 7) == 0) + type = shade_types::garage1; + else if(strncmp(obj["shadeType"].as(), "garage3", 7) == 0) + type = shade_types::garage3; + else if(strncmp(obj["shadeType"].as(), "blind", 5) == 0) + type = shade_types::blind; + else if(strncmp(obj["shadeType"].as(), "awning", 7) == 0) + type = shade_types::awning; + else if(strncmp(obj["shadeType"].as(), "shutter", 8) == 0) + type = shade_types::shutter; + else if(strncmp(obj["shadeType"].as(), "drycontact2", 12) == 0) + type = shade_types::drycontact2; + else if(strncmp(obj["shadeType"].as(), "drycontact", 11) == 0) + type = shade_types::drycontact; + } + else { + this->shadeType = static_cast(obj["shadeType"].as()); + } + } + if(!obj["proto"].isNull()) { + radio_proto proto = this->proto; + if(proto == radio_proto::GP_Relay || proto == radio_proto::GP_Remote) { + // Check to see if we are using the up and or down + // GPIOs anywhere else. + uint8_t upPin = !obj["gpioUp"].isNull() ? obj["gpioUp"].as() : this->gpioUp; + uint8_t downPin = !obj["gpioDown"].isNull() ? obj["gpioDown"].as() : this->gpioDown; + uint8_t myPin = !obj["gpioMy"].isNull() ? obj["gpioMy"].as() : this->gpioMy; + if(type == shade_types::drycontact || + ((type == shade_types::garage1 || type == shade_types::lgate1 || type == shade_types::cgate1 || type == shade_types::rgate1) + && proto == radio_proto::GP_Remote)) upPin = myPin = 255; + else if(type == shade_types::drycontact2) myPin = 255; + if(proto == radio_proto::GP_Relay) myPin = 255; + if(somfy.transceiver.config.enabled) { + if((upPin != 255 && somfy.transceiver.usesPin(upPin)) || + (downPin != 255 && somfy.transceiver.usesPin(downPin)) || + (myPin != 255 && somfy.transceiver.usesPin(myPin))) + ret = -10; + } +#ifndef CONFIG_IDF_TARGET_ESP32C6 + if(settings.connType == conn_types_t::ethernet || settings.connType == conn_types_t::ethernetpref) { + if((upPin != 255 && settings.Ethernet.usesPin(upPin)) || + (downPin != 255 && somfy.transceiver.usesPin(downPin)) || + (myPin != 255 && somfy.transceiver.usesPin(myPin))) + ret = -11; + } +#endif + if(ret == 0) { + for(uint8_t i = 0; i < SOMFY_MAX_SHADES; i++) { + SomfyShade *shade = &somfy.shades[i]; + if(shade->getShadeId() == this->getShadeId() || shade->getShadeId() == 255) continue; + if((upPin != 255 && shade->usesPin(upPin)) || + (downPin != 255 && shade->usesPin(downPin)) || + (myPin != 255 && shade->usesPin(myPin))){ + ret = -12; + break; + } + } + } + } + } + return ret; +} +int8_t SomfyShade::fromJSON(JsonObject &obj) { + int8_t err = this->validateJSON(obj); + if(err == 0) { + if(!obj["name"].isNull()) strlcpy(this->name, obj["name"], sizeof(this->name)); + if(!obj["roomId"].isNull()) this->roomId = obj["roomId"]; + if(!obj["upTime"].isNull()) this->upTime = obj["upTime"]; + if(!obj["downTime"].isNull()) this->downTime = obj["downTime"]; + if(!obj["remoteAddress"].isNull()) this->setRemoteAddress(obj["remoteAddress"]); + if(!obj["tiltTime"].isNull()) this->tiltTime = obj["tiltTime"]; + if(!obj["stepSize"].isNull()) this->stepSize = obj["stepSize"]; + if(!obj["hasTilt"].isNull()) this->tiltType = static_cast(obj["hasTilt"]) ? tilt_types::none : tilt_types::tiltmotor; + if(!obj["bitLength"].isNull()) this->bitLength = obj["bitLength"]; + if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); + if(!obj["sunSensor"].isNull()) this->setSunSensor(obj["sunSensor"]); + if(!obj["simMy"].isNull()) this->setSimMy(obj["simMy"]); + if(!obj["light"].isNull()) this->setLight(obj["light"]); + if(!obj["gpioFlags"].isNull()) this->gpioFlags = obj["gpioFlags"]; + if(!obj["gpioLLTrigger"].isNull()) { + if(obj["gpioLLTrigger"].as()) + this->gpioFlags |= (uint8_t)gpio_flags_t::LowLevelTrigger; + else + this->gpioFlags &= ~(uint8_t)gpio_flags_t::LowLevelTrigger; + } + + if(!obj["shadeType"].isNull()) { + if(obj["shadeType"].is()) { + if(strncmp(obj["shadeType"].as(), "roller", 7) == 0) + this->shadeType = shade_types::roller; + else if(strncmp(obj["shadeType"].as(), "ldrapery", 9) == 0) + this->shadeType = shade_types::ldrapery; + else if(strncmp(obj["shadeType"].as(), "rdrapery", 9) == 0) + this->shadeType = shade_types::rdrapery; + else if(strncmp(obj["shadeType"].as(), "cdrapery", 9) == 0) + this->shadeType = shade_types::cdrapery; + else if(strncmp(obj["shadeType"].as(), "garage1", 7) == 0) + this->shadeType = shade_types::garage1; + else if(strncmp(obj["shadeType"].as(), "garage3", 7) == 0) + this->shadeType = shade_types::garage3; + else if(strncmp(obj["shadeType"].as(), "blind", 5) == 0) + this->shadeType = shade_types::blind; + else if(strncmp(obj["shadeType"].as(), "awning", 7) == 0) + this->shadeType = shade_types::awning; + else if(strncmp(obj["shadeType"].as(), "shutter", 8) == 0) + this->shadeType = shade_types::shutter; + else if(strncmp(obj["shadeType"].as(), "drycontact2", 12) == 0) + this->shadeType = shade_types::drycontact2; + else if(strncmp(obj["shadeType"].as(), "drycontact", 11) == 0) + this->shadeType = shade_types::drycontact; + } + else { + this->shadeType = static_cast(obj["shadeType"].as()); + } + } + if(!obj["flipCommands"].isNull()) this->flipCommands = obj["flipCommands"].as(); + if(!obj["flipPosition"].isNull()) this->flipPosition = obj["flipPosition"].as(); + if(!obj["repeats"].isNull()) this->repeats = obj["repeats"]; + if(!obj["tiltType"].isNull()) { + if(obj["tiltType"].is()) { + if(strncmp(obj["tiltType"].as(), "none", 4) == 0) + this->tiltType = tilt_types::none; + else if(strncmp(obj["tiltType"].as(), "tiltmotor", 9) == 0) + this->tiltType = tilt_types::tiltmotor; + else if(strncmp(obj["tiltType"].as(), "integ", 5) == 0) + this->tiltType = tilt_types::integrated; + else if(strncmp(obj["tiltType"].as(), "tiltonly", 8) == 0) + this->tiltType = tilt_types::tiltonly; + } + else { + this->tiltType = static_cast(obj["tiltType"].as()); + } + } + if(!obj["linkedAddresses"].isNull()) { + uint32_t linkedAddresses[SOMFY_MAX_LINKED_REMOTES]; + memset(linkedAddresses, 0x00, sizeof(linkedAddresses)); + JsonArray arr = obj["linkedAddresses"]; + uint8_t i = 0; + for(uint32_t addr : arr) { + linkedAddresses[i++] = addr; + } + for(uint8_t j = 0; j < SOMFY_MAX_LINKED_REMOTES; j++) { + this->linkedRemotes[j].setRemoteAddress(linkedAddresses[j]); + } + } + if(!obj["flags"].isNull()) this->flags = obj["flags"]; + if(this->proto == radio_proto::GP_Remote || this->proto == radio_proto::GP_Relay) { + if(!obj["gpioUp"].isNull()) this->gpioUp = obj["gpioUp"]; + if(!obj["gpioDown"].isNull()) this->gpioDown = obj["gpioDown"]; + pinMode(this->gpioUp, OUTPUT); + pinMode(this->gpioDown, OUTPUT); + } + if(this->proto == radio_proto::GP_Remote) { + if(!obj["gpioMy"].isNull()) this->gpioMy = obj["gpioMy"]; + pinMode(this->gpioMy, OUTPUT); + } + } + return err; +} +bool SomfyRoom::fromJSON(JsonObject &obj) { + if(!obj["name"].isNull()) strlcpy(this->name, obj["name"], sizeof(this->name)); + if(!obj["sortOrder"].isNull()) this->sortOrder = obj["sortOrder"]; + return true; +} +bool SomfyGroup::fromJSON(JsonObject &obj) { + if(!obj["name"].isNull()) strlcpy(this->name, obj["name"], sizeof(this->name)); + if(!obj["roomId"].isNull()) this->roomId = obj["roomId"]; + if(!obj["remoteAddress"].isNull()) this->setRemoteAddress(obj["remoteAddress"]); + if(!obj["bitLength"].isNull()) this->bitLength = obj["bitLength"]; + if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); + if(!obj["flipCommands"].isNull()) this->flipCommands = obj["flipCommands"].as(); + + //if(!obj["sunSensor"].isNull()) this->hasSunSensor() = obj["sunSensor"]; This is calculated + if(!obj["repeats"].isNull()) this->repeats = obj["repeats"]; + if(!obj["linkedShades"].isNull()) { + uint8_t linkedShades[SOMFY_MAX_GROUPED_SHADES]; + memset(linkedShades, 0x00, sizeof(linkedShades)); + JsonArray arr = obj["linkedShades"]; + uint8_t i = 0; + for(uint8_t shadeId : arr) { + linkedShades[i++] = shadeId; + } + } + return true; +} +bool Transceiver::fromJSON(JsonObject& obj) { + if (!obj["config"].isNull()) { + JsonObject objConfig = obj["config"]; + // Parse into a copy so the radio task never sees a half updated config. + transceiver_config_t cfg = this->config; + cfg.fromJSON(objConfig); + this->setConfig(cfg); + } + return true; +} +void transceiver_config_t::fromJSON(JsonObject& obj) { + //Serial.print("Deserialize Radio JSON "); + if(!obj["type"].isNull()) this->type = obj["type"]; + if(!obj["CSNPin"].isNull()) this->CSNPin = obj["CSNPin"]; + if(!obj["MISOPin"].isNull()) this->MISOPin = obj["MISOPin"]; + if(!obj["MOSIPin"].isNull()) this->MOSIPin = obj["MOSIPin"]; + if(!obj["RXPin"].isNull()) this->RXPin = obj["RXPin"]; + if(!obj["SCKPin"].isNull()) this->SCKPin = obj["SCKPin"]; + if(!obj["TXPin"].isNull()) this->TXPin = obj["TXPin"]; + if(!obj["rxBandwidth"].isNull()) this->rxBandwidth = obj["rxBandwidth"]; // float + if(!obj["frequency"].isNull()) this->frequency = obj["frequency"]; // float + if(!obj["deviation"].isNull()) this->deviation = obj["deviation"]; // float + if(!obj["enabled"].isNull()) this->enabled = obj["enabled"]; + if(!obj["txPower"].isNull()) this->txPower = obj["txPower"]; + if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); + if(!obj["noiseDetection"].isNull()) this->noiseDetection = obj["noiseDetection"]; + ESP_LOGD(TAG, "SCK:%u MISO:%u MOSI:%u CSN:%u RX:%u TX:%u", this->SCKPin, this->MISOPin, this->MOSIPin, this->CSNPin, this->RXPin, this->TXPin); +}