Feature: JK BMS: add more values to live view (#552)
there are more interesting values available to display in the live view. however, adding them made the list of values very long. this can be mitigated by using a new column/card, which uses the available screen space nicely on bigger screens.
This commit is contained in:
parent
bb34fa74fd
commit
7928f2f8cf
@ -28,16 +28,6 @@ class BatteryStats {
|
||||
bool isValid() const { return _lastUpdateSoC > 0 && _lastUpdate > 0; }
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
void addLiveViewValue(JsonVariant& root, std::string const& name,
|
||||
T&& value, std::string const& unit, uint8_t precision) const;
|
||||
void addLiveViewText(JsonVariant& root, std::string const& name,
|
||||
std::string const& text) const;
|
||||
void addLiveViewWarning(JsonVariant& root, std::string const& name,
|
||||
bool warning) const;
|
||||
void addLiveViewAlarm(JsonVariant& root, std::string const& name,
|
||||
bool alarm) const;
|
||||
|
||||
String _manufacturer = "unknown";
|
||||
uint8_t _SoC = 0;
|
||||
uint32_t _lastUpdateSoC = 0;
|
||||
|
||||
@ -7,30 +7,44 @@
|
||||
#include "JkBmsDataPoints.h"
|
||||
|
||||
template<typename T>
|
||||
void BatteryStats::addLiveViewValue(JsonVariant& root, std::string const& name,
|
||||
T&& value, std::string const& unit, uint8_t precision) const
|
||||
static void addLiveViewInSection(JsonVariant& root,
|
||||
std::string const& section, std::string const& name,
|
||||
T&& value, std::string const& unit, uint8_t precision)
|
||||
{
|
||||
auto jsonValue = root["values"][name];
|
||||
auto jsonValue = root["values"][section][name];
|
||||
jsonValue["v"] = value;
|
||||
jsonValue["u"] = unit;
|
||||
jsonValue["d"] = precision;
|
||||
}
|
||||
|
||||
void BatteryStats::addLiveViewText(JsonVariant& root, std::string const& name,
|
||||
std::string const& text) const
|
||||
template<typename T>
|
||||
static void addLiveViewValue(JsonVariant& root, std::string const& name,
|
||||
T&& value, std::string const& unit, uint8_t precision)
|
||||
{
|
||||
root["values"][name] = text;
|
||||
addLiveViewInSection(root, "status", name, value, unit, precision);
|
||||
}
|
||||
|
||||
void BatteryStats::addLiveViewWarning(JsonVariant& root, std::string const& name,
|
||||
bool warning) const
|
||||
static void addLiveViewTextInSection(JsonVariant& root,
|
||||
std::string const& section, std::string const& name, std::string const& text)
|
||||
{
|
||||
root["values"][section][name] = text;
|
||||
}
|
||||
|
||||
static void addLiveViewTextValue(JsonVariant& root, std::string const& name,
|
||||
std::string const& text)
|
||||
{
|
||||
addLiveViewTextInSection(root, "status", name, text);
|
||||
}
|
||||
|
||||
static void addLiveViewWarning(JsonVariant& root, std::string const& name,
|
||||
bool warning)
|
||||
{
|
||||
if (!warning) { return; }
|
||||
root["issues"][name] = 1;
|
||||
}
|
||||
|
||||
void BatteryStats::addLiveViewAlarm(JsonVariant& root, std::string const& name,
|
||||
bool alarm) const
|
||||
static void addLiveViewAlarm(JsonVariant& root, std::string const& name,
|
||||
bool alarm)
|
||||
{
|
||||
if (!alarm) { return; }
|
||||
root["issues"][name] = 2;
|
||||
@ -57,9 +71,9 @@ void PylontechBatteryStats::getLiveViewData(JsonVariant& root) const
|
||||
addLiveViewValue(root, "current", _current, "A", 1);
|
||||
addLiveViewValue(root, "temperature", _temperature, "°C", 1);
|
||||
|
||||
addLiveViewText(root, "chargeEnabled", (_chargeEnabled?"yes":"no"));
|
||||
addLiveViewText(root, "dischargeEnabled", (_dischargeEnabled?"yes":"no"));
|
||||
addLiveViewText(root, "chargeImmediately", (_chargeImmediately?"yes":"no"));
|
||||
addLiveViewTextValue(root, "chargeEnabled", (_chargeEnabled?"yes":"no"));
|
||||
addLiveViewTextValue(root, "dischargeEnabled", (_dischargeEnabled?"yes":"no"));
|
||||
addLiveViewTextValue(root, "chargeImmediately", (_chargeImmediately?"yes":"no"));
|
||||
|
||||
// alarms and warnings go into the "Issues" card of the web application
|
||||
addLiveViewWarning(root, "highCurrentDischarge", _warningHighCurrentDischarge);
|
||||
@ -108,38 +122,11 @@ void JkBmsBatteryStats::getJsonData(JsonVariant& root, bool verbose) const
|
||||
addLiveViewValue(root, "power", current * voltage , "W", 2);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
auto oTemperatureOne = _dataPoints.get<Label::BatteryTempOneCelsius>();
|
||||
if (oTemperatureOne.has_value()) {
|
||||
addLiveViewValue(root, "batOneTemp", *oTemperatureOne, "°C", 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
auto oTemperatureTwo = _dataPoints.get<Label::BatteryTempTwoCelsius>();
|
||||
if (oTemperatureTwo.has_value()) {
|
||||
addLiveViewValue(root, "batTwoTemp", *oTemperatureTwo, "°C", 0);
|
||||
}
|
||||
}
|
||||
|
||||
auto oTemperatureBms = _dataPoints.get<Label::BmsTempCelsius>();
|
||||
if (oTemperatureBms.has_value()) {
|
||||
addLiveViewValue(root, "bmsTemp", *oTemperatureBms, "°C", 0);
|
||||
}
|
||||
|
||||
if (_cellVoltageTimestamp > 0) {
|
||||
if (verbose) {
|
||||
addLiveViewValue(root, "cellMinVoltage", static_cast<float>(_cellMinMilliVolt)/1000, "V", 3);
|
||||
}
|
||||
|
||||
addLiveViewValue(root, "cellAvgVoltage", static_cast<float>(_cellAvgMilliVolt)/1000, "V", 3);
|
||||
|
||||
if (verbose) {
|
||||
addLiveViewValue(root, "cellMaxVoltage", static_cast<float>(_cellMaxMilliVolt)/1000, "V", 3);
|
||||
addLiveViewValue(root, "cellDiffVoltage", (_cellMaxMilliVolt - _cellMinMilliVolt), "mV", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// labels BatteryChargeEnabled, BatteryDischargeEnabled, and
|
||||
// BalancingEnabled refer to the user setting. we want to show the
|
||||
// actual MOSFETs' state which control whether charging and discharging
|
||||
@ -148,11 +135,32 @@ void JkBmsBatteryStats::getJsonData(JsonVariant& root, bool verbose) const
|
||||
if (oStatus.has_value()) {
|
||||
using Bits = JkBms::StatusBits;
|
||||
auto chargeEnabled = *oStatus & static_cast<uint16_t>(Bits::ChargingActive);
|
||||
addLiveViewText(root, "chargeEnabled", (chargeEnabled?"yes":"no"));
|
||||
addLiveViewTextValue(root, "chargeEnabled", (chargeEnabled?"yes":"no"));
|
||||
auto dischargeEnabled = *oStatus & static_cast<uint16_t>(Bits::DischargingActive);
|
||||
addLiveViewText(root, "dischargeEnabled", (dischargeEnabled?"yes":"no"));
|
||||
addLiveViewTextValue(root, "dischargeEnabled", (dischargeEnabled?"yes":"no"));
|
||||
}
|
||||
|
||||
auto oTemperatureOne = _dataPoints.get<Label::BatteryTempOneCelsius>();
|
||||
if (oTemperatureOne.has_value()) {
|
||||
addLiveViewInSection(root, "cells", "batOneTemp", *oTemperatureOne, "°C", 0);
|
||||
}
|
||||
|
||||
auto oTemperatureTwo = _dataPoints.get<Label::BatteryTempTwoCelsius>();
|
||||
if (oTemperatureTwo.has_value()) {
|
||||
addLiveViewInSection(root, "cells", "batTwoTemp", *oTemperatureTwo, "°C", 0);
|
||||
}
|
||||
|
||||
if (_cellVoltageTimestamp > 0) {
|
||||
addLiveViewInSection(root, "cells", "cellMinVoltage", static_cast<float>(_cellMinMilliVolt)/1000, "V", 3);
|
||||
addLiveViewInSection(root, "cells", "cellAvgVoltage", static_cast<float>(_cellAvgMilliVolt)/1000, "V", 3);
|
||||
addLiveViewInSection(root, "cells", "cellMaxVoltage", static_cast<float>(_cellMaxMilliVolt)/1000, "V", 3);
|
||||
addLiveViewInSection(root, "cells", "cellDiffVoltage", (_cellMaxMilliVolt - _cellMinMilliVolt), "mV", 0);
|
||||
}
|
||||
|
||||
if (oStatus.has_value()) {
|
||||
using Bits = JkBms::StatusBits;
|
||||
auto balancingActive = *oStatus & static_cast<uint16_t>(Bits::BalancingActive);
|
||||
addLiveViewText(root, "balancingActive", (balancingActive?"yes":"no"));
|
||||
addLiveViewTextInSection(root, "cells", "balancingActive", (balancingActive?"yes":"no"));
|
||||
}
|
||||
|
||||
auto oAlarms = _dataPoints.get<Label::AlarmsBitmask>();
|
||||
|
||||
@ -27,9 +27,9 @@
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row flex-row flex-wrap align-items-start g-3">
|
||||
<div class="col order-0">
|
||||
<div v-for="(values, section) in batteryData.values" v-bind:key="section" class="col order-0">
|
||||
<div class="card" :class="{ 'border-info': true }">
|
||||
<div class="card-header text-bg-info">{{ $t('battery.Status') }}</div>
|
||||
<div class="card-header text-bg-info">{{ $t('battery.' + section) }}</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
@ -40,7 +40,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(prop, key) in batteryData.values" v-bind:key="key">
|
||||
<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'">
|
||||
|
||||
@ -803,7 +803,7 @@
|
||||
"battery": "Batterie",
|
||||
"DataAge": "letzte Aktualisierung: ",
|
||||
"Seconds": "vor {val} Sekunden",
|
||||
"Status": "Status",
|
||||
"status": "Status",
|
||||
"Property": "Eigenschaft",
|
||||
"yes": "@:base.Yes",
|
||||
"no": "@:base.No",
|
||||
@ -821,9 +821,15 @@
|
||||
"dischargeCurrentLimitation": "Entladestromlimit",
|
||||
"chargeEnabled": "Laden ermöglicht",
|
||||
"dischargeEnabled": "Entladen ermöglicht",
|
||||
"balancingActive": "Ausgleichen aktiv",
|
||||
"chargeImmediately": "Sofortiges Laden angefordert",
|
||||
"cells": "Zellen",
|
||||
"batOneTemp": "Batterietemperatur 1",
|
||||
"batTwoTemp": "Batterietemperatur 2",
|
||||
"cellMinVoltage": "Kleinste Zellspannung",
|
||||
"cellAvgVoltage": "Durchschnittliche Zellspannung",
|
||||
"cellMaxVoltage": "Höchste Zellspannung",
|
||||
"cellDiffVoltage": "Zellspannungsdifferenz",
|
||||
"balancingActive": "Ausgleichen aktiv",
|
||||
"issues": "Meldungen",
|
||||
"noIssues": "Keine Meldungen",
|
||||
"issueName": "Bezeichnung",
|
||||
|
||||
@ -813,7 +813,7 @@
|
||||
"battery": "Battery",
|
||||
"DataAge": "Data Age: ",
|
||||
"Seconds": " {val} seconds",
|
||||
"Status": "Status",
|
||||
"status": "Status",
|
||||
"Property": "Property",
|
||||
"yes": "@:base.Yes",
|
||||
"no": "@:base.No",
|
||||
@ -831,9 +831,15 @@
|
||||
"dischargeCurrentLimitation": "Discharge current limit",
|
||||
"chargeEnabled": "Charging possible",
|
||||
"dischargeEnabled": "Discharging possible",
|
||||
"balancingActive": "Balancing active",
|
||||
"chargeImmediately": "Immediate charging requested",
|
||||
"cells": "Cells",
|
||||
"batOneTemp": "Battery temperature 1",
|
||||
"batTwoTemp": "Battery temperature 2",
|
||||
"cellMinVoltage": "Minimum cell voltage",
|
||||
"cellAvgVoltage": "Average cell voltage",
|
||||
"cellMaxVoltage": "Maximum cell voltage",
|
||||
"cellDiffVoltage": "Cell voltage difference",
|
||||
"balancingActive": "Balancing active",
|
||||
"issues": "Issues",
|
||||
"noIssues": "No Issues",
|
||||
"issueName": "Name",
|
||||
|
||||
@ -772,7 +772,7 @@
|
||||
"battery": "Battery",
|
||||
"DataAge": "Data Age: ",
|
||||
"Seconds": " {val} seconds",
|
||||
"Status": "Status",
|
||||
"status": "Status",
|
||||
"Property": "Property",
|
||||
"yes": "@:base.Yes",
|
||||
"no": "@:base.No",
|
||||
@ -790,9 +790,15 @@
|
||||
"dischargeCurrentLimitation": "Discharge current limit",
|
||||
"chargeEnabled": "Charging possible",
|
||||
"dischargeEnabled": "Discharging possible",
|
||||
"balancingActive": "Balancing active",
|
||||
"chargeImmediately": "Immediate charging requested",
|
||||
"cells": "Cells",
|
||||
"batOneTemp": "Battery temperature 1",
|
||||
"batTwoTemp": "Battery temperature 2",
|
||||
"cellMinVoltage": "Minimum cell voltage",
|
||||
"cellAvgVoltage": "Average cell voltage",
|
||||
"cellMaxVoltage": "Maximum cell voltage",
|
||||
"cellDiffVoltage": "Cell voltage difference",
|
||||
"balancingActive": "Balancing active",
|
||||
"issues": "Issues",
|
||||
"noIssues": "No Issues",
|
||||
"issueName": "Name",
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import type { ValueObject } from '@/types/LiveDataStatus';
|
||||
|
||||
type BatteryData = (ValueObject | string)[];
|
||||
|
||||
export interface Battery {
|
||||
manufacturer: string;
|
||||
data_age: number;
|
||||
values: (ValueObject | string)[];
|
||||
values: BatteryData[];
|
||||
issues: number[];
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user