Feature: support JSON payload in MQTT battery provider
this changeset adds support for parsing the MQTT battery provider's SoC and voltage topics' payloads as JSON to extract a numeric value at a configurable path.
This commit is contained in:
parent
accc70dea0
commit
1a19f881aa
@ -41,6 +41,7 @@
|
|||||||
#define POWERMETER_MQTT_MAX_VALUES 3
|
#define POWERMETER_MQTT_MAX_VALUES 3
|
||||||
#define POWERMETER_HTTP_JSON_MAX_VALUES 3
|
#define POWERMETER_HTTP_JSON_MAX_VALUES 3
|
||||||
#define POWERMETER_HTTP_JSON_MAX_PATH_STRLEN 256
|
#define POWERMETER_HTTP_JSON_MAX_PATH_STRLEN 256
|
||||||
|
#define BATTERY_JSON_MAX_PATH_STRLEN 128
|
||||||
|
|
||||||
struct CHANNEL_CONFIG_T {
|
struct CHANNEL_CONFIG_T {
|
||||||
uint16_t MaxChannelPower;
|
uint16_t MaxChannelPower;
|
||||||
@ -281,7 +282,9 @@ struct CONFIG_T {
|
|||||||
uint8_t JkBmsInterface;
|
uint8_t JkBmsInterface;
|
||||||
uint8_t JkBmsPollingInterval;
|
uint8_t JkBmsPollingInterval;
|
||||||
char MqttSocTopic[MQTT_MAX_TOPIC_STRLEN + 1];
|
char MqttSocTopic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||||
|
char MqttSocJsonPath[BATTERY_JSON_MAX_PATH_STRLEN + 1];
|
||||||
char MqttVoltageTopic[MQTT_MAX_TOPIC_STRLEN + 1];
|
char MqttVoltageTopic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||||
|
char MqttVoltageJsonPath[BATTERY_JSON_MAX_PATH_STRLEN + 1];
|
||||||
} Battery;
|
} Battery;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@ -19,9 +19,10 @@ private:
|
|||||||
String _voltageTopic;
|
String _voltageTopic;
|
||||||
std::shared_ptr<MqttBatteryStats> _stats = std::make_shared<MqttBatteryStats>();
|
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,
|
void onMqttMessageSoC(espMqttClientTypes::MessageProperties const& properties,
|
||||||
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total);
|
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total,
|
||||||
|
char const* jsonPath);
|
||||||
void onMqttMessageVoltage(espMqttClientTypes::MessageProperties const& properties,
|
void onMqttMessageVoltage(espMqttClientTypes::MessageProperties const& properties,
|
||||||
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total);
|
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total,
|
||||||
|
char const* jsonPath);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,4 +17,8 @@ public:
|
|||||||
/* OpenDTU-OnBatter-specific utils go here: */
|
/* OpenDTU-OnBatter-specific utils go here: */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::pair<T, String> getJsonValueByPath(JsonDocument const& root, String const& path);
|
static std::pair<T, String> getJsonValueByPath(JsonDocument const& root, String const& path);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static std::optional<T> getNumericValueFromMqttPayload(char const* client,
|
||||||
|
std::string const& src, char const* topic, char const* jsonPath);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -257,7 +257,9 @@ bool ConfigurationClass::write()
|
|||||||
battery["jkbms_interface"] = config.Battery.JkBmsInterface;
|
battery["jkbms_interface"] = config.Battery.JkBmsInterface;
|
||||||
battery["jkbms_polling_interval"] = config.Battery.JkBmsPollingInterval;
|
battery["jkbms_polling_interval"] = config.Battery.JkBmsPollingInterval;
|
||||||
battery["mqtt_topic"] = config.Battery.MqttSocTopic;
|
battery["mqtt_topic"] = config.Battery.MqttSocTopic;
|
||||||
|
battery["mqtt_json_path"] = config.Battery.MqttSocJsonPath;
|
||||||
battery["mqtt_voltage_topic"] = config.Battery.MqttVoltageTopic;
|
battery["mqtt_voltage_topic"] = config.Battery.MqttVoltageTopic;
|
||||||
|
battery["mqtt_voltage_json_path"] = config.Battery.MqttVoltageJsonPath;
|
||||||
|
|
||||||
JsonObject huawei = doc["huawei"].to<JsonObject>();
|
JsonObject huawei = doc["huawei"].to<JsonObject>();
|
||||||
huawei["enabled"] = config.Huawei.Enabled;
|
huawei["enabled"] = config.Huawei.Enabled;
|
||||||
@ -604,7 +606,9 @@ bool ConfigurationClass::read()
|
|||||||
config.Battery.JkBmsInterface = battery["jkbms_interface"] | BATTERY_JKBMS_INTERFACE;
|
config.Battery.JkBmsInterface = battery["jkbms_interface"] | BATTERY_JKBMS_INTERFACE;
|
||||||
config.Battery.JkBmsPollingInterval = battery["jkbms_polling_interval"] | BATTERY_JKBMS_POLLING_INTERVAL;
|
config.Battery.JkBmsPollingInterval = battery["jkbms_polling_interval"] | BATTERY_JKBMS_POLLING_INTERVAL;
|
||||||
strlcpy(config.Battery.MqttSocTopic, battery["mqtt_topic"] | "", sizeof(config.Battery.MqttSocTopic));
|
strlcpy(config.Battery.MqttSocTopic, battery["mqtt_topic"] | "", sizeof(config.Battery.MqttSocTopic));
|
||||||
|
strlcpy(config.Battery.MqttSocJsonPath, battery["mqtt_json_path"] | "", sizeof(config.Battery.MqttSocJsonPath));
|
||||||
strlcpy(config.Battery.MqttVoltageTopic, battery["mqtt_voltage_topic"] | "", sizeof(config.Battery.MqttVoltageTopic));
|
strlcpy(config.Battery.MqttVoltageTopic, battery["mqtt_voltage_topic"] | "", sizeof(config.Battery.MqttVoltageTopic));
|
||||||
|
strlcpy(config.Battery.MqttVoltageJsonPath, battery["mqtt_voltage_json_path"] | "", sizeof(config.Battery.MqttVoltageJsonPath));
|
||||||
|
|
||||||
JsonObject huawei = doc["huawei"];
|
JsonObject huawei = doc["huawei"];
|
||||||
config.Huawei.Enabled = huawei["enabled"] | HUAWEI_ENABLED;
|
config.Huawei.Enabled = huawei["enabled"] | HUAWEI_ENABLED;
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "MqttBattery.h"
|
#include "MqttBattery.h"
|
||||||
#include "MqttSettings.h"
|
#include "MqttSettings.h"
|
||||||
#include "MessageOutput.h"
|
#include "MessageOutput.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
bool MqttBattery::init(bool verboseLogging)
|
bool MqttBattery::init(bool verboseLogging)
|
||||||
{
|
{
|
||||||
@ -17,7 +18,8 @@ bool MqttBattery::init(bool verboseLogging)
|
|||||||
std::bind(&MqttBattery::onMqttMessageSoC,
|
std::bind(&MqttBattery::onMqttMessageSoC,
|
||||||
this, std::placeholders::_1, std::placeholders::_2,
|
this, std::placeholders::_1, std::placeholders::_2,
|
||||||
std::placeholders::_3, std::placeholders::_4,
|
std::placeholders::_3, std::placeholders::_4,
|
||||||
std::placeholders::_5, std::placeholders::_6)
|
std::placeholders::_5, std::placeholders::_6,
|
||||||
|
config.Battery.MqttSocJsonPath)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
@ -32,7 +34,8 @@ bool MqttBattery::init(bool verboseLogging)
|
|||||||
std::bind(&MqttBattery::onMqttMessageVoltage,
|
std::bind(&MqttBattery::onMqttMessageVoltage,
|
||||||
this, std::placeholders::_1, std::placeholders::_2,
|
this, std::placeholders::_1, std::placeholders::_2,
|
||||||
std::placeholders::_3, std::placeholders::_4,
|
std::placeholders::_3, std::placeholders::_4,
|
||||||
std::placeholders::_5, std::placeholders::_6)
|
std::placeholders::_5, std::placeholders::_6,
|
||||||
|
config.Battery.MqttVoltageJsonPath)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
@ -55,25 +58,14 @@ void MqttBattery::deinit()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<float> MqttBattery::getFloat(std::string const& src, char const* topic) {
|
|
||||||
float res = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
res = std::stof(src);
|
|
||||||
}
|
|
||||||
catch(std::invalid_argument const& e) {
|
|
||||||
MessageOutput.printf("MqttBattery: Cannot parse payload '%s' in topic '%s' as float\r\n",
|
|
||||||
src.c_str(), topic);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttBattery::onMqttMessageSoC(espMqttClientTypes::MessageProperties const& properties,
|
void MqttBattery::onMqttMessageSoC(espMqttClientTypes::MessageProperties const& properties,
|
||||||
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total)
|
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total,
|
||||||
|
char const* jsonPath)
|
||||||
{
|
{
|
||||||
auto soc = getFloat(std::string(reinterpret_cast<const char*>(payload), len), topic);
|
auto soc = Utils::getNumericValueFromMqttPayload<float>("MqttBattery",
|
||||||
|
std::string(reinterpret_cast<const char*>(payload), len), topic,
|
||||||
|
jsonPath);
|
||||||
|
|
||||||
if (!soc.has_value()) { return; }
|
if (!soc.has_value()) { return; }
|
||||||
|
|
||||||
if (*soc < 0 || *soc > 100) {
|
if (*soc < 0 || *soc > 100) {
|
||||||
@ -91,9 +83,13 @@ void MqttBattery::onMqttMessageSoC(espMqttClientTypes::MessageProperties const&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttBattery::onMqttMessageVoltage(espMqttClientTypes::MessageProperties const& properties,
|
void MqttBattery::onMqttMessageVoltage(espMqttClientTypes::MessageProperties const& properties,
|
||||||
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total)
|
char const* topic, uint8_t const* payload, size_t len, size_t index, size_t total,
|
||||||
|
char const* jsonPath)
|
||||||
{
|
{
|
||||||
auto voltage = getFloat(std::string(reinterpret_cast<const char*>(payload), len), topic);
|
auto voltage = Utils::getNumericValueFromMqttPayload<float>("MqttBattery",
|
||||||
|
std::string(reinterpret_cast<const char*>(payload), len), topic,
|
||||||
|
jsonPath);
|
||||||
|
|
||||||
if (!voltage.has_value()) { return; }
|
if (!voltage.has_value()) { return; }
|
||||||
|
|
||||||
// since this project is revolving around Hoymiles microinverters, which can
|
// since this project is revolving around Hoymiles microinverters, which can
|
||||||
|
|||||||
@ -38,45 +38,13 @@ void PowerMeterMqtt::onMessage(PowerMeterMqtt::MsgProperties const& properties,
|
|||||||
char const* topic, uint8_t const* payload, size_t len, size_t index,
|
char const* topic, uint8_t const* payload, size_t len, size_t index,
|
||||||
size_t total, float* targetVariable, PowerMeterMqttValue const* cfg)
|
size_t total, float* targetVariable, PowerMeterMqttValue const* cfg)
|
||||||
{
|
{
|
||||||
std::string value(reinterpret_cast<char const*>(payload), len);
|
auto extracted = Utils::getNumericValueFromMqttPayload<float>("PowerMeterMqtt",
|
||||||
std::string logValue = value.substr(0, 32);
|
std::string(reinterpret_cast<const char*>(payload), len), topic,
|
||||||
if (value.length() > logValue.length()) { logValue += "..."; }
|
cfg->JsonPath);
|
||||||
|
|
||||||
auto log= [topic](char const* format, auto&&... args) -> void {
|
if (!extracted.has_value()) { return; }
|
||||||
MessageOutput.printf("[PowerMeterMqtt] Topic '%s': ", topic);
|
|
||||||
MessageOutput.printf(format, args...);
|
|
||||||
MessageOutput.println();
|
|
||||||
};
|
|
||||||
|
|
||||||
float newValue = 0;
|
float newValue = *extracted;
|
||||||
|
|
||||||
if (strlen(cfg->JsonPath) == 0) {
|
|
||||||
try {
|
|
||||||
newValue = std::stof(value);
|
|
||||||
}
|
|
||||||
catch (std::invalid_argument const& e) {
|
|
||||||
return log("cannot parse payload '%s' as float", logValue.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsonDocument json;
|
|
||||||
|
|
||||||
const DeserializationError error = deserializeJson(json, value);
|
|
||||||
if (error) {
|
|
||||||
return log("cannot parse payload '%s' as JSON", logValue.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.overflowed()) {
|
|
||||||
return log("payload too large to process as JSON");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pathResolutionResult = Utils::getJsonValueByPath<float>(json, cfg->JsonPath);
|
|
||||||
if (!pathResolutionResult.second.isEmpty()) {
|
|
||||||
return log("%s", pathResolutionResult.second.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
newValue = pathResolutionResult.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
using Unit_t = PowerMeterMqttValue::Unit;
|
using Unit_t = PowerMeterMqttValue::Unit;
|
||||||
switch (cfg->PowerUnit) {
|
switch (cfg->PowerUnit) {
|
||||||
@ -98,7 +66,8 @@ void PowerMeterMqtt::onMessage(PowerMeterMqtt::MsgProperties const& properties,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
log("new value: %5.2f, total: %5.2f", newValue, getPowerTotal());
|
MessageOutput.printf("[PowerMeterMqtt] Topic '%s': new value: %5.2f, "
|
||||||
|
"total: %5.2f\r\n", topic, newValue, getPowerTotal());
|
||||||
}
|
}
|
||||||
|
|
||||||
gotUpdate();
|
gotUpdate();
|
||||||
|
|||||||
@ -203,3 +203,47 @@ std::pair<T, String> Utils::getJsonValueByPath(JsonDocument const& root, String
|
|||||||
}
|
}
|
||||||
|
|
||||||
template std::pair<float, String> Utils::getJsonValueByPath(JsonDocument const& root, String const& path);
|
template std::pair<float, String> Utils::getJsonValueByPath(JsonDocument const& root, String const& path);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> Utils::getNumericValueFromMqttPayload(char const* client,
|
||||||
|
std::string const& src, char const* topic, char const* jsonPath)
|
||||||
|
{
|
||||||
|
std::string logValue = src.substr(0, 32);
|
||||||
|
if (src.length() > logValue.length()) { logValue += "..."; }
|
||||||
|
|
||||||
|
auto log = [client,topic](char const* format, auto&&... args) -> std::optional<T> {
|
||||||
|
MessageOutput.printf("[%s] Topic '%s': ", client, topic);
|
||||||
|
MessageOutput.printf(format, args...);
|
||||||
|
MessageOutput.println();
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (strlen(jsonPath) == 0) {
|
||||||
|
auto res = getFromString<T>(src.c_str());
|
||||||
|
if (!res.has_value()) {
|
||||||
|
return log("cannot parse payload '%s' as float", logValue.c_str());
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonDocument json;
|
||||||
|
|
||||||
|
const DeserializationError error = deserializeJson(json, src);
|
||||||
|
if (error) {
|
||||||
|
return log("cannot parse payload '%s' as JSON", logValue.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.overflowed()) {
|
||||||
|
return log("payload too large to process as JSON");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pathResolutionResult = getJsonValueByPath<T>(json, jsonPath);
|
||||||
|
if (!pathResolutionResult.second.isEmpty()) {
|
||||||
|
return log("%s", pathResolutionResult.second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathResolutionResult.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template std::optional<float> Utils::getNumericValueFromMqttPayload(char const* client,
|
||||||
|
std::string const& src, char const* topic, char const* jsonPath);
|
||||||
|
|||||||
@ -41,7 +41,9 @@ void WebApiBatteryClass::onStatus(AsyncWebServerRequest* request)
|
|||||||
root["jkbms_interface"] = config.Battery.JkBmsInterface;
|
root["jkbms_interface"] = config.Battery.JkBmsInterface;
|
||||||
root["jkbms_polling_interval"] = config.Battery.JkBmsPollingInterval;
|
root["jkbms_polling_interval"] = config.Battery.JkBmsPollingInterval;
|
||||||
root["mqtt_soc_topic"] = config.Battery.MqttSocTopic;
|
root["mqtt_soc_topic"] = config.Battery.MqttSocTopic;
|
||||||
|
root["mqtt_soc_json_path"] = config.Battery.MqttSocJsonPath;
|
||||||
root["mqtt_voltage_topic"] = config.Battery.MqttVoltageTopic;
|
root["mqtt_voltage_topic"] = config.Battery.MqttVoltageTopic;
|
||||||
|
root["mqtt_voltage_json_path"] = config.Battery.MqttVoltageJsonPath;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -80,7 +82,9 @@ void WebApiBatteryClass::onAdminPost(AsyncWebServerRequest* request)
|
|||||||
config.Battery.JkBmsInterface = root["jkbms_interface"].as<uint8_t>();
|
config.Battery.JkBmsInterface = root["jkbms_interface"].as<uint8_t>();
|
||||||
config.Battery.JkBmsPollingInterval = root["jkbms_polling_interval"].as<uint8_t>();
|
config.Battery.JkBmsPollingInterval = root["jkbms_polling_interval"].as<uint8_t>();
|
||||||
strlcpy(config.Battery.MqttSocTopic, root["mqtt_soc_topic"].as<String>().c_str(), sizeof(config.Battery.MqttSocTopic));
|
strlcpy(config.Battery.MqttSocTopic, root["mqtt_soc_topic"].as<String>().c_str(), sizeof(config.Battery.MqttSocTopic));
|
||||||
|
strlcpy(config.Battery.MqttSocJsonPath, root["mqtt_soc_json_path"].as<String>().c_str(), sizeof(config.Battery.MqttSocJsonPath));
|
||||||
strlcpy(config.Battery.MqttVoltageTopic, root["mqtt_voltage_topic"].as<String>().c_str(), sizeof(config.Battery.MqttVoltageTopic));
|
strlcpy(config.Battery.MqttVoltageTopic, root["mqtt_voltage_topic"].as<String>().c_str(), sizeof(config.Battery.MqttVoltageTopic));
|
||||||
|
strlcpy(config.Battery.MqttVoltageJsonPath, root["mqtt_voltage_json_path"].as<String>().c_str(), sizeof(config.Battery.MqttVoltageJsonPath));
|
||||||
|
|
||||||
WebApi.writeConfig(retMsg);
|
WebApi.writeConfig(retMsg);
|
||||||
|
|
||||||
|
|||||||
@ -672,9 +672,12 @@
|
|||||||
"ProviderMqtt": "Batteriewerte aus MQTT Broker",
|
"ProviderMqtt": "Batteriewerte aus MQTT Broker",
|
||||||
"ProviderVictron": "Victron SmartShunt per VE.Direct Schnittstelle",
|
"ProviderVictron": "Victron SmartShunt per VE.Direct Schnittstelle",
|
||||||
"ProviderPytesCan": "Pytes per CAN-Bus",
|
"ProviderPytesCan": "Pytes per CAN-Bus",
|
||||||
"MqttConfiguration": "MQTT Einstellungen",
|
"MqttSocConfiguration": "Einstellungen SoC",
|
||||||
"MqttSocTopic": "Topic für Batterie-SoC",
|
"MqttVoltageConfiguration": "Einstellungen Spannung",
|
||||||
"MqttVoltageTopic": "Topic für Batteriespannung",
|
"MqttJsonPath": "Optional: JSON-Pfad",
|
||||||
|
"MqttJsonPathDescription": "Anwendungsspezifischer JSON-Pfad um den Wert in den JSON Nutzdatzen zu finden, z.B. 'electricLevel'. Leer lassen, falls die Nutzdaten des Topics einen numerischen Wert enthält.",
|
||||||
|
"MqttSocTopic": "Topic für SoC",
|
||||||
|
"MqttVoltageTopic": "Topic für Spannung",
|
||||||
"JkBmsConfiguration": "JK BMS Einstellungen",
|
"JkBmsConfiguration": "JK BMS Einstellungen",
|
||||||
"JkBmsInterface": "Schnittstellentyp",
|
"JkBmsInterface": "Schnittstellentyp",
|
||||||
"JkBmsInterfaceUart": "TTL-UART an der MCU",
|
"JkBmsInterfaceUart": "TTL-UART an der MCU",
|
||||||
|
|||||||
@ -675,8 +675,12 @@
|
|||||||
"ProviderVictron": "Victron SmartShunt using VE.Direct interface",
|
"ProviderVictron": "Victron SmartShunt using VE.Direct interface",
|
||||||
"ProviderPytesCan": "Pytes using CAN bus",
|
"ProviderPytesCan": "Pytes using CAN bus",
|
||||||
"MqttConfiguration": "MQTT Settings",
|
"MqttConfiguration": "MQTT Settings",
|
||||||
"MqttSocTopic": "SoC value topic",
|
"MqttSocConfiguration": "SoC Settings",
|
||||||
"MqttVoltageTopic": "Voltage value topic",
|
"MqttVoltageConfiguration": "Voltage Settings",
|
||||||
|
"MqttJsonPath": "Optional: JSON Path",
|
||||||
|
"MqttJsonPathDescription": "Application specific JSON path to find the value in the JSON payload, e.g., 'electricLevel'. Leave empty if the topic's payload contains a plain numeric value.",
|
||||||
|
"MqttSocTopic": "SoC Value Topic",
|
||||||
|
"MqttVoltageTopic": "Voltage Value Topic",
|
||||||
"JkBmsConfiguration": "JK BMS Settings",
|
"JkBmsConfiguration": "JK BMS Settings",
|
||||||
"JkBmsInterface": "Interface Type",
|
"JkBmsInterface": "Interface Type",
|
||||||
"JkBmsInterfaceUart": "TTL-UART on MCU",
|
"JkBmsInterfaceUart": "TTL-UART on MCU",
|
||||||
|
|||||||
@ -598,9 +598,12 @@
|
|||||||
"ProviderJkBmsSerial": "Jikong (JK) BMS using serial connection",
|
"ProviderJkBmsSerial": "Jikong (JK) BMS using serial connection",
|
||||||
"ProviderMqtt": "Battery data from MQTT broker",
|
"ProviderMqtt": "Battery data from MQTT broker",
|
||||||
"ProviderVictron": "Victron SmartShunt using VE.Direct interface",
|
"ProviderVictron": "Victron SmartShunt using VE.Direct interface",
|
||||||
"MqttConfiguration": "MQTT Settings",
|
"MqttSocConfiguration": "SoC Settings",
|
||||||
"MqttSocTopic": "SoC value topic",
|
"MqttVoltageConfiguration": "Voltage Settings",
|
||||||
"MqttVoltageTopic": "Voltage value topic",
|
"MqttJsonPath": "Optional: JSON Path",
|
||||||
|
"MqttJsonPathDescription": "Application specific JSON path to find the value in the JSON payload, e.g., 'electricLevel'. Leave empty if the topic's payload contains a plain numeric value.",
|
||||||
|
"MqttSocTopic": "SoC Value Topic",
|
||||||
|
"MqttVoltageTopic": "Voltage Value Topic",
|
||||||
"JkBmsConfiguration": "JK BMS Settings",
|
"JkBmsConfiguration": "JK BMS Settings",
|
||||||
"JkBmsInterface": "Interface Type",
|
"JkBmsInterface": "Interface Type",
|
||||||
"JkBmsInterfaceUart": "TTL-UART on MCU",
|
"JkBmsInterfaceUart": "TTL-UART on MCU",
|
||||||
|
|||||||
@ -5,5 +5,7 @@ export interface BatteryConfig {
|
|||||||
jkbms_interface: number;
|
jkbms_interface: number;
|
||||||
jkbms_polling_interval: number;
|
jkbms_polling_interval: number;
|
||||||
mqtt_soc_topic: string;
|
mqtt_soc_topic: string;
|
||||||
|
mqtt_soc_json_path: string;
|
||||||
mqtt_voltage_topic: string;
|
mqtt_voltage_topic: string;
|
||||||
|
mqtt_voltage_json_path: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,29 +49,37 @@
|
|||||||
type="number" min="2" max="90" step="1" :postfix="$t('batteryadmin.Seconds')"/>
|
type="number" min="2" max="90" step="1" :postfix="$t('batteryadmin.Seconds')"/>
|
||||||
</CardElement>
|
</CardElement>
|
||||||
|
|
||||||
<CardElement v-show="batteryConfigList.enabled && batteryConfigList.provider == 2"
|
<template v-if="batteryConfigList.enabled && batteryConfigList.provider == 2">
|
||||||
:text="$t('batteryadmin.MqttConfiguration')" textVariant="text-bg-primary" addSpace>
|
<CardElement :text="$t('batteryadmin.MqttSocConfiguration')" textVariant="text-bg-primary" addSpace>
|
||||||
<div class="row mb-3">
|
|
||||||
<label class="col-sm-2 col-form-label">
|
<InputElement :label="$t('batteryadmin.MqttSocTopic')"
|
||||||
{{ $t('batteryadmin.MqttSocTopic') }}
|
v-model="batteryConfigList.mqtt_soc_topic"
|
||||||
</label>
|
type="text"
|
||||||
<div class="col-sm-10">
|
maxlength="256" />
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" v-model="batteryConfigList.mqtt_soc_topic" />
|
<InputElement :label="$t('batteryadmin.MqttJsonPath')"
|
||||||
</div>
|
v-model="batteryConfigList.mqtt_soc_json_path"
|
||||||
</div>
|
type="text"
|
||||||
</div>
|
maxlength="128"
|
||||||
<div class="row mb-3">
|
:tooltip="$t('batteryadmin.MqttJsonPathDescription')" />
|
||||||
<label class="col-sm-2 col-form-label">
|
|
||||||
{{ $t('batteryadmin.MqttVoltageTopic') }}
|
</CardElement>
|
||||||
</label>
|
|
||||||
<div class="col-sm-10">
|
<CardElement :text="$t('batteryadmin.MqttVoltageConfiguration')" textVariant="text-bg-primary" addSpace>
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" v-model="batteryConfigList.mqtt_voltage_topic" />
|
<InputElement :label="$t('batteryadmin.MqttVoltageTopic')"
|
||||||
</div>
|
v-model="batteryConfigList.mqtt_voltage_topic"
|
||||||
</div>
|
type="text"
|
||||||
</div>
|
maxlength="256" />
|
||||||
</CardElement>
|
|
||||||
|
<InputElement :label="$t('batteryadmin.MqttJsonPath')"
|
||||||
|
v-model="batteryConfigList.mqtt_voltage_json_path"
|
||||||
|
type="text"
|
||||||
|
maxlength="128"
|
||||||
|
:tooltip="$t('batteryadmin.MqttJsonPathDescription')" />
|
||||||
|
|
||||||
|
</CardElement>
|
||||||
|
</template>
|
||||||
|
|
||||||
<FormFooter @reload="getBatteryConfig"/>
|
<FormFooter @reload="getBatteryConfig"/>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user