* fix: DPL: start discharging at night logic error the switch "always start discharging battery at night" would cause to stop discharging the battery when there was solar power and the battery was discharged below the start threshold. this change introduces a nighttime discharging boolean variable, which is enabled the instant we decide to start a battery discharge cycle due to nighttime havin arrived. we reset this variable as soon as it is daytime (solar power available). in that case, we allow discharging the battery if the start threshold was reached. this can actually be the case if the battery is charged with cheap electricity during the night. removed comments as they merely spell out what the if statement already expresses quite nicely. * use SunPosition.isDayPeriod() to check for daytime --------- Co-authored-by: Andreas Böhm <andreas@boehm.cx>
107 lines
3.7 KiB
C++
107 lines
3.7 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>
|
|
#include <optional>
|
|
#include <TaskSchedulerDeclarations.h>
|
|
#include <frozen/string.h>
|
|
|
|
#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
|
|
|
|
class PowerLimiterClass {
|
|
public:
|
|
enum class Status : unsigned {
|
|
Initializing,
|
|
DisabledByConfig,
|
|
DisabledByMqtt,
|
|
WaitingForValidTimestamp,
|
|
PowerMeterPending,
|
|
InverterInvalid,
|
|
InverterChanged,
|
|
InverterOffline,
|
|
InverterCommandsDisabled,
|
|
InverterLimitPending,
|
|
InverterPowerCmdPending,
|
|
InverterDevInfoPending,
|
|
InverterStatsPending,
|
|
CalculatedLimitBelowMinLimit,
|
|
UnconditionalSolarPassthrough,
|
|
NoVeDirect,
|
|
NoEnergy,
|
|
HuaweiPsu,
|
|
Stable,
|
|
};
|
|
|
|
void init(Scheduler& scheduler);
|
|
uint8_t getInverterUpdateTimeouts() const { return _inverterUpdateTimeouts; }
|
|
uint8_t getPowerLimiterState();
|
|
int32_t getLastRequestedPowerLimit() { return _lastRequestedPowerLimit; }
|
|
bool getFullSolarPassThroughEnabled() const { return _fullSolarPassThroughEnabled; }
|
|
|
|
enum class Mode : unsigned {
|
|
Normal = 0,
|
|
Disabled = 1,
|
|
UnconditionalFullSolarPassthrough = 2
|
|
};
|
|
|
|
void setMode(Mode m) { _mode = m; }
|
|
Mode getMode() const { return _mode; }
|
|
void calcNextInverterRestart();
|
|
|
|
private:
|
|
void loop();
|
|
|
|
Task _loopTask;
|
|
|
|
int32_t _lastRequestedPowerLimit = 0;
|
|
bool _shutdownPending = false;
|
|
std::optional<uint32_t> _oInverterStatsMillis = std::nullopt;
|
|
std::optional<uint32_t> _oUpdateStartMillis = std::nullopt;
|
|
std::optional<int32_t> _oTargetPowerLimitWatts = std::nullopt;
|
|
std::optional<bool> _oTargetPowerState = std::nullopt;
|
|
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;
|
|
bool _nighttimeDischarging = 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;
|
|
uint8_t _inverterUpdateTimeouts = 0;
|
|
|
|
frozen::string const& getStatusText(Status status);
|
|
void announceStatus(Status status);
|
|
bool shutdown(Status status);
|
|
bool shutdown() { return shutdown(_lastStatus); }
|
|
float getBatteryVoltage(bool log = false);
|
|
int32_t inverterPowerDcToAc(std::shared_ptr<InverterAbstract> inverter, int32_t dcPower);
|
|
void unconditionalSolarPassthrough(std::shared_ptr<InverterAbstract> inverter);
|
|
bool canUseDirectSolarPower();
|
|
bool calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t solarPower, bool batteryPower);
|
|
bool updateInverter();
|
|
bool setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit);
|
|
int32_t getSolarPower();
|
|
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;
|