Files
homelab-infra/ops/glance/config/home.yml
T
Micha 8d01c3537a feat: add glance weather tile from home assistant
custom-api Wetterkachel zieht die Ecowitt-Sensoren live aus HA
(intern http://homeassistant:8123, frontend_net) im Neon-Ops-Stil.
Boeen > 40 km/h werden rot markiert (analog HA-Warnautomation).
Benoetigt GLANCE_HA_TOKEN als Glance-Stack-ENV.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 18:52:43 +02:00

602 lines
30 KiB
YAML

- name: Home
slug: home
width: wide
head-widgets:
- type: search
search-engine: duckduckgo
new-tab: true
autofocus: true
placeholder: Suche im Web oder springe per Bang...
bangs:
- title: Gitea
shortcut: "!git"
url: https://git.kaleschke.info/explore/repos?q={QUERY}
- title: Paperless
shortcut: "!doc"
url: https://paperless.kaleschke.info/documents?query={QUERY}
- title: Nextcloud
shortcut: "!cloud"
url: https://cloud.kaleschke.info/apps/files/?dir=/{QUERY}
- title: Komodo
shortcut: "!komodo"
url: https://komodo.kaleschke.info
- title: Immich
shortcut: "!foto"
url: https://immich.kaleschke.info/search?query={QUERY}
- title: Mealie
shortcut: "!rezept"
url: https://mealie.kaleschke.info/g/home/?search={QUERY}
columns:
- size: small
widgets:
- type: group
widgets:
- type: custom-api
title: Day
body-type: string
skip-json-validation: true
cache: 1s
template: |
{{ $localTime := now }}
{{ $elapsedSeconds := add (mul $localTime.Hour 3600) (mul $localTime.Minute 60) | add $localTime.Second }}
{{ $dayProgress := div (mul $elapsedSeconds 100.0) 86400.0 }}
{{ $gradient := "#70a1ff" }}
{{ if gt $dayProgress 25.0 }}{{ $gradient = "#ff6b6b, #70a1ff" }}{{ end }}
{{ if gt $dayProgress 50.0 }}{{ $gradient = "#ff6b6b, #f8e71c, #7ed6df" }}{{ end }}
{{ if gt $dayProgress 75.0 }}{{ $gradient = "#ff6b6b, #f8e71c, #7ed6df, #70a1ff" }}{{ end }}
<div style="text-align: center;">
<div style="width: 100%; height: 12px; background: #23262f; border: 1px solid color-mix(in srgb, var(--color-text-subdue) 55%, transparent); border-radius: 10px; overflow: hidden;">
<div style="height: 100%; width: {{ $dayProgress }}%; background: linear-gradient(90deg, {{ $gradient }});"></div>
</div>
<div class="size-h1" style="margin-top: 6px;">{{ printf "%.2f" $dayProgress }}% des Tages sind vorbei</div>
</div>
- type: custom-api
title: Month
body-type: string
skip-json-validation: true
cache: 1s
template: |
{{ $localTime := now }}
{{ $month := $localTime.Month }}
{{ $daysInMonth := 31 }}
{{ if eq $month 2 }}{{ $daysInMonth = 28 }}{{ end }}
{{ if or (eq $month 4) (eq $month 6) (eq $month 9) (eq $month 11) }}{{ $daysInMonth = 30 }}{{ end }}
{{ $secondsToday := add (mul $localTime.Hour 3600) (mul $localTime.Minute 60) | add $localTime.Second }}
{{ $daysElapsed := add (sub $localTime.Day 1) (div $secondsToday 86400.0) }}
{{ $monthProgress := mul (div $daysElapsed $daysInMonth) 100.0 }}
{{ $gradient := "#70a1ff" }}
{{ if gt $monthProgress 25.0 }}{{ $gradient = "#ff6b6b, #70a1ff" }}{{ end }}
{{ if gt $monthProgress 50.0 }}{{ $gradient = "#ff6b6b, #f8e71c, #7ed6df" }}{{ end }}
{{ if gt $monthProgress 75.0 }}{{ $gradient = "#ff6b6b, #f8e71c, #7ed6df, #70a1ff" }}{{ end }}
<div style="text-align: center;">
<div style="width: 100%; height: 12px; background: #23262f; border: 1px solid color-mix(in srgb, var(--color-text-subdue) 55%, transparent); border-radius: 10px; overflow: hidden;">
<div style="height: 100%; width: {{ $monthProgress }}%; background: linear-gradient(90deg, {{ $gradient }});"></div>
</div>
<div class="size-h1" style="margin-top: 6px;">{{ printf "%.2f" $monthProgress }}% des Monats sind vorbei</div>
</div>
- type: custom-api
title: Year
body-type: string
skip-json-validation: true
cache: 1s
template: |
{{ $localTime := now }}
{{ $secondsToday := add (mul $localTime.Hour 3600) (mul $localTime.Minute 60) | add $localTime.Second }}
{{ $secondsElapsed := add (mul (sub $localTime.YearDay 1) 86400) $secondsToday }}
{{ $yearProgress := div (mul $secondsElapsed 100.0) (mul 365 86400) }}
{{ $gradient := "#70a1ff" }}
{{ if gt $yearProgress 25.0 }}{{ $gradient = "#ff6b6b, #70a1ff" }}{{ end }}
{{ if gt $yearProgress 50.0 }}{{ $gradient = "#ff6b6b, #f8e71c, #7ed6df" }}{{ end }}
{{ if gt $yearProgress 75.0 }}{{ $gradient = "#ff6b6b, #f8e71c, #7ed6df, #70a1ff" }}{{ end }}
<div style="text-align: center;">
<div style="width: 100%; height: 12px; background: #23262f; border: 1px solid color-mix(in srgb, var(--color-text-subdue) 55%, transparent); border-radius: 10px; overflow: hidden;">
<div style="height: 100%; width: {{ $yearProgress }}%; background: linear-gradient(90deg, {{ $gradient }});"></div>
</div>
<div class="size-h1" style="margin-top: 6px;">{{ printf "%.2f" $yearProgress }}% des Jahres sind vorbei</div>
</div>
- type: clock
hour-format: 24h
show-progress: true
timezones:
- timezone: Europe/Berlin
label: Berlin
- timezone: UTC
label: UTC
- type: custom-api
title: Wetter · KalliHome
title-url: https://home.kaleschke.info
cache: 30s
url: http://homeassistant:8123/api/states/sensor.gw3000a_outdoor_temperature
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
Content-Type: application/json
subrequests:
feels:
url: http://homeassistant:8123/api/states/sensor.gw3000a_feels_like_temperature
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
humidity:
url: http://homeassistant:8123/api/states/sensor.gw3000a_humidity
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
wind:
url: http://homeassistant:8123/api/states/sensor.gw3000a_wind_speed
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
gust:
url: http://homeassistant:8123/api/states/sensor.gw3000a_wind_gust
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
rain:
url: http://homeassistant:8123/api/states/sensor.gw3000a_daily_rain
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
solar:
url: http://homeassistant:8123/api/states/sensor.gw3000a_solar_radiation
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
uv:
url: http://homeassistant:8123/api/states/sensor.gw3000a_uv_index
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
pressure:
url: http://homeassistant:8123/api/states/sensor.gw3000a_relative_pressure
headers:
Authorization: Bearer ${GLANCE_HA_TOKEN}
template: |
{{ $temp := .JSON.String "state" }}
{{ $feels := (.Subrequest "feels").JSON.String "state" }}
{{ $hum := (.Subrequest "humidity").JSON.String "state" }}
{{ $wind := (.Subrequest "wind").JSON.String "state" }}
{{ $gust := (.Subrequest "gust").JSON.String "state" }}
{{ $rain := (.Subrequest "rain").JSON.String "state" }}
{{ $solar := (.Subrequest "solar").JSON.String "state" }}
{{ $uv := (.Subrequest "uv").JSON.String "state" }}
{{ $press := (.Subrequest "pressure").JSON.String "state" }}
{{ $gustF := toFloat $gust }}
{{ $divider := "border-left: 1px solid hsla(220, 40%, 70%, 0.14);" }}
<div class="text-center" style="margin-bottom: 12px;">
<div class="color-highlight size-h2" style="font-weight: 700;">{{ $temp }}°C</div>
<div class="size-h6 color-subdue">gefühlt {{ $feels }}° · {{ $hum }}% feucht</div>
</div>
<div class="flex justify-between text-center" style="margin-bottom: 12px;">
<div style="flex: 1;">
<div class="size-h4 {{ if gt $gustF 40.0 }}color-negative{{ else }}color-highlight{{ end }}">{{ $wind }}</div>
<div class="size-h6 uppercase color-subdue">km/h Wind</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="size-h4 {{ if gt $gustF 40.0 }}color-negative{{ else }}color-highlight{{ end }}">{{ $gust }}</div>
<div class="size-h6 uppercase color-subdue">km/h Böe</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="size-h4 color-highlight">{{ $rain }}</div>
<div class="size-h6 uppercase color-subdue">mm heute</div>
</div>
</div>
<div class="flex justify-between text-center">
<div style="flex: 1;">
<div class="size-h4 color-highlight">{{ $solar }}</div>
<div class="size-h6 uppercase color-subdue">W/m² Solar</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="size-h4 color-highlight">{{ $uv }}</div>
<div class="size-h6 uppercase color-subdue">UV-Index</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="size-h4 color-highlight">{{ $press }}</div>
<div class="size-h6 uppercase color-subdue">hPa Druck</div>
</div>
</div>
- type: weather
location: Berlin, Germany
units: metric
hour-format: 24h
- type: calendar
first-day-of-week: monday
- type: to-do
title: Operator-Notizen
- type: bookmarks
title: Direkte Einstiege
groups:
- title: Core
color: 212 100 50
links:
- title: Komodo
url: https://komodo.kaleschke.info
icon: sh:komodo
- title: Gitea
url: https://git.kaleschke.info
icon: si:gitea
- title: Monitoring
url: https://monitoring.kaleschke.info
icon: si:grafana
- title: Ops
color: 45 70 55
links:
- title: Borg
url: https://borg.kaleschke.info
icon: mdi:archive
- title: Glances
url: https://glances.kaleschke.info
icon: sh:glances
- title: Scrutiny
url: https://scrutiny.kaleschke.info
icon: sh:scrutiny
- size: full
widgets:
- type: server-stats
title: Server Stats
servers:
- type: local
name: Kallilabcore
hide-mountpoints-by-default: false
- type: custom-api
title: Komodo Stacks
title-url: https://komodo.kaleschke.info
cache: 2m
url: http://komodo-core:9120/read
method: POST
body-type: json
body:
type: ListStacks
params: {}
headers:
X-Api-Key: ${GLANCE_KOMODO_API_KEY}
X-Api-Secret: ${GLANCE_KOMODO_API_SECRET}
Content-Type: application/json
template: |
{{ $stacks := .JSON.Array "@this" }}
{{ $total := len $stacks }}
{{ $running := 0 }}
{{ range $stacks }}{{ if eq (.String "info.state") "running" }}{{ $running = add $running 1 }}{{ end }}{{ end }}
{{ $problems := sub $total $running }}
{{ $divider := "border-left: 1px solid hsla(220, 40%, 70%, 0.14);" }}
<div style="display: flex; text-align: center;">
<div style="flex: 1;">
<div class="color-highlight size-h3">{{ $total }}</div>
<div class="size-h6 uppercase color-subdue">Stacks</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="color-positive size-h3">{{ $running }}</div>
<div class="size-h6 uppercase color-subdue">Running</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="{{ if gt $problems 0 }}color-negative{{ else }}color-subdue{{ end }} size-h3">{{ $problems }}</div>
<div class="size-h6 uppercase color-subdue">Auffaellig</div>
</div>
</div>
<div style="height: 5px; margin-top: 14px; border-radius: 999px; overflow: hidden; background: hsla(220, 30%, 60%, 0.12);">
<div style="height: 100%; width: {{ if gt $total 0 }}{{ div (mul $running 100.0) (toFloat $total) }}{{ else }}0{{ end }}%; border-radius: 999px; background: linear-gradient(90deg, hsl(150, 85%, 42%), hsl(172, 95%, 48%));"></div>
</div>
{{ if gt $problems 0 }}
<div style="display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; margin-top: 12px;">
{{ range $stacks }}
{{ if ne (.String "info.state") "running" }}
<span class="size-h6" style="padding: 3px 12px; border-radius: 999px; border: 1px solid hsla(350, 90%, 60%, 0.45); background: hsla(350, 90%, 60%, 0.08); color: var(--color-negative); letter-spacing: 0.05em;">{{ .String "name" }} · {{ .String "info.state" }}</span>
{{ end }}
{{ end }}
</div>
{{ end }}
- type: custom-api
title: Immich
title-url: https://immich.kaleschke.info
cache: 10m
url: http://immich_server:2283/api/server/statistics
headers:
x-api-key: ${GLANCE_IMMICH_API_KEY}
subrequests:
storage:
url: http://immich_server:2283/api/server/storage
headers:
x-api-key: ${GLANCE_IMMICH_API_KEY}
template: |
{{ $photos := .JSON.Int "photos" }}
{{ $videos := .JSON.Int "videos" }}
{{ $usageGiB := div (toFloat (.JSON.Int "usage")) 1073741824.0 }}
{{ $storage := .Subrequest "storage" }}
{{ $storageOK := and (ge $storage.Response.StatusCode 200) (le $storage.Response.StatusCode 299) }}
{{ $percentage := 0.0 }}
{{ if $storageOK }}{{ $percentage = $storage.JSON.Float "diskUsagePercentage" }}{{ end }}
{{ $divider := "border-left: 1px solid hsla(220, 40%, 70%, 0.14);" }}
<div style="display: flex; text-align: center;">
<div style="flex: 1;">
<div class="color-highlight size-h3">{{ $photos | formatNumber }}</div>
<div class="size-h6 uppercase color-subdue">Fotos</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="color-highlight size-h3">{{ $videos | formatNumber }}</div>
<div class="size-h6 uppercase color-subdue">Videos</div>
</div>
<div style="flex: 1; {{ $divider }}">
<div class="color-highlight size-h3">{{ printf "%.0f" $usageGiB }} GiB</div>
<div class="size-h6 uppercase color-subdue">Medien</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 12px; margin-top: 16px;">
<div style="flex: 1; height: 5px; border-radius: 999px; overflow: hidden; background: hsla(220, 30%, 60%, 0.12);">
<div style="height: 100%; width: {{ if $storageOK }}{{ printf "%.1f" $percentage }}%{{ else }}0%{{ end }}; border-radius: 999px; background: linear-gradient(90deg, hsl(205, 100%, 55%), hsl(172, 95%, 48%));"></div>
</div>
<div class="size-h6 color-subdue" style="white-space: nowrap;">{{ if $storageOK }}{{ printf "%.1f" $percentage }}% belegt{{ else }}Speicher API n/v{{ end }}</div>
</div>
- type: group
widgets:
- type: monitor
title: Core
cache: 1m
sites:
- title: AdGuard Home
url: http://192.168.178.58:8082
check-url: http://adguard
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/adguard-home.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Authelia
url: https://auth.kaleschke.info
check-url: http://authelia:9091/api/health
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/authelia.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Gitea
url: https://git.kaleschke.info
check-url: http://gitea:3000/api/healthz
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitea.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Traefik
url: https://traefik.kaleschke.info
check-url: http://traefik:8082/metrics
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/traefik.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Vaultwarden
url: https://vault.kaleschke.info
check-url: http://vaultwarden/alive
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/vaultwarden.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Komodo
url: https://komodo.kaleschke.info
check-url: http://komodo-core:9120
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/komodo.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Glance
url: https://glance.kaleschke.info
check-url: http://glance:8080
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/glance.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- type: monitor
title: Apps
cache: 1m
sites:
- title: Paperless-ngx
url: https://paperless.kaleschke.info
check-url: http://paperless-ngx:8000
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/paperless-ngx.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Paperless-GPT
url: https://paperless-gpt.kaleschke.info
check-url: http://paperless-gpt:8080
icon: mdi:robot
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Immich
url: https://immich.kaleschke.info
check-url: http://immich_server:2283/api/server/ping
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/immich.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Mealie
url: https://mealie.kaleschke.info
check-url: http://mealie:9000
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/mealie.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Nextcloud
url: https://cloud.kaleschke.info
check-url: http://nextcloud/status.php
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/nextcloud.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: ntfy
url: https://ntfy.kaleschke.info
check-url: http://ntfy/v1/health
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/ntfy.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Mail Archiver
url: https://mail.kaleschke.info
check-url: http://mail-archiver:5000
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/mailcow.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: BentoPDF
url: https://pdf.kaleschke.info
check-url: http://bentopdf:8080
icon: mdi:file-pdf-box
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- type: monitor
title: Ops
cache: 1m
sites:
- title: Monitoring Grafana
url: https://monitoring.kaleschke.info
check-url: http://monitoring-grafana:3000/api/health
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/grafana.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Glances
url: https://glances.kaleschke.info
check-url: http://glances:61208
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/glances.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Scrutiny
url: https://scrutiny.kaleschke.info
check-url: http://scrutiny:8080
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/scrutiny.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Speedtest Tracker
url: https://speedtest.kaleschke.info
check-url: http://speedtest-tracker
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/speedtest-tracker.png
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Filebrowser
url: https://files.kaleschke.info
check-url: http://filebrowser
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/filebrowser.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: code-server
url: https://code.kaleschke.info
check-url: http://code-server:8443
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/vscode.svg
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- title: Borg UI
url: https://borg.kaleschke.info
check-url: http://borg-ui:8081
icon: mdi:archive-sync
timeout: 5s
alt-status-codes: [200, 302, 401, 403]
- size: small
widgets:
- type: custom-api
title: Internet
title-url: https://speedtest.kaleschke.info
cache: 1h
url: http://speedtest-tracker/api/v1/results/latest
headers:
Authorization: Bearer ${GLANCE_SPEEDTEST_API_KEY}
Accept: application/json
subrequests:
stats:
url: http://speedtest-tracker/api/v1/stats
headers:
Authorization: Bearer ${GLANCE_SPEEDTEST_API_KEY}
Accept: application/json
template: |
{{ $ip := .JSON.String "external_ip" }}
{{ if eq $ip "" }}{{ $ip = .JSON.String "data.interface.externalIp" }}{{ end }}
{{ if eq $ip "" }}{{ $ip = .JSON.String "data.data.interface.externalIp" }}{{ end }}
{{ $isp := .JSON.String "isp" }}
{{ if eq $isp "" }}{{ $isp = .JSON.String "data.isp" }}{{ end }}
{{ if eq $isp "" }}{{ $isp = .JSON.String "data.data.isp" }}{{ end }}
{{ $download := .JSON.Float "download" }}
{{ if eq $download 0.0 }}{{ $download = .JSON.Float "data.download" }}{{ end }}
{{ if eq $download 0.0 }}{{ $download = div (.JSON.Float "download_bits") 1000000.0 }}{{ end }}
{{ if eq $download 0.0 }}{{ $download = div (.JSON.Float "data.download_bits") 1000000.0 }}{{ end }}
{{ if eq $download 0.0 }}{{ $download = div (mul (.JSON.Float "data.data.download.bandwidth") 8.0) 1000000.0 }}{{ end }}
{{ $upload := .JSON.Float "upload" }}
{{ if eq $upload 0.0 }}{{ $upload = .JSON.Float "data.upload" }}{{ end }}
{{ if eq $upload 0.0 }}{{ $upload = div (.JSON.Float "upload_bits") 1000000.0 }}{{ end }}
{{ if eq $upload 0.0 }}{{ $upload = div (.JSON.Float "data.upload_bits") 1000000.0 }}{{ end }}
{{ if eq $upload 0.0 }}{{ $upload = div (mul (.JSON.Float "data.data.upload.bandwidth") 8.0) 1000000.0 }}{{ end }}
{{ if gt $download 100000.0 }}{{ $download = div (mul $download 8.0) 1000000.0 }}{{ end }}
{{ if gt $upload 100000.0 }}{{ $upload = div (mul $upload 8.0) 1000000.0 }}{{ end }}
{{ $ping := .JSON.Float "ping" }}
{{ if eq $ping 0.0 }}{{ $ping = .JSON.Float "data.ping" }}{{ end }}
{{ if eq $ping 0.0 }}{{ $ping = .JSON.Float "data.data.ping.latency" }}{{ end }}
<div class="text-center" style="margin-bottom: 10px;">
<div class="color-primary size-h3" style="font-weight: 700;">{{ if ne $ip "" }}{{ $ip }}{{ else }}WAN online{{ end }}</div>
<div class="size-h6 color-subdue">{{ if ne $isp "" }}{{ $isp }}{{ else }}Speedtest Tracker{{ end }}</div>
</div>
{{ if and (eq $download 0.0) (eq $upload 0.0) }}
<div class="text-center color-subdue size-h6">Keine aktuellen Messdaten</div>
{{ else }}
<div class="flex justify-between text-center">
<div>
<div class="color-highlight size-h4">{{ printf "%.1f" $download }}</div>
<div class="size-h6 color-subdue">MBIT DOWN</div>
</div>
<div>
<div class="color-highlight size-h4">{{ printf "%.1f" $upload }}</div>
<div class="size-h6 color-subdue">MBIT UP</div>
</div>
<div>
<div class="color-highlight size-h4">{{ printf "%.0f ms" $ping }}</div>
<div class="size-h6 color-subdue">PING</div>
</div>
</div>
{{ end }}
- type: dns-stats
title: DNS Stats
service: adguard
url: http://adguard
username: ${GLANCE_ADGUARD_USERNAME}
password: ${GLANCE_ADGUARD_PASSWORD}
- type: custom-api
title: Borg Backup
title-url: https://borg.kaleschke.info
cache: 15m
url: http://monitoring-prometheus:9090/api/v1/query?query=(time()-homelab_borg_last_completed_timestamp_seconds)/3600
subrequests:
success:
url: http://monitoring-prometheus:9090/api/v1/query?query=homelab_borg_last_success
template: |
{{ $ageHours := .JSON.Float "data.result.0.value.1" }}
{{ $archive := .JSON.String "data.result.0.metric.archive" }}
{{ $succ := .Subrequest "success" }}
{{ $ok := $succ.JSON.Float "data.result.0.value.1" }}
{{ $status := $succ.JSON.String "data.result.0.metric.status" }}
{{ if eq (len (.JSON.Array "data.result")) 0 }}
<div class="text-center color-subdue">Keine Backup-Metrik gefunden</div>
{{ else }}
<div class="text-center">
<div class="size-h2 {{ if gt $ageHours 30.0 }}color-negative{{ else }}color-positive{{ end }}">vor {{ printf "%.0f" $ageHours }} h</div>
<div class="size-h6 color-subdue" style="margin-top: 4px;">letztes abgeschlossenes Backup</div>
<div class="size-h6 {{ if eq $ok 1.0 }}color-positive{{ else }}color-negative{{ end }}" style="margin-top: 6px;">
{{ if eq $ok 1.0 }}letzter Job erfolgreich{{ else }}letzter Job: {{ $status }}{{ end }}
</div>
{{ if ne $archive "" }}<div class="size-h6 color-subdue text-truncate" style="margin-top: 2px;">{{ $archive }}</div>{{ end }}
</div>
{{ end }}
- type: group
widgets:
- type: docker-containers
title: Network
category: network
hide-by-default: true
sock-path: tcp://glance-docker-socket-proxy:2375
containers:
$include: containers-map.yml
- type: docker-containers
title: Apps
category: apps
hide-by-default: true
sock-path: tcp://glance-docker-socket-proxy:2375
containers:
$include: containers-map.yml
- type: docker-containers
title: Ops
category: ops
hide-by-default: true
sock-path: tcp://glance-docker-socket-proxy:2375
containers:
$include: containers-map.yml