fix: report tilt and set-My commands the radio refused

moveToTiltTarget, sendTiltCommand and setMyPosition returned nothing, so
the web command queue counted tilt_command and set_my_position as sent
and never logged a refusal.  They now return false when the radio refused
a command they sent.

No native test: these live in Somfy.cpp, which the native env can't build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-13 15:06:25 +02:00
parent f0e8b1d896
commit 45776f64ce
3 changed files with 42 additions and 37 deletions

View file

@ -2386,25 +2386,26 @@ void SomfyShade::setMovement(int8_t dir) {
this->emitState();
}
}
void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
if(!this->isIdle()) return; // Don't do this if it is moving.
bool SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
if(!this->isIdle()) return true; // Don't do this if it is moving.
bool sent = true;
if(this->tiltType == tilt_types::tiltonly) {
this->p_myPos(-1.0f);
if(tilt != floor(this->currentTiltPos)) {
// The favorite is set once we get there, if the move went out.
if(tilt == floor(this->myTiltPos))
this->settingMyPos = this->moveToMyPosition();
sent = this->settingMyPos = this->moveToMyPosition();
else
this->settingMyPos = this->moveToTarget(100, tilt);
sent = this->settingMyPos = this->moveToTarget(100, tilt);
}
else if(tilt == floor(this->myTiltPos)) {
// 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->currentTiltPos != this->myTiltPos) {
this->settingMyPos = this->moveToMyPosition();
sent = this->settingMyPos = this->moveToMyPosition();
}
else if(SomfyRemote::sendCommand(somfy_commands::My, this->repeats)) {
else if((sent = SomfyRemote::sendCommand(somfy_commands::My, this->repeats))) {
this->settingPos = false;
this->settingMyPos = true;
}
@ -2414,9 +2415,9 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
// is only committed once the motor was told about it.
const float oldTiltPos = this->myTiltPos;
this->p_myTiltPos(this->currentTiltPos);
this->sendSetMy(0, this->myPos, oldTiltPos);
sent = this->sendSetMy(0, this->myPos, oldTiltPos);
this->emitState();
return;
return sent;
}
this->commitMyPosition();
this->emitState();
@ -2426,18 +2427,18 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
if(pos != floor(this->currentPos) || tilt != floor(this->currentTiltPos)) {
// The favorite is set once we get there, if the move went out.
if(pos == floor(this->myPos) && tilt == floor(this->myTiltPos))
this->settingMyPos = this->moveToMyPosition();
sent = this->settingMyPos = this->moveToMyPosition();
else
this->settingMyPos = this->moveToTarget(pos, tilt);
sent = this->settingMyPos = this->moveToTarget(pos, tilt);
}
else if(pos == floor(this->myPos) && tilt == floor(this->myTiltPos)) {
// 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 = this->moveToMyPosition();
sent = this->settingMyPos = this->moveToMyPosition();
}
else if(SomfyRemote::sendCommand(somfy_commands::My, this->repeats)) {
else if((sent = SomfyRemote::sendCommand(somfy_commands::My, this->repeats))) {
this->settingPos = false;
this->settingMyPos = true;
}
@ -2449,9 +2450,9 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
const float oldTiltPos = this->myTiltPos;
this->p_myPos(this->currentPos);
this->p_myTiltPos(this->currentTiltPos);
this->sendSetMy(0, oldPos, oldTiltPos);
sent = this->sendSetMy(0, oldPos, oldTiltPos);
this->emitState();
return;
return sent;
}
this->commitMyPosition();
this->emitState();
@ -2460,18 +2461,18 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
if(pos != floor(this->currentPos)) {
// The favorite is set once we get there, if the move went out.
if(pos == floor(this->myPos))
this->settingMyPos = this->moveToMyPosition();
sent = this->settingMyPos = this->moveToMyPosition();
else
this->settingMyPos = this->moveToTarget(pos);
sent = this->settingMyPos = this->moveToTarget(pos);
}
else if(pos == floor(this->myPos)) {
// 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 = this->moveToMyPosition();
sent = this->settingMyPos = this->moveToMyPosition();
}
else if(SomfyRemote::sendCommand(somfy_commands::My, this->repeats)) {
else if((sent = SomfyRemote::sendCommand(somfy_commands::My, this->repeats))) {
this->settingPos = false;
this->settingMyPos = true;
}
@ -2483,9 +2484,11 @@ void SomfyShade::setMyPosition(int8_t pos, int8_t tilt) {
const float oldTiltPos = this->myTiltPos;
this->p_myPos(this->currentPos);
this->p_myTiltPos(-1);
if(this->sendSetMy(0, oldPos, oldTiltPos)) this->emitState();
sent = this->sendSetMy(0, oldPos, oldTiltPos);
if(sent) this->emitState();
}
}
return sent;
}
bool SomfyShade::moveToMyPosition() {
if(!this->isIdle()) return true;
@ -2635,19 +2638,18 @@ bool SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
this->emitState();
return true;
}
void SomfyShade::sendTiltCommand(somfy_commands cmd) {
bool SomfyShade::sendTiltCommand(somfy_commands cmd) {
const uint8_t repeat = this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats;
if(cmd == somfy_commands::Up) {
if(SomfyRemote::sendCommand(cmd, repeat)) this->p_tiltTarget(0.0f);
float target;
if(cmd == somfy_commands::Up) target = 0.0f;
else if(cmd == somfy_commands::Down) target = 100.0f;
else if(cmd == somfy_commands::My) target = this->currentTiltPos;
else return true;
if(!SomfyRemote::sendCommand(cmd, repeat)) return false;
this->p_tiltTarget(target);
return true;
}
else if(cmd == somfy_commands::Down) {
if(SomfyRemote::sendCommand(cmd, repeat)) this->p_tiltTarget(100.0f);
}
else if(cmd == somfy_commands::My) {
if(SomfyRemote::sendCommand(cmd, repeat)) this->p_tiltTarget(this->currentTiltPos);
}
}
void SomfyShade::moveToTiltTarget(float target) {
bool SomfyShade::moveToTiltTarget(float target) {
somfy_commands cmd = somfy_commands::My;
if(target < this->currentTiltPos)
cmd = somfy_commands::Up;
@ -2659,7 +2661,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());
if(!SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats)) return;
if(!SomfyRemote::sendCommand(cmd, this->tiltType == tilt_types::tiltmotor ? TILT_REPEATS : this->repeats)) return false;
}
// If the blind is currently moving then the command to stop it
// will occur on its own when the tilt target is set.
@ -2667,6 +2669,7 @@ void SomfyShade::moveToTiltTarget(float target) {
this->p_tiltTarget(target);
}
if(cmd != somfy_commands::My) this->settingTiltPos = true;
return true;
}
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",

