* DPL MQTT handler: modernize * there is no need to tokenize and check the topic of a received MQTT message if we only subscribe to a single topic. all messages will be for that topic. avoid testing the topic in the callback alltogether. * use std::string and std::stoi over allocating and deleting a buffer and copying charactes around. * use a switch statement to process the actual payload. * break a long line. * DPL: fix getMode() return value getMode() returned a bool. probably its return type was not adjusted when the third mode was introduced. this lead to mode 2 being cast to true implicitly, which in turn was used to construct a String, such that "1" was published as the DPL mode when in fact it was 2. make the mode an enum class to avoid such problems in the future. inline getMode() and setMode(). fix indention.
102 lines
3.3 KiB
C++
102 lines
3.3 KiB
C++
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#pragma once
|
|
|
|
#include "Configuration.h"
|
|
#include <espMqttClient.h>
|
|
#include <Arduino.h>
|
|
#include <Hoymiles.h>
|
|
#include <memory>
|
|
#include <functional>
|
|
|
|
#define PL_UI_STATE_INACTIVE 0
|
|
#define PL_UI_STATE_CHARGING 1
|
|
#define PL_UI_STATE_USE_SOLAR_ONLY 2
|
|
#define PL_UI_STATE_USE_SOLAR_AND_BATTERY 3
|
|
|
|
#define PL_MODE_ENABLE_NORMAL_OP 0
|
|
#define PL_MODE_FULL_DISABLE 1
|
|
#define PL_MODE_SOLAR_PT_ONLY 2
|
|
|
|
typedef enum {
|
|
EMPTY_WHEN_FULL= 0,
|
|
EMPTY_AT_NIGHT
|
|
} batDrainStrategy;
|
|
|
|
|
|
class PowerLimiterClass {
|
|
public:
|
|
enum class Status : unsigned {
|
|
Initializing,
|
|
DisabledByConfig,
|
|
DisabledByMqtt,
|
|
WaitingForValidTimestamp,
|
|
PowerMeterDisabled,
|
|
PowerMeterTimeout,
|
|
PowerMeterPending,
|
|
InverterInvalid,
|
|
InverterChanged,
|
|
InverterOffline,
|
|
InverterCommandsDisabled,
|
|
InverterLimitPending,
|
|
InverterPowerCmdPending,
|
|
InverterDevInfoPending,
|
|
InverterStatsPending,
|
|
UnconditionalSolarPassthrough,
|
|
NoVeDirect,
|
|
Settling,
|
|
Stable,
|
|
};
|
|
|
|
void init();
|
|
void loop();
|
|
uint8_t getPowerLimiterState();
|
|
int32_t getLastRequestedPowerLimit();
|
|
|
|
enum class Mode : unsigned {
|
|
Normal = 0,
|
|
Disabled = 1,
|
|
UnconditionalFullSolarPassthrough = 2
|
|
};
|
|
|
|
void setMode(Mode m) { _mode = m; }
|
|
Mode getMode() const { return _mode; }
|
|
void calcNextInverterRestart();
|
|
|
|
private:
|
|
int32_t _lastRequestedPowerLimit = 0;
|
|
uint32_t _shutdownTimeout = 0;
|
|
Status _lastStatus = Status::Initializing;
|
|
uint32_t _lastStatusPrinted = 0;
|
|
uint32_t _lastCalculation = 0;
|
|
static constexpr uint32_t _calculationBackoffMsDefault = 128;
|
|
uint32_t _calculationBackoffMs = _calculationBackoffMsDefault;
|
|
Mode _mode = Mode::Normal;
|
|
std::shared_ptr<InverterAbstract> _inverter = nullptr;
|
|
bool _batteryDischargeEnabled = false;
|
|
uint32_t _nextInverterRestart = 0; // Values: 0->not calculated / 1->no restart configured / >1->time of next inverter restart in millis()
|
|
uint32_t _nextCalculateCheck = 5000; // time in millis for next NTP check to calulate restart
|
|
bool _fullSolarPassThroughEnabled = false;
|
|
bool _verboseLogging = true;
|
|
|
|
std::string const& getStatusText(Status status);
|
|
void announceStatus(Status status);
|
|
bool shutdown(Status status);
|
|
bool shutdown() { return shutdown(_lastStatus); }
|
|
int32_t inverterPowerDcToAc(std::shared_ptr<InverterAbstract> inverter, int32_t dcPower);
|
|
void unconditionalSolarPassthrough(std::shared_ptr<InverterAbstract> inverter);
|
|
bool canUseDirectSolarPower();
|
|
int32_t calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool solarPowerEnabled, bool batteryDischargeEnabled);
|
|
void commitPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t limit, bool enablePowerProduction);
|
|
bool setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit);
|
|
int32_t getSolarChargePower();
|
|
float getLoadCorrectedVoltage();
|
|
bool testThreshold(float socThreshold, float voltThreshold,
|
|
std::function<bool(float, float)> compare);
|
|
bool isStartThresholdReached();
|
|
bool isStopThresholdReached();
|
|
bool isBelowStopThreshold();
|
|
bool useFullSolarPassthrough();
|
|
};
|
|
|
|
extern PowerLimiterClass PowerLimiter;
|