Compare commits

..

3 Commits

Author SHA1 Message Date
94f00c0cef WIP using new PositionWatcher 2025-01-20 22:53:54 +11:00
049037a0a1 Update ArduinoJson to 7.3.0 2025-01-20 22:53:54 +11:00
ba6cca8992 Update RF24 to 1.4.11 2025-01-20 22:53:54 +11:00
10 changed files with 448 additions and 117 deletions

View File

@@ -51,7 +51,7 @@ void Configurator::addShadeConfiguredCallback(std::function<void (Shade)> callba
bool Configurator::tryBuild(std::string key) {
if (auto id = discoveredIds.find(key); id != discoveredIds.end()) {
if (auto friendlyName = discoveredFriendlyNames.find(key); friendlyName != discoveredFriendlyNames.end()) {
auto shade = Shade{id->second, key, friendlyName->second, -1, -1, 0, 0, nullptr};
auto shade = Shade{id->second, key, friendlyName->second, "stopped", -1, -1};
for (size_t i = 0; i < shadeConfiguredCallbacks.size(); i++) {
shadeConfiguredCallbacks[i](shade);
}

View File

@@ -0,0 +1,53 @@
#include "PositionWatcher.h"
#include <Arduino.h>
void PositionWatcher::start(int8_t newTargetValue)
{
targetValue = newTargetValue;
lastPollTime = 0;
pollingInterval = 2000;
maxAttempts = 3;
maxConsecutiveDuplicates = 2;
consecutiveDuplicates = 0;
currentAttempt = 0;
isActive = true;
}
bool PositionWatcher::shouldFetch()
{
if (isWatching() && millis() - lastPollTime > pollingInterval) {
if (currentAttempt >= maxAttempts) {
isActive = false;
return false;
}
return true;
}
return false;
}
bool PositionWatcher::isWatching()
{
return isActive;
}
void PositionWatcher::fetchQueued()
{
lastPollTime = millis();
currentAttempt++;
}
void PositionWatcher::fetchReceived(int8_t value)
{
currentAttempt = 0;
if (value == targetValue) {
isActive = false;
} else if (lastValue == value) {
consecutiveDuplicates++;
if (consecutiveDuplicates >= maxConsecutiveDuplicates) {
isActive = false;
}
} else {
consecutiveDuplicates = 1;
}
lastValue = value;
}

View File

@@ -0,0 +1,31 @@
#ifndef POSITION_WATCHER_H
#define POSITION_WATCHER_H
#include <stdint.h>
class PositionWatcher
{
private:
bool isActive;
int8_t targetValue;
int8_t lastValue;
int8_t consecutiveDuplicates;
uint32_t pollingInterval;
int8_t maxAttempts;
int8_t maxConsecutiveDuplicates;
int8_t currentAttempt;
uint32_t lastPollTime;
public:
void start(int8_t newTargetValue);
bool shouldFetch();
bool isWatching();
void fetchQueued();
void fetchReceived(int8_t value);
};
#endif // POSITION_WATCHER_H

View File

@@ -8,11 +8,13 @@ struct Shade {
uint16_t ID;
std::string key;
std::string friendlyName;
int8_t lastTargetPosition;
std::string state;
int8_t lastPosition;
uint8_t samePositionCount;
uint8_t positionFetchCount;
void* timer;
int8_t lastBattery;
bool modified;
};
#endif // SHADE_H

View File

@@ -0,0 +1,33 @@
#ifndef SHADE_COMMAND_H
#define SHADE_COMMAND_H
#include <variant>
#include <stdint.h>
#include <typeindex>
struct OpenCommand {
uint16_t shadeID;
};
struct CloseCommand {
uint16_t shadeID;
};
struct StopCommand {
uint16_t shadeID;
};
struct SetPositionCommand {
uint16_t shadeID;
float percentage;
};
struct RefreshCommand {
uint16_t shadeID;
};
using ShadeCommand = std::variant<OpenCommand, CloseCommand, StopCommand, SetPositionCommand, RefreshCommand>;
#endif // SHADE_COMMAND_H

View File

@@ -20,12 +20,10 @@ build_flags =
lib_deps =
${env.lib_deps}
nrf24/RF24@^1.4.8
nrf24/RF24@^1.4.11
plapointe6/EspMQTTClient@^1.13.3
contrem/arduino-timer@^3.0.1
RFPowerView=https://git.mattway.com.au/matt/RFPowerView.git#v0.0.3
[env:test_embedded]
@@ -39,6 +37,7 @@ lib_deps =
[env:test_desktop]
platform = native
build_type = test
lib_compat_mode = off
lib_deps =
${env.lib_deps}
ArduinoFake
@@ -47,4 +46,4 @@ lib_deps =
monitor_speed = 115200
test_framework = unity
lib_deps =
ArduinoJson=https://github.com/bblanchon/ArduinoJson#v7.0.4
bblanchon/ArduinoJson@^7.3.0

View File

@@ -1,6 +1,5 @@
#include <Arduino.h>
#include <EspMqttClient.h>
#include <arduino-timer.h>
#include <ArduinoJson.h>
#include <RFPowerView.h>
#include <random>
@@ -10,6 +9,9 @@
#include "ShadeRepository.h"
#include "HADiscovery.h"
#include "secrets.h"
#include "ShadeCommand.h"
#include "PositionWatcher.h"
#include <queue>
#define SER_BAUDRATE (115200)
@@ -49,13 +51,15 @@ Configurator configurator = Configurator();
ShadeRepository shadeRepository = ShadeRepository();
using Command = std::variant<OpenCommand, CloseCommand, StopCommand, SetPositionCommand, RefreshCommand>;
std::queue<Command> commands;
std::map<uint16_t, PositionWatcher> positionWatchers;
HADiscovery haDiscovery(topic_prefix.c_str(), [] (const char* topic, const char* message) {
client.publish(topic, message);
});
#define MAX_FETCH_COUNT (20)
auto timer = Timer<10, millis, uint16_t>();
void processPacket(const Packet*);
void processCommandMessage(const String& topic, const String &payload);
void processSetPositionMessage(const String& topic, const String &payload);
@@ -67,13 +71,12 @@ bool sendSetPosition(uint16_t destination, float percentage);
bool sendFetchPosition(uint16_t destination);
bool sendPacket(Packet *packet);
bool checkPosition(uint16_t shadeID);
void startFetchingPosition(uint16_t shadeID, int8_t targetPosition);
void publishPosition(const std::string& shadeKey, const uint8_t position);
void publishState(const std::string& shadeKey, const String& state);
void publishBattery(const std::string& shadeKey, const uint8_t battery);
void startPositionWatcher(uint16_t shadeID, uint8_t targetPosition);
void publishDiscoveryTopics();
void setup() {
@@ -112,13 +115,107 @@ void setup() {
delay(100);
shadeRepository.upsert(Shade{0x4EF1, "study_blind", "Study Blind", "stopped", -1, -1, false});
Serial.println("Ready");
}
int loopCounter = 0;
void loop() {
powerView.loop();
client.loop();
timer.tick();
if (client.isConnected()) {
if (!commands.empty()) {
auto command = commands.front();
commands.pop();
if (std::holds_alternative<OpenCommand>(command)) {
auto openCommand = std::get<OpenCommand>(command);
Serial.printf("Open command received for shade 0x%04x\n", openCommand.shadeID);
if (sendOpenPacket(openCommand.shadeID)) {
auto shade = shadeRepository.findById(openCommand.shadeID);
if (shade != nullptr) {
shade->state = "opening";
shade->modified = true;
}
startPositionWatcher(openCommand.shadeID, 100);
}
} else if (std::holds_alternative<CloseCommand>(command)) {
auto closeCommand = std::get<CloseCommand>(command);
Serial.printf("Close command received for shade 0x%04x\n", closeCommand.shadeID);
if (sendClosePacket(closeCommand.shadeID)) {
auto shade = shadeRepository.findById(closeCommand.shadeID);
if (shade != nullptr) {
shade->state = "closing";
shade->modified = true;
}
startPositionWatcher(closeCommand.shadeID, 0);
}
} else if (std::holds_alternative<StopCommand>(command)) {
auto stopCommand = std::get<StopCommand>(command);
Serial.printf("Stop command received for shade 0x%04x\n", stopCommand.shadeID);
sendStopPacket(stopCommand.shadeID);
startPositionWatcher(stopCommand.shadeID, -1);
} else if (std::holds_alternative<SetPositionCommand>(command)) {
auto setPositionCommand = std::get<SetPositionCommand>(command);
Serial.printf("Set Position command received for shade 0x%04x (%.2f)\n", setPositionCommand.shadeID, setPositionCommand.percentage);
if (sendSetPosition(setPositionCommand.shadeID, setPositionCommand.percentage)) {
auto shade = shadeRepository.findById(setPositionCommand.shadeID);
if (shade != nullptr) {
if (setPositionCommand.percentage > shade->lastPosition / 100.0f) {
shade->state = "opening";
shade->modified = true;
} else {
shade->state = "closing";
shade->modified = true;
}
}
startPositionWatcher(setPositionCommand.shadeID, setPositionCommand.percentage * 100);
}
} else if (std::holds_alternative<RefreshCommand>(command)) {
auto refreshCommand = std::get<RefreshCommand>(command);
Serial.printf("Refresh command received for shade 0x%04x\n", refreshCommand.shadeID);
startPositionWatcher(refreshCommand.shadeID, -1);
}
}
for (auto& [shadeID, watcher] : positionWatchers) {
if (watcher.shouldFetch()) {
if (sendFetchPosition(shadeID)) {
watcher.fetchQueued();
}
} else if (!watcher.isWatching()) {
positionWatchers.erase(shadeID);
auto shade = shadeRepository.findById(shadeID);
if (shade != nullptr) {
if (shade->lastPosition == 0) {
shade->state = "closed";
shade->modified = true;
} else {
shade->state = "open";
shade->modified = true;
}
}
}
}
for (auto shade = shadeRepository.begin(); shade != shadeRepository.end(); shade++) {
if (shade->modified) {
if (shade->lastPosition != -1) {
publishPosition(shade->key, shade->lastPosition);
}
if (shade->lastBattery != -1) {
publishBattery(shade->key, shade->lastBattery);
}
publishState(shade->key, shade->state.c_str());
shade->modified = false;
}
}
}
}
void processPacket(const Packet *packet) {
@@ -148,31 +245,33 @@ void processPacket(const Packet *packet) {
}
if (packet->type == PacketType::FIELDS) {
FieldsParameters parameters = std::get<FieldsParameters>(packet->parameters);
for (size_t i = 0; i < parameters.fields.size(); i++) {
Field field = parameters.fields[i];
if (field.identifier == 0x50) {
auto shade = shadeRepository.findById(source);
if (shade != nullptr) {
auto shade = shadeRepository.findById(source);
if (shade != nullptr) {
FieldsParameters parameters = std::get<FieldsParameters>(packet->parameters);
for (size_t i = 0; i < parameters.fields.size(); i++) {
Field field = parameters.fields[i];
if (field.identifier == 0x50) {
uint16_t value = std::get<uint16_t>(field.value);
uint8_t position = (uint8_t)std::round(((float)value / 0xFFFF) * 100);
if (shade->lastPosition == position) {
shade->samePositionCount++;
} else {
shade->samePositionCount = 1;
}
shade->lastPosition = position;
shade->modified = true;
publishPosition(shade->key, position);
}
} else if (field.identifier == 0x42) {
auto shade = shadeRepository.findById(source);
if (shade != nullptr) {
auto it = positionWatchers.find(shade->ID);
if (it != positionWatchers.end()) {
auto& watcher = it->second;
watcher.fetchReceived(position);
}
// TODO: set updated flag?
} else if (field.identifier == 0x42) {
uint8_t value = std::get<uint8_t>(field.value);
uint8_t battery = uint8_t(((float)value / 200) * 100);
publishBattery(shade->key, battery);
shade->lastBattery = battery;
shade->modified = true;
// TODO: set updated flag?
}
}
}
@@ -288,92 +387,45 @@ bool sendPacket(Packet *packet) {
}
}
void startPositionWatcher(uint16_t shadeID, uint8_t targetValue) {
auto& watcher = positionWatchers.try_emplace(shadeID).first->second;
watcher.start(targetValue);
}
void processCommandMessage(const String &topic, const String &payload) {
int startIndex = topic.indexOf("/") + 1;
int endIndex = topic.indexOf("/", startIndex);
auto key = topic.substring(startIndex, endIndex).c_str();
String key = topic.substring(startIndex, endIndex);
auto shade = shadeRepository.findByKey(key);
Serial.printf("Received command '%s' for shade '%s'\n", payload.c_str(), key.c_str());
auto shade = shadeRepository.findByKey(key.c_str());
if (shade != nullptr) {
if (payload == "OPEN") {
sendOpenPacket(shade->ID);
startFetchingPosition(shade->ID, 100);
publishState(shade->key, "opening");
commands.push(OpenCommand {shade->ID});
} else if (payload == "CLOSE") {
sendClosePacket(shade->ID);
startFetchingPosition(shade->ID, 0);
publishState(shade->key, "closing");
commands.push(CloseCommand {shade->ID});
} else if (payload == "STOP") {
sendStopPacket(shade->ID);
startFetchingPosition(shade->ID, -1);
timer.in(100, sendFetchPosition, shade->ID);
commands.push(StopCommand {shade->ID});
} else if (payload == "REFRESH") {
startFetchingPosition(shade->ID, -1);
commands.push(RefreshCommand {shade->ID});
}
} else {
Serial.println("Failed to find shade");
}
}
void processSetPositionMessage(const String& topic, const String &payload) {
int startIndex = topic.indexOf("/") + 1;
int endIndex = topic.indexOf("/", startIndex);
auto key = topic.substring(startIndex, endIndex).c_str();
String key = topic.substring(startIndex, endIndex);
auto shade = shadeRepository.findByKey(key);
Serial.printf("Received set position command for shade '%s' (%s)\n", key.c_str(), payload.c_str());
auto shade = shadeRepository.findByKey(key.c_str());
if (shade != nullptr) {
float percentage = payload.toInt() / 100.0f;
sendSetPosition(shade->ID, percentage);
if (payload.toInt() > shade->lastPosition) {
publishState(shade->key, "opening");
} else if (payload.toInt() < shade->lastPosition) {
publishState(shade->key, "closing");
}
startFetchingPosition(shade->ID, payload.toInt());
}
}
bool checkPosition(uint16_t shadeID) {
auto shade = shadeRepository.findById(shadeID);
if (shade != nullptr) {
// Keep fetching position if:
// - the last reported position doesn't match the target position
// - a position hasn't been reported yet
// - there is no target position
if (shade->lastTargetPosition != shade->lastPosition || shade->lastPosition == -1 || shade->lastTargetPosition == -1) {
// Keep fetching position if the count limits have not been reached
if (shade->positionFetchCount < MAX_FETCH_COUNT && shade->samePositionCount < 2) {
shade->positionFetchCount++;
sendFetchPosition(shadeID);
return true;
}
}
publishState(shade->key, shade->lastPosition > 0 ? "open" : "closed");
return false;
}
return false;
}
void startFetchingPosition(uint16_t shadeID, int8_t targetPosition) {
auto shade = shadeRepository.findById(shadeID);
if (shade != nullptr) {
// Cancel any existing timer
if (shade->timer != nullptr) {
timer.cancel(shade->timer);
shade->timer = nullptr;
}
shade->lastTargetPosition = targetPosition;
shade->positionFetchCount = 0;
shade->samePositionCount = 1;
shade->timer = timer.every(2000, checkPosition, shade->ID);
commands.push(SetPositionCommand {shade->ID, percentage});
}
}

View File

@@ -23,7 +23,7 @@ void test_publish_message_count()
HADiscovery haDiscovery = HADiscovery("my_prefix/", callback);
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
TEST_ASSERT_EQUAL_INT(3, callbackInvokedCount);
}
@@ -47,7 +47,7 @@ void test_publish_cover_message()
HADiscovery haDiscovery = HADiscovery("my_prefix/", callback);
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
TEST_ASSERT_EQUAL_INT(1, messageAssertedCount);
}
@@ -71,7 +71,7 @@ void test_publish_battery_message()
HADiscovery haDiscovery = HADiscovery("my_prefix/", callback);
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
TEST_ASSERT_EQUAL_INT(1, messageAssertedCount);
}
@@ -95,7 +95,7 @@ void test_publish_button_message()
HADiscovery haDiscovery = HADiscovery("my_prefix/", callback);
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
haDiscovery.publish(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
TEST_ASSERT_EQUAL_INT(1, messageAssertedCount);
}

View File

@@ -0,0 +1,161 @@
#include <unity.h>
#include <Arduino.h>
#include <ArduinoFake.h>
#include "PositionWatcher.h"
using namespace fakeit;
void setUp()
{
}
void tearDown()
{
}
void test_position_watcher_should_not_fetch_initially()
{
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
}
void test_position_watcher_should_fetch_after_start()
{
When(Method(ArduinoFake(), millis)).Return(10000);
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
positionWatcher.start(75);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
}
void test_position_watcher_should_not_fetch_before_polling_interval()
{
When(Method(ArduinoFake(), millis)).AlwaysReturn(10000);
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
positionWatcher.start(75);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
}
void test_position_watcher_should_fetch_after_polling_interval()
{
When(Method(ArduinoFake(), millis)).AlwaysReturn(10000);
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
positionWatcher.start(75);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
When(Method(ArduinoFake(), millis)).AlwaysReturn(20000);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
}
void test_position_watcher_should_not_fetch_after_max_attempts()
{
When(Method(ArduinoFake(), millis)).AlwaysReturn(10000);
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
positionWatcher.start(75);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
When(Method(ArduinoFake(), millis)).AlwaysReturn(20000);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
When(Method(ArduinoFake(), millis)).AlwaysReturn(30000);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
When(Method(ArduinoFake(), millis)).AlwaysReturn(40000);
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
}
void test_position_watcher_should_stop_after_enough_duplicates()
{
When(Method(ArduinoFake(), millis)).AlwaysReturn(10000);
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
positionWatcher.start(75);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
positionWatcher.fetchReceived(50);
TEST_ASSERT_TRUE(positionWatcher.isWatching());
positionWatcher.fetchQueued();
positionWatcher.fetchReceived(60);
TEST_ASSERT_TRUE(positionWatcher.isWatching());
positionWatcher.fetchQueued();
positionWatcher.fetchReceived(60);
TEST_ASSERT_FALSE(positionWatcher.isWatching());
}
void test_position_watcher_should_stop_after_target_value()
{
When(Method(ArduinoFake(), millis)).AlwaysReturn(10000);
PositionWatcher positionWatcher = PositionWatcher();
TEST_ASSERT_FALSE(positionWatcher.shouldFetch());
positionWatcher.start(75);
TEST_ASSERT_TRUE(positionWatcher.shouldFetch());
positionWatcher.fetchQueued();
positionWatcher.fetchReceived(50);
TEST_ASSERT_TRUE(positionWatcher.isWatching());
positionWatcher.fetchQueued();
positionWatcher.fetchReceived(60);
TEST_ASSERT_TRUE(positionWatcher.isWatching());
positionWatcher.fetchQueued();
positionWatcher.fetchReceived(75);
TEST_ASSERT_FALSE(positionWatcher.isWatching());
}
int runUnityTests(void)
{
UNITY_BEGIN();
RUN_TEST(test_position_watcher_should_not_fetch_initially);
RUN_TEST(test_position_watcher_should_fetch_after_start);
RUN_TEST(test_position_watcher_should_not_fetch_before_polling_interval);
RUN_TEST(test_position_watcher_should_fetch_after_polling_interval);
RUN_TEST(test_position_watcher_should_not_fetch_after_max_attempts);
RUN_TEST(test_position_watcher_should_stop_after_enough_duplicates);
RUN_TEST(test_position_watcher_should_stop_after_target_value);
return UNITY_END();
}
/**
* For Arduino framework
*/
void setup()
{
// Wait ~2 seconds before the Unity test runner
// establishes connection with a board Serial interface
delay(2000);
runUnityTests();
}
void loop() {}
int main(void)
{
return runUnityTests();
}

View File

@@ -13,7 +13,7 @@ void tearDown()
void test_shade_is_found_with_id()
{
ShadeRepository shadeRepository = ShadeRepository();
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
auto shade = shadeRepository.findById(0xABCD);
@@ -26,7 +26,7 @@ void test_shade_is_found_with_id()
void test_shade_is_found_with_key()
{
ShadeRepository shadeRepository = ShadeRepository();
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
auto shade = shadeRepository.findByKey("test_shade");
@@ -39,8 +39,8 @@ void test_shade_is_found_with_key()
void test_adding_shade_twice_only_added_once()
{
ShadeRepository shadeRepository = ShadeRepository();
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
int count = 0;
@@ -54,13 +54,13 @@ void test_adding_shade_twice_only_added_once()
void test_updating_shade_id()
{
ShadeRepository shadeRepository = ShadeRepository();
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
auto shade1 = shadeRepository.findById(0xABCD);
TEST_ASSERT_EQUAL_HEX16(0xABCD, shade1->ID);
shadeRepository.upsert(Shade{0x1234, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0x1234, "test_shade", "Test Shade", "stopped", -1, -1});
auto shade2 = shadeRepository.findById(0x1234);
@@ -74,13 +74,13 @@ void test_updating_shade_id()
void test_updating_shade_friendly_name()
{
ShadeRepository shadeRepository = ShadeRepository();
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
auto shade1 = shadeRepository.findByKey("test_shade");
TEST_ASSERT_EQUAL_STRING("Test Shade", shade1->friendlyName.c_str());
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Updated Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Updated Test Shade", "stopped", -1, -1});
auto shade2 = shadeRepository.findByKey("test_shade");
@@ -101,7 +101,7 @@ void test_shade_added_callback()
TEST_ASSERT_EQUAL_STRING("test_shade", shade.key.c_str());
});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
TEST_ASSERT_EQUAL_INT(1, callbackInvokedCount);
}
@@ -119,8 +119,8 @@ void test_shade_changed_callback()
TEST_ASSERT_EQUAL_STRING("test_shade", shade.key.c_str());
});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0x1234, "test_shade", "Updated Test Shade", -1, -1, 0, 0, nullptr});
shadeRepository.upsert(Shade{0xABCD, "test_shade", "Test Shade", "stopped", -1, -1});
shadeRepository.upsert(Shade{0x1234, "test_shade", "Updated Test Shade", "stopped", -1, -1});
TEST_ASSERT_EQUAL_INT(1, callbackInvokedCount);
}