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

Add support for Victron Cerbo / VRM portal #377

Closed
wants to merge 5 commits into from
Closed
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
3 changes: 3 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct CHANNEL_CONFIG_T {
struct INVERTER_CONFIG_T {
uint64_t Serial;
char Name[INV_MAX_NAME_STRLEN + 1];
uint8_t CurrentPhase;
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
};

Expand Down Expand Up @@ -87,6 +88,8 @@ struct CONFIG_T {
bool Mqtt_Hass_Expire;

char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];

bool Mqtt_Victron_Enabled;
};

class ConfigurationClass {
Expand Down
9 changes: 9 additions & 0 deletions include/MqttSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <Ticker.h>
#include <espMqttClient.h>
#include <memory>
#include <map>

class MqttSettingsClass {
public:
Expand All @@ -16,6 +17,14 @@ class MqttSettingsClass {
void publish(const String& subtopic, const String& payload);
void publishHass(const String& subtopic, const String& payload);

void publishVictron(const String& hoyserial, const String& payload);

const char* VictronPortalId;
std::map<String, String> VictronDeviceInstance;

String getVictronPortalId();
String getVictronDeviceInstance(const String& hoyserial);

String getPrefix();

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

#include "Configuration.h"
stromibaer marked this conversation as resolved.
Show resolved Hide resolved
#include <Arduino.h>
#include <Hoymiles.h>
#include <memory>

class MqttVictronPublishingClass {
public:
void init();
void loop();
void forceRegister();
void registerInverter();

private:
void publishField(std::shared_ptr<InverterAbstract> inv, uint8_t invphase, uint8_t fieldId);

uint32_t _lastPublishStats[INV_MAX_COUNT];
uint32_t _lastPublish;

uint8_t _publishFields[14] = {
FLD_UDC,
FLD_IDC,
FLD_PDC,
FLD_YD,
FLD_YT,
FLD_UAC,
FLD_IAC,
FLD_PAC,
FLD_F,
FLD_T,
FLD_PF,
FLD_EFF,
FLD_IRR,
FLD_PRA
};

bool _wasConnected = false;
bool _registerForced = false;
};

extern MqttVictronPublishingClass MqttVictronPublishing;
4 changes: 3 additions & 1 deletion include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@
#define MQTT_HASS_EXPIRE true
#define MQTT_HASS_RETAIN true
#define MQTT_HASS_TOPIC "homeassistant/"
#define MQTT_HASS_INDIVIDUALPANELS false
#define MQTT_HASS_INDIVIDUALPANELS false

#define MQTT_VICTRON_ENABLED false
8 changes: 8 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,15 @@ bool ConfigurationClass::write()
JsonObject security = doc.createNestedObject("security");
security["password"] = config.Security_Password;

JsonObject mqtt_victron = mqtt.createNestedObject("victron");
mqtt_victron["enabled"] = config.Mqtt_Victron_Enabled;

JsonArray inverters = doc.createNestedArray("inverters");
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
JsonObject inv = inverters.createNestedObject();
inv["serial"] = config.Inverter[i].Serial;
inv["name"] = config.Inverter[i].Name;
inv["phase"] = config.Inverter[i].CurrentPhase;

JsonArray channel = inv.createNestedArray("channel");
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
Expand Down Expand Up @@ -198,11 +202,15 @@ bool ConfigurationClass::read()
JsonObject security = doc["security"];
strlcpy(config.Security_Password, security["password"] | ACCESS_POINT_PASSWORD, sizeof(config.Security_Password));

JsonObject mqtt_victron = mqtt["victron"];
config.Mqtt_Victron_Enabled = mqtt_victron["enabled"] | MQTT_VICTRON_ENABLED;

JsonArray inverters = doc["inverters"];
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
JsonObject inv = inverters[i].as<JsonObject>();
config.Inverter[i].Serial = inv["serial"] | 0ULL;
strlcpy(config.Inverter[i].Name, inv["name"] | "", sizeof(config.Inverter[i].Name));
config.Inverter[i].CurrentPhase = inv["phase"] | 0;

JsonArray channel = inv["channel"];
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
Expand Down
87 changes: 85 additions & 2 deletions src/MqttSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (C) 2022 Thomas Basler and others
*/
#include "MqttSettings.h"
#include "ArduinoJson.h"
#include "Configuration.h"
#include "NetworkSettings.h"
#include <Hoymiles.h>
Expand Down Expand Up @@ -50,6 +51,18 @@ void MqttSettingsClass::onMqttConnect(bool sessionPresent)
mqttClient->subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE).c_str(), 0);
mqttClient->subscribe(String(topic + "+/cmd/" + TOPIC_SUB_POWER).c_str(), 0);
mqttClient->subscribe(String(topic + "+/cmd/" + TOPIC_SUB_RESTART).c_str(), 0);

// Check for doing some Victron parts...
if (!Configuration.get().Mqtt_Victron_Enabled) {
return;
}
// Loop all inverters and subscribe each for Victron Venus messages
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
auto inv = Hoymiles.getInverterByPos(i);

String str_serial = inv->serialString();
mqttClient->subscribe(String("device/HM" + str_serial + "/DBus").c_str(),0);
}
}

