mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-21 01:53:18 +00:00
Compare commits
8 Commits
fix-stale-
...
add-daily-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74ba4b83d5 | ||
|
|
70951c362b | ||
|
|
aa7af2e32b | ||
|
|
7203bbee98 | ||
|
|
3b298e35fd | ||
|
|
21dbc5acd4 | ||
|
|
94df8b3b50 | ||
|
|
10d7205a57 |
@@ -21,6 +21,7 @@ import {
|
||||
mdiWeatherWindyVariant,
|
||||
} from "@mdi/js";
|
||||
import type {
|
||||
Connection,
|
||||
HassConfig,
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
@@ -667,12 +668,12 @@ export const getForecast = (
|
||||
};
|
||||
|
||||
export const subscribeForecast = (
|
||||
hass: HomeAssistant,
|
||||
connection: Connection,
|
||||
entity_id: string,
|
||||
forecast_type: ModernForecastType,
|
||||
callback: (forecastevent: ForecastEvent) => void
|
||||
) =>
|
||||
hass.connection.subscribeMessage<ForecastEvent>(callback, {
|
||||
connection.subscribeMessage<ForecastEvent>(callback, {
|
||||
type: "weather/subscribe_forecast",
|
||||
forecast_type,
|
||||
entity_id,
|
||||
|
||||
@@ -72,7 +72,7 @@ class MoreInfoWeather extends LitElement {
|
||||
}
|
||||
|
||||
this._subscribed = subscribeForecast(
|
||||
this.hass!,
|
||||
this.hass!.connection,
|
||||
this.stateObj!.entity_id,
|
||||
this._forecastType,
|
||||
(event) => {
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type {
|
||||
Connection,
|
||||
HassEntities,
|
||||
HassEntity,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing, svg } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/ha-spinner";
|
||||
import {
|
||||
connectionContext,
|
||||
internationalizationContext,
|
||||
statesContext,
|
||||
} from "../../../data/context";
|
||||
import type { ForecastAttribute, ForecastEvent } from "../../../data/weather";
|
||||
import { subscribeForecast, WeatherEntityFeature } from "../../../data/weather";
|
||||
import type {
|
||||
HomeAssistantConnection,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../../types";
|
||||
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import type {
|
||||
DailyForecastCardFeatureConfig,
|
||||
LovelaceCardFeatureContext,
|
||||
} from "./types";
|
||||
|
||||
export const DEFAULT_DAYS_TO_SHOW = 7;
|
||||
|
||||
const MAX_BAR_WIDTH = 12;
|
||||
|
||||
export type DailyForecastType = "daily" | "twice_daily";
|
||||
|
||||
export const supportsDailyForecastCardFeature = (
|
||||
stateObj: HassEntity | undefined
|
||||
) => {
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "weather" &&
|
||||
(supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY) ||
|
||||
supportsFeature(stateObj, WeatherEntityFeature.FORECAST_TWICE_DAILY))
|
||||
);
|
||||
};
|
||||
|
||||
export const resolveDailyForecastType = (
|
||||
stateObj: HassEntity | undefined,
|
||||
configured?: DailyForecastType
|
||||
): DailyForecastType | undefined => {
|
||||
if (!stateObj) return undefined;
|
||||
const supportsDaily = supportsFeature(
|
||||
stateObj,
|
||||
WeatherEntityFeature.FORECAST_DAILY
|
||||
);
|
||||
const supportsTwiceDaily = supportsFeature(
|
||||
stateObj,
|
||||
WeatherEntityFeature.FORECAST_TWICE_DAILY
|
||||
);
|
||||
if (configured === "daily" && supportsDaily) return "daily";
|
||||
if (configured === "twice_daily" && supportsTwiceDaily) return "twice_daily";
|
||||
if (supportsDaily) return "daily";
|
||||
if (supportsTwiceDaily) return "twice_daily";
|
||||
return undefined;
|
||||
};
|
||||
|
||||
@customElement("hui-daily-forecast-card-feature")
|
||||
class HuiDailyForecastCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state()
|
||||
@consume({ context: statesContext, subscribe: true })
|
||||
@transform<HassEntities, HassEntity | undefined>({
|
||||
transformer: function (this: HuiDailyForecastCardFeature, states) {
|
||||
return this.context?.entity_id
|
||||
? states?.[this.context.entity_id]
|
||||
: undefined;
|
||||
},
|
||||
watch: ["context"],
|
||||
})
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
@transform<HomeAssistantInternationalization, LocalizeFunc>({
|
||||
transformer: ({ localize }) => localize,
|
||||
})
|
||||
private _localize!: LocalizeFunc;
|
||||
|
||||
@state()
|
||||
@consume({ context: connectionContext, subscribe: true })
|
||||
@transform<HomeAssistantConnection, Connection>({
|
||||
transformer: ({ connection }) => connection,
|
||||
})
|
||||
private _connection!: Connection;
|
||||
|
||||
@state() private _config?: DailyForecastCardFeatureConfig;
|
||||
|
||||
@state() private _forecast?: ForecastAttribute[];
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _subscribed?: Promise<UnsubscribeFunc | undefined>;
|
||||
|
||||
private _subscribedType?: DailyForecastType;
|
||||
|
||||
static getStubConfig(): DailyForecastCardFeatureConfig {
|
||||
return {
|
||||
type: "daily-forecast",
|
||||
};
|
||||
}
|
||||
|
||||
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
|
||||
await import("../editor/config-elements/hui-daily-forecast-card-feature-editor");
|
||||
return document.createElement(
|
||||
"hui-daily-forecast-card-feature-editor"
|
||||
) as LovelaceCardFeatureEditor;
|
||||
}
|
||||
|
||||
public setConfig(config: DailyForecastCardFeatureConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this.hasUpdated) {
|
||||
this._subscribeForecast();
|
||||
}
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._unsubscribeForecast();
|
||||
}
|
||||
|
||||
protected firstUpdated() {
|
||||
this._subscribeForecast();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
const resolvedType = this._resolvedForecastType();
|
||||
const contextChanged =
|
||||
changedProps.has("context") &&
|
||||
(changedProps.get("context") as LovelaceCardFeatureContext | undefined)
|
||||
?.entity_id !== this.context?.entity_id;
|
||||
const configTypeChanged =
|
||||
changedProps.has("_config") && resolvedType !== this._subscribedType;
|
||||
if (contextChanged || configTypeChanged) {
|
||||
this._unsubscribeForecast();
|
||||
this._subscribeForecast();
|
||||
}
|
||||
}
|
||||
|
||||
private _resolvedForecastType(): DailyForecastType | undefined {
|
||||
return resolveDailyForecastType(
|
||||
this._stateObj,
|
||||
this._config?.forecast_type
|
||||
);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.context ||
|
||||
!supportsDailyForecastCardFeature(this._stateObj)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
if (this._error) {
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="info">${this._error}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
if (!this._forecast) {
|
||||
return html`
|
||||
<div class="container loading">
|
||||
<ha-spinner size="small"></ha-spinner>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const daysToShow = this._config.days_to_show ?? DEFAULT_DAYS_TO_SHOW;
|
||||
const entriesPerDay = this._subscribedType === "twice_daily" ? 2 : 1;
|
||||
const entries = this._forecast
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.temperature != null &&
|
||||
!Number.isNaN(entry.temperature) &&
|
||||
entry.templow != null &&
|
||||
!Number.isNaN(entry.templow)
|
||||
)
|
||||
.slice(0, daysToShow * entriesPerDay);
|
||||
|
||||
if (!entries.length) {
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="info">
|
||||
${this._localize(
|
||||
"ui.panel.lovelace.editor.features.types.daily-forecast.no_forecast"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return html` <div class="container">${this._renderChart(entries)}</div> `;
|
||||
}
|
||||
|
||||
private _renderChart(entries: ForecastAttribute[]): TemplateResult {
|
||||
const width = this.clientWidth || 300;
|
||||
const height = this.clientHeight || 42;
|
||||
const padding = 4;
|
||||
const minGap = 4;
|
||||
const slotWidth = width / entries.length;
|
||||
const barWidth = Math.max(1, Math.min(MAX_BAR_WIDTH, slotWidth - minGap));
|
||||
|
||||
const currentTemp = Number(this._stateObj?.attributes?.temperature);
|
||||
const hasCurrentTemp = currentTemp != null && !Number.isNaN(currentTemp);
|
||||
|
||||
let tempMin = Infinity;
|
||||
let tempMax = -Infinity;
|
||||
for (const entry of entries) {
|
||||
tempMin = Math.min(tempMin, entry.templow!);
|
||||
tempMax = Math.max(tempMax, entry.temperature);
|
||||
}
|
||||
if (hasCurrentTemp) {
|
||||
tempMin = Math.min(tempMin, currentTemp);
|
||||
tempMax = Math.max(tempMax, currentTemp);
|
||||
}
|
||||
if (tempMin === tempMax) {
|
||||
tempMin -= 1;
|
||||
tempMax += 1;
|
||||
}
|
||||
|
||||
const drawableHeight = height - padding * 2;
|
||||
const yFor = (value: number) =>
|
||||
padding +
|
||||
drawableHeight -
|
||||
((value - tempMin) / (tempMax - tempMin)) * drawableHeight;
|
||||
|
||||
const bars = entries.map((entry, i) => {
|
||||
const x = slotWidth * i + (slotWidth - barWidth) / 2;
|
||||
const yHigh = yFor(entry.temperature);
|
||||
const yLow = yFor(entry.templow!);
|
||||
const barHeight = Math.max(1, yLow - yHigh);
|
||||
const rx = Math.min(barWidth / 2, barHeight / 2);
|
||||
const fill = entry.condition
|
||||
? `var(--state-weather-${slugify(entry.condition, "_")}-color, var(--feature-color))`
|
||||
: "var(--feature-color)";
|
||||
return svg`<rect
|
||||
x=${x}
|
||||
y=${yHigh}
|
||||
width=${barWidth}
|
||||
height=${barHeight}
|
||||
rx=${rx}
|
||||
ry=${rx}
|
||||
fill=${fill}
|
||||
></rect>`;
|
||||
});
|
||||
|
||||
const currentTempLine = hasCurrentTemp
|
||||
? svg`<line
|
||||
x1="0"
|
||||
x2=${width}
|
||||
y1=${yFor(currentTemp)}
|
||||
y2=${yFor(currentTemp)}
|
||||
stroke="var(--feature-color)"
|
||||
stroke-width="1"
|
||||
stroke-opacity="0.5"
|
||||
vector-effect="non-scaling-stroke"
|
||||
></line>`
|
||||
: nothing;
|
||||
|
||||
return html`
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 ${width} ${height}"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
${bars}${currentTempLine}
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
|
||||
private _unsubscribeForecast() {
|
||||
if (this._subscribed) {
|
||||
this._subscribed.then((unsub) => unsub?.()).catch(() => undefined);
|
||||
this._subscribed = undefined;
|
||||
}
|
||||
this._subscribedType = undefined;
|
||||
}
|
||||
|
||||
private async _subscribeForecast() {
|
||||
if (
|
||||
!this.context?.entity_id ||
|
||||
!this._config ||
|
||||
!this._connection ||
|
||||
this._subscribed
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const forecastType = this._resolvedForecastType();
|
||||
if (!forecastType) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entityId = this.context.entity_id;
|
||||
this._forecast = undefined;
|
||||
this._error = undefined;
|
||||
this._subscribedType = forecastType;
|
||||
|
||||
this._subscribed = subscribeForecast(
|
||||
this._connection,
|
||||
entityId,
|
||||
forecastType,
|
||||
(forecastEvent: ForecastEvent) => {
|
||||
this._forecast = forecastEvent.forecast ?? [];
|
||||
}
|
||||
).catch((err) => {
|
||||
this._subscribed = undefined;
|
||||
this._subscribedType = undefined;
|
||||
this._error = err.message || err.code;
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: var(--feature-height);
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: stretch;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.info {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: var(--ha-font-size-s);
|
||||
}
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-daily-forecast-card-feature": HuiDailyForecastCardFeature;
|
||||
}
|
||||
}
|
||||
@@ -214,7 +214,7 @@ class HuiHourlyForecastCardFeature
|
||||
const entityId = this.context.entity_id;
|
||||
|
||||
this._subscribed = subscribeForecast(
|
||||
this.hass,
|
||||
this.hass.connection,
|
||||
entityId,
|
||||
"hourly",
|
||||
(forecastEvent) => {
|
||||
|
||||
@@ -246,6 +246,12 @@ export interface HourlyForecastCardFeatureConfig {
|
||||
hours_to_show?: number;
|
||||
}
|
||||
|
||||
export interface DailyForecastCardFeatureConfig {
|
||||
type: "daily-forecast";
|
||||
forecast_type?: "daily" | "twice_daily";
|
||||
days_to_show?: number;
|
||||
}
|
||||
|
||||
export const AREA_CONTROL_DOMAINS = [
|
||||
"light",
|
||||
"fan",
|
||||
@@ -301,6 +307,7 @@ export type LovelaceCardFeatureConfig =
|
||||
| FanSpeedCardFeatureConfig
|
||||
| TrendGraphCardFeatureConfig
|
||||
| HourlyForecastCardFeatureConfig
|
||||
| DailyForecastCardFeatureConfig
|
||||
| HumidifierToggleCardFeatureConfig
|
||||
| HumidifierModesCardFeatureConfig
|
||||
| LawnMowerCommandsCardFeatureConfig
|
||||
|
||||
@@ -135,7 +135,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
this._subscribed = subscribeForecast(
|
||||
this.hass!,
|
||||
this.hass!.connection,
|
||||
this._config!.entity,
|
||||
this._config!.forecast_type as "daily" | "hourly" | "twice_daily",
|
||||
(event) => {
|
||||
|
||||
@@ -43,6 +43,7 @@ import "../card-features/hui-valve-position-card-feature";
|
||||
import "../card-features/hui-water-heater-operation-modes-card-feature";
|
||||
import "../card-features/hui-area-controls-card-feature";
|
||||
import "../card-features/hui-bar-gauge-card-feature";
|
||||
import "../card-features/hui-daily-forecast-card-feature";
|
||||
import "../card-features/hui-hourly-forecast-card-feature";
|
||||
import "../card-features/hui-trend-graph-card-feature";
|
||||
|
||||
@@ -69,6 +70,7 @@ const TYPES = new Set<LovelaceCardFeatureConfig["type"]>([
|
||||
"cover-tilt-favorite",
|
||||
"cover-tilt-position",
|
||||
"cover-tilt",
|
||||
"daily-forecast",
|
||||
"date-set",
|
||||
"fan-direction",
|
||||
"fan-oscillate",
|
||||
|
||||
@@ -40,6 +40,7 @@ import { supportsCoverPositionCardFeature } from "../../card-features/hui-cover-
|
||||
import { supportsCoverTiltCardFeature } from "../../card-features/hui-cover-tilt-card-feature";
|
||||
import { supportsCoverTiltFavoriteCardFeature } from "../../card-features/hui-cover-tilt-favorite-card-feature";
|
||||
import { supportsCoverTiltPositionCardFeature } from "../../card-features/hui-cover-tilt-position-card-feature";
|
||||
import { supportsDailyForecastCardFeature } from "../../card-features/hui-daily-forecast-card-feature";
|
||||
import { supportsDateSetCardFeature } from "../../card-features/hui-date-set-card-feature";
|
||||
import { supportsFanDirectionCardFeature } from "../../card-features/hui-fan-direction-card-feature";
|
||||
import { supportsHourlyForecastCardFeature } from "../../card-features/hui-hourly-forecast-card-feature";
|
||||
@@ -101,6 +102,7 @@ const UI_FEATURE_TYPES = [
|
||||
"cover-tilt-favorite",
|
||||
"cover-tilt-position",
|
||||
"cover-tilt",
|
||||
"daily-forecast",
|
||||
"date-set",
|
||||
"fan-direction",
|
||||
"fan-oscillate",
|
||||
@@ -149,6 +151,7 @@ const EDITABLES_FEATURE_TYPES = new Set<UiFeatureTypes>([
|
||||
"counter-actions",
|
||||
"cover-position-favorite",
|
||||
"cover-tilt-favorite",
|
||||
"daily-forecast",
|
||||
"fan-preset-modes",
|
||||
"hourly-forecast",
|
||||
"humidifier-modes",
|
||||
@@ -186,6 +189,10 @@ const SUPPORTS_FEATURE_TYPES: Record<
|
||||
"cover-tilt-favorite": supportsCoverTiltFavoriteCardFeature,
|
||||
"cover-tilt-position": supportsCoverTiltPositionCardFeature,
|
||||
"cover-tilt": supportsCoverTiltCardFeature,
|
||||
"daily-forecast": (hass, context) =>
|
||||
supportsDailyForecastCardFeature(
|
||||
context.entity_id ? hass.states[context.entity_id] : undefined
|
||||
),
|
||||
"date-set": supportsDateSetCardFeature,
|
||||
"fan-direction": supportsFanDirectionCardFeature,
|
||||
"fan-oscillate": supportsFanOscilatteCardFeature,
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type {
|
||||
HaFormSchema,
|
||||
SchemaUnion,
|
||||
} from "../../../../components/ha-form/types";
|
||||
import { getSupportedForecastTypes } from "../../../../data/weather";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import {
|
||||
DEFAULT_DAYS_TO_SHOW,
|
||||
resolveDailyForecastType,
|
||||
} from "../../card-features/hui-daily-forecast-card-feature";
|
||||
import type {
|
||||
DailyForecastCardFeatureConfig,
|
||||
LovelaceCardFeatureContext,
|
||||
} from "../../card-features/types";
|
||||
import type { LovelaceCardFeatureEditor } from "../../types";
|
||||
|
||||
@customElement("hui-daily-forecast-card-feature-editor")
|
||||
export class HuiDailyForecastCardFeatureEditor
|
||||
extends LitElement
|
||||
implements LovelaceCardFeatureEditor
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@state() private _config?: DailyForecastCardFeatureConfig;
|
||||
|
||||
public setConfig(config: DailyForecastCardFeatureConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(
|
||||
supportsDaily: boolean,
|
||||
supportsTwiceDaily: boolean,
|
||||
localize: HomeAssistant["localize"]
|
||||
) =>
|
||||
[
|
||||
{
|
||||
name: "forecast_type",
|
||||
required: true,
|
||||
disabled: !(supportsDaily && supportsTwiceDaily),
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: [
|
||||
{
|
||||
value: "daily",
|
||||
label: localize(
|
||||
"ui.panel.lovelace.editor.features.types.daily-forecast.forecast_type_options.daily"
|
||||
),
|
||||
disabled: !supportsDaily,
|
||||
},
|
||||
{
|
||||
value: "twice_daily",
|
||||
label: localize(
|
||||
"ui.panel.lovelace.editor.features.types.daily-forecast.forecast_type_options.twice_daily"
|
||||
),
|
||||
disabled: !supportsTwiceDaily,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "days_to_show",
|
||||
default: DEFAULT_DAYS_TO_SHOW,
|
||||
selector: { number: { min: 1, mode: "box" } },
|
||||
},
|
||||
] as const satisfies readonly HaFormSchema[]
|
||||
);
|
||||
|
||||
protected render() {
|
||||
if (!this.hass || !this._config) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const stateObj = this.context?.entity_id
|
||||
? this.hass.states[this.context.entity_id]
|
||||
: undefined;
|
||||
const supportedTypes = stateObj ? getSupportedForecastTypes(stateObj) : [];
|
||||
const supportsDaily = supportedTypes.includes("daily");
|
||||
const supportsTwiceDaily = supportedTypes.includes("twice_daily");
|
||||
|
||||
const resolvedType =
|
||||
resolveDailyForecastType(stateObj, this._config.forecast_type) || "daily";
|
||||
|
||||
const data: DailyForecastCardFeatureConfig = {
|
||||
...this._config,
|
||||
forecast_type: resolvedType,
|
||||
days_to_show: this._config.days_to_show ?? DEFAULT_DAYS_TO_SHOW,
|
||||
};
|
||||
|
||||
const schema = this._schema(
|
||||
supportsDaily,
|
||||
supportsTwiceDaily,
|
||||
this.hass.localize
|
||||
);
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${data}
|
||||
.schema=${schema}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
fireEvent(this, "config-changed", { config: ev.detail.value });
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
switch (schema.name) {
|
||||
case "forecast_type":
|
||||
return this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.features.types.daily-forecast.forecast_type"
|
||||
);
|
||||
case "days_to_show":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||
);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-daily-forecast-card-feature-editor": HuiDailyForecastCardFeatureEditor;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
||||
const forecastType = getDefaultForecastType(stateObj);
|
||||
if (forecastType) {
|
||||
this._subscribed = subscribeForecast(
|
||||
this.hass!,
|
||||
this.hass!.connection,
|
||||
stateObj.entity_id,
|
||||
forecastType,
|
||||
(event) => {
|
||||
|
||||
@@ -10043,6 +10043,15 @@
|
||||
"hourly-forecast": {
|
||||
"label": "Hourly forecast",
|
||||
"no_forecast": "No forecast data available"
|
||||
},
|
||||
"daily-forecast": {
|
||||
"label": "Daily forecast",
|
||||
"no_forecast": "[%key:ui::panel::lovelace::editor::features::types::hourly-forecast::no_forecast%]",
|
||||
"forecast_type": "Forecast type",
|
||||
"forecast_type_options": {
|
||||
"daily": "Daily",
|
||||
"twice_daily": "Twice daily"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user