mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Short-format numbers in energy-distribution-card (#24716)
This commit is contained in:
parent
6fbc7b2efe
commit
9f05f4df50
@ -29,6 +29,7 @@ import type {
|
|||||||
import { fetchStatistics, getStatisticMetadata } from "./recorder";
|
import { fetchStatistics, getStatisticMetadata } from "./recorder";
|
||||||
import { calcDateRange } from "../common/datetime/calc_date_range";
|
import { calcDateRange } from "../common/datetime/calc_date_range";
|
||||||
import type { DateRange } 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)[] = [];
|
const energyCollectionKeys: (string | undefined)[] = [];
|
||||||
|
|
||||||
@ -924,3 +925,31 @@ const computeConsumptionDataPartial = (
|
|||||||
|
|
||||||
return outData;
|
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 { css, html, LitElement, svg, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { formatNumber } from "../../../../common/number/format_number";
|
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
import type { EnergyData } from "../../../../data/energy";
|
import type { EnergyData } from "../../../../data/energy";
|
||||||
@ -26,6 +25,7 @@ import {
|
|||||||
getEnergyDataCollection,
|
getEnergyDataCollection,
|
||||||
getEnergyGasUnit,
|
getEnergyGasUnit,
|
||||||
getEnergyWaterUnit,
|
getEnergyWaterUnit,
|
||||||
|
formatConsumptionShort,
|
||||||
} from "../../../../data/energy";
|
} from "../../../../data/energy";
|
||||||
import { calculateStatisticsSumGrowth } from "../../../../data/recorder";
|
import { calculateStatisticsSumGrowth } from "../../../../data/recorder";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
@ -308,10 +308,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
rel="noopener no referrer"
|
rel="noopener no referrer"
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiLeaf}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiLeaf}></ha-svg-icon>
|
||||||
${formatNumber(lowCarbonEnergy || 0, this.hass.locale, {
|
${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
this.hass,
|
||||||
})}
|
lowCarbonEnergy,
|
||||||
kWh
|
"kWh"
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
<svg width="80" height="30">
|
<svg width="80" height="30">
|
||||||
<line x1="40" y1="0" x2="40" y2="30"></line>
|
<line x1="40" y1="0" x2="40" y2="30"></line>
|
||||||
@ -326,12 +327,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
>
|
>
|
||||||
<div class="circle">
|
<div class="circle">
|
||||||
<ha-svg-icon .path=${mdiSolarPower}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiSolarPower}></ha-svg-icon>
|
||||||
${formatNumber(
|
${formatConsumptionShort(
|
||||||
totalSolarProduction || 0,
|
this.hass,
|
||||||
this.hass.locale,
|
totalSolarProduction,
|
||||||
{ maximumFractionDigits: 1 }
|
"kWh"
|
||||||
)}
|
)}
|
||||||
kWh
|
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
: hasGas || hasWater
|
: hasGas || hasWater
|
||||||
@ -346,13 +346,14 @@ class HuiEnergyDistrubutionCard
|
|||||||
>
|
>
|
||||||
<div class="circle">
|
<div class="circle">
|
||||||
<ha-svg-icon .path=${mdiFire}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiFire}></ha-svg-icon>
|
||||||
${formatNumber(gasUsage || 0, this.hass.locale, {
|
${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
|
||||||
})}
|
|
||||||
${getEnergyGasUnit(
|
|
||||||
this.hass,
|
this.hass,
|
||||||
prefs,
|
gasUsage,
|
||||||
this._data.statsMetadata
|
getEnergyGasUnit(
|
||||||
|
this.hass,
|
||||||
|
prefs,
|
||||||
|
this._data.statsMetadata
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<svg width="80" height="30">
|
<svg width="80" height="30">
|
||||||
@ -383,10 +384,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
>
|
>
|
||||||
<div class="circle">
|
<div class="circle">
|
||||||
<ha-svg-icon .path=${mdiWater}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiWater}></ha-svg-icon>
|
||||||
${formatNumber(waterUsage || 0, this.hass.locale, {
|
${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
this.hass,
|
||||||
})}
|
waterUsage,
|
||||||
${getEnergyWaterUnit(this.hass)}
|
getEnergyWaterUnit(this.hass)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<svg width="80" height="30">
|
<svg width="80" height="30">
|
||||||
<path d="M40 0 v30" id="water" />
|
<path d="M40 0 v30" id="water" />
|
||||||
@ -420,10 +422,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
class="small"
|
class="small"
|
||||||
.path=${mdiArrowLeft}
|
.path=${mdiArrowLeft}
|
||||||
></ha-svg-icon
|
></ha-svg-icon
|
||||||
>${formatNumber(returnedToGrid, this.hass.locale, {
|
>${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
this.hass,
|
||||||
})}
|
returnedToGrid,
|
||||||
kWh
|
"kWh"
|
||||||
|
)}
|
||||||
</span>`
|
</span>`
|
||||||
: ""}
|
: ""}
|
||||||
<span class="consumption">
|
<span class="consumption">
|
||||||
@ -432,10 +435,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
class="small"
|
class="small"
|
||||||
.path=${mdiArrowRight}
|
.path=${mdiArrowRight}
|
||||||
></ha-svg-icon>`
|
></ha-svg-icon>`
|
||||||
: ""}${formatNumber(totalFromGrid, this.hass.locale, {
|
: ""}${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
this.hass,
|
||||||
})}
|
totalFromGrid,
|
||||||
kWh
|
"kWh"
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="label"
|
<span class="label"
|
||||||
@ -453,10 +457,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
})}"
|
})}"
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiHome}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiHome}></ha-svg-icon>
|
||||||
${formatNumber(totalHomeConsumption, this.hass.locale, {
|
${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
this.hass,
|
||||||
})}
|
totalHomeConsumption,
|
||||||
kWh
|
"kWh"
|
||||||
|
)}
|
||||||
${homeSolarCircumference !== undefined ||
|
${homeSolarCircumference !== undefined ||
|
||||||
homeLowCarbonCircumference !== undefined
|
homeLowCarbonCircumference !== undefined
|
||||||
? html`<svg>
|
? html`<svg>
|
||||||
@ -550,29 +555,23 @@ class HuiEnergyDistrubutionCard
|
|||||||
class="small"
|
class="small"
|
||||||
.path=${mdiArrowDown}
|
.path=${mdiArrowDown}
|
||||||
></ha-svg-icon
|
></ha-svg-icon
|
||||||
>${formatNumber(
|
>${formatConsumptionShort(
|
||||||
totalBatteryIn || 0,
|
this.hass,
|
||||||
this.hass.locale,
|
totalBatteryIn,
|
||||||
{
|
"kWh"
|
||||||
maximumFractionDigits: 1,
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
kWh</span
|
</span>
|
||||||
>
|
|
||||||
<span class="battery-out">
|
<span class="battery-out">
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
class="small"
|
class="small"
|
||||||
.path=${mdiArrowUp}
|
.path=${mdiArrowUp}
|
||||||
></ha-svg-icon
|
></ha-svg-icon
|
||||||
>${formatNumber(
|
>${formatConsumptionShort(
|
||||||
totalBatteryOut || 0,
|
this.hass,
|
||||||
this.hass.locale,
|
totalBatteryOut,
|
||||||
{
|
"kWh"
|
||||||
maximumFractionDigits: 1,
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
kWh</span
|
</span>
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="label"
|
<span class="label"
|
||||||
>${this.hass.localize(
|
>${this.hass.localize(
|
||||||
@ -603,10 +602,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="circle">
|
<div class="circle">
|
||||||
<ha-svg-icon .path=${mdiWater}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiWater}></ha-svg-icon>
|
||||||
${formatNumber(waterUsage || 0, this.hass.locale, {
|
${formatConsumptionShort(
|
||||||
maximumFractionDigits: 1,
|
this.hass,
|
||||||
})}
|
waterUsage,
|
||||||
${getEnergyWaterUnit(this.hass)}
|
getEnergyWaterUnit(this.hass)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span class="label"
|
<span class="label"
|
||||||
>${this.hass.localize(
|
>${this.hass.localize(
|
||||||
|
82
test/data/energy.test.ts
Normal file
82
test/data/energy.test.ts
Normal file
@ -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…
x
Reference in New Issue
Block a user