Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Kissling committed Sep 29, 2023
1 parent 4c58023 commit ae865d6
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 9 deletions.
55 changes: 47 additions & 8 deletions src/clock-weather-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
TemperatureSensor,
TemperatureUnit,
Weather,
WeatherForecast
WeatherForecast,
WeatherForecastEvent
} from './types';
import styles from './styles';
import { actionHandler } from './action-handler-directive';
Expand Down Expand Up @@ -64,6 +65,8 @@ export class ClockWeatherCard extends LitElement {

@state() private config!: MergedClockWeatherCardConfig;
@state() private currentDate!: Date;
@state() private forecastSubscriber?: Promise<() => void>;
@state() private forecasts?: WeatherForecast[];

constructor() {
super();
Expand Down Expand Up @@ -156,6 +159,18 @@ export class ClockWeatherCard extends LitElement {
`;
}

public connectedCallback(): void {
super.connectedCallback();
if (this.hasUpdated && this.config && this.hass && !this.isLegacyWeather()) {
this.subscribeForecastEvents();
}
}

public disconnectedCallback(): void {
super.disconnectedCallback();
this.unsubscribeForecastEvents();
}

private renderToday(): TemplateResult {
const weather = this.getWeather();
const state = weather.state;
Expand Down Expand Up @@ -188,11 +203,11 @@ export class ClockWeatherCard extends LitElement {
private renderForecast(): TemplateResult[] {
const weather = this.getWeather();
const currentTemp = roundIfNotNull(this.getCurrentTemperature());
const items = this.config.forecast_days;
const maxItemsCount = this.config.forecast_days;
const hourly = this.config.hourly_forecast;
const temperatureUnit = weather.attributes.temperature_unit;

const forecasts = this.extractForecasts(weather.attributes.forecast, items, hourly);
const forecasts = this.mergeForecasts(maxItemsCount, hourly);

const minTemps = forecasts.map((f) => f.templow);
const maxTemps = forecasts.map((f) => f.temperature);
Expand Down Expand Up @@ -371,8 +386,7 @@ export class ClockWeatherCard extends LitElement {

private getWeather(): Weather {
const weather = this.hass.states[this.config.entity] as Weather | undefined;
if (!weather) throw new Error('Weather entity could not be found.');
if (!weather?.attributes?.forecast) throw new Error('Weather entity does not have attribute "forecast".');
if (!weather) throw new Error(`Weather entity "${this.config.entity}" could not be found.`);
return weather;
}

Expand Down Expand Up @@ -492,10 +506,11 @@ export class ClockWeatherCard extends LitElement {
return localize(key, this.getLocale());
}

private extractForecasts(forecasts: WeatherForecast[], items: number, hourly: boolean): MergedWeatherForecast[] {
private mergeForecasts(maxItemsCount: number, hourly: boolean): MergedWeatherForecast[] {
const forecasts = this.getWeather().attributes.forecast ?? this.forecasts ?? [];
const agg = forecasts.reduce((forecasts, forecast) => {
const d = new Date(forecast.datetime);
const unit = !hourly ? d.getDate() : d.getDate()+"_"+d.getHours();
const unit = !hourly ? d.getDate() : `${d.getMonth()}-${d.getDate()}-${+d.getHours()}`;
forecasts[unit] = forecasts[unit] || [];
forecasts[unit].push(forecast);
return forecasts;
Expand All @@ -509,7 +524,7 @@ export class ClockWeatherCard extends LitElement {
return agg;
}, [])
.sort((a,b) => a.datetime.getTime() - b.datetime.getTime())
.slice(0, items);
.slice(0, maxItemsCount);
}

private toZonedDate(date: Date): Date {
Expand Down Expand Up @@ -548,5 +563,29 @@ export class ClockWeatherCard extends LitElement {
precipitation: precipitation,
}
}

private subscribeForecastEvents(): void {
const callback = (event: WeatherForecastEvent) => {
this.forecasts = event.forecast;
console.log('updated forecasts', this.forecasts);
};
this.forecastSubscriber = this.hass.connection.subscribeMessage<WeatherForecastEvent>(callback, {
type: "weather/subscribe_forecast",
// TODO compare supported_features with is_daily
forecast_type: this.config.hourly_forecast ? 'hourly' : 'daily',
entity_id: this.config.entity,
});
}

private unsubscribeForecastEvents(): void {
if (this.forecastSubscriber) {
this.forecastSubscriber.then((unsub) => unsub());
}
}

private isLegacyWeather(): boolean {
return (this.getWeather().attributes.forecast?.length ?? 0) > 0;
// TODO && this.getWeather().attributes.supported_features
}
}

14 changes: 13 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,20 @@ export interface MergedClockWeatherCardConfig extends LovelaceCardConfig {
use_browser_time: boolean;
}

export const enum WeatherEntityFeature {
FORECAST_DAILY = 1,
FORECAST_HOURLY = 2,
FORECAST_TWICE_DAILY = 4,
}

export interface Weather extends HassEntity {
state: string;
attributes: {
temperature?: number;
temperature_unit: TemperatureUnit;
precipitation_unit: string;
forecast: WeatherForecast[];
forecast?: WeatherForecast[];
supported_features: WeatherEntityFeature;
};
}

Expand Down Expand Up @@ -93,3 +100,8 @@ export interface TemperatureSensor extends HassEntity {
unit_of_measurement?: TemperatureUnit;
};
}

export type WeatherForecastEvent = {
forecast: WeatherForecast[];
type: "hourly" | "daily" | "twice_daily";
}

0 comments on commit ae865d6

Please sign in to comment.