Feature: SDM power meter: poll asynchronously
This commit is contained in:
parent
8a46ba9541
commit
347dd67684
@ -1,7 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "PowerMeterProvider.h"
|
#include "PowerMeterProvider.h"
|
||||||
#include "SDM.h"
|
#include "SDM.h"
|
||||||
@ -20,16 +22,20 @@ public:
|
|||||||
~PowerMeterSerialSdm();
|
~PowerMeterSerialSdm();
|
||||||
|
|
||||||
bool init() final;
|
bool init() final;
|
||||||
void loop() final;
|
void loop() final { } // polling is performed asynchronously
|
||||||
float getPowerTotal() const final;
|
float getPowerTotal() const final;
|
||||||
bool isDataValid() const final;
|
bool isDataValid() const final;
|
||||||
void doMqttPublish() const final;
|
void doMqttPublish() const final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void pollingLoopHelper(void* context);
|
||||||
|
std::atomic<bool> _taskDone;
|
||||||
|
void pollingLoop();
|
||||||
|
|
||||||
Phases _phases;
|
Phases _phases;
|
||||||
PowerMeterSerialSdmConfig const _cfg;
|
PowerMeterSerialSdmConfig const _cfg;
|
||||||
|
|
||||||
uint32_t _lastPoll;
|
uint32_t _lastPoll = 0;
|
||||||
|
|
||||||
float _phase1Power = 0.0;
|
float _phase1Power = 0.0;
|
||||||
float _phase2Power = 0.0;
|
float _phase2Power = 0.0;
|
||||||
@ -40,9 +46,14 @@ private:
|
|||||||
float _energyImport = 0.0;
|
float _energyImport = 0.0;
|
||||||
float _energyExport = 0.0;
|
float _energyExport = 0.0;
|
||||||
|
|
||||||
mutable std::mutex _mutex;
|
mutable std::mutex _valueMutex;
|
||||||
|
|
||||||
static char constexpr _sdmSerialPortOwner[] = "SDM power meter";
|
static char constexpr _sdmSerialPortOwner[] = "SDM power meter";
|
||||||
std::unique_ptr<HardwareSerial> _upSdmSerial = nullptr;
|
std::unique_ptr<HardwareSerial> _upSdmSerial = nullptr;
|
||||||
std::unique_ptr<SDM> _upSdm = nullptr;
|
std::unique_ptr<SDM> _upSdm = nullptr;
|
||||||
|
|
||||||
|
TaskHandle_t _taskHandle = nullptr;
|
||||||
|
bool _stopPolling;
|
||||||
|
mutable std::mutex _pollingMutex;
|
||||||
|
std::condition_variable _cv;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,19 @@
|
|||||||
|
|
||||||
PowerMeterSerialSdm::~PowerMeterSerialSdm()
|
PowerMeterSerialSdm::~PowerMeterSerialSdm()
|
||||||
{
|
{
|
||||||
|
_taskDone = false;
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_pollingMutex);
|
||||||
|
_stopPolling = true;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
_cv.notify_all();
|
||||||
|
|
||||||
|
if (_taskHandle != nullptr) {
|
||||||
|
while (!_taskDone) { delay(10); }
|
||||||
|
_taskHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (_upSdmSerial) {
|
if (_upSdmSerial) {
|
||||||
_upSdmSerial->end();
|
_upSdmSerial->end();
|
||||||
_upSdmSerial = nullptr;
|
_upSdmSerial = nullptr;
|
||||||
@ -34,12 +47,20 @@ bool PowerMeterSerialSdm::init()
|
|||||||
SERIAL_8N1, pin.powermeter_rx, pin.powermeter_tx);
|
SERIAL_8N1, pin.powermeter_rx, pin.powermeter_tx);
|
||||||
_upSdm->begin();
|
_upSdm->begin();
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_pollingMutex);
|
||||||
|
_stopPolling = false;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
uint32_t constexpr stackSize = 3072;
|
||||||
|
xTaskCreate(PowerMeterSerialSdm::pollingLoopHelper, "PM:SDM",
|
||||||
|
stackSize, this, 1/*prio*/, &_taskHandle);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PowerMeterSerialSdm::getPowerTotal() const
|
float PowerMeterSerialSdm::getPowerTotal() const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_mutex);
|
std::lock_guard<std::mutex> l(_valueMutex);
|
||||||
return _phase1Power + _phase2Power + _phase3Power;
|
return _phase1Power + _phase2Power + _phase3Power;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +72,7 @@ bool PowerMeterSerialSdm::isDataValid() const
|
|||||||
|
|
||||||
void PowerMeterSerialSdm::doMqttPublish() const
|
void PowerMeterSerialSdm::doMqttPublish() const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_mutex);
|
std::lock_guard<std::mutex> l(_valueMutex);
|
||||||
mqttPublish("power1", _phase1Power);
|
mqttPublish("power1", _phase1Power);
|
||||||
mqttPublish("power2", _phase2Power);
|
mqttPublish("power2", _phase2Power);
|
||||||
mqttPublish("power3", _phase3Power);
|
mqttPublish("power3", _phase3Power);
|
||||||
@ -62,14 +83,30 @@ void PowerMeterSerialSdm::doMqttPublish() const
|
|||||||
mqttPublish("export", _energyExport);
|
mqttPublish("export", _energyExport);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerMeterSerialSdm::loop()
|
void PowerMeterSerialSdm::pollingLoopHelper(void* context)
|
||||||
{
|
{
|
||||||
if (!_upSdm) { return; }
|
auto pInstance = static_cast<PowerMeterSerialSdm*>(context);
|
||||||
|
pInstance->pollingLoop();
|
||||||
|
pInstance->_taskDone = true;
|
||||||
|
vTaskDelete(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
if ((millis() - _lastPoll) < (_cfg.PollingInterval * 1000)) {
|
void PowerMeterSerialSdm::pollingLoop()
|
||||||
return;
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_pollingMutex);
|
||||||
|
|
||||||
|
while (!_stopPolling) {
|
||||||
|
auto elapsedMillis = millis() - _lastPoll;
|
||||||
|
auto intervalMillis = _cfg.PollingInterval * 1000;
|
||||||
|
if (_lastPoll > 0 && elapsedMillis < intervalMillis) {
|
||||||
|
auto sleepMs = intervalMillis - elapsedMillis;
|
||||||
|
_cv.wait_for(lock, std::chrono::milliseconds(sleepMs),
|
||||||
|
[this] { return _stopPolling; }); // releases the mutex
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastPoll = millis();
|
||||||
|
|
||||||
uint8_t addr = _cfg.Address;
|
uint8_t addr = _cfg.Address;
|
||||||
|
|
||||||
// reading takes a "very long" time as each readVal() is a synchronous
|
// reading takes a "very long" time as each readVal() is a synchronous
|
||||||
@ -92,7 +129,7 @@ void PowerMeterSerialSdm::loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_mutex);
|
std::lock_guard<std::mutex> l(_valueMutex);
|
||||||
_phase1Power = static_cast<float>(phase1Power);
|
_phase1Power = static_cast<float>(phase1Power);
|
||||||
_phase2Power = static_cast<float>(phase2Power);
|
_phase2Power = static_cast<float>(phase2Power);
|
||||||
_phase3Power = static_cast<float>(phase3Power);
|
_phase3Power = static_cast<float>(phase3Power);
|
||||||
@ -103,9 +140,8 @@ void PowerMeterSerialSdm::loop()
|
|||||||
_energyExport = static_cast<float>(energyExport);
|
_energyExport = static_cast<float>(energyExport);
|
||||||
}
|
}
|
||||||
|
|
||||||
gotUpdate();
|
|
||||||
|
|
||||||
MessageOutput.printf("[PowerMeterSerialSdm] TotalPower: %5.2f\r\n", getPowerTotal());
|
MessageOutput.printf("[PowerMeterSerialSdm] TotalPower: %5.2f\r\n", getPowerTotal());
|
||||||
|
|
||||||
_lastPoll = millis();
|
gotUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user