Skip to content

Commit

Permalink
Feature: JK BMS: add more values to live view
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
schlimmchen committed Dec 16, 2023
1 parent fb2ca28 commit aca4518
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 59 deletions.
10 changes: 0 additions & 10 deletions include/BatteryStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
94 changes: 51 additions & 43 deletions src/BatteryStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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[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)
{
addLiveViewInSection(root, "values", name, value, unit, precision);
}

static void addLiveViewTextInSection(JsonVariant& root,
std::string const& section, std::string const& name, std::string const& text)
{
root["values"][name] = text;
root[section][name] = text;
}

void BatteryStats::addLiveViewWarning(JsonVariant& root, std::string const& name,
bool warning) const
static void addLiveViewTextValue(JsonVariant& root, std::string const& name,
std::string const& text)
{
addLiveViewTextInSection(root, "values", 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;
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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>();
Expand Down
10 changes: 7 additions & 3 deletions webapp/src/components/BatteryView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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="section in batterySections" v-bind:key="section.dataPath" 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.header) }}</div>
<div class="card-body">
<table class="table table-striped table-hover">
<thead>
Expand All @@ -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 batteryData[section.dataPath]" v-bind:key="key">
<th scope="row">{{ $t('battery.' + key) }}</th>
<td style="text-align: right">
<template v-if="typeof prop === 'string'">
Expand Down Expand Up @@ -121,6 +121,10 @@ export default defineComponent({
dataAgeInterval: 0,
dataLoading: true,
batteryData: {} as Battery,
batterySections: [
{ dataPath: "values", header: "Status" },
{ dataPath: "cells", header: "Cells" }
],
isFirstFetchAfterConnect: true,
alertMessageLimit: "",
Expand Down
8 changes: 7 additions & 1 deletion webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -812,9 +812,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",
Expand Down
8 changes: 7 additions & 1 deletion webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -822,9 +822,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",
Expand Down
8 changes: 7 additions & 1 deletion webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,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",
Expand Down

0 comments on commit aca4518

Please sign in to comment.