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

Feature: VE.Direct: Support for a second MPPT tracker #706

Merged
merged 2 commits into from
Mar 17, 2024
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
33 changes: 16 additions & 17 deletions include/Battery.h
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <stdint.h>
#include <memory>
#include <mutex>
#include <TaskSchedulerDeclarations.h>

#include "BatteryStats.h"

class BatteryProvider {
public:
// returns true if the provider is ready for use, false otherwise
virtual bool init(bool verboseLogging) = 0;

virtual void deinit() = 0;
virtual void loop() = 0;
virtual std::shared_ptr<BatteryStats> getStats() const = 0;
public:
// returns true if the provider is ready for use, false otherwise
virtual bool init(bool verboseLogging) = 0;
virtual void deinit() = 0;
virtual void loop() = 0;
virtual std::shared_ptr<BatteryStats> getStats() const = 0;
virtual bool usesHwPort2() const { return false; }
};

class BatteryClass {
public:
void init(Scheduler&);
void updateSettings();
public:
void init(Scheduler&);
void updateSettings();

std::shared_ptr<BatteryStats const> getStats() const;
private:
void loop();
std::shared_ptr<BatteryStats const> getStats() const;

Task _loopTask;
private:
void loop();

mutable std::mutex _mutex;
std::unique_ptr<BatteryProvider> _upProvider = nullptr;
Task _loopTask;
mutable std::mutex _mutex;
std::unique_ptr<BatteryProvider> _upProvider = nullptr;
};

extern BatteryClass Battery;
8 changes: 5 additions & 3 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#define DEV_MAX_MAPPING_NAME_STRLEN 63

#define VICTRON_MAX_COUNT 2

#define POWERMETER_MAX_PHASES 3
#define POWERMETER_MAX_HTTP_URL_STRLEN 1024
#define POWERMETER_MAX_USERNAME_STRLEN 64
Expand Down Expand Up @@ -198,7 +200,7 @@ struct CONFIG_T {
bool HttpIndividualRequests;
POWERMETER_HTTP_PHASE_CONFIG_T Http_Phase[POWERMETER_MAX_PHASES];
} PowerMeter;

