Add weather forecast options to more info (#17823)

This commit is contained in:
Bram Kragten 2023-09-05 13:29:56 +02:00 committed by GitHub
parent c3c4bb4421
commit 32472ca627
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 25 deletions

View File

@ -36,7 +36,9 @@ export const enum WeatherEntityFeature {
FORECAST_TWICE_DAILY = 4, FORECAST_TWICE_DAILY = 4,
} }
export type ForecastType = "legacy" | "hourly" | "daily" | "twice_daily"; export type ModernForecastType = "hourly" | "daily" | "twice_daily";
export type ForecastType = ModernForecastType | "legacy";
interface ForecastAttribute { interface ForecastAttribute {
temperature: number; temperature: number;
@ -636,7 +638,7 @@ export const getForecast = (
export const subscribeForecast = ( export const subscribeForecast = (
hass: HomeAssistant, hass: HomeAssistant,
entity_id: string, entity_id: string,
forecast_type: "daily" | "hourly" | "twice_daily", forecast_type: ModernForecastType,
callback: (forecastevent: ForecastEvent) => void callback: (forecastevent: ForecastEvent) => void
) => ) =>
hass.connection.subscribeMessage<ForecastEvent>(callback, { hass.connection.subscribeMessage<ForecastEvent>(callback, {
@ -645,6 +647,22 @@ export const subscribeForecast = (
entity_id, entity_id,
}); });
export const getSupportedForecastTypes = (
stateObj: HassEntityBase
): ModernForecastType[] => {
const supported: ModernForecastType[] = [];
if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY)) {
supported.push("daily");
}
if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_TWICE_DAILY)) {
supported.push("twice_daily");
}
if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_HOURLY)) {
supported.push("hourly");
}
return supported;
};
export const getDefaultForecastType = (stateObj: HassEntityBase) => { export const getDefaultForecastType = (stateObj: HassEntityBase) => {
if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY)) { if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY)) {
return "daily"; return "daily";

View File

@ -1,6 +1,4 @@
import "@material/mwc-button"; import "@material/mwc-button";
import "@material/mwc-tab-bar/mwc-tab-bar";
import "@material/mwc-tab/mwc-tab";
import { mdiEyedropper } from "@mdi/js"; import { mdiEyedropper } from "@mdi/js";
import { import {
css, css,

View File

@ -1,3 +1,5 @@
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { import {
mdiEye, mdiEye,
mdiGauge, mdiGauge,
@ -14,14 +16,17 @@ import {
nothing, nothing,
} from "lit"; } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { formatDateWeekdayDay } from "../../../common/datetime/format_date"; import { formatDateWeekdayDay } from "../../../common/datetime/format_date";
import { formatTimeWeekday } from "../../../common/datetime/format_time"; import { formatTimeWeekday } from "../../../common/datetime/format_time";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import { import {
ForecastEvent, ForecastEvent,
ModernForecastType,
WeatherEntity, WeatherEntity,
getDefaultForecastType, getDefaultForecastType,
getForecast, getForecast,
getSupportedForecastTypes,
getWind, getWind,
subscribeForecast, subscribeForecast,
weatherIcons, weatherIcons,
@ -36,6 +41,8 @@ class MoreInfoWeather extends LitElement {
@state() private _forecastEvent?: ForecastEvent; @state() private _forecastEvent?: ForecastEvent;
@state() private _forecastType?: ModernForecastType;
@state() private _subscribed?: Promise<() => void>; @state() private _subscribed?: Promise<() => void>;
private _unsubscribeForecastEvents() { private _unsubscribeForecastEvents() {
@ -43,25 +50,28 @@ class MoreInfoWeather extends LitElement {
this._subscribed.then((unsub) => unsub()); this._subscribed.then((unsub) => unsub());
this._subscribed = undefined; this._subscribed = undefined;
} }
this._forecastEvent = undefined;
} }
private async _subscribeForecastEvents() { private async _subscribeForecastEvents() {
this._unsubscribeForecastEvents(); this._unsubscribeForecastEvents();
if (!this.isConnected || !this.hass || !this.stateObj) { if (
!this.isConnected ||
!this.hass ||
!this.stateObj ||
!this._forecastType
) {
return; return;
} }
const forecastType = getDefaultForecastType(this.stateObj); this._subscribed = subscribeForecast(
if (forecastType) { this.hass!,
this._subscribed = subscribeForecast( this.stateObj!.entity_id,
this.hass!, this._forecastType,
this.stateObj!.entity_id, (event) => {
forecastType, this._forecastEvent = event;
(event) => { }
this._forecastEvent = event; );
}
);
}
} }
public connectedCallback() { public connectedCallback() {
@ -93,10 +103,10 @@ class MoreInfoWeather extends LitElement {
return false; return false;
} }
protected updated(changedProps: PropertyValues): void { protected willUpdate(changedProps: PropertyValues): void {
super.updated(changedProps); super.willUpdate(changedProps);
if (changedProps.has("stateObj") || !this._subscribed) { if ((changedProps.has("stateObj") || !this._subscribed) && this.stateObj) {
const oldState = changedProps.get("stateObj") as const oldState = changedProps.get("stateObj") as
| WeatherEntity | WeatherEntity
| undefined; | undefined;
@ -104,16 +114,25 @@ class MoreInfoWeather extends LitElement {
oldState?.entity_id !== this.stateObj?.entity_id || oldState?.entity_id !== this.stateObj?.entity_id ||
!this._subscribed !this._subscribed
) { ) {
this._forecastType = getDefaultForecastType(this.stateObj);
this._subscribeForecastEvents(); this._subscribeForecastEvents();
} }
} else if (changedProps.has("_forecastType")) {
this._subscribeForecastEvents();
} }
} }
private _supportedForecasts = memoizeOne((stateObj: WeatherEntity) =>
getSupportedForecastTypes(stateObj)
);
protected render() { protected render() {
if (!this.hass || !this.stateObj) { if (!this.hass || !this.stateObj) {
return nothing; return nothing;
} }
const supportedForecasts = this._supportedForecasts(this.stateObj);
const forecastData = getForecast( const forecastData = getForecast(
this.stateObj.attributes, this.stateObj.attributes,
this._forecastEvent this._forecastEvent
@ -210,6 +229,23 @@ class MoreInfoWeather extends LitElement {
<div class="section"> <div class="section">
${this.hass.localize("ui.card.weather.forecast")}: ${this.hass.localize("ui.card.weather.forecast")}:
</div> </div>
${supportedForecasts.length > 1
? html`<mwc-tab-bar
.activeIndex=${supportedForecasts.findIndex(
(item) => item === this._forecastType
)}
@MDCTabBar:activated=${this._handleForecastTypeChanged}
>
${supportedForecasts.map(
(forecastType) =>
html`<mwc-tab
.label=${this.hass!.localize(
`ui.card.weather.${forecastType}`
)}
></mwc-tab>`
)}
</mwc-tab-bar>`
: nothing}
${forecast.map((item) => ${forecast.map((item) =>
this._showValue(item.templow) || this._showValue(item.temperature) this._showValue(item.templow) || this._showValue(item.temperature)
? html`<div class="flex"> ? html`<div class="flex">
@ -283,12 +319,23 @@ class MoreInfoWeather extends LitElement {
`; `;
} }
private _handleForecastTypeChanged(ev: CustomEvent): void {
this._forecastType = this._supportedForecasts(this.stateObj!)[
ev.detail.index
];
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return css` return css`
ha-svg-icon { ha-svg-icon {
color: var(--paper-item-icon-color); color: var(--paper-item-icon-color);
margin-left: 8px; margin-left: 8px;
} }
mwc-tab-bar {
margin-bottom: 4px;
}
.section { .section {
margin: 16px 0 8px 0; margin: 16px 0 8px 0;
font-size: 1.2em; font-size: 1.2em;

View File

@ -1,5 +1,3 @@
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,

View File

@ -1,8 +1,6 @@
import "@material/mwc-button/mwc-button"; import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item"; import "@material/mwc-list/mwc-list-item";
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-alert"; import "../../../components/ha-alert";

View File

@ -1,5 +1,3 @@
import "@material/mwc-tab-bar/mwc-tab-bar";
import "@material/mwc-tab/mwc-tab";
import Fuse from "fuse.js"; import Fuse from "fuse.js";
import { import {
css, css,

View File

@ -261,6 +261,9 @@
"forecast_daily": "Forecast daily", "forecast_daily": "Forecast daily",
"forecast_hourly": "Forecast hourly", "forecast_hourly": "Forecast hourly",
"forecast_twice_daily": "Forecast twice daily", "forecast_twice_daily": "Forecast twice daily",
"daily": "Daily",
"hourly": "Hourly",
"twice_daily": "Twice daily",
"high": "High", "high": "High",
"low": "Low" "low": "Low"
} }