void MqttSettingsClass::onMqttDisconnect(espMqttClientTypes::DisconnectReason reason)
Expand Down Expand Up @@ -102,17 +115,65 @@ void MqttSettingsClass::onMqttMessage(const espMqttClientTypes::MessagePropertie
subtopic = strtok_r(rest, "/", &rest);
setting = strtok_r(rest, "/", &rest);

uint64_t serial;

if (serial_str == NULL || subtopic == NULL || setting == NULL) {

// Victron message only on startup after subscribe
// device/116181045449/DBus = JSON
char* rest = &token_topic[strlen("device/HM")];
serial_str = strtok_r(rest, "/", &rest);

if (serial_str == NULL) {
return;
}

serial = strtoull(serial_str, 0, 16);
auto inv = Hoymiles.getInverterBySerial(serial);

if (inv == nullptr) {
Serial.print(F("Can not register inverter: "));
Serial.println(serial);
return;
}

char* strlimit = new char[len + 1];
stromibaer marked this conversation as resolved.
Show resolved Hide resolved
memcpy(strlimit, payload, len);
strlimit[len] = '\0';

DynamicJsonDocument docDbus(64);
deserializeJson(docDbus, strlimit);

delete[] strlimit;

VictronPortalId = docDbus["portalId"];

DynamicJsonDocument docInstance(64);
docInstance = docDbus["deviceInstance"];
String deviceInstance = docInstance[serial_str];

String inverter = serial_str;
VictronDeviceInstance.insert({inverter, deviceInstance});

if (VictronDeviceInstance.find(inverter)!=VictronDeviceInstance.end()) {
String valfound = VictronDeviceInstance[inverter];
Serial.print(F("Register inverter: "));
Serial.print(serial_str);
Serial.print(F(" to Victron Venus OS with portalId: "));
Serial.print(VictronPortalId);
Serial.print(F(" and deviceInstance: "));
Serial.println(valfound);
}
return;
}

uint64_t serial;
serial = strtoull(serial_str, 0, 16);

auto inv = Hoymiles.getInverterBySerial(serial);

if (inv == nullptr) {
Serial.println(F("Inverter not found"));
Serial.print(F("Inverter not found: "));
Serial.println(serial);
return;
}

Expand Down Expand Up @@ -228,6 +289,23 @@ bool MqttSettingsClass::getConnected()
return mqttClient->connected();
}

String MqttSettingsClass::getVictronPortalId()
{
return VictronPortalId;
}

String MqttSettingsClass::getVictronDeviceInstance(const String& hoyserial)
{
if (VictronDeviceInstance.find(hoyserial)!=VictronDeviceInstance.end()) {
return VictronDeviceInstance[hoyserial];
} else {
Serial.print(F("No Victron deviceInstance found for inverter: "));
Serial.println(hoyserial);
String ret = hoyserial + "NOdevInstance";
return ret;
}
}

String MqttSettingsClass::getPrefix()
{
return Configuration.get().Mqtt_Topic;
Expand All @@ -247,6 +325,11 @@ void MqttSettingsClass::publishHass(const String& subtopic, const String& payloa
mqttClient->publish(topic.c_str(), 0, Configuration.get().Mqtt_Hass_Retain, payload.c_str());
}

void MqttSettingsClass::publishVictron(const String& topic, const String& payload)
{
mqttClient->publish(topic.c_str(), 0, 1, payload.c_str());
}

void MqttSettingsClass::init()
{
using std::placeholders::_1;
Expand Down
Loading