diff --git a/ConfigFile.cpp b/ConfigFile.cpp index 0fb4a3b..21d6da4 100644 --- a/ConfigFile.cpp +++ b/ConfigFile.cpp @@ -6,9 +6,9 @@ extern Preferences pref; -#define SHADE_HDR_VER 9 +#define SHADE_HDR_VER 10 #define SHADE_HDR_SIZE 16 -#define SHADE_REC_SIZE 242 +#define SHADE_REC_SIZE 248 bool ConfigFile::begin(const char* filename, bool readOnly) { this->file = LittleFS.open(filename, readOnly ? "r" : "w"); @@ -330,8 +330,12 @@ bool ShadeConfigFile::loadFile(SomfyShadeController *s, const char *filename) { shade->target = floor(shade->currentPos); shade->tiltTarget = floor(shade->currentTiltPos); if(this->header.version >= 9) { - shade->inverted = this->readBool(false); + shade->flipCommands = this->readBool(false); } + if(this->header.version >= 10) { + shade->flipPosition = this->readBool(false); + } + if(shade->getShadeId() == 255) shade->clear(); } pref.end(); if(opened) { @@ -378,7 +382,8 @@ bool ShadeConfigFile::writeShadeRecord(SomfyShade *shade) { this->writeFloat(0.0f, 5); // currentPos this->writeFloat(0.0f, 5); // currentTiltPos } - this->writeBool(shade->inverted, CFG_REC_END); + this->writeBool(shade->flipCommands); + this->writeBool(shade->flipPosition, CFG_REC_END); return true; } bool ShadeConfigFile::exists() { return LittleFS.exists("/shades.cfg"); } diff --git a/MQTT.cpp b/MQTT.cpp index 24fc5b3..bc3c4c4 100644 --- a/MQTT.cpp +++ b/MQTT.cpp @@ -226,6 +226,10 @@ bool MQTTClass::publish(const char *topic, uint16_t val) { snprintf(g_content, sizeof(g_content), "%u", val); return this->publish(topic, g_content); } +bool MQTTClass::publish(const char *topic, bool val) { + snprintf(g_content, sizeof(g_content), "%s", val ? "true" : "false"); + return this->publish(topic, g_content); +} bool MQTTClass::connected() { if(settings.MQTT.enabled) return mqttClient.connected(); return false; diff --git a/MQTT.h b/MQTT.h index 338c3da..de90f01 100644 --- a/MQTT.h +++ b/MQTT.h @@ -22,6 +22,7 @@ class MQTTClass { bool publish(const char *topic, int8_t val); bool publish(const char *topic, uint32_t val); bool publish(const char *topic, uint16_t val); + bool publish(const char *topic, bool val); bool subscribe(const char *topic); bool unsubscribe(const char *topic); static void receive(const char *topic, byte *payload, uint32_t length); diff --git a/Network.cpp b/Network.cpp index 851c0af..13228e5 100644 --- a/Network.cpp +++ b/Network.cpp @@ -172,9 +172,9 @@ void Network::setConnected(conn_types connType) { SSDP.setURL(0, "/"); if(MDNS.begin(settings.hostname)) { Serial.printf("MDNS Responder Started: serverId=%s\n", settings.serverId); - MDNS.addService("http", "tcp", 80); - MDNS.addServiceTxt("http", "tcp", "board", "ESP32"); - MDNS.addServiceTxt("http", "tcp", "model", "ESPSomfyRTS"); + //MDNS.addService("http", "tcp", 80); + //MDNS.addServiceTxt("http", "tcp", "board", "ESP32"); + //MDNS.addServiceTxt("http", "tcp", "model", "ESPSomfyRTS"); MDNS.addService("espsomfy_rts", "tcp", 8080); MDNS.addServiceTxt("espsomfy_rts", "tcp", "serverId", String(settings.serverId)); diff --git a/Somfy.cpp b/Somfy.cpp index 6399ab9..4387108 100644 --- a/Somfy.cpp +++ b/Somfy.cpp @@ -506,6 +506,51 @@ SomfyShade * SomfyShadeController::getShadeById(uint8_t shadeId) { } return nullptr; } +void SomfyShade::clear() { + this->setShadeId(255); + this->setRemoteAddress(0); + this->moveStart = 0; + this->tiltStart = 0; + this->noSunStart = 0; + this->sunStart = 0; + this->windStart = 0; + this->windLast = 0; + this->noWindStart = 0; + this->noSunDone = true; + this->sunDone = true; + this->windDone = true; + this->noWindDone = true; + this->startPos = 0.0f; + this->startTiltPos = 0.0f; + this->settingMyPos = false; + this->settingPos = false; + this->settingTiltPos = false; + this->awaitMy = 0; + this->flipPosition = false; + this->flipCommands = false; + this->lastRollingCode = 0; + this->shadeType = shade_types::roller; + this->tiltType = tilt_types::none; + this->txQueue.clear(); + this->currentPos = 0.0f; + this->currentTiltPos = 0.0f; + this->direction = 0; + this->tiltDirection = 0; + this->target = 0.0f; + this->tiltTarget = 0.0f; + this->myPos = -1.0f; + this->myTiltPos = -1.0f; + this->bitLength = somfy.transceiver.config.type; + this->proto = somfy.transceiver.config.proto; + for(uint8_t i = 0; i < SOMFY_MAX_LINKED_REMOTES; i++) + this->linkedRemotes[i].setRemoteAddress(0); + this->paired = false; + this->name[0] = 0x00; + this->upTime = 10000; + this->downTime = 10000; + this->tiltTime = 7000; + this->stepSize = 100; +} bool SomfyShade::linkRemote(uint32_t address, uint16_t rollingCode) { // Check to see if the remote is already linked. If it is // just return true after setting the rolling code @@ -963,31 +1008,34 @@ void SomfyShade::publish() { snprintf(topic, sizeof(topic), "shades/%u/remoteAddress", this->shadeId); mqtt.publish(topic, this->getRemoteAddress()); snprintf(topic, sizeof(topic), "shades/%u/position", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->currentPos))); + mqtt.publish(topic, this->transformPosition(this->currentPos)); snprintf(topic, sizeof(topic), "shades/%u/direction", this->shadeId); mqtt.publish(topic, this->direction); snprintf(topic, sizeof(topic), "shades/%u/target", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->target))); + mqtt.publish(topic, this->transformPosition(this->target)); snprintf(topic, sizeof(topic), "shades/%u/lastRollingCode", this->shadeId); mqtt.publish(topic, this->lastRollingCode); snprintf(topic, sizeof(topic), "shades/%u/mypos", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->myPos))); + mqtt.publish(topic, this->transformPosition(this->myPos)); snprintf(topic, sizeof(topic), "shades/%u/myTiltPos", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->myTiltPos))); + mqtt.publish(topic, this->transformPosition(this->myTiltPos)); snprintf(topic, sizeof(topic), "shades/%u/shadeType", this->shadeId); mqtt.publish(topic, static_cast(this->shadeType)); snprintf(topic, sizeof(topic), "shades/%u/tiltType", this->shadeId); mqtt.publish(topic, static_cast(this->tiltType)); snprintf(topic, sizeof(topic), "shades/%u/flags", this->shadeId); mqtt.publish(topic, this->flags); - + snprintf(topic, sizeof(topic), "shades/%u/flipCommands", this->shadeId); + mqtt.publish(topic, this->flipCommands); + snprintf(topic, sizeof(topic), "shades/%u/flipPosition", this->shadeId); + mqtt.publish(topic, this->flipPosition); if(this->tiltType != tilt_types::none) { snprintf(topic, sizeof(topic), "shades/%u/tiltDirection", this->shadeId); mqtt.publish(topic, this->tiltDirection); snprintf(topic, sizeof(topic), "shades/%u/tiltPosition", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->currentTiltPos))); + mqtt.publish(topic, this->transformPosition(this->currentTiltPos)); snprintf(topic, sizeof(topic), "shades/%u/tiltTarget", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->tiltTarget))); + mqtt.publish(topic, this->transformPosition(this->tiltTarget)); } else if (this->shadeType == shade_types::awning) { const uint8_t sunFlag = !!(this->flags & static_cast(somfy_flags_t::SunFlag)); @@ -1004,37 +1052,43 @@ void SomfyShade::publish() { } } void SomfyShade::emitState(const char *evt) { this->emitState(255, evt); } +int8_t SomfyShade::transformPosition(float fpos) { return static_cast(this->flipPosition && fpos >= 0.00f ? floor(100.0f - fpos) : floor(fpos)); } void SomfyShade::emitState(uint8_t num, const char *evt) { - char buf[320]; + char buf[420]; if(this->tiltType != tilt_types::none) - snprintf(buf, sizeof(buf), "{\"shadeId\":%d,\"type\":%u,\"remoteAddress\":%d,\"name\":\"%s\",\"direction\":%d,\"position\":%d,\"target\":%d,\"mypos\":%d,\"myTiltPos\":%d,\"tiltType\":%u,\"tiltDirection\":%d,\"tiltTarget\":%d,\"tiltPosition\":%d,\"flags\":%d}", - this->shadeId, static_cast(this->shadeType), this->getRemoteAddress(), this->name, this->direction, static_cast(floor(this->currentPos)), static_cast(floor(this->target)), static_cast(floor(this->myPos)), static_cast(this->myTiltPos), static_cast(this->tiltType), this->tiltDirection, static_cast(floor(this->tiltTarget)), static_cast(floor(this->currentTiltPos)),this->flags); + snprintf(buf, sizeof(buf), "{\"shadeId\":%d,\"type\":%u,\"remoteAddress\":%d,\"name\":\"%s\",\"direction\":%d,\"position\":%d,\"target\":%d,\"mypos\":%d,\"myTiltPos\":%d,\"tiltType\":%u,\"tiltDirection\":%d,\"tiltTarget\":%d,\"tiltPosition\":%d,\"flipCommands\":%s,\"flipPosition\":%s,\"flags\":%d}", + this->shadeId, static_cast(this->shadeType), this->getRemoteAddress(), this->name, this->direction, + this->transformPosition(this->currentPos), this->transformPosition(this->target), this->transformPosition(this->myPos), this->transformPosition(this->myTiltPos), static_cast(this->tiltType), this->tiltDirection, + this->transformPosition(this->tiltTarget), this->transformPosition(this->currentTiltPos), + this->flipCommands ? "true" : "false", this->flipPosition ? "true": "false", this->flags); else - snprintf(buf, sizeof(buf), "{\"shadeId\":%d,\"type\":%u,\"remoteAddress\":%d,\"name\":\"%s\",\"direction\":%d,\"position\":%d,\"target\":%d,\"mypos\":%d,\"tiltType\":%u,\"flags\":%d}", - this->shadeId, static_cast(this->shadeType), this->getRemoteAddress(), this->name, this->direction, static_cast(floor(this->currentPos)), static_cast(floor(this->target)), static_cast(floor(this->myPos)), static_cast(this->tiltType), this->flags); + snprintf(buf, sizeof(buf), "{\"shadeId\":%d,\"type\":%u,\"remoteAddress\":%d,\"name\":\"%s\",\"direction\":%d,\"position\":%d,\"target\":%d,\"mypos\":%d,\"tiltType\":%u,\"flipCommands\":%s,\"flipPosition\":%s,\"flags\":%d}", + this->shadeId, static_cast(this->shadeType), this->getRemoteAddress(), this->name, this->direction, + this->transformPosition(this->currentPos), this->transformPosition(this->target), this->transformPosition(this->myPos), + static_cast(this->tiltType), this->flipCommands ? "true" : "false", this->flipPosition ? "true": "false", this->flags); if(num >= 255) sockEmit.sendToClients(evt, buf); else sockEmit.sendToClient(num, evt, buf); if(mqtt.connected()) { char topic[32]; snprintf(topic, sizeof(topic), "shades/%u/position", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->currentPos))); + mqtt.publish(topic, this->transformPosition(this->currentPos)); snprintf(topic, sizeof(topic), "shades/%u/direction", this->shadeId); mqtt.publish(topic, this->direction); snprintf(topic, sizeof(topic), "shades/%u/target", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->target))); + mqtt.publish(topic, this->transformPosition(this->target)); snprintf(topic, sizeof(topic), "shades/%u/lastRollingCode", this->shadeId); mqtt.publish(topic, this->lastRollingCode); snprintf(topic, sizeof(topic), "shades/%u/mypos", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->myPos))); + mqtt.publish(topic, this->transformPosition(this->myPos)); snprintf(topic, sizeof(topic), "shades/%u/tiltType", this->shadeId); mqtt.publish(topic, static_cast(this->tiltType)); if(this->tiltType != tilt_types::none) { snprintf(topic, sizeof(topic), "shades/%u/myTiltPos", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->myTiltPos))); + mqtt.publish(topic, this->transformPosition(this->myTiltPos)); snprintf(topic, sizeof(topic), "shades/%u/tiltPosition", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->currentTiltPos))); + mqtt.publish(topic, this->transformPosition(this->currentTiltPos)); snprintf(topic, sizeof(topic), "shades/%u/tiltTarget", this->shadeId); - mqtt.publish(topic, static_cast(floor(this->tiltTarget))); + mqtt.publish(topic, this->transformPosition(this->tiltTarget)); } else if (this->shadeType == shade_types::awning) { const uint8_t sunFlag = !!(this->flags & static_cast(somfy_flags_t::SunFlag)); @@ -1645,7 +1699,8 @@ bool SomfyShade::fromJSON(JsonObject &obj) { this->shadeType = static_cast(obj["shadeType"].as()); } } - if(obj.containsKey("inverted")) this->inverted = obj["inverted"].as(); + if(obj.containsKey("flipCommands")) this->flipCommands = obj["flipCommands"].as(); + if(obj.containsKey("flipPosition")) this->flipPosition = obj["flipPosition"].as(); if(obj.containsKey("tiltType")) { if(obj["tiltType"].is()) { if(strncmp(obj["tiltType"].as(), "none", 4) == 0) @@ -1689,15 +1744,15 @@ bool SomfyShade::toJSON(JsonObject &obj) { obj["paired"] = this->paired; //obj["remotePrefId"] = this->getRemotePrefId(); obj["lastRollingCode"] = this->lastRollingCode; - obj["position"] = static_cast(floor(this->currentPos)); - obj["tiltPosition"] = static_cast(floor(this->currentTiltPos)); + obj["position"] = this->transformPosition(this->currentPos); + obj["tiltPosition"] = this->transformPosition(this->currentTiltPos); obj["tiltDirection"] = this->tiltDirection; obj["tiltTime"] = this->tiltTime; obj["stepSize"] = this->stepSize; - obj["tiltTarget"] = static_cast(floor(this->tiltTarget)); - obj["target"] = this->target; - obj["myPos"] = static_cast(floor(this->myPos)); - obj["myTiltPos"] = static_cast(floor(this->myTiltPos)); + obj["tiltTarget"] = this->transformPosition(this->tiltTarget); + obj["target"] = this->transformPosition(this->target); + obj["myPos"] = this->transformPosition(this->myPos); + obj["myTiltPos"] = this->transformPosition(this->myTiltPos); obj["direction"] = this->direction; obj["tiltType"] = static_cast(this->tiltType); obj["tiltTime"] = this->tiltTime; @@ -1705,7 +1760,8 @@ bool SomfyShade::toJSON(JsonObject &obj) { obj["bitLength"] = this->bitLength; obj["proto"] = static_cast(this->proto); obj["flags"] = this->flags; - obj["inverted"] = this->inverted; + obj["flipCommands"] = this->flipCommands; + obj["flipPosition"] = this->flipPosition; SomfyRemote::toJSON(obj); JsonArray arr = obj.createNestedArray("linkedRemotes"); for(uint8_t i = 0; i < SOMFY_MAX_LINKED_REMOTES; i++) { @@ -1863,7 +1919,7 @@ SomfyShade *SomfyShadeController::addShade() { return shade; } somfy_commands SomfyRemote::transformCommand(somfy_commands cmd) { - if(this->inverted) { + if(this->flipCommands) { switch(cmd) { case somfy_commands::Up: return somfy_commands::Down; @@ -1935,14 +1991,7 @@ bool SomfyShadeController::deleteShade(uint8_t shadeId) { for(uint8_t i = 0; i < SOMFY_MAX_SHADES; i++) { if(this->shades[i].getShadeId() == shadeId) { shades[i].emitState("shadeRemoved"); - this->shades[i].setShadeId(255); - this->shades[i].currentPos = 0; - this->shades[i].currentTiltPos = 0; - this->shades[i].myPos = -1.0f; - this->shades[i].myTiltPos = -1.0f; - this->shades[i].shadeType = shade_types::roller; - this->shades[i].tiltType = tilt_types::none; - this->shades[i].flags = 0; + this->shades[i].clear(); } } if(this->useNVS()) { diff --git a/Somfy.h b/Somfy.h index e142444..fd447a2 100644 --- a/Somfy.h +++ b/Somfy.h @@ -167,7 +167,8 @@ class SomfyRemote { uint32_t m_remoteAddress = 0; public: radio_proto proto = radio_proto::RTS; - bool inverted = false; + bool flipCommands = false; + uint8_t flags = 0; uint8_t bitLength = 0; char *getRemotePrefId() {return m_remotePrefId;} @@ -205,6 +206,7 @@ class SomfyShade : public SomfyRemote { bool settingTiltPos = false; uint32_t awaitMy = 0; public: + bool flipPosition = false; shade_types shadeType = shade_types::roller; tilt_types tiltType = tilt_types::none; void load(); @@ -215,10 +217,10 @@ class SomfyShade : public SomfyRemote { //uint16_t movement = 0; int8_t direction = 0; // 0 = stopped, 1=down, -1=up. int8_t tiltDirection = 0; // 0=stopped, 1=clockwise, -1=counter clockwise - float target = 0.0; - float tiltTarget = 0.0; - float myPos = -1.0; - float myTiltPos = -1.0; + float target = 0.0f; + float tiltTarget = 0.0f; + float myPos = -1.0f; + float myTiltPos = -1.0f; SomfyLinkedRemote linkedRemotes[SOMFY_MAX_LINKED_REMOTES]; bool paired = false; bool fromJSON(JsonObject &obj); @@ -254,6 +256,8 @@ class SomfyShade : public SomfyRemote { void commitShadePosition(); void commitTiltPosition(); void commitMyPosition(); + void clear(); + int8_t transformPosition(float fpos); }; struct transceiver_config_t { diff --git a/SomfyController.ino.esp32.bin b/SomfyController.ino.esp32.bin index 12662fe..607a82c 100644 Binary files a/SomfyController.ino.esp32.bin and b/SomfyController.ino.esp32.bin differ diff --git a/SomfyController.littlefs.bin b/SomfyController.littlefs.bin index f2343aa..b88c3a3 100644 Binary files a/SomfyController.littlefs.bin and b/SomfyController.littlefs.bin differ diff --git a/Web.cpp b/Web.cpp index 5ffe9db..ff0f418 100644 --- a/Web.cpp +++ b/Web.cpp @@ -167,7 +167,7 @@ void Web::begin() { Serial.println(apiServer.arg("plain")); // Send the command to the shade. if(target <= 100) - shade->moveToTarget(target); + shade->moveToTarget(shade->transformPosition(target)); else shade->sendCommand(command, repeat); DynamicJsonDocument sdoc(512); @@ -231,7 +231,7 @@ void Web::begin() { Serial.println(apiServer.arg("plain")); // Send the command to the shade. if(target <= 100) - shade->moveToTiltTarget(target); + shade->moveToTiltTarget(shade->transformPosition(target)); else shade->sendTiltCommand(command); DynamicJsonDocument sdoc(512); @@ -688,7 +688,7 @@ void Web::begin() { Serial.println(server.arg("plain")); // Send the command to the shade. if(target <= 100) - shade->moveToTiltTarget(target); + shade->moveToTiltTarget(shade->transformPosition(target)); else shade->sendTiltCommand(command); DynamicJsonDocument sdoc(512); @@ -755,7 +755,7 @@ void Web::begin() { Serial.println(server.arg("plain")); // Send the command to the shade. if(target <= 100) - shade->moveToTarget(target); + shade->moveToTarget(shade->transformPosition(target)); else shade->sendCommand(command, repeat); DynamicJsonDocument sdoc(512); @@ -813,7 +813,7 @@ void Web::begin() { if(tilt < 0) tilt = shade->myPos; if(shade->tiltType == tilt_types::none) tilt = -1; if(pos >= 0 && pos <= 100) - shade->setMyPosition(pos, tilt); + shade->setMyPosition(shade->transformPosition(pos), shade->transformPosition(tilt)); DynamicJsonDocument sdoc(512); JsonObject sobj = sdoc.to(); shade->toJSON(sobj); diff --git a/data/index.html b/data/index.html index 3e735e4..1a84913 100644 --- a/data/index.html +++ b/data/index.html @@ -296,13 +296,18 @@ -
+
- - + + +
+
+
+
+ +
-
` : '
'; divCtl += `
`; divCtl += `
`; @@ -1304,7 +1304,7 @@ class Somfy { console.log(state); let icons = document.querySelectorAll(`.somfy-shade-icon[data-shadeid="${state.shadeId}"]`); for (let i = 0; i < icons.length; i++) { - icons[i].style.setProperty('--shade-position', `${state.position}%`); + icons[i].style.setProperty('--shade-position', `${state.flipPosition ? 100 - state.position : state.position}%`); } if (state.tiltType !== 0) { let tilts = document.querySelectorAll(`.icss-window-tilt[data-shadeid="${state.shadeId}"]`); @@ -1323,7 +1323,7 @@ class Somfy { divs[i].setAttribute('data-direction', state.direction); divs[i].setAttribute('data-position', state.position); divs[i].setAttribute('data-target', state.target); - divs[i].setAttribute('data-mypos', state.mypos); + divs[i].setAttribute('data-mypos', state.myPos); divs[i].setAttribute('data-windy', (state.flags & 0x10) === 0x10 ? 'true' : 'false'); divs[i].setAttribute('data-sunny', (state.flags & 0x20) === 0x20 ? 'true' : 'false'); if (typeof state.myTiltPos !== 'undefined') divs[i].setAttribute('data-mytiltpos', state.myTiltPos); @@ -1486,7 +1486,8 @@ class Somfy { document.getElementById('selShadeProto').value = shade.proto || 0; document.getElementById('slidStepSize').value = shade.stepSize || 100; document.getElementById('spanStepSize').innerHTML = shade.stepSize.fmt('#,##0'); - document.getElementById('cbInverted').value = shade.inverted || false; + document.getElementById('cbFlipCommands').value = shade.flipCommands || false; + document.getElementById('cbFlipPosition').value = shade.flipPosition || false; } }); } @@ -1520,7 +1521,8 @@ class Somfy { document.getElementById('spanStepSize').innerHTML = shade.stepSize.fmt('#,##0'); document.getElementById('fldTiltTime').value = shade.tiltTime; document.getElementById('selTiltType').value = shade.tiltType; - document.getElementById('cbInverted').checked = shade.inverted; + document.getElementById('cbFlipCommands').checked = shade.flipCommands; + document.getElementById('cbFlipPosition').checked = shade.flipPosition; this.onShadeTypeChanged(document.getElementById('selShadeType')); let ico = document.getElementById('icoShade'); switch (shade.shadeType) { @@ -1537,8 +1539,8 @@ class Somfy { tilt.style.display = shade.tiltType !== 0 ? '' : 'none'; tilt.setAttribute('data-tiltposition', shade.tiltPosition); tilt.setAttribute('data-shadeid', shade.shadeId); - ico.style.setProperty('--shade-position', `${shade.position}%`); - ico.style.setProperty('--tilt-position', `${shade.tiltPosition}%`); + ico.style.setProperty('--shade-position', `${shade.flipPosition ? 100 - shade.position : shade.position}%`); + ico.style.setProperty('--tilt-position', `${shade.flipPosition ? 100 - shade.tiltPosition : shade.tiltPosition}%`); ico.setAttribute('data-shadeid', shade.shadeId); somfy.onShadeBitLengthChanged(document.getElementById('selShadeBitLength')); document.getElementById('btnSetRollingCode').style.display = 'inline-block'; @@ -1579,7 +1581,8 @@ class Somfy { bitLength: parseInt(document.getElementById('selShadeBitLength').value, 10) || 56, proto: parseInt(document.getElementById('selShadeProto').value, 10) || 0, stepSize: parseInt(document.getElementById('slidStepSize').value, 10) || 100, - inverted: document.getElementById('cbInverted').checked + flipCommands: document.getElementById('cbFlipCommands').checked, + flipPosition: document.getElementById('cbFlipPosition').checked }; if (obj.shadeType === 1) { obj.tiltType = parseInt(document.getElementById('selTiltType').value, 10); @@ -1687,7 +1690,7 @@ class Somfy { document.getElementsByName('shadeUpTime')[0].value = shade.upTime; document.getElementsByName('shadeDownTime')[0].value = shade.downTime; let ico = document.getElementById('icoShade'); - ico.style.setProperty('--shade-position', `${shade.position}%`); + ico.style.setProperty('--shade-position', `${shade.flipPosition ? 100 - shade.position : shade.position}%`); ico.setAttribute('data-shadeid', shade.shadeId); if (shade.paired) { document.getElementById('btnUnpairShade').style.display = 'inline-block'; @@ -1719,7 +1722,7 @@ class Somfy { document.getElementsByName('shadeUpTime')[0].value = shade.upTime; document.getElementsByName('shadeDownTime')[0].value = shade.downTime; let ico = document.getElementById('icoShade'); - ico.style.setProperty('--shade-position', `${shade.position}%`); + ico.style.setProperty('--shade-position', `${shade.flipPosition ? 100 - shade.position : shade.position}%`); ico.setAttribute('data-shadeid', shade.shadeId); if (shade.paired) { document.getElementById('btnUnpairShade').style.display = 'inline-block'; @@ -1797,7 +1800,7 @@ class Somfy { document.getElementsByName('shadeUpTime')[0].value = shade.upTime; document.getElementsByName('shadeDownTime')[0].value = shade.downTime; let ico = document.getElementById('icoShade'); - ico.style.setProperty('--shade-position', `${shade.position}%`); + ico.style.setProperty('--shade-position', `${shade.flipPosition ? 100 - shade.position : shade.position}%`); ico.setAttribute('data-shadeid', shade.shadeId); if (shade.paired) { document.getElementById('btnUnpairShade').style.display = 'inline-block';