View file

@ -263,8 +263,9 @@ class SomfyShade : public SomfyRemote {
bool isAtTarget();
bool isToggle();
bool moveToTarget(float pos, float tilt = -1.0f);
void moveToTiltTarget(float target);
void sendTiltCommand(somfy_commands cmd);
// These return false when the radio refused a command they sent.
bool moveToTiltTarget(float target);
bool sendTiltCommand(somfy_commands cmd);
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);
@ -273,7 +274,8 @@ class SomfyShade : public SomfyRemote {
void emitState(uint8_t num, const char *evt = "shadeState");
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);
// False when the radio refused a command it sent.
bool setMyPosition(int8_t pos, int8_t tilt = -1);
bool moveToMyPosition();
void processWaitingFrame();
void publish();

View file

@ -160,8 +160,8 @@ void Web::processQueue() {
case web_cmd_t::tilt_command: {
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
if(shade) {
if(cmd.target <= 100) shade->moveToTiltTarget(shade->transformPosition(cmd.target));
else shade->sendTiltCommand(cmd.command);
if(cmd.target <= 100) sent = shade->moveToTiltTarget(shade->transformPosition(cmd.target));
else sent = shade->sendTiltCommand(cmd.command);
}
break;
}
@ -209,7 +209,7 @@ void Web::processQueue() {
}
case web_cmd_t::set_my_position: {
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
if(shade) shade->setMyPosition(cmd.position, cmd.tiltPosition);
if(shade) sent = shade->setMyPosition(cmd.position, cmd.tiltPosition);
break;
}
case web_cmd_t::unpair_shade: {