Skip to content

Commit

Permalink
Move motor into ValveControlStrategy implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
lptr committed Oct 27, 2024
1 parent 4a3105e commit 887dd3e
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 56 deletions.
5 changes: 2 additions & 3 deletions main/peripherals/flow_control/FlowControl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ class FlowControl : public Peripheral<FlowControlConfig> {
shared_ptr<MqttDriver::MqttRoot> mqttRoot,
PcntManager& pcnt,
SleepManager& sleepManager,
PwmMotorDriver& controller,
ValveControlStrategy& strategy,
InternalPinPtr pin,
double qFactor,
milliseconds measurementFrequency)
: Peripheral<FlowControlConfig>(name, mqttRoot)
, valve(name, sleepManager, controller, strategy, mqttRoot, [this]() {
, valve(name, sleepManager, strategy, mqttRoot, [this]() {
publishTelemetry();
})
, flowMeter(name, mqttRoot, pcnt, pin, qFactor, measurementFrequency) {
Expand Down Expand Up @@ -95,6 +94,7 @@ class FlowControlFactory
ValveControlStrategy* strategy;
try {
strategy = createValveControlStrategy(
targetMotor,
valveConfig.strategy.get(),
valveConfig.switchDuration.get(),
valveConfig.holdDuty.get() / 100.0);
Expand All @@ -107,7 +107,6 @@ class FlowControlFactory

services.pcntManager,
services.sleepManager,
targetMotor,
*strategy,

flowMeterConfig.pin.get(),
Expand Down
6 changes: 3 additions & 3 deletions main/peripherals/valve/Valve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ class Valve
Valve(
const String& name,
SleepManager& sleepManager,
PwmMotorDriver& controller,
ValveControlStrategy& strategy,
shared_ptr<MqttDriver::MqttRoot> mqttRoot)
: Peripheral<ValveConfig>(name, mqttRoot)
, valve(name, sleepManager, controller, strategy, mqttRoot, [this]() {
, valve(name, sleepManager, strategy, mqttRoot, [this]() {
publishTelemetry();
}) {
}
Expand Down Expand Up @@ -77,13 +76,14 @@ class ValveFactory
ValveControlStrategy* strategy;
try {
strategy = createValveControlStrategy(
targetMotor,
deviceConfig.strategy.get(),
deviceConfig.switchDuration.get(),
deviceConfig.holdDuty.get() / 100.0);
} catch (const std::exception& e) {
throw PeripheralCreationException("failed to create strategy: " + String(e.what()));
}
return make_unique<Valve>(name, services.sleepManager, targetMotor, *strategy, mqttRoot);
return make_unique<Valve>(name, services.sleepManager, *strategy, mqttRoot);
}
};

Expand Down
89 changes: 43 additions & 46 deletions main/peripherals/valve/ValveComponent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ namespace farmhub::peripherals::valve {

class ValveControlStrategy {
public:
virtual void open(PwmMotorDriver& controller) = 0;
virtual void close(PwmMotorDriver& controller) = 0;
virtual void open() = 0;
virtual void close() = 0;
virtual ValveState getDefaultState() const = 0;

virtual String describe() const = 0;
Expand All @@ -46,31 +46,33 @@ class HoldingValveControlStrategy
: public ValveControlStrategy {

public:
HoldingValveControlStrategy(milliseconds switchDuration, double holdDuty)
: switchDuration(switchDuration)
HoldingValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty)
: controller(controller)
, switchDuration(switchDuration)
, holdDuty(holdDuty) {
}

protected:
void driveAndHold(PwmMotorDriver& controller, ValveState targetState) {
void driveAndHold(ValveState targetState) {
switch (targetState) {
case ValveState::OPEN:
driveAndHold(controller, MotorPhase::FORWARD);
driveAndHold(MotorPhase::FORWARD);
break;
case ValveState::CLOSED:
driveAndHold(controller, MotorPhase::REVERSE);
driveAndHold(MotorPhase::REVERSE);
break;
default:
// Ignore
break;
}
}

PwmMotorDriver& controller;
const milliseconds switchDuration;
const double holdDuty;

private:
void driveAndHold(PwmMotorDriver& controller, MotorPhase phase) {
void driveAndHold(MotorPhase phase) {
controller.drive(phase, 1.0);
delay(switchDuration.count());
controller.drive(phase, holdDuty);
Expand All @@ -80,15 +82,15 @@ class HoldingValveControlStrategy
class NormallyClosedValveControlStrategy
: public HoldingValveControlStrategy {
public:
NormallyClosedValveControlStrategy(milliseconds switchDuration, double holdDuty)
: HoldingValveControlStrategy(switchDuration, holdDuty) {
NormallyClosedValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty)
: HoldingValveControlStrategy(controller, switchDuration, holdDuty) {
}

void open(PwmMotorDriver& controller) override {
driveAndHold(controller, ValveState::OPEN);
void open() override {
driveAndHold(ValveState::OPEN);
}

void close(PwmMotorDriver& controller) override {
void close() override {
controller.stop();
}

Expand All @@ -104,16 +106,16 @@ class NormallyClosedValveControlStrategy
class NormallyOpenValveControlStrategy
: public HoldingValveControlStrategy {
public:
NormallyOpenValveControlStrategy(milliseconds switchDuration, double holdDuty)
: HoldingValveControlStrategy(switchDuration, holdDuty) {
NormallyOpenValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double holdDuty)
: HoldingValveControlStrategy(controller, switchDuration, holdDuty) {
}

void open(PwmMotorDriver& controller) override {
void open() override {
controller.stop();
}

void close(PwmMotorDriver& controller) override {
driveAndHold(controller, ValveState::CLOSED);
void close() override {
driveAndHold(ValveState::CLOSED);
}

ValveState getDefaultState() const override {
Expand All @@ -128,18 +130,19 @@ class NormallyOpenValveControlStrategy
class LatchingValveControlStrategy
: public ValveControlStrategy {
public:
LatchingValveControlStrategy(milliseconds switchDuration, double switchDuty = 1.0)
: switchDuration(switchDuration)
LatchingValveControlStrategy(PwmMotorDriver& controller, milliseconds switchDuration, double switchDuty = 1.0)
: controller(controller)
, switchDuration(switchDuration)
, switchDuty(switchDuty) {
}

void open(PwmMotorDriver& controller) override {
void open() override {
controller.drive(MotorPhase::FORWARD, switchDuty);
delay(switchDuration.count());
controller.stop();
}

void close(PwmMotorDriver& controller) override {
void close() override {
controller.drive(MotorPhase::REVERSE, switchDuty);
delay(switchDuration.count());
controller.stop();
Expand All @@ -154,6 +157,7 @@ class LatchingValveControlStrategy
}

private:
PwmMotorDriver& controller;
const milliseconds switchDuration;
const double switchDuty;
};
Expand All @@ -163,55 +167,45 @@ class ValveComponent : public Component {
ValveComponent(
const String& name,
SleepManager& sleepManager,
PwmMotorDriver& controller,
ValveControlStrategy& strategy,
shared_ptr<MqttDriver::MqttRoot> mqttRoot,
std::function<void()> publishTelemetry)
: Component(name, mqttRoot)
, sleepManager(sleepManager)
, controller(controller)
, nvs(name)
, strategy(strategy)
, publishTelemetry(publishTelemetry) {

Log.info("Creating valve '%s' with strategy %s",
name.c_str(), strategy.describe().c_str());

controller.stop();

// Rewrite this to a switch statement
if (strategy.getDefaultState() == ValveState::OPEN) {
state = ValveState::OPEN;
} else if (strategy.getDefaultState() == ValveState::CLOSED) {
state = ValveState::CLOSED;
}

ValveState initState;
switch (strategy.getDefaultState()) {
case ValveState::OPEN:
Log.info("Assuming valve '%s' is open by default",
name.c_str());
state = ValveState::OPEN;
initState = ValveState::OPEN;
break;
case ValveState::CLOSED:
Log.info("Assuming valve '%s' is closed by default",
name.c_str());
state = ValveState::CLOSED;
initState = ValveState::CLOSED;
break;
default:
// Try to load from NVS
ValveState lastStoredState;
if (nvs.get("state", lastStoredState)) {
state = lastStoredState;
initState = lastStoredState;
Log.info("Restored state for valve '%s' from NVS: %d",
name.c_str(), static_cast<int>(state));
} else {
Log.info("No stored state for valve '%s'",
initState = ValveState::CLOSED;
Log.info("No stored state for valve '%s', defaulting to closed",
name.c_str());
}
break;
}

// TODO Restore stored state?
doTransitionTo(initState);

mqttRoot->registerCommand("override", [this](const JsonObject& request, JsonObject& response) {
ValveState targetState = request["state"].as<ValveState>();
Expand Down Expand Up @@ -313,14 +307,14 @@ class ValveComponent : public Component {
void open() {
Log.info("Opening valve '%s'", name.c_str());
KeepAwake keepAwake(sleepManager);
strategy.open(controller);
strategy.open();
setState(ValveState::OPEN);
}

void close() {
Log.info("Closing valve '%s'", name.c_str());
KeepAwake keepAwake(sleepManager);
strategy.close(controller);
strategy.close();
setState(ValveState::CLOSED);
}

Expand All @@ -329,7 +323,15 @@ class ValveComponent : public Component {
if (this->state == state) {
return;
}
doTransitionTo(state);

mqttRoot->publish("events/state", [=](JsonObject& json) {
json["state"] = state;
});
publishTelemetry();
}

void doTransitionTo(ValveState state) {
switch (state) {
case ValveState::OPEN:
open();
Expand All @@ -341,10 +343,6 @@ class ValveComponent : public Component {
// Ignore
break;
}
mqttRoot->publish("events/state", [=](JsonObject& json) {
json["state"] = state;
});
publishTelemetry();
}

void setState(ValveState state) {
Expand All @@ -356,7 +354,6 @@ class ValveComponent : public Component {
}

SleepManager& sleepManager;
PwmMotorDriver& controller;
NvsStore nvs;
ValveControlStrategy& strategy;
std::function<void()> publishTelemetry;
Expand Down
8 changes: 4 additions & 4 deletions main/peripherals/valve/ValveConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ enum class ValveControlStrategyType {
Latching
};

static ValveControlStrategy* createValveControlStrategy(ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) {
static ValveControlStrategy* createValveControlStrategy(PwmMotorDriver& motor, ValveControlStrategyType strategy, milliseconds switchDuration, double holdDuty) {
switch (strategy) {
case ValveControlStrategyType::NormallyOpen:
return new NormallyOpenValveControlStrategy(switchDuration, holdDuty);
return new NormallyOpenValveControlStrategy(motor, switchDuration, holdDuty);
case ValveControlStrategyType::NormallyClosed:
return new NormallyClosedValveControlStrategy(switchDuration, holdDuty);
return new NormallyClosedValveControlStrategy(motor, switchDuration, holdDuty);
case ValveControlStrategyType::Latching:
return new LatchingValveControlStrategy(switchDuration, holdDuty);
return new LatchingValveControlStrategy(motor, switchDuration, holdDuty);
default:
throw std::runtime_error("Unknown strategy");
}
Expand Down

0 comments on commit 887dd3e

Please sign in to comment.