struct {
bool Enabled;
bool VerboseLogging;
Expand All @@ -225,7 +227,7 @@ struct CONFIG_T {
float FullSolarPassThroughStartVoltage;
float FullSolarPassThroughStopVoltage;
} PowerLimiter;

struct {
bool Enabled;
bool VerboseLogging;
Expand All @@ -243,7 +245,7 @@ struct CONFIG_T {
float Auto_Power_Voltage_Limit;
float Auto_Power_Enable_Voltage_Limit;
float Auto_Power_Lower_Power_Limit;
float Auto_Power_Upper_Power_Limit;
float Auto_Power_Upper_Power_Limit;
} Huawei;


Expand Down
1 change: 1 addition & 0 deletions include/JkBmsController.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Controller : public BatteryProvider {
void deinit() final;
void loop() final;
std::shared_ptr<BatteryStats> getStats() const final { return _stats; }
bool usesHwPort2() const final { return true; }

private:
enum class Status : unsigned {
Expand Down
32 changes: 16 additions & 16 deletions include/MqttBattery.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@
#include <espMqttClient.h>

class MqttBattery : public BatteryProvider {
public:
MqttBattery() = default;
public:
MqttBattery() = default;

bool init(bool verboseLogging) final;
void deinit() final;
void loop() final { return; } // this class is event-driven
std::shared_ptr<BatteryStats> getStats() const final { return _stats; }
bool init(bool verboseLogging) final;
void deinit() final;
void loop() final { return; } // this class is event-driven
std::shared_ptr<BatteryStats> getStats() const final { return _stats; }

private:
bool _verboseLogging = false;
String _socTopic;
String _voltageTopic;
std::shared_ptr<MqttBatteryStats> _stats = std::make_shared<MqttBatteryStats>();
private:
bool _verboseLogging = false;
String _socTopic;
String _voltageTopic;
std::shared_ptr<MqttBatteryStats> _stats = std::make_shared<MqttBatteryStats>();

std::optional<float> getFloat(std::string const& src, char const* topic);
void onMqttMessageSoC(espMqttClientTypes::MessageProperties const& properties,
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total);
void onMqttMessageVoltage(espMqttClientTypes::MessageProperties const& properties,
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total);
std::optional<float> getFloat(std::string const& src, char const* topic);
void onMqttMessageSoC(espMqttClientTypes::MessageProperties const& properties,
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total);
void onMqttMessageVoltage(espMqttClientTypes::MessageProperties const& properties,
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total);
};
8 changes: 6 additions & 2 deletions include/MqttHandleVedirect.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "VeDirectMpptController.h"
#include "Configuration.h"
#include <Arduino.h>
#include <map>
#include <TaskSchedulerDeclarations.h>

#ifndef VICTRON_PIN_RX
Expand All @@ -20,7 +21,7 @@ class MqttHandleVedirectClass {
void forceUpdate();
private:
void loop();
VeDirectMpptController::veMpptStruct _kvFrame{};
std::map<std::string, VeDirectMpptController::veMpptStruct> _kvFrames;

Task _loopTask;

Expand All @@ -31,6 +32,9 @@ class MqttHandleVedirectClass {
uint32_t _nextPublishFull = 1;

bool _PublishFull;

void publish_mppt_data(const VeDirectMpptController::spData_t &spMpptData,
VeDirectMpptController::veMpptStruct &frame) const;
};

extern MqttHandleVedirectClass MqttHandleVedirect;
extern MqttHandleVedirectClass MqttHandleVedirect;
14 changes: 10 additions & 4 deletions include/MqttHandleVedirectHass.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@ class MqttHandleVedirectHassClass {
private:
void loop();
void publish(const String& subtopic, const String& payload);
void publishBinarySensor(const char* caption, const char* icon, const char* subTopic, const char* payload_on, const char* payload_off);
void publishSensor(const char* caption, const char* icon, const char* subTopic, const char* deviceClass = NULL, const char* stateClass = NULL, const char* unitOfMeasurement = NULL);
void createDeviceInfo(JsonObject& object);
void publishBinarySensor(const char *caption, const char *icon, const char *subTopic,
const char *payload_on, const char *payload_off,
const VeDirectMpptController::spData_t &spMpptData);
void publishSensor(const char *caption, const char *icon, const char *subTopic,
const char *deviceClass, const char *stateClass,
const char *unitOfMeasurement,
const VeDirectMpptController::spData_t &spMpptData);
void createDeviceInfo(JsonObject &object,
const VeDirectMpptController::spData_t &spMpptData);

Task _loopTask;

bool _wasConnected = false;
bool _updateForced = false;
};

extern MqttHandleVedirectHassClass MqttHandleVedirectHass;
extern MqttHandleVedirectHassClass MqttHandleVedirectHass;
4 changes: 3 additions & 1 deletion include/PinMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct PinMapping_t {
uint8_t display_reset;
int8_t victron_tx;
int8_t victron_rx;
int8_t victron_tx2;
int8_t victron_rx2;
int8_t battery_rx;
int8_t battery_rxen;
int8_t battery_tx;
Expand All @@ -63,7 +65,7 @@ class PinMappingClass {
bool isValidCmt2300Config() const;
bool isValidEthConfig() const;
bool isValidHuaweiConfig() const;

private:
PinMapping_t _pinMapping;
};
Expand Down
27 changes: 27 additions & 0 deletions include/SerialPortManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <map>

class SerialPortManagerClass {
public:
bool allocateMpptPort(int port);
bool allocateBatteryPort(int port);
void invalidateBatteryPort();
void invalidateMpptPorts();

private:
enum Owner {
BATTERY,
MPPT
};

std::map<uint8_t, Owner> allocatedPorts;

bool allocatePort(uint8_t port, Owner owner);
void invalidate(Owner owner);

static const char* print(Owner owner);
};

extern SerialPortManagerClass SerialPortManager;
7 changes: 6 additions & 1 deletion include/VictronMppt.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <memory>

#include "VeDirectMpptController.h"
#include "Configuration.h"
#include <TaskSchedulerDeclarations.h>

class VictronMpptClass {
Expand All @@ -16,12 +17,14 @@ class VictronMpptClass {
void updateSettings();

bool isDataValid() const;
bool isDataValid(size_t idx) const;

// returns the data age of all controllers,
// i.e, the youngest data's age is returned.
uint32_t getDataAgeMillis() const;
uint32_t getDataAgeMillis(size_t idx) const;

VeDirectMpptController::spData_t getData(size_t idx = 0) const;
std::optional<VeDirectMpptController::spData_t> getData(size_t idx = 0) const;

// total output of all MPPT charge controllers in Watts
int32_t getPowerOutputWatts() const;
Expand Down Expand Up @@ -50,6 +53,8 @@ class VictronMpptClass {
mutable std::mutex _mutex;
using controller_t = std::unique_ptr<VeDirectMpptController>;
std::vector<controller_t> _controllers;

bool initController(int8_t rx, int8_t tx, bool logging, int hwSerialPort);
};

extern VictronMpptClass VictronMppt;
1 change: 1 addition & 0 deletions include/VictronSmartShunt.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class VictronSmartShunt : public BatteryProvider {
void deinit() final { }
void loop() final;
std::shared_ptr<BatteryStats> getStats() const final { return _stats; }
bool usesHwPort2() const final { return true; }

private:
uint32_t _lastUpdate = 0;
Expand Down
12 changes: 7 additions & 5 deletions include/WebApi_ws_vedirect_live.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include "ArduinoJson.h"
#include "Configuration.h"
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
#include <VeDirectMpptController.h>
Expand All @@ -13,16 +14,17 @@ class WebApiWsVedirectLiveClass {
void init(AsyncWebServer& server, Scheduler& scheduler);

private:
void generateJsonResponse(JsonVariant& root);
void generateJsonResponse(JsonVariant& root, bool fullUpdate);
static void populateJson(const JsonObject &root, const VeDirectMpptController::spData_t &spMpptData);
void onLivedataStatus(AsyncWebServerRequest* request);
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);

AsyncWebServer* _server;
AsyncWebSocket _ws;

uint32_t _lastWsPublish = 0;
uint32_t _dataAgeMillis = 0;
static constexpr uint16_t _responseSize = 1024 + 128;
uint32_t _lastFullPublish = 0;
uint32_t _dataAgeMillis[VICTRON_MAX_COUNT] = { 0 };
static constexpr uint16_t _responseSize = VICTRON_MAX_COUNT * (1024 + 128);

std::mutex _mutex;

Expand All @@ -31,4 +33,4 @@ class WebApiWsVedirectLiveClass {

Task _sendDataTask;
void sendDataTaskCb();
};
};
8 changes: 1 addition & 7 deletions lib/VeDirectFrameHandler/VeDirectFrameHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,7 @@ int VeDirectFrameHandler::hexRxEvent(uint8_t inbyte) {
}

bool VeDirectFrameHandler::isDataValid(veStruct const& frame) const {
if (_lastUpdate == 0) {
return false;
}
if (strlen(frame.SER) == 0) {
return false;
}
return true;
return strlen(frame.SER) > 0 && _lastUpdate > 0 && (millis() - _lastUpdate) < (10 * 1000);
}

uint32_t VeDirectFrameHandler::getLastUpdate() const
Expand Down
4 changes: 2 additions & 2 deletions lib/VeDirectFrameHandler/VeDirectMpptController.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <Arduino.h>
#include "VeDirectMpptController.h"

void VeDirectMpptController::init(int8_t rx, int8_t tx, Print* msgOut, bool verboseLogging)
void VeDirectMpptController::init(int8_t rx, int8_t tx, Print* msgOut, bool verboseLogging, uint16_t hwSerialPort)
{
VeDirectFrameHandler::init(rx, tx, msgOut, verboseLogging, 1);
VeDirectFrameHandler::init(rx, tx, msgOut, verboseLogging, hwSerialPort);
_spData = std::make_shared<veMpptStruct>();
if (_verboseLogging) { _msgOut->println("Finished init MPPTController"); }
}
Expand Down
4 changes: 2 additions & 2 deletions lib/VeDirectFrameHandler/VeDirectMpptController.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class VeDirectMpptController : public VeDirectFrameHandler {
public:
VeDirectMpptController() = default;

void init(int8_t rx, int8_t tx, Print* msgOut, bool verboseLogging);
void init(int8_t rx, int8_t tx, Print* msgOut, bool verboseLogging, uint16_t hwSerialPort);
bool isDataValid() const; // return true if data valid and not outdated

struct veMpptStruct : veStruct {
Expand All @@ -49,7 +49,7 @@ class VeDirectMpptController : public VeDirectFrameHandler {
double VPV; // panel voltage in V
double IPV; // panel current in A (calculated)
bool LOAD; // virtual load output state (on if battery voltage reaches upper limit, off if battery reaches lower limit)
uint8_t CS; // current state of operation e. g. OFF or Bulk
uint8_t CS; // current state of operation e.g. OFF or Bulk
uint8_t ERR; // error code
uint32_t OR; // off reason
uint32_t HSDS; // day sequence number 1...365
Expand Down
Loading
Loading