Short-format numbers in energy-distribution-card (#24716)
parent
6fbc7b2efe
commit
9f05f4df50
|
@ -29,6 +29,7 @@ import type {
|
|||
import { fetchStatistics, getStatisticMetadata } from "./recorder";
|
||||
import { calcDateRange } from "../common/datetime/calc_date_range";
|
||||
import type { DateRange } from "../common/datetime/calc_date_range";
|
||||
import { formatNumber } from "../common/number/format_number";
|
||||
|
||||
const energyCollectionKeys: (string | undefined)[] = [];
|
||||
|
||||
|
@ -924,3 +925,31 @@ const computeConsumptionDataPartial = (
|
|||
|
||||
return outData;
|
||||
};
|
||||
|
||||
export const formatConsumptionShort = (
|
||||
hass: HomeAssistant,
|
||||
consumption: number | null,
|
||||
unit: string
|
||||
): string => {
|
||||
if (!consumption) {
|
||||
return `0 ${unit}`;
|
||||
}
|
||||
const units = ["kWh", "MWh", "GWh", "TWh"];
|
||||
let pickedUnit = unit;
|
||||
let val = consumption;
|
||||
let unitIndex = units.findIndex((u) => u === unit);
|
||||
if (unitIndex >= 0) {
|
||||
while (val >= 1000 && unitIndex < units.length - 1) {
|
||||
val /= 1000;
|
||||
unitIndex++;
|
||||
}
|
||||
pickedUnit = units[unitIndex];
|
||||
}
|
||||
return (
|
||||
formatNumber(val, hass.locale, {
|
||||
maximumFractionDigits: val < 10 ? 2 : val < 100 ? 1 : 0,
|
||||
}) +
|
||||
" " +
|
||||
pickedUnit
|
||||
);
|
||||
};
|
||||
|
|
|
@ -17,7 +17,6 @@ import type { PropertyValues } from "lit";
|
|||
import { css, html, LitElement, svg, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { formatNumber } from "../../../../common/number/format_number";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import type { EnergyData } from "../../../../data/energy";
|
||||
|
@ -26,6 +25,7 @@ import {
|
|||
getEnergyDataCollection,
|
||||
getEnergyGasUnit,
|
||||
getEnergyWaterUnit,
|
||||
formatConsumptionShort,
|
||||
} from "../../../../data/energy";
|
||||
import { calculateStatisticsSumGrowth } from "../../../../data/recorder";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
|
@ -308,10 +308,11 @@ class HuiEnergyDistrubutionCard
|
|||
rel="noopener no referrer"
|
||||
>
|
||||
<ha-svg-icon .path=${mdiLeaf}></ha-svg-icon>
|
||||
${formatNumber(lowCarbonEnergy || 0, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
kWh
|
||||
${formatConsumptionShort(
|
||||
this.hass,
|
||||
lowCarbonEnergy,
|
||||
"kWh"
|
||||
)}
|
||||
</a>
|
||||
<svg width="80" height="30">
|
||||
<line x1="40" y1="0" x2="40" y2="30"></line>
|
||||
|
@ -326,12 +327,11 @@ class HuiEnergyDistrubutionCard
|
|||
>
|
||||
<div class="circle">
|
||||
<ha-svg-icon .path=${mdiSolarPower}></ha-svg-icon>
|
||||
${formatNumber(
|
||||
totalSolarProduction || 0,
|
||||
this.hass.locale,
|
||||
{ maximumFractionDigits: 1 }
|
||||
${formatConsumptionShort(
|
||||
this.hass,
|
||||
totalSolarProduction,
|
||||
"kWh"
|
||||
)}
|
||||
kWh
|
||||
</div>
|
||||
</div>`
|
||||
: hasGas || hasWater
|
||||
|
@ -346,13 +346,14 @@ class HuiEnergyDistrubutionCard
|
|||
>
|
||||
<div class="circle">
|
||||
<ha-svg-icon .path=${mdiFire}></ha-svg-icon>
|
||||
${formatNumber(gasUsage || 0, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
${getEnergyGasUnit(
|
||||
${formatConsumptionShort(
|
||||
this.hass,
|
||||
prefs,
|
||||
this._data.statsMetadata
|
||||
gasUsage,
|
||||
getEnergyGasUnit(
|
||||
this.hass,
|
||||
prefs,
|
||||
this._data.statsMetadata
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<svg width="80" height="30">
|
||||
|
@ -383,10 +384,11 @@ class HuiEnergyDistrubutionCard
|
|||
>
|
||||
<div class="circle">
|
||||
<ha-svg-icon .path=${mdiWater}></ha-svg-icon>
|
||||
${formatNumber(waterUsage || 0, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
${getEnergyWaterUnit(this.hass)}
|
||||
${formatConsumptionShort(
|
||||
this.hass,
|
||||
waterUsage,
|
||||
getEnergyWaterUnit(this.hass)
|
||||
)}
|
||||
</div>
|
||||
<svg width="80" height="30">
|
||||
<path d="M40 0 v30" id="water" />
|
||||
|
@ -420,10 +422,11 @@ class HuiEnergyDistrubutionCard
|
|||
class="small"
|
||||
.path=${mdiArrowLeft}
|
||||
></ha-svg-icon
|
||||
>${formatNumber(returnedToGrid, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
kWh
|
||||
>${formatConsumptionShort(
|
||||
this.hass,
|
||||
returnedToGrid,
|
||||
"kWh"
|
||||
)}
|
||||
</span>`
|
||||
: ""}
|
||||
<span class="consumption">
|
||||
|
@ -432,10 +435,11 @@ class HuiEnergyDistrubutionCard
|
|||
class="small"
|
||||
.path=${mdiArrowRight}
|
||||
></ha-svg-icon>`
|
||||
: ""}${formatNumber(totalFromGrid, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
kWh
|
||||
: ""}${formatConsumptionShort(
|
||||
this.hass,
|
||||
totalFromGrid,
|
||||
"kWh"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<span class="label"
|
||||
|
@ -453,10 +457,11 @@ class HuiEnergyDistrubutionCard
|
|||
})}"
|
||||
>
|
||||
<ha-svg-icon .path=${mdiHome}></ha-svg-icon>
|
||||
${formatNumber(totalHomeConsumption, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
kWh
|
||||
${formatConsumptionShort(
|
||||
this.hass,
|
||||
totalHomeConsumption,
|
||||
"kWh"
|
||||
)}
|
||||
${homeSolarCircumference !== undefined ||
|
||||
homeLowCarbonCircumference !== undefined
|
||||
? html`<svg>
|
||||
|
@ -550,29 +555,23 @@ class HuiEnergyDistrubutionCard
|
|||
class="small"
|
||||
.path=${mdiArrowDown}
|
||||
></ha-svg-icon
|
||||
>${formatNumber(
|
||||
totalBatteryIn || 0,
|
||||
this.hass.locale,
|
||||
{
|
||||
maximumFractionDigits: 1,
|
||||
}
|
||||
>${formatConsumptionShort(
|
||||
this.hass,
|
||||
totalBatteryIn,
|
||||
"kWh"
|
||||
)}
|
||||
kWh</span
|
||||
>
|
||||
</span>
|
||||
<span class="battery-out">
|
||||
<ha-svg-icon
|
||||
class="small"
|
||||
.path=${mdiArrowUp}
|
||||
></ha-svg-icon
|
||||
>${formatNumber(
|
||||
totalBatteryOut || 0,
|
||||
this.hass.locale,
|
||||
{
|
||||
maximumFractionDigits: 1,
|
||||
}
|
||||
>${formatConsumptionShort(
|
||||
this.hass,
|
||||
totalBatteryOut,
|
||||
"kWh"
|
||||
)}
|
||||
kWh</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<span class="label"
|
||||
>${this.hass.localize(
|
||||
|
@ -603,10 +602,11 @@ class HuiEnergyDistrubutionCard
|
|||
</svg>
|
||||
<div class="circle">
|
||||
<ha-svg-icon .path=${mdiWater}></ha-svg-icon>
|
||||
${formatNumber(waterUsage || 0, this.hass.locale, {
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
${getEnergyWaterUnit(this.hass)}
|
||||
${formatConsumptionShort(
|
||||
this.hass,
|
||||
waterUsage,
|
||||
getEnergyWaterUnit(this.hass)
|
||||
)}
|
||||
</div>
|
||||
<span class="label"
|
||||
>${this.hass.localize(
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import { assert, describe, it } from "vitest";
|
||||
|
||||
import {
|
||||
type FrontendLocaleData,
|
||||
NumberFormat,
|
||||
TimeFormat,
|
||||
FirstWeekday,
|
||||
DateFormat,
|
||||
TimeZone,
|
||||
} from "../../src/data/translation";
|
||||
import { formatConsumptionShort } from "../../src/data/energy";
|
||||
import type { HomeAssistant } from "../../src/types";
|
||||
|
||||
describe("Energy Short Format Test", () => {
|
||||
// Create default to not have to specify a not relevant TimeFormat over and over again.
|
||||
const defaultLocale: FrontendLocaleData = {
|
||||
language: "en",
|
||||
number_format: NumberFormat.language,
|
||||
time_format: TimeFormat.language,
|
||||
date_format: DateFormat.language,
|
||||
time_zone: TimeZone.local,
|
||||
first_weekday: FirstWeekday.language,
|
||||
};
|
||||
|
||||
const hass = { locale: defaultLocale } as HomeAssistant;
|
||||
it("Formats", () => {
|
||||
assert.strictEqual(formatConsumptionShort(hass, 0, "kWh"), "0 kWh");
|
||||
assert.strictEqual(formatConsumptionShort(hass, 0, "GWh"), "0 GWh");
|
||||
assert.strictEqual(formatConsumptionShort(hass, 0, "gal"), "0 gal");
|
||||
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 0.12345, "kWh"),
|
||||
"0.12 kWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 10.12345, "kWh"),
|
||||
"10.1 kWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 500.12345, "kWh"),
|
||||
"500 kWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 1512.34567, "kWh"),
|
||||
"1.51 MWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 15123.4567, "kWh"),
|
||||
"15.1 MWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 151234.5678, "kWh"),
|
||||
"151 MWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 1512345.6789, "kWh"),
|
||||
"1.51 GWh"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 15123456789.9, "kWh"),
|
||||
"15.1 TWh"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 15123456789000.9, "kWh"),
|
||||
"15,123 TWh"
|
||||
);
|
||||
|
||||
assert.strictEqual(formatConsumptionShort(hass, 1000.1, "GWh"), "1 TWh");
|
||||
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, 10000.12345, "gal"),
|
||||
"10,000 gal"
|
||||
);
|
||||
|
||||
// Don't really modify negative numbers, but make sure it's something sane.
|
||||
assert.strictEqual(
|
||||
formatConsumptionShort(hass, -1234.56, "kWh"),
|
||||
"-1,234.56 kWh"
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue