Feature: add support for Pytes batteries using CAN (#1088)
Co-authored-by: Bernhard Kirchen <schlimmchen@posteo.net>
This commit is contained in:
parent
83c59d7811
commit
6a3f90ff95
@ -14,8 +14,10 @@ public:
|
||||
virtual void onMessage(twai_message_t rx_message) = 0;
|
||||
|
||||
protected:
|
||||
uint8_t readUnsignedInt8(uint8_t *data);
|
||||
uint16_t readUnsignedInt16(uint8_t *data);
|
||||
int16_t readSignedInt16(uint8_t *data);
|
||||
uint32_t readUnsignedInt32(uint8_t *data);
|
||||
float scaleValue(int16_t value, float factor);
|
||||
bool getBit(uint8_t value, uint8_t bit);
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ class BatteryStats {
|
||||
String _manufacturer = "unknown";
|
||||
String _hwversion = "";
|
||||
String _fwversion = "";
|
||||
String _serial = "";
|
||||
uint32_t _lastUpdate = 0;
|
||||
|
||||
private:
|
||||
@ -115,6 +116,84 @@ class PylontechBatteryStats : public BatteryStats {
|
||||
bool _chargeImmediately;
|
||||
};
|
||||
|
||||
class PytesBatteryStats : public BatteryStats {
|
||||
friend class PytesCanReceiver;
|
||||
|
||||
public:
|
||||
void getLiveViewData(JsonVariant& root) const final;
|
||||
void mqttPublish() const final;
|
||||
float getChargeCurrent() const { return _current; } ;
|
||||
float getChargeCurrentLimitation() const { return _chargeCurrentLimit; } ;
|
||||
|
||||
private:
|
||||
void setManufacturer(String&& m) { _manufacturer = std::move(m); }
|
||||
void setLastUpdate(uint32_t ts) { _lastUpdate = ts; }
|
||||
void updateSerial() {
|
||||
if (!_serialPart1.isEmpty() && !_serialPart2.isEmpty()) {
|
||||
_serial = _serialPart1 + _serialPart2;
|
||||
}
|
||||
}
|
||||
|
||||
String _serialPart1 = "";
|
||||
String _serialPart2 = "";
|
||||
|
||||
float _chargeVoltageLimit;
|
||||
float _chargeCurrentLimit;
|
||||
float _dischargeVoltageLimit;
|
||||
float _dischargeCurrentLimit;
|
||||
|
||||
uint16_t _stateOfHealth;
|
||||
|
||||
// total current into (positive) or from (negative)
|
||||
// the battery, i.e., the charging current
|
||||
float _current;
|
||||
float _temperature;
|
||||
|
||||
uint16_t _cellMinMilliVolt;
|
||||
uint16_t _cellMaxMilliVolt;
|
||||
float _cellMinTemperature;
|
||||
float _cellMaxTemperature;
|
||||
|
||||
String _cellMinVoltageName;
|
||||
String _cellMaxVoltageName;
|
||||
String _cellMinTemperatureName;
|
||||
String _cellMaxTemperatureName;
|
||||
|
||||
uint8_t _moduleCountOnline;
|
||||
uint8_t _moduleCountOffline;
|
||||
|
||||
uint8_t _moduleCountBlockingCharge;
|
||||
uint8_t _moduleCountBlockingDischarge;
|
||||
|
||||
uint16_t _totalCapacity;
|
||||
uint16_t _availableCapacity;
|
||||
|
||||
float _chargedEnergy = -1;
|
||||
float _dischargedEnergy = -1;
|
||||
|
||||
bool _alarmUnderVoltage;
|
||||
bool _alarmOverVoltage;
|
||||
bool _alarmOverCurrentCharge;
|
||||
bool _alarmOverCurrentDischarge;
|
||||
bool _alarmUnderTemperature;
|
||||
bool _alarmOverTemperature;
|
||||
bool _alarmUnderTemperatureCharge;
|
||||
bool _alarmOverTemperatureCharge;
|
||||
bool _alarmInternalFailure;
|
||||
bool _alarmCellImbalance;
|
||||
|
||||
bool _warningLowVoltage;
|
||||
bool _warningHighVoltage;
|
||||
bool _warningHighChargeCurrent;
|
||||
bool _warningHighDischargeCurrent;
|
||||
bool _warningLowTemperature;
|
||||
bool _warningHighTemperature;
|
||||
bool _warningLowTemperatureCharge;
|
||||
bool _warningHighTemperatureCharge;
|
||||
bool _warningInternalFailure;
|
||||
bool _warningCellImbalance;
|
||||
};
|
||||
|
||||
class JkBmsBatteryStats : public BatteryStats {
|
||||
public:
|
||||
void getLiveViewData(JsonVariant& root) const final {
|
||||
|
||||
19
include/PytesCanReceiver.h
Normal file
19
include/PytesCanReceiver.h
Normal file
@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "Configuration.h"
|
||||
#include "Battery.h"
|
||||
#include "BatteryCanReceiver.h"
|
||||
#include <driver/twai.h>
|
||||
|
||||
class PytesCanReceiver : public BatteryCanReceiver {
|
||||
public:
|
||||
bool init(bool verboseLogging) final;
|
||||
void onMessage(twai_message_t rx_message) final;
|
||||
|
||||
std::shared_ptr<BatteryStats> getStats() const final { return _stats; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<PytesBatteryStats> _stats =
|
||||
std::make_shared<PytesBatteryStats>();
|
||||
};
|
||||
@ -5,6 +5,7 @@
|
||||
#include "JkBmsController.h"
|
||||
#include "VictronSmartShunt.h"
|
||||
#include "MqttBattery.h"
|
||||
#include "PytesCanReceiver.h"
|
||||
|
||||
BatteryClass Battery;
|
||||
|
||||
@ -57,6 +58,9 @@ void BatteryClass::updateSettings()
|
||||
case 3:
|
||||
_upProvider = std::make_unique<VictronSmartShunt>();
|
||||
break;
|
||||
case 4:
|
||||
_upProvider = std::make_unique<PytesCanReceiver>();
|
||||
break;
|
||||
default:
|
||||
MessageOutput.printf("[Battery] Unknown provider: %d\r\n", config.Battery.Provider);
|
||||
return;
|
||||
|
||||
@ -130,15 +130,28 @@ void BatteryCanReceiver::loop()
|
||||
return;
|
||||
}
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[%s] Received CAN message: 0x%04X -",
|
||||
_providerName, rx_message.identifier);
|
||||
|
||||
for (int i = 0; i < rx_message.data_length_code; i++) {
|
||||
MessageOutput.printf(" %02X", rx_message.data[i]);
|
||||
}
|
||||
|
||||
MessageOutput.printf("\r\n");
|
||||
}
|
||||
|
||||
onMessage(rx_message);
|
||||
}
|
||||
|
||||
uint8_t BatteryCanReceiver::readUnsignedInt8(uint8_t *data)
|
||||
{
|
||||
return data[0];
|
||||
}
|
||||
|
||||
uint16_t BatteryCanReceiver::readUnsignedInt16(uint8_t *data)
|
||||
{
|
||||
uint8_t bytes[2];
|
||||
bytes[0] = *data;
|
||||
bytes[1] = *(data + 1);
|
||||
return (bytes[1] << 8) + bytes[0];
|
||||
return (data[1] << 8) | data[0];
|
||||
}
|
||||
|
||||
int16_t BatteryCanReceiver::readSignedInt16(uint8_t *data)
|
||||
@ -146,6 +159,11 @@ int16_t BatteryCanReceiver::readSignedInt16(uint8_t *data)
|
||||
return this->readUnsignedInt16(data);
|
||||
}
|
||||
|
||||
uint32_t BatteryCanReceiver::readUnsignedInt32(uint8_t *data)
|
||||
{
|
||||
return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
|
||||
}
|
||||
|
||||
float BatteryCanReceiver::scaleValue(int16_t value, float factor)
|
||||
{
|
||||
return value * factor;
|
||||
|
||||
@ -26,9 +26,12 @@ static void addLiveViewValue(JsonVariant& root, std::string const& name,
|
||||
}
|
||||
|
||||
static void addLiveViewTextInSection(JsonVariant& root,
|
||||
std::string const& section, std::string const& name, std::string const& text)
|
||||
std::string const& section, std::string const& name,
|
||||
std::string const& text, bool translate = true)
|
||||
{
|
||||
root["values"][section][name] = text;
|
||||
auto jsonValue = root["values"][section][name];
|
||||
jsonValue["value"] = text;
|
||||
jsonValue["translate"] = translate;
|
||||
}
|
||||
|
||||
static void addLiveViewTextValue(JsonVariant& root, std::string const& name,
|
||||
@ -62,6 +65,9 @@ bool BatteryStats::updateAvailable(uint32_t since) const
|
||||
void BatteryStats::getLiveViewData(JsonVariant& root) const
|
||||
{
|
||||
root["manufacturer"] = _manufacturer;
|
||||
if (!_serial.isEmpty()) {
|
||||
root["serial"] = _serial;
|
||||
}
|
||||
if (!_fwversion.isEmpty()) {
|
||||
root["fwversion"] = _fwversion;
|
||||
}
|
||||
@ -113,6 +119,78 @@ void PylontechBatteryStats::getLiveViewData(JsonVariant& root) const
|
||||
addLiveViewAlarm(root, "bmsInternal", _alarmBmsInternal);
|
||||
}
|
||||
|
||||
void PytesBatteryStats::getLiveViewData(JsonVariant& root) const
|
||||
{
|
||||
BatteryStats::getLiveViewData(root);
|
||||
|
||||
// values go into the "Status" card of the web application
|
||||
addLiveViewValue(root, "current", _current, "A", 1);
|
||||
addLiveViewValue(root, "chargeVoltage", _chargeVoltageLimit, "V", 1);
|
||||
addLiveViewValue(root, "chargeCurrentLimitation", _chargeCurrentLimit, "A", 1);
|
||||
addLiveViewValue(root, "dischargeVoltageLimitation", _dischargeVoltageLimit, "V", 1);
|
||||
addLiveViewValue(root, "dischargeCurrentLimitation", _dischargeCurrentLimit, "A", 1);
|
||||
addLiveViewValue(root, "stateOfHealth", _stateOfHealth, "%", 0);
|
||||
addLiveViewValue(root, "temperature", _temperature, "°C", 1);
|
||||
|
||||
addLiveViewValue(root, "capacity", _totalCapacity, "Ah", 0);
|
||||
addLiveViewValue(root, "availableCapacity", _availableCapacity, "Ah", 0);
|
||||
|
||||
if (_chargedEnergy != -1) {
|
||||
addLiveViewValue(root, "chargedEnergy", _chargedEnergy, "kWh", 2);
|
||||
}
|
||||
|
||||
if (_dischargedEnergy != -1) {
|
||||
addLiveViewValue(root, "dischargedEnergy", _dischargedEnergy, "kWh", 2);
|
||||
}
|
||||
|
||||
addLiveViewInSection(root, "cells", "cellMinVoltage", static_cast<float>(_cellMinMilliVolt)/1000, "V", 3);
|
||||
addLiveViewInSection(root, "cells", "cellMaxVoltage", static_cast<float>(_cellMaxMilliVolt)/1000, "V", 3);
|
||||
addLiveViewInSection(root, "cells", "cellDiffVoltage", (_cellMaxMilliVolt - _cellMinMilliVolt), "mV", 0);
|
||||
addLiveViewInSection(root, "cells", "cellMinTemperature", _cellMinTemperature, "°C", 0);
|
||||
addLiveViewInSection(root, "cells", "cellMaxTemperature", _cellMaxTemperature, "°C", 0);
|
||||
|
||||
addLiveViewTextInSection(root, "cells", "cellMinVoltageName", _cellMinVoltageName.c_str(), false);
|
||||
addLiveViewTextInSection(root, "cells", "cellMaxVoltageName", _cellMaxVoltageName.c_str(), false);
|
||||
addLiveViewTextInSection(root, "cells", "cellMinTemperatureName", _cellMinTemperatureName.c_str(), false);
|
||||
addLiveViewTextInSection(root, "cells", "cellMaxTemperatureName", _cellMaxTemperatureName.c_str(), false);
|
||||
|
||||
addLiveViewInSection(root, "modules", "online", _moduleCountOnline, "", 0);
|
||||
addLiveViewInSection(root, "modules", "offline", _moduleCountOffline, "", 0);
|
||||
addLiveViewInSection(root, "modules", "blockingCharge", _moduleCountBlockingCharge, "", 0);
|
||||
addLiveViewInSection(root, "modules", "blockingDischarge", _moduleCountBlockingDischarge, "", 0);
|
||||
|
||||
// alarms and warnings go into the "Issues" card of the web application
|
||||
addLiveViewWarning(root, "highCurrentDischarge", _warningHighDischargeCurrent);
|
||||
addLiveViewAlarm(root, "overCurrentDischarge", _alarmOverCurrentDischarge);
|
||||
|
||||
addLiveViewWarning(root, "highCurrentCharge", _warningHighChargeCurrent);
|
||||
addLiveViewAlarm(root, "overCurrentCharge", _alarmOverCurrentCharge);
|
||||
|
||||
addLiveViewWarning(root, "lowVoltage", _warningLowVoltage);
|
||||
addLiveViewAlarm(root, "underVoltage", _alarmUnderVoltage);
|
||||
|
||||
addLiveViewWarning(root, "highVoltage", _warningHighVoltage);
|
||||
addLiveViewAlarm(root, "overVoltage", _alarmOverVoltage);
|
||||
|
||||
addLiveViewWarning(root, "lowTemperature", _warningLowTemperature);
|
||||
addLiveViewAlarm(root, "underTemperature", _alarmUnderTemperature);
|
||||
|
||||
addLiveViewWarning(root, "highTemperature", _warningHighTemperature);
|
||||
addLiveViewAlarm(root, "overTemperature", _alarmOverTemperature);
|
||||
|
||||
addLiveViewWarning(root, "lowTemperatureCharge", _warningLowTemperatureCharge);
|
||||
addLiveViewAlarm(root, "underTemperatureCharge", _alarmUnderTemperatureCharge);
|
||||
|
||||
addLiveViewWarning(root, "highTemperatureCharge", _warningHighTemperatureCharge);
|
||||
addLiveViewAlarm(root, "overTemperatureCharge", _alarmOverTemperatureCharge);
|
||||
|
||||
addLiveViewWarning(root, "bmsInternal", _warningInternalFailure);
|
||||
addLiveViewAlarm(root, "bmsInternal", _alarmInternalFailure);
|
||||
|
||||
addLiveViewWarning(root, "cellDiffVoltage", _warningCellImbalance);
|
||||
addLiveViewAlarm(root, "cellDiffVoltage", _alarmCellImbalance);
|
||||
}
|
||||
|
||||
void JkBmsBatteryStats::getJsonData(JsonVariant& root, bool verbose) const
|
||||
{
|
||||
BatteryStats::getLiveViewData(root);
|
||||
@ -259,6 +337,68 @@ void PylontechBatteryStats::mqttPublish() const
|
||||
MqttSettings.publish("battery/charging/chargeImmediately", String(_chargeImmediately));
|
||||
}
|
||||
|
||||
void PytesBatteryStats::mqttPublish() const
|
||||
{
|
||||
BatteryStats::mqttPublish();
|
||||
|
||||
MqttSettings.publish("battery/settings/chargeVoltage", String(_chargeVoltageLimit));
|
||||
MqttSettings.publish("battery/settings/chargeCurrentLimitation", String(_chargeCurrentLimit));
|
||||
MqttSettings.publish("battery/settings/dischargeCurrentLimitation", String(_dischargeCurrentLimit));
|
||||
MqttSettings.publish("battery/settings/dischargeVoltageLimitation", String(_dischargeVoltageLimit));
|
||||
|
||||
MqttSettings.publish("battery/stateOfHealth", String(_stateOfHealth));
|
||||
MqttSettings.publish("battery/current", String(_current));
|
||||
MqttSettings.publish("battery/temperature", String(_temperature));
|
||||
|
||||
if (_chargedEnergy != -1) {
|
||||
MqttSettings.publish("battery/chargedEnergy", String(_chargedEnergy));
|
||||
}
|
||||
|
||||
if (_dischargedEnergy != -1) {
|
||||
MqttSettings.publish("battery/dischargedEnergy", String(_dischargedEnergy));
|
||||
}
|
||||
|
||||
MqttSettings.publish("battery/capacity", String(_totalCapacity));
|
||||
MqttSettings.publish("battery/availableCapacity", String(_availableCapacity));
|
||||
|
||||
MqttSettings.publish("battery/CellMinMilliVolt", String(_cellMinMilliVolt));
|
||||
MqttSettings.publish("battery/CellMaxMilliVolt", String(_cellMaxMilliVolt));
|
||||
MqttSettings.publish("battery/CellDiffMilliVolt", String(_cellMaxMilliVolt - _cellMinMilliVolt));
|
||||
MqttSettings.publish("battery/CellMinTemperature", String(_cellMinTemperature));
|
||||
MqttSettings.publish("battery/CellMaxTemperature", String(_cellMaxTemperature));
|
||||
MqttSettings.publish("battery/CellMinVoltageName", String(_cellMinVoltageName));
|
||||
MqttSettings.publish("battery/CellMaxVoltageName", String(_cellMaxVoltageName));
|
||||
MqttSettings.publish("battery/CellMinTemperatureName", String(_cellMinTemperatureName));
|
||||
MqttSettings.publish("battery/CellMaxTemperatureName", String(_cellMaxTemperatureName));
|
||||
|
||||
MqttSettings.publish("battery/modulesOnline", String(_moduleCountOnline));
|
||||
MqttSettings.publish("battery/modulesOffline", String(_moduleCountOffline));
|
||||
MqttSettings.publish("battery/modulesBlockingCharge", String(_moduleCountBlockingCharge));
|
||||
MqttSettings.publish("battery/modulesBlockingDischarge", String(_moduleCountBlockingDischarge));
|
||||
|
||||
MqttSettings.publish("battery/alarm/overCurrentDischarge", String(_alarmOverCurrentDischarge));
|
||||
MqttSettings.publish("battery/alarm/overCurrentCharge", String(_alarmOverCurrentCharge));
|
||||
MqttSettings.publish("battery/alarm/underVoltage", String(_alarmUnderVoltage));
|
||||
MqttSettings.publish("battery/alarm/overVoltage", String(_alarmOverVoltage));
|
||||
MqttSettings.publish("battery/alarm/underTemperature", String(_alarmUnderTemperature));
|
||||
MqttSettings.publish("battery/alarm/overTemperature", String(_alarmOverTemperature));
|
||||
MqttSettings.publish("battery/alarm/underTemperatureCharge", String(_alarmUnderTemperatureCharge));
|
||||
MqttSettings.publish("battery/alarm/overTemperatureCharge", String(_alarmOverTemperatureCharge));
|
||||
MqttSettings.publish("battery/alarm/bmsInternal", String(_alarmInternalFailure));
|
||||
MqttSettings.publish("battery/alarm/cellImbalance", String(_alarmCellImbalance));
|
||||
|
||||
MqttSettings.publish("battery/warning/highCurrentDischarge", String(_warningHighDischargeCurrent));
|
||||
MqttSettings.publish("battery/warning/highCurrentCharge", String(_warningHighChargeCurrent));
|
||||
MqttSettings.publish("battery/warning/lowVoltage", String(_warningLowVoltage));
|
||||
MqttSettings.publish("battery/warning/highVoltage", String(_warningHighVoltage));
|
||||
MqttSettings.publish("battery/warning/lowTemperature", String(_warningLowTemperature));
|
||||
MqttSettings.publish("battery/warning/highTemperature", String(_warningHighTemperature));
|
||||
MqttSettings.publish("battery/warning/lowTemperatureCharge", String(_warningLowTemperatureCharge));
|
||||
MqttSettings.publish("battery/warning/highTemperatureCharge", String(_warningHighTemperatureCharge));
|
||||
MqttSettings.publish("battery/warning/bmsInternal", String(_warningInternalFailure));
|
||||
MqttSettings.publish("battery/warning/cellImbalance", String(_warningCellImbalance));
|
||||
}
|
||||
|
||||
void JkBmsBatteryStats::mqttPublish() const
|
||||
{
|
||||
BatteryStats::mqttPublish();
|
||||
|
||||
@ -125,6 +125,61 @@ void MqttHandleBatteryHassClass::loop()
|
||||
publishSensor("Midpoint Voltage", NULL, "midpointVoltage", "voltage", "measurement", "V");
|
||||
publishSensor("Midpoint Deviation", NULL, "midpointDeviation", "battery", "measurement", "%");
|
||||
break;
|
||||
case 4: // Pytes Battery
|
||||
publishSensor("Charge voltage (BMS)", NULL, "settings/chargeVoltage", "voltage", "measurement", "V");
|
||||
publishSensor("Charge current limit", NULL, "settings/chargeCurrentLimitation", "current", "measurement", "A");
|
||||
publishSensor("Discharge current limit", NULL, "settings/dischargeCurrentLimitation", "current", "measurement", "A");
|
||||
publishSensor("Discharge voltage limit", NULL, "settings/dischargeVoltageLimitation", "voltage", "measurement", "V");
|
||||
|
||||
publishSensor("Voltage", "mdi:battery-charging", "voltage", "voltage", "measurement", "V");
|
||||
publishSensor("Current", "mdi:current-dc", "current", "current", "measurement", "A");
|
||||
publishSensor("State of Health (SOH)", "mdi:heart-plus", "stateOfHealth", NULL, "measurement", "%");
|
||||
publishSensor("Temperature", "mdi:thermometer", "temperature", "temperature", "measurement", "°C");
|
||||
|
||||
publishSensor("Charged Energy", NULL, "chargedEnergy", "energy", "total_increasing", "kWh");
|
||||
publishSensor("Discharged Energy", NULL, "dischargedEnergy", "energy", "total_increasing", "kWh");
|
||||
|
||||
publishSensor("Total Capacity", NULL, "capacity");
|
||||
publishSensor("Available Capacity", NULL, "availableCapacity");
|
||||
|
||||
publishSensor("Cell Min Voltage", NULL, "CellMinMilliVolt", "voltage", "measurement", "mV");
|
||||
publishSensor("Cell Max Voltage", NULL, "CellMaxMilliVolt", "voltage", "measurement", "mV");
|
||||
publishSensor("Cell Voltage Diff", "mdi:battery-alert", "CellDiffMilliVolt", "voltage", "measurement", "mV");
|
||||
publishSensor("Cell Min Temperature", NULL, "CellMinTemperature", "temperature", "measurement", "°C");
|
||||
publishSensor("Cell Max Temperature", NULL, "CellMaxTemperature", "temperature", "measurement", "°C");
|
||||
|
||||
publishSensor("Cell Min Voltage Label", NULL, "CellMinVoltageName");
|
||||
publishSensor("Cell Max Voltage Label", NULL, "CellMaxVoltageName");
|
||||
publishSensor("Cell Min Temperature Label", NULL, "CellMinTemperatureName");
|
||||
publishSensor("Cell Max Temperature Label", NULL, "CellMaxTemperatureName");
|
||||
|
||||
publishSensor("Modules Online", "mdi:counter", "modulesOnline");
|
||||
publishSensor("Modules Offline", "mdi:counter", "modulesOffline");
|
||||
publishSensor("Modules Blocking Charge", "mdi:counter", "modulesBlockingCharge");
|
||||
publishSensor("Modules Blocking Discharge", "mdi:counter", "modulesBlockingDischarge");
|
||||
|
||||
publishBinarySensor("Alarm Discharge current", "mdi:alert", "alarm/overCurrentDischarge", "1", "0");
|
||||
publishBinarySensor("Alarm High charge current", "mdi:alert", "alarm/overCurrentCharge", "1", "0");
|
||||
publishBinarySensor("Alarm Voltage low", "mdi:alert", "alarm/underVoltage", "1", "0");
|
||||
publishBinarySensor("Alarm Voltage high", "mdi:alert", "alarm/overVoltage", "1", "0");
|
||||
publishBinarySensor("Alarm Temperature low", "mdi:thermometer-low", "alarm/underTemperature", "1", "0");
|
||||
publishBinarySensor("Alarm Temperature high", "mdi:thermometer-high", "alarm/overTemperature", "1", "0");
|
||||
publishBinarySensor("Alarm Temperature low (charge)", "mdi:thermometer-low", "alarm/underTemperatureCharge", "1", "0");
|
||||
publishBinarySensor("Alarm Temperature high (charge)", "mdi:thermometer-high", "alarm/overTemperatureCharge", "1", "0");
|
||||
publishBinarySensor("Alarm BMS internal", "mdi:alert", "alarm/bmsInternal", "1", "0");
|
||||
publishBinarySensor("Alarm Cell Imbalance", "mdi:alert-outline", "alarm/cellImbalance", "1", "0");
|
||||
|
||||
publishBinarySensor("Warning Discharge current", "mdi:alert-outline", "warning/highCurrentDischarge", "1", "0");
|
||||
publishBinarySensor("Warning High charge current", "mdi:alert-outline", "warning/highCurrentCharge", "1", "0");
|
||||
publishBinarySensor("Warning Voltage low", "mdi:alert-outline", "warning/lowVoltage", "1", "0");
|
||||
publishBinarySensor("Warning Voltage high", "mdi:alert-outline", "warning/highVoltage", "1", "0");
|
||||
publishBinarySensor("Warning Temperature low", "mdi:thermometer-low", "warning/lowTemperature", "1", "0");
|
||||
publishBinarySensor("Warning Temperature high", "mdi:thermometer-high", "warning/highTemperature", "1", "0");
|
||||
publishBinarySensor("Warning Temperature low (charge)", "mdi:thermometer-low", "warning/lowTemperatureCharge", "1", "0");
|
||||
publishBinarySensor("Warning Temperature high (charge)", "mdi:thermometer-high", "warning/highTemperatureCharge", "1", "0");
|
||||
publishBinarySensor("Warning BMS internal", "mdi:alert-outline", "warning/bmsInternal", "1", "0");
|
||||
publishBinarySensor("Warning Cell Imbalance", "mdi:alert-outline", "warning/cellImbalance", "1", "0");
|
||||
break;
|
||||
}
|
||||
|
||||
_doPublish = false;
|
||||
|
||||
293
src/PytesCanReceiver.cpp
Normal file
293
src/PytesCanReceiver.cpp
Normal file
@ -0,0 +1,293 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include "PytesCanReceiver.h"
|
||||
#include "MessageOutput.h"
|
||||
#include "PinMapping.h"
|
||||
#include <driver/twai.h>
|
||||
#include <ctime>
|
||||
|
||||
bool PytesCanReceiver::init(bool verboseLogging)
|
||||
{
|
||||
return BatteryCanReceiver::init(verboseLogging, "Pytes");
|
||||
}
|
||||
|
||||
void PytesCanReceiver::onMessage(twai_message_t rx_message)
|
||||
{
|
||||
switch (rx_message.identifier) {
|
||||
case 0x351: {
|
||||
_stats->_chargeVoltageLimit = this->scaleValue(this->readUnsignedInt16(rx_message.data), 0.1);
|
||||
_stats->_chargeCurrentLimit = this->scaleValue(this->readUnsignedInt16(rx_message.data + 2), 0.1);
|
||||
_stats->_dischargeCurrentLimit = this->scaleValue(this->readUnsignedInt16(rx_message.data + 4), 0.1);
|
||||
_stats->_dischargeVoltageLimit = this->scaleValue(this->readSignedInt16(rx_message.data + 6), 0.1);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] chargeVoltageLimit: %f chargeCurrentLimit: %f dischargeCurrentLimit: %f dischargeVoltageLimit: %f\r\n",
|
||||
_stats->_chargeVoltageLimit, _stats->_chargeCurrentLimit,
|
||||
_stats->_dischargeCurrentLimit, _stats->_dischargeVoltageLimit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x355: {
|
||||
_stats->setSoC(static_cast<uint8_t>(this->readUnsignedInt16(rx_message.data)), 0/*precision*/, millis());
|
||||
_stats->_stateOfHealth = this->readUnsignedInt16(rx_message.data + 2);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] soc: %d soh: %d\r\n",
|
||||
_stats->getSoC(), _stats->_stateOfHealth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x356: {
|
||||
_stats->setVoltage(this->scaleValue(this->readSignedInt16(rx_message.data), 0.01), millis());
|
||||
_stats->_current = this->scaleValue(this->readSignedInt16(rx_message.data + 2), 0.1);
|
||||
_stats->_temperature = this->scaleValue(this->readSignedInt16(rx_message.data + 4), 0.1);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] voltage: %f current: %f temperature: %f\r\n",
|
||||
_stats->getVoltage(), _stats->_current, _stats->_temperature);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x35A: { // Alarms and Warnings
|
||||
uint16_t alarmBits = rx_message.data[0];
|
||||
_stats->_alarmOverVoltage = this->getBit(alarmBits, 2);
|
||||
_stats->_alarmUnderVoltage = this->getBit(alarmBits, 4);
|
||||
_stats->_alarmOverTemperature = this->getBit(alarmBits, 6);
|
||||
|
||||
alarmBits = rx_message.data[1];
|
||||
_stats->_alarmUnderTemperature = this->getBit(alarmBits, 0);
|
||||
_stats->_alarmOverTemperatureCharge = this->getBit(alarmBits, 2);
|
||||
_stats->_alarmUnderTemperatureCharge = this->getBit(alarmBits, 4);
|
||||
_stats->_alarmOverCurrentDischarge = this->getBit(alarmBits, 6);
|
||||
|
||||
alarmBits = rx_message.data[2];
|
||||
_stats->_alarmOverCurrentCharge = this->getBit(alarmBits, 0);
|
||||
_stats->_alarmInternalFailure = this->getBit(alarmBits, 6);
|
||||
|
||||
alarmBits = rx_message.data[3];
|
||||
_stats->_alarmCellImbalance = this->getBit(alarmBits, 0);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] Alarms: %d %d %d %d %d %d %d %d %d %d\r\n",
|
||||
_stats->_alarmOverVoltage,
|
||||
_stats->_alarmUnderVoltage,
|
||||
_stats->_alarmOverTemperature,
|
||||
_stats->_alarmUnderTemperature,
|
||||
_stats->_alarmOverTemperatureCharge,
|
||||
_stats->_alarmUnderTemperatureCharge,
|
||||
_stats->_alarmOverCurrentDischarge,
|
||||
_stats->_alarmOverCurrentCharge,
|
||||
_stats->_alarmInternalFailure,
|
||||
_stats->_alarmCellImbalance);
|
||||
}
|
||||
|
||||
uint16_t warningBits = rx_message.data[4];
|
||||
_stats->_warningHighVoltage = this->getBit(warningBits, 2);
|
||||
_stats->_warningLowVoltage = this->getBit(warningBits, 4);
|
||||
_stats->_warningHighTemperature = this->getBit(warningBits, 6);
|
||||
|
||||
warningBits = rx_message.data[5];
|
||||
_stats->_warningLowTemperature = this->getBit(warningBits, 0);
|
||||
_stats->_warningHighTemperatureCharge = this->getBit(warningBits, 2);
|
||||
_stats->_warningLowTemperatureCharge = this->getBit(warningBits, 4);
|
||||
_stats->_warningHighDischargeCurrent = this->getBit(warningBits, 6);
|
||||
|
||||
warningBits = rx_message.data[6];
|
||||
_stats->_warningHighChargeCurrent = this->getBit(warningBits, 0);
|
||||
_stats->_warningInternalFailure = this->getBit(warningBits, 6);
|
||||
|
||||
warningBits = rx_message.data[7];
|
||||
_stats->_warningCellImbalance = this->getBit(warningBits, 0);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] Warnings: %d %d %d %d %d %d %d %d %d %d\r\n",
|
||||
_stats->_warningHighVoltage,
|
||||
_stats->_warningLowVoltage,
|
||||
_stats->_warningHighTemperature,
|
||||
_stats->_warningLowTemperature,
|
||||
_stats->_warningHighTemperatureCharge,
|
||||
_stats->_warningLowTemperatureCharge,
|
||||
_stats->_warningHighDischargeCurrent,
|
||||
_stats->_warningHighChargeCurrent,
|
||||
_stats->_warningInternalFailure,
|
||||
_stats->_warningCellImbalance);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x35E: {
|
||||
String manufacturer(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (manufacturer.isEmpty()) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] Manufacturer: %s\r\n", manufacturer.c_str());
|
||||
}
|
||||
|
||||
_stats->setManufacturer(std::move(manufacturer));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x35F: { // BatteryInfo
|
||||
auto fwVersionPart1 = String(this->readUnsignedInt8(rx_message.data + 2));
|
||||
auto fwVersionPart2 = String(this->readUnsignedInt8(rx_message.data + 3));
|
||||
_stats->_fwversion = "v" + fwVersionPart1 + "." + fwVersionPart2;
|
||||
|
||||
_stats->_availableCapacity = this->readUnsignedInt16(rx_message.data + 4);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] fwversion: %s availableCapacity: %d Ah\r\n",
|
||||
_stats->_fwversion.c_str(), _stats->_availableCapacity);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x372: { // BankInfo
|
||||
_stats->_moduleCountOnline = this->readUnsignedInt16(rx_message.data);
|
||||
_stats->_moduleCountBlockingCharge = this->readUnsignedInt16(rx_message.data + 2);
|
||||
_stats->_moduleCountBlockingDischarge = this->readUnsignedInt16(rx_message.data + 4);
|
||||
_stats->_moduleCountOffline = this->readUnsignedInt16(rx_message.data + 6);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] moduleCountOnline: %d moduleCountBlockingCharge: %d moduleCountBlockingDischarge: %d moduleCountOffline: %d\r\n",
|
||||
_stats->_moduleCountOnline, _stats->_moduleCountBlockingCharge,
|
||||
_stats->_moduleCountBlockingDischarge, _stats->_moduleCountOffline);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x373: { // CellInfo
|
||||
_stats->_cellMinMilliVolt = this->readUnsignedInt16(rx_message.data);
|
||||
_stats->_cellMaxMilliVolt = this->readUnsignedInt16(rx_message.data + 2);
|
||||
_stats->_cellMinTemperature = this->readUnsignedInt16(rx_message.data + 4) - 273;
|
||||
_stats->_cellMaxTemperature = this->readUnsignedInt16(rx_message.data + 6) - 273;
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] lowestCellMilliVolt: %d highestCellMilliVolt: %d minimumCellTemperature: %f maximumCellTemperature: %f\r\n",
|
||||
_stats->_cellMinMilliVolt, _stats->_cellMaxMilliVolt,
|
||||
_stats->_cellMinTemperature, _stats->_cellMaxTemperature);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x374: { // Battery/Cell name (string) with "Lowest Cell Voltage"
|
||||
String cellMinVoltageName(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (cellMinVoltageName.isEmpty()) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] cellMinVoltageName: %s\r\n",
|
||||
cellMinVoltageName.c_str());
|
||||
}
|
||||
|
||||
_stats->_cellMinVoltageName = cellMinVoltageName;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x375: { // Battery/Cell name (string) with "Highest Cell Voltage"
|
||||
String cellMaxVoltageName(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (cellMaxVoltageName.isEmpty()) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] cellMaxVoltageName: %s\r\n",
|
||||
cellMaxVoltageName.c_str());
|
||||
}
|
||||
|
||||
_stats->_cellMaxVoltageName = cellMaxVoltageName;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x376: { // Battery/Cell name (string) with "Minimum Cell Temperature"
|
||||
String cellMinTemperatureName(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (cellMinTemperatureName.isEmpty()) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] cellMinTemperatureName: %s\r\n",
|
||||
cellMinTemperatureName.c_str());
|
||||
}
|
||||
|
||||
_stats->_cellMinTemperatureName = cellMinTemperatureName;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x377: { // Battery/Cell name (string) with "Maximum Cell Temperature"
|
||||
String cellMaxTemperatureName(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (cellMaxTemperatureName.isEmpty()) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] cellMaxTemperatureName: %s\r\n",
|
||||
cellMaxTemperatureName.c_str());
|
||||
}
|
||||
|
||||
_stats->_cellMaxTemperatureName = cellMaxTemperatureName;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x378: { // History: Charged / Discharged Energy
|
||||
_stats->_chargedEnergy = this->scaleValue(this->readUnsignedInt32(rx_message.data), 0.1);
|
||||
_stats->_dischargedEnergy = this->scaleValue(this->readUnsignedInt32(rx_message.data + 4), 0.1);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] chargedEnergy: %f dischargedEnergy: %f\r\n",
|
||||
_stats->_chargedEnergy, _stats->_dischargedEnergy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x379: { // BatterySize: Installed Ah
|
||||
_stats->_totalCapacity = this->readUnsignedInt16(rx_message.data);
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] totalCapacity: %d Ah\r\n",
|
||||
_stats->_totalCapacity);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x380: { // Serialnumber - part 1
|
||||
String snPart1(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (snPart1.isEmpty() || !isgraph(snPart1.charAt(0))) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] snPart1: %s\r\n", snPart1.c_str());
|
||||
}
|
||||
|
||||
_stats->_serialPart1 = snPart1;
|
||||
_stats->updateSerial();
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x381: { // Serialnumber - part 2
|
||||
String snPart2(reinterpret_cast<char*>(rx_message.data),
|
||||
rx_message.data_length_code);
|
||||
|
||||
if (snPart2.isEmpty() || !isgraph(snPart2.charAt(0))) { break; }
|
||||
|
||||
if (_verboseLogging) {
|
||||
MessageOutput.printf("[Pytes] snPart2: %s\r\n", snPart2.c_str());
|
||||
}
|
||||
|
||||
_stats->_serialPart2 = snPart2;
|
||||
_stats->updateSerial();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return; // do not update last update timestamp
|
||||
break;
|
||||
}
|
||||
|
||||
_stats->setLastUpdate(millis());
|
||||
}
|
||||
@ -18,6 +18,9 @@
|
||||
<div style="padding-right: 2em;">
|
||||
{{ $t('battery.battery') }}: {{ batteryData.manufacturer }}
|
||||
</div>
|
||||
<div style="padding-right: 2em;" v-if="'serial' in batteryData">
|
||||
{{ $t('home.SerialNumber') }}{{ batteryData.serial }}
|
||||
</div>
|
||||
<div style="padding-right: 2em;" v-if="'fwversion' in batteryData">
|
||||
{{ $t('battery.FwVersion') }}: {{ batteryData.fwversion }}
|
||||
</div>
|
||||
@ -49,8 +52,11 @@
|
||||
<tr v-for="(prop, key) in values" v-bind:key="key">
|
||||
<th scope="row">{{ $t('battery.' + key) }}</th>
|
||||
<td style="text-align: right">
|
||||
<template v-if="typeof prop === 'string'">
|
||||
{{ $t('battery.' + prop) }}
|
||||
<template v-if="isStringValue(prop) && prop.translate">
|
||||
{{ $t('battery.' + prop.value) }}
|
||||
</template>
|
||||
<template v-else-if="isStringValue(prop)">
|
||||
{{ prop.value }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $n(prop.v, 'decimal', {
|
||||
@ -59,8 +65,11 @@
|
||||
}}
|
||||
</template>
|
||||
</td>
|
||||
<td v-if="typeof prop === 'string'"></td>
|
||||
<td v-else>{{prop.u}}</td>
|
||||
<td>
|
||||
<template v-if="!isStringValue(prop)">
|
||||
{{prop.u}}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -114,7 +123,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import type { Battery } from '@/types/BatteryDataStatus';
|
||||
import type { Battery, StringValue } from '@/types/BatteryDataStatus';
|
||||
import type { ValueObject } from '@/types/LiveDataStatus';
|
||||
import { handleResponse, authHeader, authUrl } from '@/utils/authentication';
|
||||
|
||||
export default defineComponent({
|
||||
@ -144,6 +154,9 @@ export default defineComponent({
|
||||
this.closeSocket();
|
||||
},
|
||||
methods: {
|
||||
isStringValue(value: ValueObject | StringValue) : value is StringValue {
|
||||
return value && typeof value === 'object' && 'translate' in value;
|
||||
},
|
||||
getInitialData() {
|
||||
console.log("Get initalData for Battery");
|
||||
this.dataLoading = true;
|
||||
|
||||
@ -654,6 +654,7 @@
|
||||
"ProviderJkBmsSerial": "Jikong (JK) BMS per serieller Verbindung",
|
||||
"ProviderMqtt": "Batteriewerte aus MQTT Broker",
|
||||
"ProviderVictron": "Victron SmartShunt per VE.Direct Schnittstelle",
|
||||
"ProviderPytesCan": "Pytes per CAN-Bus",
|
||||
"MqttConfiguration": "MQTT Einstellungen",
|
||||
"MqttSocTopic": "Topic für Batterie-SoC",
|
||||
"MqttVoltageTopic": "Topic für Batteriespannung",
|
||||
@ -891,14 +892,22 @@
|
||||
"voltage": "Spannung",
|
||||
"current": "Strom",
|
||||
"power": "Leistung",
|
||||
"capacity": "Gesamtkapazität",
|
||||
"availableCapacity": "Verfügbare Kapazität",
|
||||
"temperature": "Temperatur",
|
||||
"bmsTemp": "BMS-Temperatur",
|
||||
"chargeVoltage": "Gewünschte Ladespannung (BMS)",
|
||||
"chargeCurrentLimitation": "Ladestromlimit",
|
||||
"dischargeCurrentLimitation": "Entladestromlimit",
|
||||
"dischargeVoltageLimitation": "Entladespannungslimit",
|
||||
"chargeEnabled": "Laden ermöglicht",
|
||||
"dischargeEnabled": "Entladen ermöglicht",
|
||||
"chargeImmediately": "Sofortiges Laden angefordert",
|
||||
"modules": "Batteriemodule",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"blockingCharge": "Ladung blockiert",
|
||||
"blockingDischarge": "Entladung blockiert",
|
||||
"cells": "Zellen",
|
||||
"batOneTemp": "Batterietemperatur 1",
|
||||
"batTwoTemp": "Batterietemperatur 2",
|
||||
@ -906,6 +915,12 @@
|
||||
"cellAvgVoltage": "Durchschnittliche Zellspannung",
|
||||
"cellMaxVoltage": "Höchste Zellspannung",
|
||||
"cellDiffVoltage": "Zellspannungsdifferenz",
|
||||
"cellMinTemperature": "Niedrigste Zelltemperatur",
|
||||
"cellMaxTemperature": "Höchste Zelltemperatur",
|
||||
"cellMinVoltageName": "Kleinste Zellspannung (Label)",
|
||||
"cellMaxVoltageName": "Höchste Zellspannung (Label)",
|
||||
"cellMinTemperatureName": "Niedrigste Zelltemperatur (Label)",
|
||||
"cellMaxTemperatureName": "Höchste Zelltemperatur (Label)",
|
||||
"balancingActive": "Ausgleichen aktiv",
|
||||
"issues": "Meldungen",
|
||||
"noIssues": "Keine Meldungen",
|
||||
@ -933,8 +948,12 @@
|
||||
"overCurrentCharge": "Überstrom (Laden)",
|
||||
"lowTemperature": "Geringe Temperatur",
|
||||
"underTemperature": "Untertemperatur",
|
||||
"lowTemperatureCharge": "Geringe Temperatur (Laden)",
|
||||
"underTemperatureCharge": "Untertemperatur (Laden)",
|
||||
"highTemperature": "Hohe Temperatur",
|
||||
"overTemperature": "Übertemperatur",
|
||||
"highTemperatureCharge": "Hohe Temperatur (Laden)",
|
||||
"overTemperatureCharge": "Übertemperatur (Laden)",
|
||||
"lowSOC": "Geringer Ladezustand",
|
||||
"lowVoltage": "Niedrige Spannung",
|
||||
"underVoltage": "Unterspannung",
|
||||
|
||||
@ -660,6 +660,7 @@
|
||||
"ProviderJkBmsSerial": "Jikong (JK) BMS using serial connection",
|
||||
"ProviderMqtt": "Battery data from MQTT broker",
|
||||
"ProviderVictron": "Victron SmartShunt using VE.Direct interface",
|
||||
"ProviderPytesCan": "Pytes using CAN bus",
|
||||
"MqttConfiguration": "MQTT Settings",
|
||||
"MqttSocTopic": "SoC value topic",
|
||||
"MqttVoltageTopic": "Voltage value topic",
|
||||
@ -898,14 +899,22 @@
|
||||
"voltage": "Voltage",
|
||||
"current": "Current",
|
||||
"power": "Power",
|
||||
"capacity": "Total capacity",
|
||||
"availableCapacity": "Available capacity",
|
||||
"temperature": "Temperature",
|
||||
"bmsTemp": "BMS temperature",
|
||||
"chargeVoltage": "Requested charge voltage",
|
||||
"chargeCurrentLimitation": "Charge current limit",
|
||||
"dischargeCurrentLimitation": "Discharge current limit",
|
||||
"dischargeVoltageLimitation": "Discharge voltage limit",
|
||||
"chargeEnabled": "Charging possible",
|
||||
"dischargeEnabled": "Discharging possible",
|
||||
"chargeImmediately": "Immediate charging requested",
|
||||
"modules": "Battery modules",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"blockingCharge": "Charging blocked",
|
||||
"blockingDischarge": "Discharging blocked",
|
||||
"cells": "Cells",
|
||||
"batOneTemp": "Battery temperature 1",
|
||||
"batTwoTemp": "Battery temperature 2",
|
||||
@ -913,6 +922,12 @@
|
||||
"cellAvgVoltage": "Average cell voltage",
|
||||
"cellMaxVoltage": "Maximum cell voltage",
|
||||
"cellDiffVoltage": "Cell voltage difference",
|
||||
"cellMinTemperature": "Minimum cell temperature",
|
||||
"cellMaxTemperature": "Maximum cell temperature",
|
||||
"cellMinVoltageName": "Minimum cell voltage (label)",
|
||||
"cellMaxVoltageName": "Maximum cell voltage (label)",
|
||||
"cellMinTemperatureName": "Minimum cell temperature (label)",
|
||||
"cellMaxTemperatureName": "Maximum cell temperature (label)",
|
||||
"balancingActive": "Balancing active",
|
||||
"issues": "Issues",
|
||||
"noIssues": "No Issues",
|
||||
@ -940,8 +955,12 @@
|
||||
"overCurrentCharge": "Overcurrent (charge)",
|
||||
"lowTemperature": "Low temperature",
|
||||
"underTemperature": "Undertemperature",
|
||||
"lowTemperatureCharge": "Low temperature (charge)",
|
||||
"underTemperatureCharge": "Undertemperature (charge)",
|
||||
"highTemperature": "High temperature",
|
||||
"overTemperature": "Overtemperature",
|
||||
"highTemperatureCharge": "High temperature (charge)",
|
||||
"overTemperatureCharge": "Overtemperature (charge)",
|
||||
"lowVoltage": "Low voltage",
|
||||
"lowSOC": "Low state of charge",
|
||||
"underVoltage": "Undervoltage",
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
import type { ValueObject } from '@/types/LiveDataStatus';
|
||||
|
||||
type BatteryData = (ValueObject | string)[];
|
||||
export interface StringValue {
|
||||
value: string;
|
||||
translate: boolean;
|
||||
}
|
||||
|
||||
type BatteryData = (ValueObject | StringValue)[];
|
||||
|
||||
export interface Battery {
|
||||
manufacturer: string;
|
||||
serial: string;
|
||||
fwversion: string;
|
||||
hwversion: string;
|
||||
data_age: number;
|
||||
|
||||
@ -108,6 +108,7 @@ export default defineComponent({
|
||||
{ key: 1, value: 'JkBmsSerial' },
|
||||
{ key: 2, value: 'Mqtt' },
|
||||
{ key: 3, value: 'Victron' },
|
||||
{ key: 4, value: 'PytesCan' },
|
||||
],
|
||||
jkBmsInterfaceTypeList: [
|
||||
{ key: 0, value: 'Uart' },
|
||||
|
||||
Loading…
Reference in New Issue
Block a user