mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
fix: propagate radio TX result to callers instead of pre-checking
- Send functions return whether the radio took the command. - Shade, group and tilt state only change when the command was queued. - Rolling code is committed only after the frame is queued. - repeatFrame advances the repeat counter only on success. - Remove canTransmit/canQueueTx; queueTx is the single authority. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a426efe53f
commit
ad15ecacd4
2 changed files with 129 additions and 125 deletions
225
src/Somfy.cpp
225
src/Somfy.cpp
|
|
@ -2894,8 +2894,8 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
void SomfyShade::moveToMyPosition() {
|
||||
if(!this->isIdle()) return;
|
||||
bool SomfyShade::moveToMyPosition() {
|
||||
if(!this->isIdle()) return true;
|
||||
ESP_LOGI(TAG, "Moving to My Position");
|
||||
if(this->tiltType == tilt_types::tiltonly) {
|
||||
this->p_currentPos(100.0f);
|
||||
|
|
@ -2903,27 +2903,25 @@ void SomfyShade::moveToMyPosition() {
|
|||
}
|
||||
if(this->currentPos == this->myPos) {
|
||||
if(this->tiltType != tilt_types::none) {
|
||||
if(this->currentTiltPos == this->myTiltPos) return; // Nothing to see here since we are already here.
|
||||
if(this->currentTiltPos == this->myTiltPos) return true; // Nothing to see here since we are already here.
|
||||
}
|
||||
else
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if(this->myPos == -1 && (this->tiltType == tilt_types::none || this->myTiltPos == -1)) return;
|
||||
if(this->tiltType != tilt_types::tiltonly && this->myPos >= 0.0f && this->myPos <= 100.0f) this->p_target(this->myPos);
|
||||
if(this->myTiltPos >= 0.0f && this->myTiltPos <= 100.0f) this->p_tiltTarget(this->myTiltPos);
|
||||
if(this->myPos == -1 && (this->tiltType == tilt_types::none || this->myTiltPos == -1)) return true;
|
||||
this->settingPos = false;
|
||||
if(this->simMy()) {
|
||||
ESP_LOGI(TAG, "Moving to simulated favorite");
|
||||
this->moveToTarget(this->myPos, this->myTiltPos);
|
||||
if(!this->moveToTarget(this->myPos, this->myTiltPos)) return false;
|
||||
}
|
||||
else
|
||||
SomfyRemote::sendCommand(somfy_commands::My, this->repeats);
|
||||
else if(!SomfyRemote::sendCommand(somfy_commands::My, this->repeats)) return false;
|
||||
if(this->tiltType != tilt_types::tiltonly && this->myPos >= 0.0f && this->myPos <= 100.0f) this->p_target(this->myPos);
|
||||
if(this->myTiltPos >= 0.0f && this->myTiltPos <= 100.0f) this->p_tiltTarget(this->myTiltPos);
|
||||
return true;
|
||||
}
|
||||
void SomfyShade::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); }
|
||||
void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) {
|
||||
bool SomfyShade::sendCommand(somfy_commands cmd) { return this->sendCommand(cmd, this->repeats); }
|
||||
bool SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) {
|
||||
ESP_LOGD(TAG, "Send command start");
|
||||
// Don't move the simulated state for a command the radio can't take.
|
||||
if(!this->canTransmit()) return;
|
||||
// This sendCommand function will always be called externally. sendCommand at the remote level
|
||||
// is expected to be called internally when the motor needs commanded.
|
||||
if(this->bitLength == 0) this->bitLength = somfy.transceiver.config.type;
|
||||
|
|
@ -2932,21 +2930,22 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
|
|||
if((cmd == somfy_commands::Up && this->direction == -1) ||
|
||||
(cmd == somfy_commands::Down && this->direction == 1)) {
|
||||
ESP_LOGD(TAG, "Same command as dir");
|
||||
SomfyRemote::sendCommand(cmd, repeat);
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat)) return false;
|
||||
this->p_target(this->currentPos);
|
||||
this->p_tiltTarget(this->currentTiltPos);
|
||||
this->setMovement(0);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
// The simulated state is only moved for commands the radio took.
|
||||
if(cmd == somfy_commands::Up) {
|
||||
if(this->tiltType == tilt_types::euromode) {
|
||||
// In euromode we need to long press for 2 seconds on the
|
||||
// up command.
|
||||
SomfyRemote::sendCommand(cmd, TILT_REPEATS);
|
||||
this->p_target(0.0f);
|
||||
if(!SomfyRemote::sendCommand(cmd, TILT_REPEATS)) return false;
|
||||
this->p_target(0.0f);
|
||||
}
|
||||
else {
|
||||
SomfyRemote::sendCommand(cmd, repeat);
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat)) return false;
|
||||
if(this->tiltType == tilt_types::tiltonly) {
|
||||
this->p_target(100.0f);
|
||||
this->p_tiltTarget(0.0f);
|
||||
|
|
@ -2960,11 +2959,11 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
|
|||
if(this->tiltType == tilt_types::euromode) {
|
||||
// In euromode we need to long press for 2 seconds on the
|
||||
// down command.
|
||||
SomfyRemote::sendCommand(cmd, TILT_REPEATS);
|
||||
this->p_target(100.0f);
|
||||
if(!SomfyRemote::sendCommand(cmd, TILT_REPEATS)) return false;
|
||||
this->p_target(100.0f);
|
||||
}
|
||||
else {
|
||||
SomfyRemote::sendCommand(cmd, repeat);
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat)) return false;
|
||||
if(this->tiltType == tilt_types::tiltonly) {
|
||||
this->p_target(100.0f);
|
||||
this->p_tiltTarget(100.0f);
|
||||
|
|
@ -2975,43 +2974,45 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
|
|||
}
|
||||
}
|
||||
else if(cmd == somfy_commands::My) {
|
||||
if(this->isToggle() || this->shadeType == shade_types::drycontact)
|
||||
SomfyRemote::sendCommand(cmd, repeat);
|
||||
else if(this->shadeType == shade_types::drycontact2){
|
||||
if(this->isToggle() || this->shadeType == shade_types::drycontact) {
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat)) return false;
|
||||
}
|
||||
else if(this->shadeType == shade_types::drycontact2){
|
||||
ESP_LOGD(TAG, "Send command start 1");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
else if(this->isIdle()) {
|
||||
this->moveToMyPosition();
|
||||
bool sent = this->moveToMyPosition();
|
||||
ESP_LOGD(TAG, "Send command end 2");
|
||||
return;
|
||||
return sent;
|
||||
}
|
||||
else {
|
||||
SomfyRemote::sendCommand(cmd, repeat);
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat)) return false;
|
||||
if(this->tiltType != tilt_types::tiltonly) this->p_target(this->currentPos);
|
||||
this->p_tiltTarget(this->currentTiltPos);
|
||||
}
|
||||
}
|
||||
else if(cmd == somfy_commands::Toggle) {
|
||||
if(this->bitLength != 80) SomfyRemote::sendCommand(somfy_commands::My, repeat, stepSize);
|
||||
else SomfyRemote::sendCommand(somfy_commands::Toggle, repeat);
|
||||
if(this->bitLength != 80) { if(!SomfyRemote::sendCommand(somfy_commands::My, repeat, stepSize)) return false; }
|
||||
else if(!SomfyRemote::sendCommand(somfy_commands::Toggle, repeat)) return false;
|
||||
}
|
||||
else if(this->isToggle() && cmd == somfy_commands::Prog) {
|
||||
SomfyRemote::sendCommand(somfy_commands::Toggle, repeat, stepSize);
|
||||
if(!SomfyRemote::sendCommand(somfy_commands::Toggle, repeat, stepSize)) return false;
|
||||
}
|
||||
else {
|
||||
SomfyRemote::sendCommand(cmd, repeat, stepSize);
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat, stepSize)) return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "Send command end");
|
||||
return true;
|
||||
}
|
||||
void SomfyGroup::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); }
|
||||
void SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) {
|
||||
bool SomfyGroup::sendCommand(somfy_commands cmd) { return this->sendCommand(cmd, this->repeats); }
|
||||
bool SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) {
|
||||
ESP_LOGI(TAG, "[Group %u] sendCommand cmd=%s repeat=%u", this->getGroupId(), translateSomfyCommand(cmd).c_str(), repeat);
|
||||
if(!this->canTransmit()) return;
|
||||
// This sendCommand function will always be called externally. sendCommand at the remote level
|
||||
// is expected to be called internally when the motor needs commanded.
|
||||
if(this->bitLength == 0) this->bitLength = somfy.transceiver.config.type;
|
||||
SomfyRemote::sendCommand(cmd, repeat, stepSize);
|
||||
// Leave the group and its shades alone if the radio didn't take the command.
|
||||
if(!SomfyRemote::sendCommand(cmd, repeat, stepSize)) return false;
|
||||
|
||||
switch(cmd) {
|
||||
case somfy_commands::My:
|
||||
|
|
@ -3039,25 +3040,21 @@ void SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
|
|||
}
|
||||
this->updateFlags();
|
||||
this->emitState();
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void SomfyShade::sendTiltCommand(somfy_commands cmd) {
|
||||
if(!this->canTransmit()) return;
|
||||
const uint8_t repeat = this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats;
|
||||
if(cmd == somfy_commands::Up) {
|
||||
SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats);
|
||||
this->p_tiltTarget(0.0f);
|
||||
if(SomfyRemote::sendCommand(cmd, repeat)) this->p_tiltTarget(0.0f);
|
||||
}
|
||||
else if(cmd == somfy_commands::Down) {
|
||||
SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats);
|
||||
this->p_tiltTarget(100.0f);
|
||||
if(SomfyRemote::sendCommand(cmd, repeat)) this->p_tiltTarget(100.0f);
|
||||
}
|
||||
else if(cmd == somfy_commands::My) {
|
||||
SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats);
|
||||
this->p_tiltTarget(this->currentTiltPos);
|
||||
if(SomfyRemote::sendCommand(cmd, repeat)) this->p_tiltTarget(this->currentTiltPos);
|
||||
}
|
||||
}
|
||||
void SomfyShade::moveToTiltTarget(float target) {
|
||||
if(!this->canTransmit()) return;
|
||||
somfy_commands cmd = somfy_commands::My;
|
||||
if(target < this->currentTiltPos)
|
||||
cmd = somfy_commands::Up;
|
||||
|
|
@ -3069,7 +3066,7 @@ void SomfyShade::moveToTiltTarget(float target) {
|
|||
if(cmd != somfy_commands::My) {
|
||||
ESP_LOGI(TAG, "Moving Tilt to %.2f%% from %.2f%% using %s",
|
||||
target, this->currentTiltPos, translateSomfyCommand(cmd).c_str());
|
||||
SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats);
|
||||
if(!SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats)) return;
|
||||
}
|
||||
// If the blind is currently moving then the command to stop it
|
||||
// will occur on its own when the tilt target is set.
|
||||
|
|
@ -3078,7 +3075,7 @@ void SomfyShade::moveToTiltTarget(float target) {
|
|||
}
|
||||
if(cmd != somfy_commands::My) this->settingTiltPos = true;
|
||||
}
|
||||
void SomfyShade::moveToTarget(float pos, float tilt) {
|
||||
bool SomfyShade::moveToTarget(float pos, float tilt) {
|
||||
ESP_LOGI(TAG, "[Shade %u] moveToTarget(pos=%.2f, tilt=%.2f) settingPos=%d direction=%d currentTarget=%.2f currentPos=%.2f",
|
||||
this->getShadeId(), pos, tilt, this->settingPos, this->direction, this->target, this->currentPos);
|
||||
somfy_commands cmd = somfy_commands::My;
|
||||
|
|
@ -3087,10 +3084,10 @@ void SomfyShade::moveToTarget(float pos, float tilt) {
|
|||
this->p_target(pos);
|
||||
this->p_currentPos(pos);
|
||||
this->emitState();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if(!this->canTransmit()) return;
|
||||
if(this->tiltType == tilt_types::tiltonly) {
|
||||
// A tilt only shade is always at 100%.
|
||||
this->p_target(100.0f);
|
||||
this->p_myPos(-1.0f);
|
||||
this->p_currentPos(100.0f);
|
||||
|
|
@ -3116,7 +3113,7 @@ void SomfyShade::moveToTarget(float pos, float tilt) {
|
|||
ESP_LOGI(TAG, "Moving to %.2f%% from %.2f%% using %s",
|
||||
pos, this->currentPos, translateSomfyCommand(cmd).c_str());
|
||||
}
|
||||
SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::euromode ? TILT_REPEATS : this->repeats);
|
||||
if(!SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::euromode ? TILT_REPEATS : this->repeats)) return false;
|
||||
this->settingPos = true;
|
||||
this->p_target(pos);
|
||||
if(tilt >= 0) {
|
||||
|
|
@ -3124,6 +3121,7 @@ void SomfyShade::moveToTarget(float pos, float tilt) {
|
|||
this->settingTiltPos = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool SomfyShade::save() {
|
||||
#ifdef USE_NVS
|
||||
|
|
@ -3863,74 +3861,74 @@ somfy_commands SomfyRemote::transformCommand(somfy_commands cmd) {
|
|||
}
|
||||
return cmd;
|
||||
}
|
||||
void SomfyRemote::sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat) {
|
||||
if(!this->canTransmit()) return;
|
||||
bool SomfyRemote::sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat) {
|
||||
uint8_t flags = (this->flags >> 4) & 0x0F;
|
||||
if(isWindy > 0) flags |= 0x01;
|
||||
if(isSunny > 0) flags |= 0x02;
|
||||
if(isWindy == 0) flags &= ~0x01;
|
||||
if(isSunny == 0) flags &= ~0x02;
|
||||
|
||||
// Now ship this off as an 80 bit command.
|
||||
this->lastFrame.remoteAddress = this->getRemoteAddress();
|
||||
this->lastFrame.repeats = repeat;
|
||||
this->lastFrame.bitLength = this->bitLength;
|
||||
this->lastFrame.rollingCode = (uint16_t)flags;
|
||||
this->lastFrame.encKey = 160; // Sensor commands are always encryption code 160.
|
||||
this->lastFrame.cmd = somfy_commands::Sensor;
|
||||
this->lastFrame.processed = false;
|
||||
// Now ship this off as an 80 bit command. Built aside so lastFrame only
|
||||
// changes when the frame is queued.
|
||||
somfy_frame_t frame = this->lastFrame;
|
||||
frame.remoteAddress = this->getRemoteAddress();
|
||||
frame.repeats = repeat;
|
||||
frame.bitLength = this->bitLength;
|
||||
frame.rollingCode = (uint16_t)flags;
|
||||
frame.encKey = 160; // Sensor commands are always encryption code 160.
|
||||
frame.cmd = somfy_commands::Sensor;
|
||||
frame.processed = false;
|
||||
ESP_LOGD(TAG, "CMD:%s ADDR:%d RCODE:%d REPEAT:%d",
|
||||
translateSomfyCommand(this->lastFrame.cmd).c_str(),
|
||||
this->lastFrame.remoteAddress, this->lastFrame.rollingCode, repeat);
|
||||
if(somfy.sendFrame(this->lastFrame, repeat)) somfy.processFrame(this->lastFrame, true);
|
||||
translateSomfyCommand(frame.cmd).c_str(),
|
||||
frame.remoteAddress, frame.rollingCode, repeat);
|
||||
if(!somfy.sendFrame(frame, repeat)) return false;
|
||||
this->lastFrame = frame;
|
||||
somfy.processFrame(this->lastFrame, true);
|
||||
return true;
|
||||
}
|
||||
bool SomfyRemote::canTransmit() {
|
||||
// GPIO remotes don't use the radio.
|
||||
if(this->proto == radio_proto::GP_Relay || this->proto == radio_proto::GP_Remote) return true;
|
||||
if(somfy.transceiver.canQueueTx()) return true;
|
||||
ESP_LOGE(TAG, "Radio TX unavailable, dropping command for %d", this->getRemoteAddress());
|
||||
return false;
|
||||
}
|
||||
void SomfyRemote::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); }
|
||||
void SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) { this->sendCommandAfter(cmd, repeat, stepSize, 0); }
|
||||
void SomfyRemote::sendCommandAfter(somfy_commands cmd, uint8_t repeat, uint8_t stepSize, uint16_t delayMs) {
|
||||
// Check before taking a rolling code so a dropped command doesn't consume one.
|
||||
if(!this->canTransmit()) return;
|
||||
this->lastFrame.rollingCode = this->getNextRollingCode();
|
||||
this->lastFrame.remoteAddress = this->getRemoteAddress();
|
||||
this->lastFrame.cmd = this->transformCommand(cmd);
|
||||
this->lastFrame.repeats = repeat;
|
||||
this->lastFrame.bitLength = this->bitLength;
|
||||
this->lastFrame.stepSize = stepSize;
|
||||
this->lastFrame.valid = true;
|
||||
bool SomfyRemote::sendCommand(somfy_commands cmd) { return this->sendCommand(cmd, this->repeats); }
|
||||
bool SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) { return this->sendCommandAfter(cmd, repeat, stepSize, 0); }
|
||||
bool SomfyRemote::sendCommandAfter(somfy_commands cmd, uint8_t repeat, uint8_t stepSize, uint16_t delayMs) {
|
||||
// Build the frame aside and only take the rolling code once the frame is
|
||||
// queued so a dropped command leaves the remote untouched.
|
||||
somfy_frame_t frame = this->lastFrame;
|
||||
frame.rollingCode = this->peekNextRollingCode();
|
||||
frame.remoteAddress = this->getRemoteAddress();
|
||||
frame.cmd = this->transformCommand(cmd);
|
||||
frame.repeats = repeat;
|
||||
frame.bitLength = this->bitLength;
|
||||
frame.stepSize = stepSize;
|
||||
frame.valid = true;
|
||||
// Match the encKey to the rolling code. These keys range from 160 to 175.
|
||||
this->lastFrame.encKey = 0xA0 | static_cast<uint8_t>(this->lastFrame.rollingCode & 0x000F);
|
||||
this->lastFrame.proto = this->proto;
|
||||
if(this->lastFrame.bitLength == 0) this->lastFrame.bitLength = bit_length;
|
||||
if(this->lastFrame.rollingCode == 0) ESP_LOGE(TAG, "Setting rcode to 0");
|
||||
this->p_lastRollingCode(this->lastFrame.rollingCode);
|
||||
frame.encKey = 0xA0 | static_cast<uint8_t>(frame.rollingCode & 0x000F);
|
||||
frame.proto = this->proto;
|
||||
if(frame.bitLength == 0) frame.bitLength = bit_length;
|
||||
if(frame.rollingCode == 0) ESP_LOGE(TAG, "Setting rcode to 0");
|
||||
// We have to set the processed to clear this if we are sending
|
||||
// another command.
|
||||
this->lastFrame.processed = false;
|
||||
frame.processed = false;
|
||||
if(this->proto == radio_proto::GP_Relay) {
|
||||
ESP_LOGD(TAG, "CMD:%s ADDR:%d RCODE:%d SETTING GPIO",
|
||||
translateSomfyCommand(this->lastFrame.cmd).c_str(),
|
||||
this->lastFrame.remoteAddress, this->lastFrame.rollingCode);
|
||||
translateSomfyCommand(frame.cmd).c_str(),
|
||||
frame.remoteAddress, frame.rollingCode);
|
||||
}
|
||||
else if(this->proto == radio_proto::GP_Remote) {
|
||||
ESP_LOGD(TAG, "CMD:%s ADDR:%d RCODE:%d TRIGGER GPIO",
|
||||
translateSomfyCommand(this->lastFrame.cmd).c_str(),
|
||||
this->lastFrame.remoteAddress, this->lastFrame.rollingCode);
|
||||
this->triggerGPIOs(this->lastFrame);
|
||||
translateSomfyCommand(frame.cmd).c_str(),
|
||||
frame.remoteAddress, frame.rollingCode);
|
||||
this->triggerGPIOs(frame);
|
||||
}
|
||||
else {
|
||||
ESP_LOGD(TAG, "CMD:%s ADDR:%d RCODE:%d REPEAT:%d",
|
||||
translateSomfyCommand(this->lastFrame.cmd).c_str(),
|
||||
this->lastFrame.remoteAddress, this->lastFrame.rollingCode, repeat);
|
||||
translateSomfyCommand(frame.cmd).c_str(),
|
||||
frame.remoteAddress, frame.rollingCode, repeat);
|
||||
// Only simulate the command if it is actually going on air.
|
||||
if(!somfy.sendFrame(this->lastFrame, repeat, delayMs)) return;
|
||||
if(!somfy.sendFrame(frame, repeat, delayMs)) return false;
|
||||
}
|
||||
this->commitRollingCode(frame.rollingCode);
|
||||
this->lastFrame = frame;
|
||||
somfy.processFrame(this->lastFrame, true);
|
||||
return true;
|
||||
}
|
||||
bool SomfyRemote::isLastCommand(somfy_commands cmd) {
|
||||
if(this->lastFrame.cmd != cmd || this->lastFrame.rollingCode != this->lastRollingCode) {
|
||||
|
|
@ -3939,21 +3937,23 @@ bool SomfyRemote::isLastCommand(somfy_commands cmd) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
void SomfyRemote::repeatFrame(uint8_t repeat) {
|
||||
bool SomfyRemote::repeatFrame(uint8_t repeat) {
|
||||
if(this->proto == radio_proto::GP_Relay)
|
||||
return;
|
||||
return true;
|
||||
else if(this->proto == radio_proto::GP_Remote) {
|
||||
this->triggerGPIOs(this->lastFrame);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
// The first frame is encoded with the current repeat counter and the radio
|
||||
// task counts up from there for each repeat frame.
|
||||
somfy_tx_job_t job;
|
||||
encodeTxJob(job, this->lastFrame, repeat);
|
||||
job.firstRepeat = this->lastFrame.repeats + 2;
|
||||
// Only advance the counter for frames that will go on air.
|
||||
if(!somfy.transceiver.queueTx(job)) return false;
|
||||
this->lastFrame.repeats += repeat + 1;
|
||||
somfy.transceiver.queueTx(job);
|
||||
//somfy.processFrame(this->lastFrame, true);
|
||||
return true;
|
||||
}
|
||||
bool SomfyShadeController::sendFrame(somfy_frame_t &frame, uint8_t repeat, uint16_t delayMs, bool priority) {
|
||||
somfy_tx_job_t job;
|
||||
|
|
@ -4027,17 +4027,23 @@ bool SomfyShadeController::deleteGroup(uint8_t groupId) {
|
|||
}
|
||||
|
||||
bool SomfyShadeController::loadShadesFile(const char *filename) { return ShadeConfigFile::load(this, filename); }
|
||||
uint16_t SomfyRemote::getNextRollingCode() {
|
||||
// The next rolling code is only read here. It is consumed by commitRollingCode
|
||||
// once the frame using it has been queued.
|
||||
uint16_t SomfyRemote::peekNextRollingCode() {
|
||||
if(!pref.begin("ShadeCodes")) {
|
||||
ESP_LOGE(TAG, "getNextRollingCode() pref.begin(ShadeCodes) FAILED");
|
||||
ESP_LOGE(TAG, "peekNextRollingCode() pref.begin(ShadeCodes) FAILED");
|
||||
}
|
||||
uint16_t code = pref.getUShort(this->m_remotePrefId, 0);
|
||||
code++;
|
||||
pref.end();
|
||||
return (uint16_t)(code + 1);
|
||||
}
|
||||
void SomfyRemote::commitRollingCode(uint16_t code) {
|
||||
if(!pref.begin("ShadeCodes")) {
|
||||
ESP_LOGE(TAG, "commitRollingCode() pref.begin(ShadeCodes) FAILED");
|
||||
}
|
||||
pref.putUShort(this->m_remotePrefId, code);
|
||||
pref.end();
|
||||
this->p_lastRollingCode(code);
|
||||
//Serial.printf("Getting Next Rolling code %d\n", this->lastRollingCode);
|
||||
return code;
|
||||
}
|
||||
uint16_t SomfyRemote::p_lastRollingCode(uint16_t code) {
|
||||
uint16_t old = this->lastRollingCode;
|
||||
|
|
@ -5069,7 +5075,7 @@ void Transceiver::loop() {
|
|||
}
|
||||
}
|
||||
bool Transceiver::queueTx(somfy_tx_job_t &job) {
|
||||
if(!txJobQueue) {
|
||||
if(!txJobQueue || !txTaskHandle) {
|
||||
ESP_LOGE(TAG, "Radio task not started, dropping transmission");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -5090,9 +5096,6 @@ bool Transceiver::queueTx(somfy_tx_job_t &job) {
|
|||
else xQueueSendToBack(txJobQueue, &job, 0);
|
||||
return true;
|
||||
}
|
||||
bool Transceiver::canQueueTx(bool priority) {
|
||||
return txJobQueue && txTaskHandle && !txSuspendMask && uxQueueSpacesAvailable(txJobQueue) > (priority ? 0 : TX_RESERVED_SLOTS);
|
||||
}
|
||||
void Transceiver::flushTx() {
|
||||
TxQueueLock lock;
|
||||
++txGen;
|
||||
|
|
|
|||
29
src/Somfy.h
29
src/Somfy.h
|
|
@ -273,7 +273,8 @@ class SomfyRemote {
|
|||
char *getRemotePrefId() {return m_remotePrefId;}
|
||||
virtual void setRemoteAddress(uint32_t address);
|
||||
virtual uint32_t getRemoteAddress();
|
||||
virtual uint16_t getNextRollingCode();
|
||||
uint16_t peekNextRollingCode();
|
||||
void commitRollingCode(uint16_t code);
|
||||
virtual uint16_t setRollingCode(uint16_t code);
|
||||
bool hasSunSensor();
|
||||
bool hasLight();
|
||||
|
|
@ -281,12 +282,13 @@ class SomfyRemote {
|
|||
void setSunSensor(bool bHasSensor);
|
||||
void setLight(bool bHasLight);
|
||||
void setSimMy(bool bSimMy);
|
||||
virtual void sendCommand(somfy_commands cmd);
|
||||
virtual void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
void sendCommandAfter(somfy_commands cmd, uint8_t repeat, uint8_t stepSize, uint16_t delayMs);
|
||||
void sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat);
|
||||
void repeatFrame(uint8_t repeat);
|
||||
bool canTransmit();
|
||||
// The send functions return false only when the radio could not take the
|
||||
// command. Nothing about the remote or shade state has changed in that case.
|
||||
virtual bool sendCommand(somfy_commands cmd);
|
||||
virtual bool sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
bool sendCommandAfter(somfy_commands cmd, uint8_t repeat, uint8_t stepSize, uint16_t delayMs);
|
||||
bool sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat);
|
||||
bool repeatFrame(uint8_t repeat);
|
||||
virtual uint16_t p_lastRollingCode(uint16_t code);
|
||||
somfy_commands transformCommand(somfy_commands cmd);
|
||||
virtual void triggerGPIOs(somfy_frame_t &frame);
|
||||
|
|
@ -358,11 +360,11 @@ class SomfyShade : public SomfyRemote {
|
|||
void setTarget(float target);
|
||||
bool isAtTarget();
|
||||
bool isToggle();
|
||||
void moveToTarget(float pos, float tilt = -1.0f);
|
||||
bool moveToTarget(float pos, float tilt = -1.0f);
|
||||
void moveToTiltTarget(float target);
|
||||
void sendTiltCommand(somfy_commands cmd);
|
||||
void sendCommand(somfy_commands cmd);
|
||||
void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
bool sendCommand(somfy_commands cmd);
|
||||
bool sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
bool linkRemote(uint32_t remoteAddress, uint16_t rollingCode = 0);
|
||||
bool unlinkRemote(uint32_t remoteAddress);
|
||||
void emitState(const char *evt = "shadeState");
|
||||
|
|
@ -370,7 +372,7 @@ class SomfyShade : public SomfyRemote {
|
|||
void emitCommand(somfy_commands cmd, const char *source, uint32_t sourceAddress, const char *evt = "shadeCommand");
|
||||
void emitCommand(uint8_t num, somfy_commands cmd, const char *source, uint32_t sourceAddress, const char *evt = "shadeCommand");
|
||||
void setMyPosition(int8_t pos, int8_t tilt = -1);
|
||||
void moveToMyPosition();
|
||||
bool moveToMyPosition();
|
||||
void processWaitingFrame();
|
||||
void publish();
|
||||
void unpublish();
|
||||
|
|
@ -437,8 +439,8 @@ class SomfyGroup : public SomfyRemote {
|
|||
void updateFlags();
|
||||
void emitState(const char *evt = "groupState");
|
||||
void emitState(uint8_t num, const char *evt = "groupState");
|
||||
void sendCommand(somfy_commands cmd);
|
||||
void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
bool sendCommand(somfy_commands cmd);
|
||||
bool sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
int8_t p_direction(int8_t dir);
|
||||
bool publish(const char *topic, uint8_t val, bool retain = false);
|
||||
bool publish(const char *topic, int8_t val, bool retain = false);
|
||||
|
|
@ -544,7 +546,6 @@ class Transceiver {
|
|||
somfy_frame_t& lastFrame();
|
||||
void sendFrame(byte *frame, uint8_t sync, uint8_t bitLength = 56);
|
||||
bool queueTx(somfy_tx_job_t &job);
|
||||
bool canQueueTx(bool priority = false);
|
||||
void flushTx();
|
||||
void suspendTx(uint8_t reason);
|
||||
void resumeTx(uint8_t reason);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue