Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: switch context when processing DPL MQTT requests #572

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/MqttHandlePowerLimiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "Configuration.h"
#include <espMqttClient.h>
#include <TaskSchedulerDeclarations.h>
#include <mutex>
#include <deque>
#include <functional>

class MqttHandlePowerLimiterClass {
public:
Expand All @@ -18,6 +21,11 @@ class MqttHandlePowerLimiterClass {
uint32_t _lastPublishStats;
uint32_t _lastPublish;

// MQTT callbacks to process updates on subscribed topics are executed in
// the MQTT thread's context. we use this queue to switch processing the
// user requests into the main loop's context (TaskScheduler context).
mutable std::mutex _mqttMutex;
std::deque<std::function<void()>> _mqttCallbacks;
};

extern MqttHandlePowerLimiterClass MqttHandlePowerLimiter;
32 changes: 20 additions & 12 deletions src/MqttHandlePowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,21 @@ void MqttHandlePowerLimiterClass::init(Scheduler& scheduler)

void MqttHandlePowerLimiterClass::loop()
{
if (!MqttSettings.getConnected() ) {
std::unique_lock<std::mutex> mqttLock(_mqttMutex);

const CONFIG_T& config = Configuration.get();

if (!config.PowerLimiter.Enabled) {
_mqttCallbacks.clear();
return;
}

const CONFIG_T& config = Configuration.get();
for (auto& callback : _mqttCallbacks) { callback(); }
_mqttCallbacks.clear();

mqttLock.unlock();

if (!MqttSettings.getConnected() ) { return; }

if ((millis() - _lastPublish) > (config.Mqtt.PublishInterval * 1000) ) {
auto val = static_cast<unsigned>(PowerLimiter.getMode());
Expand All @@ -53,13 +63,6 @@ void MqttHandlePowerLimiterClass::loop()
void MqttHandlePowerLimiterClass::onCmdMode(const espMqttClientTypes::MessageProperties& properties,
const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total)
{
const CONFIG_T& config = Configuration.get();

// ignore messages if PowerLimiter is disabled
if (!config.PowerLimiter.Enabled) {
return;
}

std::string strValue(reinterpret_cast<const char*>(payload), len);
int intValue = -1;
try {
Expand All @@ -71,19 +74,24 @@ void MqttHandlePowerLimiterClass::onCmdMode(const espMqttClientTypes::MessagePro
return;
}

std::lock_guard<std::mutex> mqttLock(_mqttMutex);

using Mode = PowerLimiterClass::Mode;
switch (static_cast<Mode>(intValue)) {
case Mode::UnconditionalFullSolarPassthrough:
MessageOutput.println("Power limiter unconditional full solar PT");
PowerLimiter.setMode(Mode::UnconditionalFullSolarPassthrough);
_mqttCallbacks.push_back(std::bind(&PowerLimiterClass::setMode,
&PowerLimiter, Mode::UnconditionalFullSolarPassthrough));
break;
case Mode::Disabled:
MessageOutput.println("Power limiter disabled (override)");
PowerLimiter.setMode(Mode::Disabled);
_mqttCallbacks.push_back(std::bind(&PowerLimiterClass::setMode,
&PowerLimiter, Mode::Disabled));
break;
case Mode::Normal:
MessageOutput.println("Power limiter normal operation");
PowerLimiter.setMode(Mode::Normal);
_mqttCallbacks.push_back(std::bind(&PowerLimiterClass::setMode,
&PowerLimiter, Mode::Normal));
break;
default:
MessageOutput.printf("PowerLimiter - unknown mode %d\r\n", intValue);
Expand Down