diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts
index e77d75c2b5..4c7a931d0f 100644
--- a/src/data/entity_registry.ts
+++ b/src/data/entity_registry.ts
@@ -33,6 +33,18 @@ export interface UpdateEntityRegistryEntryResult {
require_restart?: boolean;
}
+export interface SensorEntityOptions {
+ unit_of_measurement?: string | null;
+}
+
+export interface WeatherEntityOptions {
+ precipitation_unit?: string | null;
+ pressure_unit?: string | null;
+ temperature_unit?: string | null;
+ visibility_unit?: string | null;
+ wind_speed_unit?: string | null;
+}
+
export interface EntityRegistryEntryUpdateParams {
name?: string | null;
icon?: string | null;
@@ -42,9 +54,7 @@ export interface EntityRegistryEntryUpdateParams {
hidden_by: string | null;
new_entity_id?: string;
options_domain?: string;
- options?: {
- unit_of_measurement?: string | null;
- };
+ options?: SensorEntityOptions | WeatherEntityOptions;
}
export const findBatteryEntity = (
diff --git a/src/data/weather.ts b/src/data/weather.ts
index a09385b526..f77da5c9b0 100644
--- a/src/data/weather.ts
+++ b/src/data/weather.ts
@@ -37,14 +37,24 @@ interface ForecastAttribute {
humidity?: number;
condition?: string;
daytime?: boolean;
+ pressure?: number;
+ wind_speed?: string;
}
interface WeatherEntityAttributes extends HassEntityAttributeBase {
- temperature: number;
+ attribution?: string;
humidity?: number;
forecast?: ForecastAttribute[];
- wind_speed: string;
- wind_bearing: string;
+ pressure?: number;
+ temperature?: number;
+ visibility?: number;
+ wind_bearing?: number | string;
+ wind_speed?: number;
+ precipitation_unit: string;
+ pressure_unit: string;
+ temperature_unit: string;
+ visibility_unit: string;
+ wind_speed_unit: string;
}
export interface WeatherEntity extends HassEntityBase {
@@ -138,16 +148,16 @@ const cardinalDirections = [
"N",
];
-const getWindBearingText = (degree: string): string => {
- const degreenum = parseInt(degree, 10);
+const getWindBearingText = (degree: number | string): string => {
+ const degreenum = typeof degree === "number" ? degree : parseInt(degree, 10);
if (isFinite(degreenum)) {
// eslint-disable-next-line no-bitwise
return cardinalDirections[(((degreenum + 11.25) / 22.5) | 0) % 16];
}
- return degree;
+ return typeof degree === "number" ? degree.toString() : degree;
};
-const getWindBearing = (bearing: string): string => {
+const getWindBearing = (bearing: number | string): string => {
if (bearing != null) {
return getWindBearingText(bearing);
}
@@ -156,14 +166,19 @@ const getWindBearing = (bearing: string): string => {
export const getWind = (
hass: HomeAssistant,
- speed: string,
- bearing: string
+ stateObj: WeatherEntity,
+ speed?: number,
+ bearing?: number | string
): string => {
- const speedText = `${formatNumber(speed, hass.locale)} ${getWeatherUnit(
- hass!,
- "wind_speed"
- )}`;
- if (bearing !== null) {
+ const speedText =
+ speed !== undefined && speed !== null
+ ? `${formatNumber(speed, hass.locale)} ${getWeatherUnit(
+ hass!,
+ stateObj,
+ "wind_speed"
+ )}`
+ : "-";
+ if (bearing !== undefined && bearing !== null) {
const cardinalDirection = getWindBearing(bearing);
return `${speedText} (${
hass.localize(
@@ -176,19 +191,28 @@ export const getWind = (
export const getWeatherUnit = (
hass: HomeAssistant,
+ stateObj: WeatherEntity,
measure: string
): string => {
const lengthUnit = hass.config.unit_system.length || "";
switch (measure) {
- case "pressure":
- return lengthUnit === "km" ? "hPa" : "inHg";
- case "wind_speed":
- return `${lengthUnit}/h`;
case "visibility":
- case "length":
- return lengthUnit;
+ return stateObj.attributes.visibility_unit || lengthUnit;
case "precipitation":
- return lengthUnit === "km" ? "mm" : "in";
+ return stateObj.attributes.precipitation_unit || lengthUnit === "km"
+ ? "mm"
+ : "in";
+ case "pressure":
+ return stateObj.attributes.pressure_unit || lengthUnit === "km"
+ ? "hPa"
+ : "inHg";
+ case "temperature":
+ return (
+ stateObj.attributes.temperature_unit ||
+ hass.config.unit_system.temperature
+ );
+ case "wind_speed":
+ return stateObj.attributes.wind_speed_unit || `${lengthUnit}/h`;
case "humidity":
case "precipitation_probability":
return "%";
@@ -233,7 +257,7 @@ export const getSecondaryWeatherAttribute = (
`
: hass!.localize(`ui.card.weather.attributes.${attribute}`)}
${formatNumber(value, hass.locale, { maximumFractionDigits: 1 })}
- ${getWeatherUnit(hass!, attribute)}
+ ${getWeatherUnit(hass!, stateObj, attribute)}
`;
};
@@ -268,7 +292,7 @@ const getWeatherExtrema = (
return undefined;
}
- const unit = getWeatherUnit(hass!, "temperature");
+ const unit = getWeatherUnit(hass!, stateObj, "temperature");
return html`
${tempHigh ? `${formatNumber(tempHigh, hass.locale)} ${unit}` : ""}
diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts
index e93e9cbfe8..a680dbd754 100644
--- a/src/dialogs/more-info/controls/more-info-weather.ts
+++ b/src/dialogs/more-info/controls/more-info-weather.ts
@@ -5,7 +5,6 @@ import {
mdiWaterPercent,
mdiWeatherWindy,
} from "@mdi/js";
-import { HassEntity } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
@@ -23,6 +22,7 @@ import {
getWeatherUnit,
getWind,
isForecastHourly,
+ WeatherEntity,
weatherIcons,
} from "../../../data/weather";
import { HomeAssistant } from "../../../types";
@@ -31,7 +31,7 @@ import { HomeAssistant } from "../../../types";
class MoreInfoWeather extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
- @property() public stateObj?: HassEntity;
+ @property() public stateObj?: WeatherEntity;
protected shouldUpdate(changedProps: PropertyValues): boolean {
if (changedProps.has("stateObj")) {
@@ -58,19 +58,23 @@ class MoreInfoWeather extends LitElement {
const hourly = isForecastHourly(this.stateObj.attributes.forecast);
return html`
-
-
-
- ${this.hass.localize("ui.card.weather.attributes.temperature")}
-
-
- ${formatNumber(
- this.stateObj.attributes.temperature,
- this.hass.locale
- )}
- ${getWeatherUnit(this.hass, "temperature")}
-
-
+ ${this._showValue(this.stateObj.attributes.temperature)
+ ? html`
+
+
+
+ ${this.hass.localize("ui.card.weather.attributes.temperature")}
+
+
+ ${formatNumber(
+ this.stateObj.attributes.temperature!,
+ this.hass.locale
+ )}
+ ${getWeatherUnit(this.hass, this.stateObj, "temperature")}
+
+
+ `
+ : ""}
${this._showValue(this.stateObj.attributes.pressure)
? html`
@@ -80,10 +84,10 @@ class MoreInfoWeather extends LitElement {
${formatNumber(
- this.stateObj.attributes.pressure,
+ this.stateObj.attributes.pressure!,
this.hass.locale
)}
- ${getWeatherUnit(this.hass, "pressure")}
+ ${getWeatherUnit(this.hass, this.stateObj, "pressure")}
`
@@ -97,7 +101,7 @@ class MoreInfoWeather extends LitElement {
${formatNumber(
- this.stateObj.attributes.humidity,
+ this.stateObj.attributes.humidity!,
this.hass.locale
)}
%
@@ -115,7 +119,8 @@ class MoreInfoWeather extends LitElement {
${getWind(
this.hass,
- this.stateObj.attributes.wind_speed,
+ this.stateObj,
+ this.stateObj.attributes.wind_speed!,
this.stateObj.attributes.wind_bearing
)}
@@ -131,10 +136,10 @@ class MoreInfoWeather extends LitElement {
${formatNumber(
- this.stateObj.attributes.visibility,
+ this.stateObj.attributes.visibility!,
this.hass.locale
)}
- ${getWeatherUnit(this.hass, "length")}
+ ${getWeatherUnit(this.hass, this.stateObj, "visibility")}
`
@@ -173,16 +178,24 @@ class MoreInfoWeather extends LitElement {
`}
${this._showValue(item.templow)
- ? `${formatNumber(item.templow, this.hass.locale)}
- ${getWeatherUnit(this.hass, "temperature")}`
+ ? `${formatNumber(item.templow!, this.hass.locale)}
+ ${getWeatherUnit(
+ this.hass,
+ this.stateObj!,
+ "temperature"
+ )}`
: hourly
? ""
: "—"}
${this._showValue(item.temperature)
- ? `${formatNumber(item.temperature, this.hass.locale)}
- ${getWeatherUnit(this.hass, "temperature")}`
+ ? `${formatNumber(item.temperature!, this.hass.locale)}
+ ${getWeatherUnit(
+ this.hass,
+ this.stateObj!,
+ "temperature"
+ )}`
: "—"}
`
@@ -240,7 +253,7 @@ class MoreInfoWeather extends LitElement {
`;
}
- private _showValue(item: string): boolean {
+ private _showValue(item: number | string | undefined): boolean {
return typeof item !== "undefined" && item !== null;
}
}
diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts
index f525a5468b..5ee92cc750 100644
--- a/src/panels/config/entities/entity-registry-settings.ts
+++ b/src/panels/config/entities/entity-registry-settings.ts
@@ -110,6 +110,14 @@ const OVERRIDE_SENSOR_UNITS = {
pressure: ["hPa", "Pa", "kPa", "bar", "cbar", "mbar", "mmHg", "inHg", "psi"],
};
+const OVERRIDE_WEATHER_UNITS = {
+ precipitation: ["mm", "in"],
+ pressure: ["hPa", "mbar", "mmHg", "inHg"],
+ temperature: ["°C", "°F"],
+ visibility: ["km", "mi"],
+ wind_speed: ["km/h", "mph", "m/s"],
+};
+
const SWITCH_AS_DOMAINS = ["cover", "fan", "light", "lock", "siren"];
@customElement("entity-registry-settings")
@@ -140,6 +148,16 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
@state() private _unit_of_measurement?: string | null;
+ @state() private _precipitation_unit?: string | null;
+
+ @state() private _pressure_unit?: string | null;
+
+ @state() private _temperature_unit?: string | null;
+
+ @state() private _visibility_unit?: string | null;
+
+ @state() private _wind_speed_unit?: string | null;
+
@state() private _error?: string;
@state() private _submitting?: boolean;
@@ -223,6 +241,16 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
this._unit_of_measurement = stateObj?.attributes?.unit_of_measurement;
}
+ if (domain === "weather") {
+ const stateObj: HassEntity | undefined =
+ this.hass.states[this.entry.entity_id];
+ this._precipitation_unit = stateObj?.attributes?.precipitation_unit;
+ this._pressure_unit = stateObj?.attributes?.pressure_unit;
+ this._temperature_unit = stateObj?.attributes?.temperature_unit;
+ this._visibility_unit = stateObj?.attributes?.visibility_unit;
+ this._wind_speed_unit = stateObj?.attributes?.wind_speed_unit;
+ }
+
const deviceClasses: string[][] = OVERRIDE_DEVICE_CLASSES[domain];
if (!deviceClasses) {
@@ -358,6 +386,90 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
`
: ""}
+ ${domain === "weather"
+ ? html`
+
+ ${OVERRIDE_WEATHER_UNITS.precipitation.map(
+ (unit: string) => html`
+ ${unit}
+ `
+ )}
+
+
+ ${OVERRIDE_WEATHER_UNITS.pressure.map(
+ (unit: string) => html`
+ ${unit}
+ `
+ )}
+
+
+ ${OVERRIDE_WEATHER_UNITS.temperature.map(
+ (unit: string) => html`
+ ${unit}
+ `
+ )}
+
+
+ ${OVERRIDE_WEATHER_UNITS.visibility.map(
+ (unit: string) => html`
+ ${unit}
+ `
+ )}
+
+
+ ${OVERRIDE_WEATHER_UNITS.wind_speed.map(
+ (unit: string) => html`
+ ${unit}
+ `
+ )}
+
+ `
+ : ""}
${domain === "switch"
? html`
- ${formatNumber(
- stateObj.attributes.temperature,
- this.hass.locale
- )} ${getWeatherUnit(this.hass, "temperature")}
+ ${stateObj.attributes.temperature !== undefined &&
+ stateObj.attributes.temperature !== null
+ ? html`
+ ${formatNumber(
+ stateObj.attributes.temperature,
+ this.hass.locale
+ )} ${getWeatherUnit(
+ this.hass,
+ stateObj,
+ "temperature"
+ )}
+ `
+ : html` `}
${this._config.secondary_info_attribute !== undefined
@@ -255,6 +264,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
"wind_speed"
? getWind(
this.hass,
+ stateObj,
stateObj.attributes.wind_speed,
stateObj.attributes.wind_bearing
)
@@ -267,6 +277,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
)}
${getWeatherUnit(
this.hass,
+ stateObj,
this._config.secondary_info_attribute
)}
`}
diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
index e2e0971399..3b0d17ff37 100644
--- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
@@ -114,7 +114,9 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
})}
>
- ${UNAVAILABLE_STATES.includes(stateObj.state)
+ ${UNAVAILABLE_STATES.includes(stateObj.state) ||
+ stateObj.attributes.temperature === undefined ||
+ stateObj.attributes.temperature === null
? computeStateDisplay(
this.hass.localize,
stateObj,
@@ -125,7 +127,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
stateObj.attributes.temperature,
this.hass.locale
)}
- ${getWeatherUnit(this.hass, "temperature")}
+ ${getWeatherUnit(this.hass, stateObj, "temperature")}
`}
diff --git a/src/translations/en.json b/src/translations/en.json
index 059fd3b2ea..076cc9f6e0 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -811,6 +811,11 @@
"icon_error": "Icons should be in the format 'prefix:iconname', e.g. 'mdi:home'",
"entity_id": "Entity ID",
"unit_of_measurement": "Unit of Measurement",
+ "precipitation_unit": "Precipitation unit",
+ "pressure_unit": "Barometric pressure unit",
+ "temperature_unit": "Temperature unit",
+ "visibility_unit": "Visibility unit",
+ "wind_speed_unit": "Wind speed unit",
"device_class": "Show as",
"device_classes": {
"binary_sensor": {