diff --git a/ConfigSettings.h b/ConfigSettings.h index e851201..61ca78d 100644 --- a/ConfigSettings.h +++ b/ConfigSettings.h @@ -3,7 +3,7 @@ #ifndef configsettings_h #define configsettings_h -#define FW_VERSION "v1.5.3" +#define FW_VERSION "v1.5.4" enum DeviceStatus { DS_OK = 0, DS_ERROR = 1, diff --git a/Somfy.cpp b/Somfy.cpp index 594b6f6..0e8565c 100644 --- a/Somfy.cpp +++ b/Somfy.cpp @@ -24,7 +24,7 @@ uint8_t rxmode = 0; // Indicates whether the radio is in receive mode. Just to #define RECEIVE_ATTR #endif -#define SETMY_REPEATS 15 +#define SETMY_REPEATS 35 #define TILT_REPEATS 15 int sort_asc(const void *cmp1, const void *cmp2) { @@ -1123,7 +1123,7 @@ void SomfyShade::setMovement(int8_t dir) { } } void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) { - if(this->direction != 0) return; // Don't do this if it is moving. + if(!this->isIdle()) return; // Don't do this if it is moving. if(this->tiltType != tilt_types::none) { if(tilt < 0) tilt = 0; if(pos != floor(this->currentPos) || tilt != floor(currentTiltPos)) { @@ -1134,12 +1134,21 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) { this->moveToTarget(pos, tilt); } else if(pos == floor(this->myPos) && tilt == floor(this->myTiltPos)) { - SomfyRemote::sendCommand(somfy_commands::My, SETMY_REPEATS); - this->myPos = this->myTiltPos = -1; - this->commitMyPosition(); - this->emitState(); + // Of so we need to clear the my position. These motors are finicky so send + // a my command to ensure we are actually at the my position then send the clear + // command. There really is no other way to do this. + if(this->currentPos != this->myPos || this->currentTiltPos != this->myTiltPos) { + this->settingMyPos = true; + this->moveToMyPosition(); + } + else { + SomfyRemote::sendCommand(somfy_commands::My, 1); + this->settingPos = false; + this->settingMyPos = true; + } } else { + SomfyRemote::sendCommand(somfy_commands::My, SETMY_REPEATS); this->myPos = this->currentPos; this->myTiltPos = this->currentTiltPos; } @@ -1155,12 +1164,21 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) { this->moveToTarget(pos); } else if(pos == floor(this->myPos)) { - SomfyRemote::sendCommand(somfy_commands::My, SETMY_REPEATS); - this->myPos = this->myTiltPos = -1; - this->commitMyPosition(); - this->emitState(); + // Of so we need to clear the my position. These motors are finicky so send + // a my command to ensure we are actually at the my position then send the clear + // command. There really is no other way to do this. + if(this->myPos != this->currentPos) { + this->settingMyPos = true; + this->moveToMyPosition(); + } + else { + SomfyRemote::sendCommand(somfy_commands::My, 1); + this->settingPos = false; + this->settingMyPos = true; + } } else { + SomfyRemote::sendCommand(somfy_commands::My, SETMY_REPEATS); this->myPos = currentPos; this->myTiltPos = -1; this->commitMyPosition(); @@ -1190,6 +1208,7 @@ void SomfyShade::moveToMyPosition() { Serial.println(this->direction); if(this->myPos >= 0.0f && this->myPos <= 100.0f) this->target = this->myPos; if(this->myTiltPos >= 0.0f && this->myTiltPos <= 100.0f) this->tiltTarget = this->myTiltPos; + this->settingPos = false; SomfyRemote::sendCommand(somfy_commands::My); } void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat) { @@ -1719,13 +1738,53 @@ static uint16_t timing_index = 0; static somfy_rx_t somfy_rx; static somfy_rx_queue_t rx_queue; - +bool somfy_tx_queue_t::pop(somfy_tx_t *tx) { + // Read the oldest index. + for(uint8_t i = MAX_TX_BUFFER - 1; i >= 0; i--) { + if(this->index[i] < MAX_TX_BUFFER) { + uint8_t ndx = this->index[i]; + memcpy(tx, &this->items[ndx], sizeof(somfy_tx_t)); + memset(&this->items[ndx], 0x00, sizeof(somfy_tx_t)); + this->length--; + this->index[i] = 255; + return true; + } + } + return false; +} +bool somfy_tx_queue_t::push(uint32_t await, somfy_commands cmd, uint8_t repeats) { + if(this->length >= MAX_TX_BUFFER) { + uint8_t ndx = this->index[MAX_TX_BUFFER - 1]; + this->index[MAX_TX_BUFFER - 1] = 255; + this->length = MAX_TX_BUFFER - 1; + if(ndx < MAX_TX_BUFFER) memset(&this->items[ndx], 0x00, sizeof(somfy_tx_t)); + } + // 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 + // is indexed int slot 0. + for(uint8_t i = 0; i < MAX_TX_BUFFER; i++) { + if(this->items[i].await == 0) { + this->items[i].await = await; + this->items[i].cmd = cmd; + this->items[i].repeats = repeats; + // Move the index so that it is the at position 0. The oldest item will fall off. + for(uint8_t j = MAX_TX_BUFFER - 1; j > 0; j--) { + this->index[j] = this->index[j - 1]; + } + this->length++; + this->index[0] = i; + return true; + } + } + return false; +} void somfy_rx_queue_t::init() { Serial.println("Initializing RX Queue"); memset(&this->items[0], 0x00, sizeof(somfy_rx_t) * MAX_RX_BUFFER); memset(&this->index[0], 0xFF, MAX_RX_BUFFER); this->length = 0; } + bool somfy_rx_queue_t::pop(somfy_rx_t *rx) { // Read off the data from the oldest index. //Serial.println("Popping RX Queue"); diff --git a/Somfy.h b/Somfy.h index 32dbf14..b8058a4 100644 --- a/Somfy.h +++ b/Somfy.h @@ -46,12 +46,14 @@ somfy_commands translateSomfyCommand(const String& string); #define MAX_TIMINGS 300 #define MAX_RX_BUFFER 3 +#define MAX_TX_BUFFER 3 typedef enum { waiting_synchro = 0, receiving_data = 1, complete = 2 } t_status; + typedef struct somfy_rx_t { t_status status; uint8_t bit_length = 56; @@ -74,6 +76,20 @@ typedef struct somfy_rx_queue_t { //void push(somfy_rx_t *rx); bool pop(somfy_rx_t *rx); }; +typedef struct somfy_tx_t { + uint32_t await = 0; + somfy_commands cmd; + uint8_t repeats; +}; +typedef 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); } + void clear() { memset(&this->index[0], 255, MAX_TX_BUFFER); memset(&this->items[0], 0x00, sizeof(somfy_tx_queue_t) * MAX_TX_BUFFER); } + uint8_t length = 0; + uint8_t index[MAX_TX_BUFFER]; + somfy_tx_t items[MAX_TX_BUFFER]; + bool pop(somfy_tx_t *tx); + bool push(uint32_t await, somfy_commands cmd, uint8_t repeats); +}; typedef struct somfy_frame_t { bool valid = false; bool processed = false; @@ -134,6 +150,7 @@ class SomfyShade : public SomfyRemote { shade_types shadeType = shade_types::roller; tilt_types tiltType = tilt_types::none; void load(); + somfy_tx_queue_t txQueue; somfy_frame_t lastFrame; float currentPos = 0.0f; float currentTiltPos = 0.0f; diff --git a/SomfyController.ino.esp32.bin b/SomfyController.ino.esp32.bin index b9e6853..9b95c43 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 48b78ad..1136f2b 100644 Binary files a/SomfyController.littlefs.bin and b/SomfyController.littlefs.bin differ diff --git a/Web.cpp b/Web.cpp index fb856d6..2493488 100644 --- a/Web.cpp +++ b/Web.cpp @@ -810,6 +810,7 @@ void Web::begin() { if (shade) { // Send the command to the shade. if(tilt < 0) tilt = shade->myPos; + if(shade->tiltType == tilt_types::none) tilt = -1; if(pos >= 0 && pos <= 100) shade->setMyPosition(pos, tilt); DynamicJsonDocument sdoc(512); diff --git a/data/appversion b/data/appversion index a73b432..63ebd3f 100644 --- a/data/appversion +++ b/data/appversion @@ -1 +1 @@ -1.5.2 \ No newline at end of file +1.5.4 \ No newline at end of file diff --git a/data/index.html b/data/index.html index 97eb027..2ba889d 100644 --- a/data/index.html +++ b/data/index.html @@ -3,10 +3,10 @@ - - + + - +
diff --git a/data/index.js b/data/index.js index fe2f5d8..d981a6c 100644 --- a/data/index.js +++ b/data/index.js @@ -378,7 +378,7 @@ async function reopenSocket() { await initSockets(); } class General { - appVersion = 'v1.5.3'; + appVersion = 'v1.5.4'; reloadApp = false; async init() { this.setAppVersion(); @@ -1182,10 +1182,10 @@ class Somfy { if (myTiltPos >= 0 && tiltType > 0) html += `
Tilt:${myTiltPos}%
`; html += `
`; - html += ``; + html += ``; html += ``; html += '' html += `
`; @@ -1201,12 +1201,14 @@ class Somfy { shade.appendChild(div); let elTarget = div.querySelector('input#slidShadeTarget'); let elTiltTarget = div.querySelector('input#slidShadeTiltTarget'); + elTarget.value = currPos; + elTiltTarget.value = currTiltPos; let elBtn = div.querySelector('button#btnSetMyPosition'); if (tiltType > 0) div.querySelector('div#divTiltTarget').style.display = ''; let fnProcessChange = () => { let pos = parseInt(elTarget.value, 10); let tilt = parseInt(elTiltTarget.value, 10); - if (pos === myPos && tilt === myTiltPos) { + if (pos === myPos && (tiltType === 0 || tilt === myTiltPos)) { elBtn.innerHTML = 'Clear My Position'; elBtn.style.background = 'orangered'; }