1
0
Fork 0

Apply home-assistant

This commit is contained in:
Malte Brandy 2021-12-06 14:32:32 +01:00
parent 3b856af81f
commit 443121705a
5 changed files with 665 additions and 50 deletions

View file

@ -3,23 +3,18 @@
let
#wireguard = import ../../../common/wireguard.nix;
#inherit (config.m-0) hosts prefix;
#nixos-unstable = (import ../../../nix/sources.nix).nixos-unstable;
#inherit (import ../../../common/common.nix { inherit pkgs; }) syncthing;
in
{
#disabledModules = [
# "services/misc/home-assistant.nix"
#];
imports = [
#"${nixos-unstable}/nixos/modules/services/misc/home-assistant.nix"
./hardware-configuration.nix
../../roles
../../roles/admin.nix
../../roles/fonts.nix
../../roles/earlyoom.nix
../../roles/standalone
../../roles/home-assistant-local
];
fileSystems =
@ -58,6 +53,7 @@ in
systemd.tmpfiles.rules = [
"d /disk/persist/root 700 root root - -"
"d /disk/persist/root/.ssh 700 root root - -"
"d /disk/persist/etc/ssh 755 root root - -"
"d /disk/persist/maralorn 700 maralorn users - -"
"d /home/maralorn/.config 700 maralorn users - -"
"z / 755 - - - -"
@ -65,8 +61,8 @@ in
"d /disk/volatile/maralorn 700 maralorn users - -"
"d /disk/persist/var/lib/hass - - - - -"
"d /tmp/scans/scans 777 ftp ftp - -"
"L+ /var/lib/waydroid - - - - /disk/persist/var/lib/waydroid"
"L+ /root/.ssh - - - - /disk/persist/root/.ssh"
"L+ /etc/ssh - - - - /disk/persist/etc/ssh"
];
boot = {
@ -127,43 +123,20 @@ in
};
security.rtkit.enable = true;
hardware.printers.ensurePrinters = [
{
name = "Klio";
location = "Wohnzimmer";
description = "Brother MFC-L3750CDW";
deviceUri = "ipp://klio.lo.m-0.eu/ipp";
model = "everywhere";
}
];
hardware.printers = {
ensureDefaultPrinter = "Klio";
ensurePrinters = [
{
name = "Klio";
location = "Wohnzimmer";
description = "Brother MFC-L3750CDW";
deviceUri = "ipp://klio.lo.m-0.eu/ipp";
model = "everywhere";
}
];
};
services = {
nginx = {
enable = true;
virtualHosts = {
"home.lo.m-0.eu" = {
extraConfig = "proxy_buffering off;";
locations."/" = {
proxyPass = "http://[::1]:8123";
proxyWebsockets = true;
};
};
"fluffy.lo.m-0.eu" = {
default = true;
locations."/".extraConfig = "return 301 http://home.lo.m-0.eu$request_uri;";
};
};
};
home-assistant = {
enable = true;
configDir = "/disk/persist/var/lib/hass";
config = {
met = { };
default_config = { };
zha = { };
ipp = { };
brother = { };
};
};
unbound.enable = true;
fwupd.enable = true;
#upower.enable = true;
printing.enable = true;

View file

@ -0,0 +1,133 @@
{ pkgs, ... }:
let
inherit (import ../../../nix/sources.nix) nixos-unstable;
in
{
disabledModules = [
"services/misc/home-assistant.nix"
];
imports = [
"${nixos-unstable}/nixos/modules/services/misc/home-assistant.nix"
./hexa-cards.nix
];
systemd.tmpfiles.rules = [
"d /disk/persist/var/lib/hass - - - - -"
];
services = {
home-assistant = {
enable = true;
package = pkgs.home-assistant.overrideAttrs (
oldAttrs: {
doInstallCheck = false;
patches = (oldAttrs.patches or [ ]) ++ [ ./warnwetter.patch ];
}
);
configDir = "/disk/persist/var/lib/hass";
config = {
homeassistant = {
name = "Kiesstraße 10, 1. OG, links";
latitude = "49.8766";
longitude = "8.6524";
elevation = "150";
unit_system = "metric";
currency = "EUR";
time_zone = "Europe/Berlin";
external_url = "http://home.wg.m-0.eu";
internal_url = "http://home.lo.m-0.eu";
};
automation = { };
history = { };
image = { };
sun = { };
logbook = { };
config = { };
mobile_app = { };
recorder = { };
ssdp = { };
system_health = { };
zha = { };
ipp = { };
brother = { };
sensor = [
{
platform = "rmvtransport";
next_departure = [
{
station = "3024634";
}
];
}
];
weather = [
{
platform = "warnwetter";
name = "DWD Darmstadt";
station_id = "L886";
}
];
http = {
use_x_forwarded_for = true;
trusted_proxies = [ "::1" ];
};
prometheus = {
namespace = "hass";
};
};
lovelaceConfig = {
views = [
{
title = "Kiesstraße 10, 1. OG, links";
cards = [
{
type = "weather-forecast";
entity = "weather.dwd_darmstadt";
}
{
type = "custom:sun-card";
}
{
type = "picture";
image = "https://www.dwd.de/DWD/wetter/radar/radfilm_hes_akt.gif";
}
#{
# type = "history-graph";
# entities = [
# "sensor.pegasus_battery_level"
# "sensor.pegasus_battery_state"
# "sensor.kalliope_battery_level"
# "sensor.kalliope_battery_state"
# ];
#}
{
type = "custom:rmv-card";
entity = "sensor.darmstadt_schulstrasse";
}
];
}
];
};
};
nginx = {
enable = true;
virtualHosts = {
"home.lo.m-0.eu" = {
extraConfig = "proxy_buffering off;";
locations."/" = {
proxyPass = "http://[::1]:8123";
proxyWebsockets = true;
};
locations."/custom/" = {
alias = "/run/hass/";
};
};
"fluffy.lo.m-0.eu" = {
default = true;
locations."/".extraConfig = "return 301 http://home.lo.m-0.eu$request_uri;";
};
};
};
};
}

View file

@ -0,0 +1,35 @@
{ pkgs, ... }:
let
nur = import pkgs.sources.hexa-nur-packages { };
mkLovelaceModule = name: {
url = "custom/${name}.js?${nur.hassLovelaceModules."${name}".version}";
type = "module";
};
in
{
systemd.tmpfiles.rules = [
# Lovelace Cards
"d /run/hass 0700 nginx nginx"
"L+ /run/hass/mini-graph-card.js - - - - ${nur.hassLovelaceModules.mini-graph-card}/mini-graph-card-bundle.js"
"L+ /run/hass/mini-media-player.js - - - - ${nur.hassLovelaceModules.mini-media-player}/mini-media-player-bundle.js"
"L+ /run/hass/multiple-entity-row.js - - - - ${nur.hassLovelaceModules.multiple-entity-row}/multiple-entity-row.js"
"L+ /run/hass/sun-card.js - - - - ${nur.hassLovelaceModules.sun-card}/sun-card.js"
"L+ /run/hass/swipe-navigation.js - - - - ${nur.hassLovelaceModules.swipe-navigation}/swipe-navigation.js"
"L+ /run/hass/rmv-card.js - - - - ${nur.hassLovelaceModules.rmv-card}/rmv-card.js"
"L+ /run/hass/weather-card-chart.js - - - - ${nur.hassLovelaceModules.weather-card-chart}/weather-card-chart.js"
];
services.home-assistant.config.lovelace = {
resources = [
(mkLovelaceModule "mini-graph-card")
(mkLovelaceModule "mini-media-player")
(mkLovelaceModule "multiple-entity-row")
(mkLovelaceModule "rmv-card")
(mkLovelaceModule "weather-card-chart")
(mkLovelaceModule "sun-card")
(mkLovelaceModule "swipe-navigation")
];
};
}

View file

@ -0,0 +1,481 @@
From 92f85569b2ec8beabfb7ea6aea462fba5e5af39d Mon Sep 17 00:00:00 2001
From: Martin Weinelt <hexa@darmstadt.ccc.de>
Date: Sat, 20 Mar 2021 17:33:14 +0100
Subject: [PATCH] warnwetter: init
---
CODEOWNERS | 1 +
.../components/warnwetter/__init__.py | 1 +
.../components/warnwetter/manifest.json | 7 +
homeassistant/components/warnwetter/sensor.py | 302 ++++++++++++++++++
.../components/warnwetter/weather.py | 115 +++++++
5 files changed, 426 insertions(+)
create mode 100644 homeassistant/components/warnwetter/__init__.py
create mode 100644 homeassistant/components/warnwetter/manifest.json
create mode 100644 homeassistant/components/warnwetter/sensor.py
create mode 100644 homeassistant/components/warnwetter/weather.py
diff --git a/CODEOWNERS b/CODEOWNERS
index 0e069f94e7..596beebec8 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -525,6 +525,7 @@ homeassistant/components/vlc_telnet/* @rodripf @dmcc
homeassistant/components/volkszaehler/* @fabaff
homeassistant/components/volumio/* @OnFreund
homeassistant/components/waqi/* @andrey-git
+homeassistant/components/warnwetter/* @mtdcr
homeassistant/components/watson_tts/* @rutkai
homeassistant/components/weather/* @fabaff
homeassistant/components/webostv/* @bendavid
diff --git a/homeassistant/components/warnwetter/__init__.py b/homeassistant/components/warnwetter/__init__.py
new file mode 100644
index 0000000000..538fc5a2dc
--- /dev/null
+++ b/homeassistant/components/warnwetter/__init__.py
@@ -0,0 +1 @@
+"""The warnwetter component."""
diff --git a/homeassistant/components/warnwetter/manifest.json b/homeassistant/components/warnwetter/manifest.json
new file mode 100644
index 0000000000..cf37e4824e
--- /dev/null
+++ b/homeassistant/components/warnwetter/manifest.json
@@ -0,0 +1,7 @@
+{
+ "domain": "warnwetter",
+ "name": "DWD WarnWetter API",
+ "documentation": "https://www.home-assistant.io/integrations/warnwetter",
+ "dependencies": ["weather"],
+ "codeowners": ["@mtdcr"]
+}
diff --git a/homeassistant/components/warnwetter/sensor.py b/homeassistant/components/warnwetter/sensor.py
new file mode 100644
index 0000000000..65bbe2bdce
--- /dev/null
+++ b/homeassistant/components/warnwetter/sensor.py
@@ -0,0 +1,302 @@
+"""Sensor platform for data from WarnWetter."""
+from datetime import datetime, timedelta
+import json
+import logging
+from typing import Any, Dict, Optional, Union
+
+from aiohttp.hdrs import USER_AGENT
+import pytz
+import requests
+import voluptuous as vol
+
+from homeassistant.components.weather import (
+ ATTR_FORECAST_CONDITION,
+ ATTR_FORECAST_PRECIPITATION,
+ ATTR_FORECAST_TEMP,
+ ATTR_FORECAST_TEMP_LOW,
+ ATTR_FORECAST_TIME,
+ ATTR_FORECAST_WIND_BEARING,
+ ATTR_FORECAST_WIND_SPEED,
+)
+from homeassistant.const import (
+ ATTR_ATTRIBUTION,
+ ATTR_ICON,
+ ATTR_TEMPERATURE,
+ ATTR_TIME,
+ CONF_MONITORED_CONDITIONS,
+ CONF_NAME,
+ DEGREE,
+ DEVICE_CLASS_HUMIDITY,
+ DEVICE_CLASS_PRESSURE,
+ DEVICE_CLASS_TEMPERATURE,
+ DEVICE_CLASS_TIMESTAMP,
+ PERCENTAGE,
+ PRESSURE_HPA,
+ SPEED_KILOMETERS_PER_HOUR,
+ TEMP_CELSIUS,
+ TIME_HOURS,
+ TIME_MINUTES,
+ __version__,
+)
+import homeassistant.helpers.config_validation as cv
+from homeassistant.helpers.entity import Entity
+from homeassistant.util import Throttle
+
+_LOGGER = logging.getLogger(__name__)
+
+ATTR_STATION = "station"
+ATTR_UPDATED = "updated"
+ATTRIBUTION = "Data provided by WarnWetter"
+
+CONF_STATION_ID = "station_id"
+
+MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
+MIN_TIME_BETWEEN_FORECAST_UPDATES = timedelta(minutes=30)
+
+ATTR_DEWPOINT = "dewpoint"
+ATTR_HUMIDITY = "humidity"
+ATTR_MAXWIND = "maxwind"
+ATTR_MEANWIND = "meanwind"
+ATTR_PRECIPITATION = "precipitation"
+ATTR_PRECIPITATION3H = "precipitation3h"
+ATTR_PRESSURE = "pressure"
+ATTR_SUNSHINE = "sunshine"
+ATTR_TOTALSNOW = "totalsnow"
+ATTR_WINDDIRECTION = "winddirection"
+
+SENSOR_TYPES = {
+ ATTR_DEWPOINT: ("Dew Point", DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, 10),
+ ATTR_HUMIDITY: ("Humidity", DEVICE_CLASS_HUMIDITY, PERCENTAGE, 10),
+ ATTR_ICON: ("Icon", None, None, 1),
+ ATTR_MAXWIND: ("Top Wind Speed", None, SPEED_KILOMETERS_PER_HOUR, 10),
+ ATTR_MEANWIND: ("Wind Speed", None, SPEED_KILOMETERS_PER_HOUR, 10),
+ ATTR_PRECIPITATION: ("Precipitation", None, f"mm/{TIME_HOURS}", 10),
+ ATTR_PRECIPITATION3H: (
+ f"Precipitation 3{TIME_HOURS}",
+ None,
+ f"mm/3{TIME_HOURS}",
+ 10,
+ ),
+ ATTR_PRESSURE: ("Pressure", DEVICE_CLASS_PRESSURE, PRESSURE_HPA, 10),
+ ATTR_SUNSHINE: ("Sun Last Hour", None, TIME_MINUTES, 10),
+ ATTR_TEMPERATURE: ("Temperature", DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, 10),
+ ATTR_TIME: ("Update Time", DEVICE_CLASS_TIMESTAMP, None, 1000),
+ ATTR_TOTALSNOW: ("Snow", None, "cm", 10),
+ ATTR_WINDDIRECTION: ("Wind Bearing", None, DEGREE, 10),
+}
+
+CONDITION_CLASSES = {
+ "cloudy": {4},
+ "fog": {5, 6},
+ "hail": {17, 24, 25},
+ "lightning": {26},
+ "lightning-rainy": {27, 28, 29, 30},
+ "partlycloudy": {2, 3},
+ "pouring": {18, 19},
+ "rainy": {7, 8, 9, 10, 11},
+ "snowy": {14, 15, 16, 22, 23},
+ "snowy-rainy": {12, 13, 20, 21},
+ "sunny": {1},
+ "windy": {31},
+}
+
+PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
+ {
+ vol.Required(CONF_MONITORED_CONDITIONS, default=["temperature"]): vol.All(
+ cv.ensure_list, [vol.In(SENSOR_TYPES)]
+ ),
+ vol.Required(CONF_STATION_ID): cv.string,
+ vol.Required(CONF_NAME): cv.string,
+ }
+)
+
+
+def setup_platform(hass, config, add_entities, discovery_info=None):
+ """Set up the WarnWetter sensor platform."""
+ name = config[CONF_NAME]
+ probe = WarnWetterMeasurements(config[CONF_STATION_ID])
+
+ add_entities(
+ [
+ WarnWetterSensor(probe, variable, name)
+ for variable in config[CONF_MONITORED_CONDITIONS]
+ ],
+ True,
+ )
+
+
+class WarnWetterSensor(Entity):
+ """Implementation of a WarnWetter sensor."""
+
+ def __init__(self, probe, variable, name):
+ """Initialize the sensor."""
+ self.probe = probe
+ self.client_name = name
+ self.variable = variable
+
+ @property
+ def unique_id(self) -> Optional[str]:
+ """Return a unique ID."""
+ return f"{self.probe.station_id}:{self.variable}"
+
+ @property
+ def name(self) -> Optional[str]:
+ """Return the name of the entity."""
+ return f"{self.client_name} {SENSOR_TYPES[self.variable][0]}"
+
+ @property
+ def state(self) -> Union[None, str, int, float]:
+ """Return the state of the entity."""
+ return self.probe.data.get(self.variable)
+
+ @property
+ def device_state_attributes(self) -> Optional[Dict[str, Any]]:
+ """Return device specific state attributes."""
+ return {
+ ATTR_ATTRIBUTION: ATTRIBUTION,
+ ATTR_STATION: self.probe.station_id,
+ ATTR_UPDATED: self.probe.last_update.isoformat(),
+ }
+
+ @property
+ def device_class(self) -> Optional[str]:
+ """Return the class of this device, from component DEVICE_CLASSES."""
+ return SENSOR_TYPES[self.variable][1]
+
+ @property
+ def unit_of_measurement(self) -> Optional[str]:
+ """Return the unit of measurement of this entity, if any."""
+ return SENSOR_TYPES[self.variable][2]
+
+ def update(self):
+ """Delegate update to probe."""
+ self.probe.update()
+
+
+class WarnWetterClient:
+ """Base class for static json data."""
+
+ API_URL = "https://s3.eu-central-1.amazonaws.com/app-prod-static.warnwetter.de/v16/%s_%s.json"
+ API_HEADERS = {USER_AGENT: f"home-assistant.warnwetter/ {__version__}"}
+
+ def __init__(self, resource, station_id, interval_h):
+ """Initialize WarnWetterClient."""
+ self._station_id = station_id
+ self._api_url = self.API_URL % (resource, station_id)
+ self._interval_h = interval_h
+ self.data = {}
+
+ @property
+ def station_id(self):
+ """Return station ID."""
+ return self._station_id
+
+ @property
+ def last_update(self):
+ """Return the timestamp of the most recent data."""
+ time = self.data.get("time")
+ if time is not None:
+ return datetime.fromtimestamp(int(time)).replace(
+ tzinfo=pytz.timezone("Europe/Berlin")
+ )
+
+ def _current_observations(self):
+ """Fetch the latest JSON data."""
+ try:
+ response = requests.get(self._api_url, headers=self.API_HEADERS, timeout=15)
+ response.raise_for_status()
+ return json.loads(response.content)
+ except requests.exceptions.HTTPError:
+ _LOGGER.error("While fetching data")
+
+ def _fetch_json(self):
+ """Get the latest data from WarnWetter."""
+ if self.last_update and (
+ self.last_update + timedelta(hours=self._interval_h)
+ > datetime.utcnow().replace(tzinfo=pytz.utc)
+ ):
+ return None
+
+ return self._current_observations()
+
+ @classmethod
+ def _icons_to_condition(cls, icons):
+ """Convert icon numbers to conditions (first match)."""
+ for icon in icons:
+ for key, val in CONDITION_CLASSES.items():
+ if icon in val:
+ return key
+
+
+class WarnWetterForecast(WarnWetterClient):
+ """A class consuming forecast data."""
+
+ def __init__(self, station_id):
+ """Initialize WarnWetterForecast."""
+ super().__init__("forecast_mosmix", station_id, 4)
+
+ @Throttle(MIN_TIME_BETWEEN_FORECAST_UPDATES)
+ def update(self):
+ """Update state."""
+ src = self._fetch_json()
+ if not src:
+ return
+
+ data = {
+ "forecast": [],
+ }
+ for key, value in src.items():
+ if key == "days" and isinstance(value, list):
+ for day in value:
+ data["forecast"].append(
+ {
+ ATTR_FORECAST_TIME: day.get("dayDate"),
+ ATTR_FORECAST_TEMP_LOW: day.get("temperatureMin") / 10.0,
+ ATTR_FORECAST_TEMP: day.get("temperatureMax") / 10.0,
+ ATTR_FORECAST_CONDITION: self._condition(day),
+ ATTR_FORECAST_PRECIPITATION: day.get("precipitation")
+ / 10.0,
+ ATTR_FORECAST_WIND_SPEED: day.get("windSpeed") / 10.0,
+ ATTR_FORECAST_WIND_BEARING: day.get("windDirection") / 10.0,
+ # ATTR_FORECAST_WIND_GUST: day.get('windGust') / 10.0,
+ # ATTR_FORECAST_SUNSHINE: day.get('sunshine') / 10.0,
+ }
+ )
+
+ elif key == "forecast" and isinstance(value, dict):
+ data["time"] = value.get("start", 0) // 1000
+
+ self.data = data
+
+ @classmethod
+ def _condition(cls, day):
+ keys = ("icon", "icon1", "icon2")
+ icons = filter(None, (day.get(icon) for icon in keys))
+ return cls._icons_to_condition(icons)
+
+
+class WarnWetterMeasurements(WarnWetterClient):
+ """A class consuming measured data."""
+
+ def __init__(self, station_id):
+ """Initialize WarnWetterMeasurements."""
+ super().__init__("current_measurement", station_id, 1)
+
+ @Throttle(MIN_TIME_BETWEEN_UPDATES)
+ def update(self):
+ """Update state."""
+ src = self._fetch_json()
+ if not src:
+ return
+
+ data = {}
+ for key, value in src.items():
+ spec = SENSOR_TYPES.get(key)
+ if spec:
+ if isinstance(value, int) and value != 32767:
+ if key == "icon":
+ data[key] = self._icons_to_condition([value])
+ else:
+ data[key] = value / spec[3]
+
+ self.data = data
diff --git a/homeassistant/components/warnwetter/weather.py b/homeassistant/components/warnwetter/weather.py
new file mode 100644
index 0000000000..f00155c2bf
--- /dev/null
+++ b/homeassistant/components/warnwetter/weather.py
@@ -0,0 +1,115 @@
+"""Weather platform for data from WarnWetter."""
+import logging
+from typing import Optional
+
+import voluptuous as vol
+
+from homeassistant.components.weather import (
+ ATTR_FORECAST_CONDITION,
+ PLATFORM_SCHEMA,
+ WeatherEntity,
+)
+from homeassistant.const import ATTR_ICON, ATTR_TEMPERATURE, CONF_NAME, TEMP_CELSIUS
+from homeassistant.helpers import config_validation as cv
+
+# Reuse data and API logic from the sensor implementation
+from .sensor import (
+ ATTR_HUMIDITY,
+ ATTR_MEANWIND,
+ ATTR_PRESSURE,
+ ATTR_WINDDIRECTION,
+ ATTRIBUTION,
+ CONF_STATION_ID,
+ WarnWetterForecast,
+ WarnWetterMeasurements,
+)
+
+_LOGGER = logging.getLogger(__name__)
+
+PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
+ {vol.Required(CONF_NAME): cv.string, vol.Required(CONF_STATION_ID): cv.string}
+)
+
+
+def setup_platform(hass, config, add_entities, discovery_info=None):
+ """Set up the WarnWetter weather platform."""
+ mprobe = WarnWetterMeasurements(config[CONF_STATION_ID])
+ fprobe = WarnWetterForecast(config[CONF_STATION_ID])
+ entity = WarnWetterWeather(mprobe, fprobe, config[CONF_NAME])
+ add_entities([entity], True)
+
+
+class WarnWetterWeather(WeatherEntity):
+ """Representation of a weather condition."""
+
+ def __init__(self, mprobe, fprobe, stationname):
+ """Initialize WarnWetterWeather."""
+ self.mprobe = mprobe
+ self.fprobe = fprobe
+ self.stationname = stationname
+
+ @property
+ def unique_id(self) -> Optional[str]:
+ """Return a unique ID."""
+ return self.mprobe.station_id
+
+ @property
+ def name(self) -> Optional[str]:
+ """Return the name of the entity."""
+ return self.stationname
+
+ @property
+ def temperature(self):
+ """Return the platform temperature."""
+ return self.mprobe.data.get(ATTR_TEMPERATURE)
+
+ @property
+ def temperature_unit(self):
+ """Return the unit of measurement."""
+ return TEMP_CELSIUS
+
+ @property
+ def pressure(self):
+ """Return the pressure."""
+ return self.mprobe.data.get(ATTR_PRESSURE)
+
+ @property
+ def humidity(self):
+ """Return the humidity."""
+ return self.mprobe.data.get(ATTR_HUMIDITY)
+
+ @property
+ def wind_speed(self):
+ """Return the wind speed."""
+ return self.mprobe.data.get(ATTR_MEANWIND)
+
+ @property
+ def wind_bearing(self):
+ """Return the wind bearing."""
+ return self.mprobe.data.get(ATTR_WINDDIRECTION)
+
+ @property
+ def attribution(self):
+ """Return the attribution."""
+ return ATTRIBUTION
+
+ @property
+ def forecast(self):
+ """Return the forecast."""
+ return self.fprobe.data.get("forecast")
+
+ @property
+ def condition(self):
+ """Return the current condition."""
+ icon = self.mprobe.data.get(ATTR_ICON)
+ if icon:
+ return icon
+
+ forecast = self.forecast
+ if forecast:
+ return forecast[0].get(ATTR_FORECAST_CONDITION)
+
+ def update(self):
+ """Update state."""
+ self.mprobe.update()
+ self.fprobe.update()
--
2.30.1

View file

@ -12,13 +12,6 @@
);
config = {
default_config = { };
panel_iframe = {
graphen = { title = "Graphen"; url = "https://stats.maralorn.de/?kiosk"; icon = "mdi:chart-line"; };
tasks = { title = "Tasks"; url = "https://tasks.maralorn.de"; icon = "mdi:format-list-checks"; };
ci = { title = "CI"; url = "https://ci.maralorn.de"; icon = "mdi:code-tags-check"; };
monitoring = { title = "Monitoring"; url = "https://monitoring.maralorn.de/alerts"; icon = "mdi:binoculars"; };
alerts = { title = "Alerts"; url = "https://alerts.maralorn.de"; icon = "mdi:bell"; };
};
sensor = [
{
platform = "rmvtransport";