ESPSomfy-RTS/src/SomfyGroup.cpp
cjkas ef1d0a0882 refactor: move SomfyGroup into SomfyGroup.cpp
Linking shades, the group flags and direction, sending group commands and
saving move out of Somfy.cpp unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:43:05 +02:00

134 lines
4 KiB
C++

#include "esp_log.h"
#include "Somfy.h"
static const char *TAG = "Somfy";
extern SomfyShadeController somfy;
void SomfyGroup::clear() {
this->setGroupId(255);
this->setRemoteAddress(0);
this->repeats = 0;
this->roomId = 0;
this->name[0] = 0x00;
memset(&this->linkedShades, 0x00, sizeof(this->linkedShades));
}
bool SomfyGroup::linkShade(uint8_t shadeId) {
// Check to see if the shade is already linked. If it is just return true
for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] == shadeId) {
return true;
}
}
for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] == 0) {
this->linkedShades[i] = shadeId;
somfy.commit();
return true;
}
}
return false;
}
bool SomfyGroup::unlinkShade(uint8_t shadeId) {
bool removed = false;
for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] == shadeId) {
this->linkedShades[i] = 0;
removed = true;
}
}
// Compress the linked shade ids so we can stop looking on the first 0
if(removed) {
this->compressLinkedShadeIds();
somfy.commit();
}
return removed;
}
void SomfyGroup::compressLinkedShadeIds() {
// [1,0,4,3,0,0,0] i:0,j:0
// [1,0,4,3,0,0,0] i:1,j:1
// [1,4,0,3,0,0,0] i:2,j:1
// [1,4,3,0,0,0,0] i:3,j:2
// [1,4,3,0,0,0,0] i:4,j:2
// [1,2,0,0,3,0,0] i:0,j:0
// [1,2,0,0,3,0,0] i:1,j:1
// [1,2,0,0,3,0,0] i:2,j:2
// [1,2,0,0,3,0,0] i:3,j:2
// [1,2,3,0,0,0,0] i:4,j:2
// [1,2,3,0,0,0,0] i:5,j:3
for(uint8_t i = 0, j = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] != 0) {
if(i != j) {
this->linkedShades[j] = this->linkedShades[i];
this->linkedShades[i] = 0;
}
j++;
}
}
}
bool SomfyGroup::hasShadeId(uint8_t shadeId) {
for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] == 0) break;
if(this->linkedShades[i] == shadeId) return true;
}
return false;
}
void SomfyGroup::updateFlags() {
uint8_t oldFlags = this->flags;
this->flags = 0;
for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] != 0) {
SomfyShade *shade = somfy.getShadeById(this->linkedShades[i]);
if(shade) this->flags |= shade->flags;
}
else break;
}
if(oldFlags != this->flags) this->emitState();
}
int8_t SomfyGroup::p_direction(int8_t dir) {
int8_t old = this->direction;
if(old != dir) {
this->direction = dir;
this->publish("direction", this->direction);
}
return old;
}
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);
// 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;
// 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:
this->p_direction(0);
break;
case somfy_commands::Up:
this->p_direction(-1);
break;
case somfy_commands::Down:
this->p_direction(1);
break;
default:
break;
}
for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) {
if(this->linkedShades[i] != 0) {
SomfyShade *shade = somfy.getShadeById(this->linkedShades[i]);
if(shade) {
ESP_LOGI(TAG, "[Group %u] processInternalCommand on shade %u cmd=%s", this->getGroupId(), shade->getShadeId(), translateSomfyCommand(cmd).c_str());
shade->processInternalCommand(cmd, repeat);
shade->emitCommand(cmd, "group", this->getRemoteAddress());
}
}
}
this->updateFlags();
this->emitState();
return true;
}
bool SomfyGroup::save() { somfy.commit(); return true; }