vajera wrote: Mon Dec 22, 2025 11:29 pm
To przy okazji wrzuć przykładowy kod dla tych przycisków ... Usuń
Usuń to bardziej skomplikowany temat.
Przycisk "usuń" w Cloud po prostu kasuje dany kanał (jak klikniesz przy subdevice, to kasuje wszystkie kanały danego subdevice), odpowiednio je oznacza i robi restart połączenia z urządzeniem.
Następnie urządzenie się łączy i rejestruje z tymi usuniętymi kanałami (bo urządzenie jeszcze nie wie o usunięciu). W odpowiedzi dostaje channel confilict z informacją, że kanały zostały usunięte.
Urządzenie musi po swojej stronie skasować te kanały (i nie wstawiać niczego na ich miejsce) i ponownie się zarejestrować. Serwer je wspuści dopiero, jak urządzenie skasuje wszystkie kanały skasowane na serwerze.
To ogólnie jest bardziej złożony temat niż te poprzednie przyciski....
W skróce:
Trzeba dodać flagi do SuplaDevice:
Code: Select all
SuplaDevice.addFlags(SUPLA_DEVICE_FLAG_BLOCK_ADDING_CHANNELS_AFTER_DELETION);
SuplaDevice.addFlags(SUPLA_DEVICE_FLAG_ALWAYS_ALLOW_CHANNEL_DELETION);
Lub:
Code: Select all
sensor->getChannel()->setFlag(
SUPLA_CHANNEL_FLAG_ALWAYS_ALLOW_CHANNEL_DELETION);
Wariant SUPLA_DEVICE_FLAG_ALWAYS_ALLOW_CHANNEL_DELETION pozwala kasować wszystkie kanały z urządzenia (po stronie Clouda). Tego używam w Box.
Natomiast Z2S ma kanały "systemowe", które chyba nie są kasowalne (notyfikacje?)
Wtedy użyj tej flagi SUPLA_CHANNEL_FLAG_ALWAYS_ALLOW_CHANNEL_DELETION - tylko ją trzeba ustawić na wszystkich kanałach, które można kasować (tego używam w HPD Alert RC1 ).
Możesz też tego użyć np. do kasowania "wirtualnych kanałów" z bramki.
Natomiast cała trudność jest w logice kasowania kanałów i urządzeń.
Potrzeba dodać klasę:
Code: Select all
class ConflictResolver : public Supla::Device::ChannelConflictResolver
i zaimplementować tą metodę:
Code: Select all
virtual bool onChannelConflictReport(
uint8_t *channelReport,
uint8_t channelReportSize,
bool hasConfilictInvalidType,
bool hasConfilictChannelMissingOnServer,
bool hasConflictChannelMissingOnDevice) = 0;
Instancję tej klasy podpinasz do:
Code: Select all
SuplaDevice.setChannelConflictResolver(instancja);
Tak wygląda przykładowa implementacja tej metody:
Code: Select all
bool ConflictResolver::onChannelConflictReport(
uint8_t *channelReport,
uint8_t channelReportSize,
bool hasConflictInvalidType,
bool hasConflictChannelMissingOnServer,
bool hasConflictChannelMissingOnDevice) {
if (hasConflictChannelMissingOnDevice) {
SUPLA_LOG_ERROR("ConflictResolver: Channel conflict - channel missing "
"on device. Not recoverable. Aborting...");
return false;
}
if (hasConflictInvalidType) {
SUPLA_LOG_ERROR("ConflictResolver: Channel conflict - channel type "
"mismatch. Not recoverable. Aborting...");
return false;
}
if (hasConflictChannelMissingOnServer) {
SUPLA_LOG_INFO(
"ConflictResolver: Channel conflict - channel missing "
"on server. Trying to remove affected devices...");
auto maxChannelNumber = Supla::RegisterDevice::getMaxChannelNumberUsed();
for (int i = 0; i <= maxChannelNumber; i++) {
if ((i >= channelReportSize || channelReport[i] == 0) &&
!Supla::RegisterDevice::isChannelNumberFree(i)) {
Supla::Element *device = getDeviceByChannelNumber(i);
if (device != nullptr) {
Supla::AutoLock lock(sdc->getTimerAccessMutex());
device->purgeConfig();
delete device;
device = nullptr;
if (!Supla::Storage::IsStateStorageValid()) {
Supla::Storage::WriteStateStorage();
}
}
}
}
}
return false;
}
Tutaj szukamy "elementów" obsługujących dany channel number. Możliwe, że u Ciebie będzie wygodniej przejść z tego elementu o danym numerze kanału, na element obsługujący dany "subdevice" (w poprzednim poście są linki do supla srpc, gdzie jest przykład jak to zrobić).
Jest teź mutex ustawiony o nazwie "lock". Tutaj lukfud ostatnio trochę działała i ESP32 w Supli pod Arduino dostało obsługę mutexów, więc to powinno działać

. Lock jest potrzebny, aby nie usunąć instancji danej klasy, np. gdy jest dla niej aktywne przetwarzanie w metodach onFastTimer lub onTimer - co by mogło skutkować crashem.
Metoda dostaje info o tym jakiego rodzaju konflikt kanałów jest wykryty. Przy "braku kanału po stronie urządzenia" oraz "niewłaściwy typ kanału" nie ma tutaj procedury ratunkowej

. Ale ten trzeci typ, to jest to co robimy przy "usuń" po stronie serwera.
Oczywiście to co trzeba usunąć i jak to poprawnie zrobić, to zostaje do implementacji po stronie bramki.