diff --git a/scripts/translations/fetch.py b/scripts/translations/fetch.py
index 3afc718b..a2e490dc 100755
--- a/scripts/translations/fetch.py
+++ b/scripts/translations/fetch.py
@@ -100,6 +100,8 @@ def process_dir(_dir, _output, _keys):
("return_home", ["ui.dialogs.more_info_control.vacuum.return_home"]),
("start_pause", ["ui.dialogs.more_info_control.vacuum.start_pause"]),
("battery", ["ui.dialogs.entity_registry.editor.device_classes.binary_sensor.battery"]),
+ ("weather_forecast", ["ui.panel.lovelace.editor.card.weather-forecast.name"]),
+ ("count", ["ui.panel.config.automation.editor.actions.type.repeat.count"]),
("set_white", ["ui.dialogs.more_info_control.light.set_white"]),
("vacuum_commands", ["ui.dialogs.more_info_control.vacuum.commands"]),
("target", ["ui.card.water_heater.target"]),
diff --git a/src/lib/Modal/SidebarItemConfig.svelte b/src/lib/Modal/SidebarItemConfig.svelte
index ce8742f0..df9981d9 100644
--- a/src/lib/Modal/SidebarItemConfig.svelte
+++ b/src/lib/Modal/SidebarItemConfig.svelte
@@ -22,6 +22,7 @@
import Divider from '$lib/Sidebar/Divider.svelte';
import Navigate from '$lib/Sidebar/Navigate.svelte';
import Weather from '$lib/Sidebar/Weather.svelte';
+ import WeatherForecast from '$lib/Sidebar/WeatherForecast.svelte';
import Iframe from '$lib/Sidebar/Iframe.svelte';
import Image from '$lib/Sidebar/Image.svelte';
import Camera from '$lib/Sidebar/Camera.svelte';
@@ -180,6 +181,14 @@
entity_id: 'weather.openweathermap'
}
},
+ {
+ id: 'weatherforecast',
+ type: $lang('weather_forecast'),
+ component: WeatherForecast,
+ props: {
+ entity_id: 'weather.forecast_home'
+ }
+ },
{
id: 'navigate',
type: $lang('navigate'),
@@ -230,6 +239,9 @@
case 'weather':
openModal(() => import('$lib/Modal/WeatherConfig.svelte'), { sel });
break;
+ case 'weatherforecast':
+ openModal(() => import('$lib/Modal/WeatherForecastConfig.svelte'), { sel });
+ break;
case 'camera':
openModal(() => import('$lib/Modal/CameraConfig.svelte'), {
sel,
diff --git a/src/lib/Modal/WeatherForecastConfig.svelte b/src/lib/Modal/WeatherForecastConfig.svelte
new file mode 100644
index 00000000..b67a7546
--- /dev/null
+++ b/src/lib/Modal/WeatherForecastConfig.svelte
@@ -0,0 +1,118 @@
+
+
+{#if isOpen}
+
+ {$lang('weather_forecast')}
+
+ {$lang('preview')}
+
+
+
+
+
+ {$lang('entity')}
+
+ {#if weatherStates}
+
+{/if}
diff --git a/src/lib/Sidebar/Index.svelte b/src/lib/Sidebar/Index.svelte
index 3ef0a965..1ed91e7c 100644
--- a/src/lib/Sidebar/Index.svelte
+++ b/src/lib/Sidebar/Index.svelte
@@ -28,6 +28,7 @@
let Time: typeof import('$lib/Sidebar/Time.svelte');
let Timer: typeof import('$lib/Sidebar/Timer.svelte');
let Weather: typeof import('$lib/Sidebar/Weather.svelte');
+ let WeatherForecast: typeof import('$lib/Sidebar/WeatherForecast.svelte');
const importsMap = {
bar: () => import('$lib/Sidebar/Bar.svelte').then((module) => (Bar = module)),
@@ -45,7 +46,9 @@
template: () => import('$lib/Sidebar/Template.svelte').then((module) => (Template = module)),
time: () => import('$lib/Sidebar/Time.svelte').then((module) => (Time = module)),
timer: () => import('$lib/Sidebar/Timer.svelte').then((module) => (Timer = module)),
- weather: () => import('$lib/Sidebar/Weather.svelte').then((module) => (Weather = module))
+ weather: () => import('$lib/Sidebar/Weather.svelte').then((module) => (Weather = module)),
+ weatherforecast: () =>
+ import('$lib/Sidebar/WeatherForecast.svelte').then((module) => (WeatherForecast = module))
};
$: if ($dashboard?.sidebar) importComponents();
@@ -114,6 +117,8 @@
openModal(() => import('$lib/Modal/TimerConfig.svelte'), { sel });
} else if (sel?.type === 'weather') {
openModal(() => import('$lib/Modal/WeatherConfig.svelte'), { sel });
+ } else if (sel?.type === 'weatherforecast') {
+ openModal(() => import('$lib/Modal/WeatherForecastConfig.svelte'), { sel });
} else {
openModal(() => import('$lib/Modal/SidebarItemConfig.svelte'), { sel });
@@ -325,6 +330,17 @@
show_apparent={item?.show_apparent}
/>
+
+
+ {:else if WeatherForecast && item?.type === 'weatherforecast'}
+
{/if}
{/each}
diff --git a/src/lib/Sidebar/WeatherForecast.svelte b/src/lib/Sidebar/WeatherForecast.svelte
new file mode 100644
index 00000000..87d767c4
--- /dev/null
+++ b/src/lib/Sidebar/WeatherForecast.svelte
@@ -0,0 +1,155 @@
+
+
+{#if entity_state}
+
+ {#each forecast as forecast, i}
+
+
+ {#if forecast_diff < 24}
+ {new Intl.DateTimeFormat($selectedLanguage, { hour: 'numeric' }).format(
+ new Date(forecast.date)
+ )}
+ {:else}
+ {new Intl.DateTimeFormat($selectedLanguage, { weekday: 'short' }).format(
+ new Date(forecast.date)
+ )}
+ {/if}
+
+
+ {#if forecast.icon.local}
+
+
+
+ {:else}
+
+ {/if}
+
+
+ {Math.round(forecast.temperature)}{attributes?.temperature_unit || '°'}
+
+
+ {/each}
+
+{:else}
+
+ {$lang('weather_forecast')}
+
+{/if}
+
+
diff --git a/src/lib/Types.ts b/src/lib/Types.ts
index 1d3ad6b5..6af8cc61 100644
--- a/src/lib/Types.ts
+++ b/src/lib/Types.ts
@@ -83,6 +83,7 @@ export type SidebarItem = BarItem &
TemplateItem &
TimeItem &
WeatherItem &
+ WeatherForecastItem &
DividerItem;
export interface BarItem {
@@ -198,3 +199,12 @@ export interface WeatherItem {
extra_sensor_icon?: string;
show_apparent?: boolean;
}
+
+export interface WeatherForecastItem {
+ type?: string;
+ id?: number;
+ entity_id?: string;
+ state?: string;
+ icon_pack?: string;
+ number_of_items?: number;
+}
diff --git a/src/lib/Weather.ts b/src/lib/Weather.ts
new file mode 100644
index 00000000..283785de
--- /dev/null
+++ b/src/lib/Weather.ts
@@ -0,0 +1,253 @@
+import { readable } from 'svelte/store';
+
+// A set of icons, e.g. meteocons, weather icons
+export interface WeatherIconSet {
+ type: string;
+ conditions: WeatherIconConditions;
+}
+
+// Conditions as defined in
+export interface WeatherIconConditions {
+ 'clear-night': WeatherIconMapping;
+ cloudy: WeatherIconMapping;
+ fog: WeatherIconMapping;
+ hail: WeatherIconMapping;
+ lightning: WeatherIconMapping;
+ 'lightning-rainy': WeatherIconMapping;
+ partlycloudy: WeatherIconMapping;
+ pouring: WeatherIconMapping;
+ rainy: WeatherIconMapping;
+ snowy: WeatherIconMapping;
+ 'snowy-rainy': WeatherIconMapping;
+ sunny: WeatherIconMapping;
+ windy: WeatherIconMapping;
+ 'windy-variant': WeatherIconMapping;
+ exceptional: WeatherIconMapping;
+}
+
+// Icon variants for day & night. Icons which are either-or should be the same icon (clear-night, sunny, potentially others depending on the library)
+export interface WeatherIconMapping {
+ local?: boolean;
+ icon_variant_day: string;
+ icon_variant_night: string;
+}
+
+export const iconMapMaterialSymbolsLight: WeatherIconSet = {
+ type: 'materialsymbolslight',
+ conditions: {
+ 'clear-night': {
+ icon_variant_day: 'material-symbols-light:bedtime-outline-rounded',
+ icon_variant_night: 'material-symbols-light:bedtime-outline-rounded'
+ },
+ cloudy: {
+ icon_variant_day: 'material-symbols-light:cloud-outline',
+ icon_variant_night: 'material-symbols-light:cloud-outline'
+ },
+ exceptional: {
+ icon_variant_day: 'material-symbols-light:warning-outline-rounded',
+ icon_variant_night: 'material-symbols-light:warning-outline-rounded'
+ },
+ fog: {
+ icon_variant_day: 'material-symbols-light:foggy-outline',
+ icon_variant_night: 'material-symbols-light:foggy-outline'
+ },
+ hail: {
+ icon_variant_day: 'material-symbols-light:weather-hail-outline-rounded',
+ icon_variant_night: 'material-symbols-light:weather-hail-outline-rounded'
+ },
+ lightning: {
+ icon_variant_day: 'material-symbols-light:thunderstorm-outline-rounded',
+ icon_variant_night: 'material-symbols-light:thunderstorm-outline-rounded'
+ },
+ 'lightning-rainy': {
+ icon_variant_day: 'material-symbols-light:thunderstorm-outline-rounded',
+ icon_variant_night: 'material-symbols-light:thunderstorm-outline-rounded'
+ },
+ partlycloudy: {
+ icon_variant_day: 'material-symbols-light:partly-cloudy-day-outline',
+ icon_variant_night: 'material-symbols-light:nights-stay-outline-rounded'
+ },
+ pouring: {
+ icon_variant_day: 'material-symbols-light:rainy-outline',
+ icon_variant_night: 'material-symbols-light:rainy-outline'
+ },
+ rainy: {
+ icon_variant_day: 'material-symbols-light:rainy-outline',
+ icon_variant_night: 'material-symbols-light:rainy-outline'
+ },
+ snowy: {
+ icon_variant_day: 'material-symbols-light:cloudy-snowing-outline',
+ icon_variant_night: 'material-symbols-light:cloudy-snowing-outline'
+ },
+ 'snowy-rainy': {
+ icon_variant_day: 'material-symbols-light:weather-mix-outline-rounded',
+ icon_variant_night: 'material-symbols-light:weather-mix-outline-rounded'
+ },
+ sunny: {
+ icon_variant_day: 'material-symbols-light:sunny-outline-rounded',
+ icon_variant_night: 'material-symbols-light:sunny-outline-rounded'
+ },
+ windy: {
+ icon_variant_day: 'material-symbols-light:mist',
+ icon_variant_night: 'material-symbols-light:mist'
+ },
+ 'windy-variant': {
+ icon_variant_day: 'material-symbols-light:mistd',
+ icon_variant_night: 'material-symbols-light:mist'
+ }
+ }
+};
+
+export const iconMapMeteocons: WeatherIconSet = {
+ type: 'meteocons',
+ conditions: {
+ 'clear-night': {
+ local: true,
+ icon_variant_day: '/weather/meteocons/clear-night-day',
+ icon_variant_night: '/weather/meteocons/clear-night-night'
+ },
+ cloudy: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/cloudy-day',
+ icon_variant_night: '/weather/meteocons/cloudy-night'
+ },
+ exceptional: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/exceptional-day',
+ icon_variant_night: '/weather/meteocons/exceptional-night'
+ },
+ fog: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/fog-day',
+ icon_variant_night: '/weather/meteocons/fog-night'
+ },
+ hail: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/hail-day',
+ icon_variant_night: '/weather/meteocons/hail-night'
+ },
+ lightning: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/lightning-day',
+ icon_variant_night: '/weather/meteocons/lightning-night'
+ },
+ 'lightning-rainy': {
+ local: true,
+ icon_variant_day: '/weather/meteocons/lightning-rainy-day',
+ icon_variant_night: '/weather/meteocons/lightning-rainy-night'
+ },
+ partlycloudy: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/partlycloudy-day',
+ icon_variant_night: '/weather/meteocons/partlycloudy-night'
+ },
+ pouring: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/pouring-day',
+ icon_variant_night: '/weather/meteocons/pouring-night'
+ },
+ rainy: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/rainy-day',
+ icon_variant_night: '/weather/meteocons/rainy-night'
+ },
+ snowy: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/snowy-day',
+ icon_variant_night: '/weather/meteocons/snowy-night'
+ },
+ 'snowy-rainy': {
+ local: true,
+ icon_variant_day: '/weather/meteocons/snowy-rainy-day',
+ icon_variant_night: '/weather/meteocons/snowy-rainy-night'
+ },
+ sunny: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/sunny-day',
+ icon_variant_night: '/weather/meteocons/sunny-night'
+ },
+ windy: {
+ local: true,
+ icon_variant_day: '/weather/meteocons/windy-day',
+ icon_variant_night: '/weather/meteocons/windy-night'
+ },
+ 'windy-variant': {
+ local: true,
+ icon_variant_day: '/weather/meteocons/windy-variant-day',
+ icon_variant_night: '/weather/meteocons/windy-variant-night'
+ }
+ }
+};
+
+export const iconMapWeatherIcons: WeatherIconSet = {
+ type: 'weathericons',
+ conditions: {
+ 'clear-night': {
+ icon_variant_day: 'wi:night-clear',
+ icon_variant_night: 'wi:night-clear'
+ },
+ cloudy: {
+ icon_variant_day: 'wi:day-cloudy',
+ icon_variant_night: 'wi:night-alt-cloudy'
+ },
+ exceptional: {
+ icon_variant_day: 'wi:na',
+ icon_variant_night: 'wi:na'
+ },
+ fog: {
+ icon_variant_day: 'wi:day-fog',
+ icon_variant_night: 'wi:night-fog'
+ },
+ hail: {
+ icon_variant_day: 'wi:day-hail',
+ icon_variant_night: 'wi:night-alt-hail'
+ },
+ lightning: {
+ icon_variant_day: 'wi:day-lightning',
+ icon_variant_night: 'wi:night-alt-lightning'
+ },
+ 'lightning-rainy': {
+ icon_variant_day: 'wi:day-thunderstorm',
+ icon_variant_night: 'wi:night-alt-thunderstorm'
+ },
+ partlycloudy: {
+ icon_variant_day: 'wi:day-cloudy',
+ icon_variant_night: 'wi:night-alt-cloudy'
+ },
+ pouring: {
+ icon_variant_day: 'wi:day-rain',
+ icon_variant_night: 'wi:night-alt-rain'
+ },
+ rainy: {
+ icon_variant_day: 'wi:day-rain',
+ icon_variant_night: 'wi:night-alt-rain'
+ },
+ snowy: {
+ icon_variant_day: 'wi:day-snow',
+ icon_variant_night: 'wi:night-alt-snow'
+ },
+ 'snowy-rainy': {
+ icon_variant_day: 'wi:day-sleet',
+ icon_variant_night: 'wi:night-alt-sleet'
+ },
+ sunny: {
+ icon_variant_day: 'wi:day-sunny',
+ icon_variant_night: 'wi:day-sunny'
+ },
+ windy: {
+ icon_variant_day: 'wi:strong-wind',
+ icon_variant_night: 'wi:strong-wind'
+ },
+ 'windy-variant': {
+ icon_variant_day: 'wi:strong-wind',
+ icon_variant_night: 'wi:strong-wind'
+ }
+ }
+};
+
+// Weather icon mapping
+export const iconMap = readable>({
+ materialsymbolslight: iconMapMaterialSymbolsLight,
+ meteocons: iconMapMeteocons,
+ weathericons: iconMapWeatherIcons
+});