You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
10 KiB
266 lines
10 KiB
######################################################################
|
|
# @CCOSTAN - Follow Me on X
|
|
# For more info visit https://www.vcloudinfo.com/click-here
|
|
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
|
|
# -------------------------------------------------------------------
|
|
# Infrastructure Partial - Website health sections
|
|
# Website uptime + response windows + domain expiry telemetry view.
|
|
# -------------------------------------------------------------------
|
|
# Related Issue: 1584
|
|
# Notes: Uses direct Uptime Kuma entities (no aggregate uptime min sensors).
|
|
######################################################################
|
|
|
|
# -------------------------------------------------------------------
|
|
# Website hero (mandatory first full-width container)
|
|
# -------------------------------------------------------------------
|
|
- type: grid
|
|
column_span: 4
|
|
columns: 1
|
|
square: false
|
|
cards:
|
|
- type: custom:layout-card
|
|
grid_options:
|
|
columns: full
|
|
layout_type: custom:grid-layout
|
|
layout:
|
|
grid-template-columns: repeat(2, minmax(0, 1fr))
|
|
grid-auto-flow: row
|
|
grid-auto-rows: min-content
|
|
grid-gap: 12px
|
|
margin: 0
|
|
mediaquery:
|
|
"(max-width: 900px)":
|
|
grid-template-columns: repeat(1, minmax(0, 1fr))
|
|
cards:
|
|
- type: custom:vertical-stack-in-card
|
|
grid_options:
|
|
columns: full
|
|
card_mod:
|
|
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
|
|
cards:
|
|
- type: custom:button-card
|
|
template: bearstone_infra_panel_header
|
|
name: Website Uptime
|
|
- type: custom:layout-card
|
|
layout_type: custom:grid-layout
|
|
layout:
|
|
grid-template-columns: repeat(2, minmax(0, 1fr))
|
|
grid-auto-flow: row
|
|
grid-auto-rows: min-content
|
|
grid-gap: 12px
|
|
margin: 0
|
|
mediaquery:
|
|
"(max-width: 900px)":
|
|
grid-template-columns: repeat(1, minmax(0, 1fr))
|
|
cards:
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row_running
|
|
entity: binary_sensor.vcloudinfo_com
|
|
name: vcloudinfo.com
|
|
icon: mdi:web
|
|
state_display: >
|
|
[[[ return entity.state === 'on' ? 'UP' : (entity.state || 'unknown').toUpperCase(); ]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row_running
|
|
entity: binary_sensor.www_kingcrafthomes_com
|
|
name: kingcrafthomes.com
|
|
icon: mdi:web
|
|
state_display: >
|
|
[[[ return entity.state === 'on' ? 'UP' : (entity.state || 'unknown').toUpperCase(); ]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row_running
|
|
entity: binary_sensor.bear_stone
|
|
name: Bear Stone
|
|
icon: mdi:web-check
|
|
state_display: >
|
|
[[[ return entity.state === 'on' ? 'UP' : (entity.state || 'unknown').toUpperCase(); ]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row
|
|
entity: binary_sensor.vcloudinfo_com
|
|
name: vcloudinfo.com uptime
|
|
icon: mdi:chart-line
|
|
state_display: >
|
|
[[[
|
|
const pick = (metric, window) => {
|
|
const suffix = `${metric}_${window}`;
|
|
const candidates = Object.keys(states).filter((k) =>
|
|
k.startsWith('sensor.') &&
|
|
k.includes('vcloudinfo_com') &&
|
|
k.endsWith(suffix)
|
|
);
|
|
const eid = candidates[0];
|
|
return eid ? (states[eid]?.state ?? 'n/a') : 'n/a';
|
|
};
|
|
const uptime1d = pick('uptime', '1d');
|
|
const uptime30d = pick('uptime', '30d');
|
|
const uptime365d = pick('uptime', '365d');
|
|
return `1d ${uptime1d}% | 30d ${uptime30d}% | 365d ${uptime365d}%`;
|
|
]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row
|
|
entity: binary_sensor.vcloudinfo_com
|
|
name: vcloudinfo.com response
|
|
icon: mdi:timer-outline
|
|
state_display: >
|
|
[[[
|
|
const pick = (metric, window) => {
|
|
const suffix = `${metric}_${window}`;
|
|
const candidates = Object.keys(states).filter((k) =>
|
|
k.startsWith('sensor.') &&
|
|
k.includes('vcloudinfo_com') &&
|
|
k.endsWith(suffix)
|
|
);
|
|
const eid = candidates[0];
|
|
return eid ? (states[eid]?.state ?? 'n/a') : 'n/a';
|
|
};
|
|
const r1d = pick('avg_response_time', '1d');
|
|
const r30d = pick('avg_response_time', '30d');
|
|
const r365d = pick('avg_response_time', '365d');
|
|
return `1d ${r1d}s | 30d ${r30d}s | 365d ${r365d}s`;
|
|
]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row
|
|
entity: binary_sensor.www_kingcrafthomes_com
|
|
name: kingcrafthomes.com uptime
|
|
icon: mdi:chart-line
|
|
state_display: >
|
|
[[[
|
|
const pick = (metric, window) => {
|
|
const suffix = `${metric}_${window}`;
|
|
const candidates = Object.keys(states).filter((k) =>
|
|
k.startsWith('sensor.') &&
|
|
(k.includes('kingcrafthomes_com') || k.includes('www_kingcrafthomes_com')) &&
|
|
k.endsWith(suffix)
|
|
);
|
|
const eid = candidates[0];
|
|
return eid ? (states[eid]?.state ?? 'n/a') : 'n/a';
|
|
};
|
|
const uptime1d = pick('uptime', '1d');
|
|
const uptime30d = pick('uptime', '30d');
|
|
const uptime365d = pick('uptime', '365d');
|
|
return `1d ${uptime1d}% | 30d ${uptime30d}% | 365d ${uptime365d}%`;
|
|
]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row
|
|
entity: binary_sensor.www_kingcrafthomes_com
|
|
name: kingcrafthomes.com response
|
|
icon: mdi:timer-outline
|
|
state_display: >
|
|
[[[
|
|
const pick = (metric, window) => {
|
|
const suffix = `${metric}_${window}`;
|
|
const candidates = Object.keys(states).filter((k) =>
|
|
k.startsWith('sensor.') &&
|
|
(k.includes('kingcrafthomes_com') || k.includes('www_kingcrafthomes_com')) &&
|
|
k.endsWith(suffix)
|
|
);
|
|
const eid = candidates[0];
|
|
return eid ? (states[eid]?.state ?? 'n/a') : 'n/a';
|
|
};
|
|
const r1d = pick('avg_response_time', '1d');
|
|
const r30d = pick('avg_response_time', '30d');
|
|
const r365d = pick('avg_response_time', '365d');
|
|
return `1d ${r1d}s | 30d ${r30d}s | 365d ${r365d}s`;
|
|
]]]
|
|
|
|
- type: custom:vertical-stack-in-card
|
|
grid_options:
|
|
columns: full
|
|
card_mod:
|
|
style: !include /config/dashboards/infrastructure/card_mod/infra_panel.yaml
|
|
cards:
|
|
- type: custom:button-card
|
|
template: bearstone_infra_panel_header
|
|
name: Domain Expiry
|
|
- type: custom:layout-card
|
|
layout_type: custom:grid-layout
|
|
layout:
|
|
grid-template-columns: repeat(2, minmax(0, 1fr))
|
|
grid-auto-flow: row
|
|
grid-auto-rows: min-content
|
|
grid-gap: 12px
|
|
margin: 0
|
|
mediaquery:
|
|
"(max-width: 900px)":
|
|
grid-template-columns: repeat(1, minmax(0, 1fr))
|
|
cards:
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row
|
|
entity: sensor.vcloudinfo_com_days_until_expiration
|
|
name: vcloudinfo.com
|
|
icon: mdi:calendar-clock
|
|
state_display: >
|
|
[[[
|
|
const days = states['sensor.vcloudinfo_com_days_until_expiration']?.state ?? 'n/a';
|
|
const expRaw = states['sensor.vcloudinfo_com_expires']?.state;
|
|
let exp = 'n/a';
|
|
const s = String(expRaw ?? '');
|
|
if (s && !['unknown','unavailable','none',''].includes(s.toLowerCase())) {
|
|
if (/^\d{4}-\d{2}-\d{2}/.test(s)) {
|
|
exp = s.slice(0, 10);
|
|
} else {
|
|
const dt = new Date(s);
|
|
if (!Number.isNaN(dt.getTime())) {
|
|
const y = dt.getFullYear();
|
|
const m = String(dt.getMonth() + 1).padStart(2, '0');
|
|
const d = String(dt.getDate()).padStart(2, '0');
|
|
exp = `${y}-${m}-${d}`;
|
|
}
|
|
}
|
|
}
|
|
return `${days}d | ${exp}`;
|
|
]]]
|
|
- type: custom:button-card
|
|
template: bearstone_infra_list_row
|
|
entity: sensor.kingcrafthomes_com_days_until_expiration
|
|
name: kingcrafthomes.com
|
|
icon: mdi:calendar-clock
|
|
state_display: >
|
|
[[[
|
|
const days = states['sensor.kingcrafthomes_com_days_until_expiration']?.state ?? 'n/a';
|
|
const expRaw = states['sensor.kingcrafthomes_com_expires']?.state;
|
|
let exp = 'n/a';
|
|
const s = String(expRaw ?? '');
|
|
if (s && !['unknown','unavailable','none',''].includes(s.toLowerCase())) {
|
|
if (/^\d{4}-\d{2}-\d{2}/.test(s)) {
|
|
exp = s.slice(0, 10);
|
|
} else {
|
|
const dt = new Date(s);
|
|
if (!Number.isNaN(dt.getTime())) {
|
|
const y = dt.getFullYear();
|
|
const m = String(dt.getMonth() + 1).padStart(2, '0');
|
|
const d = String(dt.getDate()).padStart(2, '0');
|
|
exp = `${y}-${m}-${d}`;
|
|
}
|
|
}
|
|
}
|
|
return `${days}d | ${exp}`;
|
|
]]]
|
|
|
|
- type: grid
|
|
column_span: 4
|
|
columns: 3
|
|
square: false
|
|
cards:
|
|
- type: custom:button-card
|
|
template: bearstone_infra_alert_row
|
|
entity: binary_sensor.infra_website_degraded
|
|
name: Website status degraded
|
|
icon: mdi:web-off
|
|
variables:
|
|
alert_kind: binary_on
|
|
- type: custom:button-card
|
|
template: bearstone_infra_alert_row
|
|
entity: binary_sensor.infra_website_uptime_slo_breach
|
|
name: Uptime SLO breach
|
|
icon: mdi:alert-decagram
|
|
variables:
|
|
alert_kind: binary_on
|
|
- type: custom:button-card
|
|
template: bearstone_infra_alert_row
|
|
entity: binary_sensor.infra_website_latency_degraded
|
|
name: Website latency degraded
|
|
icon: mdi:timer-alert
|
|
variables:
|
|
alert_kind: binary_on
|