diff --git a/src/main.cpp b/src/main.cpp index 6dc086c5..48ebbf54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,6 @@ #include #include -#include - #include #include diff --git a/src/peripherals/flow_control/FlowControl.hpp b/src/peripherals/flow_control/FlowControl.hpp index 581bd5c5..ce0eba03 100644 --- a/src/peripherals/flow_control/FlowControl.hpp +++ b/src/peripherals/flow_control/FlowControl.hpp @@ -29,7 +29,9 @@ class FlowControl : public Peripheral { PwmMotorDriver& controller, ValveControlStrategy& strategy, gpio_num_t pin, double qFactor, milliseconds measurementFrequency) : Peripheral(name, mqttRoot) - , valve(name, controller, strategy, mqttRoot) + , valve(name, controller, strategy, mqttRoot, [this]() { + publishTelemetry(); + }) , flowMeter(name, mqttRoot, pin, qFactor, measurementFrequency) { } diff --git a/src/peripherals/valve/Valve.hpp b/src/peripherals/valve/Valve.hpp index 5d8ffc24..ff8f46ee 100644 --- a/src/peripherals/valve/Valve.hpp +++ b/src/peripherals/valve/Valve.hpp @@ -34,7 +34,9 @@ class Valve public: Valve(const String& name, PwmMotorDriver& controller, ValveControlStrategy& strategy, shared_ptr mqttRoot) : Peripheral(name, mqttRoot) - , valve(name, controller, strategy, mqttRoot) { + , valve(name, controller, strategy, mqttRoot, [this]() { + publishTelemetry(); + }) { } void configure(const ValveConfig& config) override { diff --git a/src/peripherals/valve/ValveComponent.hpp b/src/peripherals/valve/ValveComponent.hpp index 5d457223..6c1c2159 100644 --- a/src/peripherals/valve/ValveComponent.hpp +++ b/src/peripherals/valve/ValveComponent.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include @@ -152,10 +154,11 @@ class LatchingValveControlStrategy class ValveComponent : public Component { public: - ValveComponent(const String& name, PwmMotorDriver& controller, ValveControlStrategy& strategy, shared_ptr mqttRoot) + ValveComponent(const String& name, PwmMotorDriver& controller, ValveControlStrategy& strategy, shared_ptr mqttRoot, std::function publishTelemetry) : Component(name, mqttRoot) , controller(controller) - , strategy(strategy) { + , strategy(strategy) + , publishTelemetry(publishTelemetry) { Log.infoln("Creating valve '%s' with strategy %s", name.c_str(), strategy.describe().c_str()); @@ -179,14 +182,14 @@ class ValveComponent : public Component { Task::loop(name, 3072, [this, name](Task& task) { auto now = system_clock::now(); - if (overrideState != ValveState::NONE && now > overrideUntil) { + if (overrideState != ValveState::NONE && now > overrideUntil.load()) { Log.traceln("Valve '%s' override expired", name.c_str()); overrideUntil = time_point(); overrideState = ValveState::NONE; } ValveStateUpdate update; if (overrideState != ValveState::NONE) { - update = { overrideState, duration_cast(overrideUntil - now) }; + update = { overrideState, duration_cast(overrideUntil.load() - now) }; Log.traceln("Valve '%s' override state is %d, will change after %F sec", name.c_str(), static_cast(update.state), update.transitionAfter.count() / 1000.0); } else { @@ -197,15 +200,16 @@ class ValveComponent : public Component { setState(update.state); // TODO Account for time spent in setState() updateQueue.pollIn(update.transitionAfter, [this](const std::variant& change) { - std::visit([this](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - overrideState = arg.state; - overrideUntil = arg.until; - } else if constexpr (std::is_same_v) { - schedules = std::list(arg.schedules); - } - }, + std::visit( + [this](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + overrideState = arg.state; + overrideUntil = arg.until; + } else if constexpr (std::is_same_v) { + schedules = std::list(arg.schedules); + } + }, change); }); }); @@ -219,6 +223,15 @@ class ValveComponent : public Component { void populateTelemetry(JsonObject& telemetry) { telemetry["state"] = this->state; + auto overrideUntil = this->overrideUntil.load(); + if (overrideUntil != time_point()) { + time_t rawtime = system_clock::to_time_t(overrideUntil); + auto timeinfo = gmtime(&rawtime); + char buffer[80]; + strftime(buffer, 80, "%FT%TZ", timeinfo); + telemetry["overrideEnd"] = string(buffer); + telemetry["overrideState"] = this->overrideState.load(); + } } private: @@ -255,11 +268,15 @@ class ValveComponent : public Component { // Ignore break; } - // TODO Publish event + mqttRoot->publish("events/state", [=](JsonObject& json) { + json["state"] = state; + }); + publishTelemetry(); } PwmMotorDriver& controller; ValveControlStrategy& strategy; + std::function publishTelemetry; ValveState state = ValveState::NONE; @@ -274,9 +291,9 @@ class ValveComponent : public Component { std::list schedules; }; - std::list schedules; - ValveState overrideState = ValveState::NONE; - time_point overrideUntil; + std::list schedules = {}; + std::atomic overrideState = ValveState::NONE; + std::atomic> overrideUntil = time_point(); Queue> updateQueue { "eventQueue", 1 }; }; diff --git a/src/peripherals/valve/ValveScheduler.hpp b/src/peripherals/valve/ValveScheduler.hpp index ef875d1c..dc31e099 100644 --- a/src/peripherals/valve/ValveScheduler.hpp +++ b/src/peripherals/valve/ValveScheduler.hpp @@ -39,9 +39,10 @@ class ValveSchedule { return duration; } - const time_point start; - const seconds period; - const seconds duration; +private: + time_point start; + seconds period; + seconds duration; }; struct ValveStateUpdate { diff --git a/test/ValveSchedulerTest.cpp b/test/ValveSchedulerTest.cpp index 13851943..584da257 100644 --- a/test/ValveSchedulerTest.cpp +++ b/test/ValveSchedulerTest.cpp @@ -31,9 +31,9 @@ class ValveSchedulerTest : public testing::Test { TEST_F(ValveSchedulerTest, can_create_schedule) { ValveSchedule schedule(base, hours { 1 }, minutes { 1 }); - EXPECT_EQ(schedule.start, base); - EXPECT_EQ(schedule.period, hours { 1 }); - EXPECT_EQ(schedule.duration, minutes { 1 }); + EXPECT_EQ(schedule.getStart(), base); + EXPECT_EQ(schedule.getPeriod(), hours { 1 }); + EXPECT_EQ(schedule.getDuration(), minutes { 1 }); } // TEST_F(ValveSchedulerTest, can_create_schedule_from_json) {