diff --git a/ConfigFile.cpp b/ConfigFile.cpp index 4b33b98..aa27ea4 100644 --- a/ConfigFile.cpp +++ b/ConfigFile.cpp @@ -6,9 +6,9 @@ extern Preferences pref; -#define SHADE_HDR_VER 6 +#define SHADE_HDR_VER 7 #define SHADE_HDR_SIZE 16 -#define SHADE_REC_SIZE 228 +#define SHADE_REC_SIZE 232 bool ConfigFile::begin(const char* filename, bool readOnly) { this->file = LittleFS.open(filename, readOnly ? "r" : "w"); @@ -285,7 +285,9 @@ bool ShadeConfigFile::loadFile(SomfyShadeController *s, const char *filename) { shade->tiltType = this->readBool(false) ? tilt_types::none : tilt_types::tiltmotor; else shade->tiltType = static_cast(this->readUInt8(0)); - + if(this->header.version > 6) { + shade->proto = static_cast(this->readUInt8(0)); + } if(this->header.version > 1) { shade->bitLength = this->readUInt8(56); } @@ -345,6 +347,7 @@ bool ShadeConfigFile::writeShadeRecord(SomfyShade *shade) { this->writeUInt32(shade->getRemoteAddress()); this->writeString(shade->name, sizeof(shade->name)); this->writeUInt8(static_cast(shade->tiltType)); + this->writeUInt8(static_cast(shade->proto)); this->writeUInt8(shade->bitLength); this->writeUInt32(shade->upTime); this->writeUInt32(shade->downTime); diff --git a/ConfigSettings.h b/ConfigSettings.h index 61ca78d..bea2f18 100644 --- a/ConfigSettings.h +++ b/ConfigSettings.h @@ -3,7 +3,7 @@ #ifndef configsettings_h #define configsettings_h -#define FW_VERSION "v1.5.4" +#define FW_VERSION "v1.6.0beta" enum DeviceStatus { DS_OK = 0, DS_ERROR = 1, diff --git a/Somfy.cpp b/Somfy.cpp index 0e8565c..e40a25f 100644 --- a/Somfy.cpp +++ b/Somfy.cpp @@ -120,6 +120,23 @@ void somfy_frame_t::decodeFrame(byte* frame) { // Pull in the data for an 80-bit step command. if(this->cmd == somfy_commands::StepDown) this->cmd = (somfy_commands)((decoded[1] >> 4) | ((decoded[8] & 0x08) << 4)); + if(this->cmd == somfy_commands::RTWProto) { + this->proto = radio_proto::RTW; + switch(this->encKey) { + case 140: + this->cmd = somfy_commands::Prog; + break; + case 134: + this->cmd = somfy_commands::Up; + break; + case 133: + this->cmd = somfy_commands::My; + break; + case 136: + this->cmd = somfy_commands::Down; + break; + } + } this->rollingCode = decoded[3] + (decoded[2] << 8); this->remoteAddress = (decoded[6] + (decoded[5] << 8) + (decoded[4] << 16)); this->valid = this->checksum == checksum && this->remoteAddress > 0 && this->remoteAddress < 16777215 && this->rollingCode > 0; @@ -141,7 +158,7 @@ void somfy_frame_t::decodeFrame(byte* frame) { case somfy_commands::UnknownC: case somfy_commands::UnknownD: case somfy_commands::UnknownE: - case somfy_commands::UnknownF: + case somfy_commands::RTWProto: this->valid = false; break; case somfy_commands::StepUp: @@ -223,22 +240,42 @@ void somfy_frame_t::encodeFrame(byte *frame) { frame[7] = 132; frame[8] = 0; frame[9] = 29; - switch(this->cmd) { - case somfy_commands::StepUp: - frame[7] = 132; - frame[8] = 56; - frame[9] = 22; - break; - case somfy_commands::StepDown: - frame[7] = 132; - frame[8] = 48; - frame[9] = 30; - break; - case somfy_commands::Prog: - frame[7] = 196; - frame[8] = 0; - frame[9] = 25; - break; + // Ok so if this is an RTW things are a bit different. + if(this->proto == radio_proto::RTW) { + frame[1] = 0xF0; + switch(this->cmd) { + case somfy_commands::Prog: + frame[0] = 140; + break; + case somfy_commands::Up: + frame[0] = 134; + break; + case somfy_commands::Down: + frame[0] = 136; + break; + case somfy_commands::My: + frame[0] = 133; + break; + } + } + else { + switch(this->cmd) { + case somfy_commands::StepUp: + frame[7] = 132; + frame[8] = 56; + frame[9] = 22; + break; + case somfy_commands::StepDown: + frame[7] = 132; + frame[8] = 48; + frame[9] = 30; + break; + case somfy_commands::Prog: + frame[7] = 196; + frame[8] = 0; + frame[9] = 25; + break; + } } byte checksum = 0; @@ -1348,6 +1385,7 @@ bool SomfyShade::fromJSON(JsonObject &obj) { if(obj.containsKey("stepSize")) this->stepSize = obj["stepSize"]; if(obj.containsKey("hasTilt")) this->tiltType = static_cast(obj["hasTilt"]) ? tilt_types::none : tilt_types::tiltmotor; if(obj.containsKey("bitLength")) this->bitLength = obj["bitLength"]; + if(obj.containsKey("proto")) this->proto = static_cast(obj["proto"].as()); if(obj.containsKey("shadeType")) { if(obj["shadeType"].is()) { if(strncmp(obj["shadeType"].as(), "roller", 7) == 0) @@ -1417,6 +1455,7 @@ bool SomfyShade::toJSON(JsonObject &obj) { obj["tiltTime"] = this->tiltTime; obj["shadeType"] = static_cast(this->shadeType); obj["bitLength"] = this->bitLength; + obj["proto"] = static_cast(this->proto); SomfyRemote::toJSON(obj); JsonArray arr = obj.createNestedArray("linkedRemotes"); for(uint8_t i = 0; i < SOMFY_MAX_LINKED_REMOTES; i++) { @@ -1583,6 +1622,7 @@ void SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat) { frame.bitLength = this->bitLength; // Match the encKey to the rolling code. These keys range from 160 to 175. frame.encKey = 0xA0 | static_cast(frame.rollingCode & 0x000F); + frame.proto = this->proto; if(frame.bitLength == 0) frame.bitLength = bit_length; this->lastRollingCode = frame.rollingCode; somfy.sendFrame(frame, repeat); @@ -2115,7 +2155,7 @@ void transceiver_config_t::fromJSON(JsonObject& obj) { if(obj.containsKey("deviation")) this->deviation = obj["deviation"]; // float if(obj.containsKey("enabled")) this->enabled = obj["enabled"]; if(obj.containsKey("txPower")) this->txPower = obj["txPower"]; - + if(obj.containsKey("proto")) this->proto = static_cast(obj["proto"].as()); /* if (obj.containsKey("internalCCMode")) this->internalCCMode = obj["internalCCMode"]; if (obj.containsKey("modulationMode")) this->modulationMode = obj["modulationMode"]; @@ -2155,6 +2195,7 @@ void transceiver_config_t::toJSON(JsonObject& obj) { obj["frequency"] = this->frequency; // float obj["deviation"] = this->deviation; // float obj["txPower"] = this->txPower; + obj["proto"] = static_cast(this->proto); /* obj["internalCCMode"] = this->internalCCMode; obj["modulationMode"] = this->modulationMode; @@ -2201,6 +2242,7 @@ void transceiver_config_t::save() { pref.putBool("enabled", this->enabled); pref.putBool("radioInit", true); pref.putChar("txPower", this->txPower); + pref.putChar("proto", static_cast(this->proto)); /* pref.putBool("internalCCMode", this->internalCCMode); @@ -2253,7 +2295,7 @@ void transceiver_config_t::load() { this->enabled = pref.getBool("enabled", this->enabled); this->txPower = pref.getChar("txPower", this->txPower); this->rxBandwidth = pref.getFloat("rxBandwidth", this->rxBandwidth); - + this->proto = static_cast(pref.getChar("proto", static_cast(this->proto))); this->removeNVSKey("internalCCMode"); this->removeNVSKey("modulationMode"); this->removeNVSKey("channel"); diff --git a/Somfy.h b/Somfy.h index b8058a4..07455f9 100644 --- a/Somfy.h +++ b/Somfy.h @@ -9,7 +9,10 @@ typedef struct appver_t { uint8_t minor; uint8_t build; }; - +enum class radio_proto : byte { + RTS = 0x00, + RTW = 0x01 +}; enum class somfy_commands : byte { Unknown0 = 0x0, My = 0x1, @@ -26,7 +29,7 @@ enum class somfy_commands : byte { UnknownC = 0xC, UnknownD = 0xD, UnknownE = 0xE, // This command byte has been witnessed in the wild but cannot tell if it is from Somfy. No rolling code is sent with this and it is 56-bits. - UnknownF = 0xF, + RTWProto = 0xF, // RTW Protocol // Command extensions for 80 bit frames StepUp = 0x8B }; @@ -93,6 +96,7 @@ typedef struct somfy_tx_queue_t { typedef struct somfy_frame_t { bool valid = false; bool processed = false; + radio_proto proto = radio_proto::RTS; int rssi = 0; byte lqi = 0x0; somfy_commands cmd; @@ -121,6 +125,7 @@ class SomfyRemote { char m_remotePrefId[11] = ""; uint32_t m_remoteAddress = 0; public: + radio_proto proto = radio_proto::RTS; uint8_t bitLength = 0; char *getRemotePrefId() {return m_remotePrefId;} virtual bool toJSON(JsonObject &obj); @@ -202,6 +207,7 @@ typedef struct transceiver_config_t { bool printBuffer = false; bool enabled = false; uint8_t type = 56; // 56 or 80 bit protocol. + radio_proto proto = radio_proto::RTS; uint8_t SCKPin = 18; uint8_t TXPin = 12; uint8_t RXPin = 13; diff --git a/SomfyController.ino.esp32.bin b/SomfyController.ino.esp32.bin index 9b95c43..fb16818 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 1136f2b..646642b 100644 Binary files a/SomfyController.littlefs.bin and b/SomfyController.littlefs.bin differ diff --git a/Web.cpp b/Web.cpp index 2493488..524a37b 100644 --- a/Web.cpp +++ b/Web.cpp @@ -469,12 +469,14 @@ void Web::begin() { }); server.on("/getNextShade", []() { webServer.sendCORSHeaders(); - StaticJsonDocument<128> doc; + StaticJsonDocument<256> doc; uint8_t shadeId = somfy.getNextShadeId(); JsonObject obj = doc.to(); obj["shadeId"] = shadeId; obj["remoteAddress"] = somfy.getNextRemoteAddress(shadeId); obj["bitLength"] = somfy.transceiver.config.type; + obj["stepSize"] = 100; + obj["proto"] = static_cast(somfy.transceiver.config.proto); serializeJson(doc, g_content); server.send(200, _encoding_json, g_content); }); diff --git a/data/appversion b/data/appversion index 63ebd3f..ce6a70b 100644 --- a/data/appversion +++ b/data/appversion @@ -1 +1 @@ -1.5.4 \ No newline at end of file +1.6.0 \ No newline at end of file diff --git a/data/index.html b/data/index.html index 2ba889d..c3a8cab 100644 --- a/data/index.html +++ b/data/index.html @@ -3,10 +3,10 @@ - - + + - +
@@ -219,8 +219,15 @@
-
- + + + + +
+
+ @@ -318,7 +325,14 @@