fix: set rolling codes only on the main loop

Sending a command reads a remote's next rolling code, queues the frame and
commits the code, all on loop(). /setRollingCode, a shades restore and
/updateShadeConfig wrote the same codes from the web server task, so a set
could be undone by a command's commit, and a restore could save an older
code to NVS that survived the reboot. All three now go through the web
command queue to loop(). They don't use the radio, so they are never held
back or refused while it is busy.

/restore now answers after queueing the restore. A broken options string
used to send an error after the success answer had already gone out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-14 16:01:55 +02:00
parent 1128431e8c
commit 4a33b0d7dd
4 changed files with 120 additions and 69 deletions

View file

@ -10,17 +10,24 @@ static const web_cmd_t RADIO_COMMANDS[] = {
void setUp() {}
void tearDown() {}
static void test_only_set_positions_stays_off_the_radio() {
static const web_cmd_t LOOP_COMMANDS[] = {
web_cmd_t::set_positions, web_cmd_t::set_rolling_code, web_cmd_t::restore_shades, web_cmd_t::load_shades
};
static void test_only_loop_commands_stay_off_the_radio() {
int offRadio = 0;
for(uint8_t t = 0; t <= static_cast<uint8_t>(web_cmd_t::unpair_shade); t++) {
for(uint8_t t = 0; t <= static_cast<uint8_t>(web_cmd_t::load_shades); t++) {
if(!webCommandUsesRadio(static_cast<web_cmd_t>(t))) offRadio++;
}
TEST_ASSERT_EQUAL_INT(1, offRadio);
TEST_ASSERT_FALSE(webCommandUsesRadio(web_cmd_t::set_positions));
TEST_ASSERT_EQUAL_INT(4, offRadio);
for(web_cmd_t t : LOOP_COMMANDS) TEST_ASSERT_FALSE(webCommandUsesRadio(t));
}
static void test_set_positions_is_never_held() {
TEST_ASSERT_FALSE(holdWebCommand(web_cmd_t::set_positions, false, false));
TEST_ASSERT_FALSE(holdWebCommand(web_cmd_t::set_positions, true, false));
static void test_loop_commands_are_never_held() {
// Nothing goes on air, so a full or suspended radio doesn't matter.
for(web_cmd_t t : LOOP_COMMANDS) {
TEST_ASSERT_FALSE(holdWebCommand(t, false, false));
TEST_ASSERT_FALSE(holdWebCommand(t, true, false));
}
}
static void test_radio_command_waits_for_room() {
for(web_cmd_t t : RADIO_COMMANDS) {
@ -46,8 +53,8 @@ int main(int argc, char **argv) {
(void)argc;
(void)argv;
UNITY_BEGIN();
RUN_TEST(test_only_set_positions_stays_off_the_radio);
RUN_TEST(test_set_positions_is_never_held);
RUN_TEST(test_only_loop_commands_stay_off_the_radio);
RUN_TEST(test_loop_commands_are_never_held);
RUN_TEST(test_radio_command_waits_for_room);
RUN_TEST(test_commands_are_not_held_while_suspended);
RUN_TEST(test_unpair_waits_out_a_suspend);