From 4f414df70b31f1ee9861e6793dc535d118aa2d75 Mon Sep 17 00:00:00 2001 From: Matthias Alphart Date: Wed, 13 Nov 2024 22:34:59 +0100 Subject: [PATCH] Show last value for group address in project tab (#181) --- src/localize/languages/de.json | 2 + src/localize/languages/en.json | 2 + src/services/websocket.service.ts | 5 +++ src/views/group_monitor.ts | 4 +- src/views/project_view.ts | 66 ++++++++++++++++++++++++++++++- 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/localize/languages/de.json b/src/localize/languages/de.json index 2291de7..2edb116 100644 --- a/src/localize/languages/de.json +++ b/src/localize/languages/de.json @@ -34,9 +34,11 @@ "project_view_version_l2": "minimal unterstützte Version", "project_view_version_l3": "Lade die Projektdatei erneut hoch, um das ETS Projekt Werkzeug zu nutzen", "project_view_table_address": "Adresse", + "project_view_table_last_value": "Letzter Wert", "project_view_table_name": "Name", "project_view_table_description": "Beschreibung", "project_view_table_dpt": "DPT", + "project_view_table_updated": "Aktualisiert", "Incoming": "Eingehend", "Outgoing": "Ausgehend" } diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index a74bddb..6f307f7 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -35,9 +35,11 @@ "project_view_version_l2": "minimum version required", "project_view_version_l3": "Please resubmit your ETS project file.", "project_view_table_address": "Address", + "project_view_table_last_value": "Last value", "project_view_table_name": "Name", "project_view_table_description": "Description", "project_view_table_dpt": "DPT", + "project_view_table_updated": "Updated", "project_view_add_switch": "Add switch", "Incoming": "Incoming", "Outgoing": "Outgoing" diff --git a/src/services/websocket.service.ts b/src/services/websocket.service.ts index f05e548..575fe1e 100644 --- a/src/services/websocket.service.ts +++ b/src/services/websocket.service.ts @@ -40,6 +40,11 @@ export const getGroupMonitorInfo = (hass: HomeAssistant): Promise => + hass.callWS({ + type: "knx/group_telegrams", + }); + export const subscribeKnxTelegrams = ( hass: HomeAssistant, callback: (telegram: TelegramDict) => void, diff --git a/src/views/group_monitor.ts b/src/views/group_monitor.ts index 247c6f0..c406703 100644 --- a/src/views/group_monitor.ts +++ b/src/views/group_monitor.ts @@ -86,8 +86,8 @@ export class KNXGroupMonitor extends LitElement { sortable: true, direction: "desc", type: "numeric", - minWidth: "60px", // 4 digits - maxWidth: "60px", + minWidth: "68px", // 5 digits + maxWidth: "68px", }, timestamp: { showNarrow: false, diff --git a/src/views/project_view.ts b/src/views/project_view.ts index 7bd2b4d..ea62f4a 100644 --- a/src/views/project_view.ts +++ b/src/views/project_view.ts @@ -13,6 +13,8 @@ import "@ha/components/ha-icon-button"; import "@ha/components/ha-icon-overflow-menu"; import "@ha/components/data-table/ha-data-table"; import type { DataTableColumnContainer } from "@ha/components/data-table/ha-data-table"; +import { relativeTime } from "@ha/common/datetime/relative_time"; +import { navigate } from "@ha/common/navigate"; import "../components/knx-project-tree-view"; @@ -21,8 +23,10 @@ import { compare } from "compare-versions"; import { HomeAssistant, Route } from "@ha/types"; import { KNX } from "../types/knx"; import type { GroupRangeSelectionChangedEvent } from "../components/knx-project-tree-view"; -import { GroupAddress } from "../types/websocket"; +import { subscribeKnxTelegrams, getGroupTelegrams } from "../services/websocket.service"; +import { GroupAddress, TelegramDict } from "../types/websocket"; import { KNXLogger } from "../tools/knx-logger"; +import { TelegramDictFormatter } from "../utils/format"; const logger = new KNXLogger("knx-project-view"); // Minimum XKNXProject Version needed which was used for parsing the ETS Project @@ -47,7 +51,19 @@ export class KNXProjectView extends LitElement { @state() private _groupRangeAvailable: boolean = false; - protected firstUpdated() { + @state() private _subscribed?: () => void; + + @state() private _lastTelegrams: { [ga: string]: TelegramDict } = {}; + + public disconnectedCallback() { + super.disconnectedCallback(); + if (this._subscribed) { + this._subscribed(); + this._subscribed = undefined; + } + } + + protected async firstUpdated() { if (!this.knx.project) { this.knx.loadProject().then(() => { this._isGroupRangeAvailable(); @@ -57,6 +73,18 @@ export class KNXProjectView extends LitElement { // project was already loaded this._isGroupRangeAvailable(); } + + getGroupTelegrams(this.hass) + .then((groupTelegrams) => { + this._lastTelegrams = groupTelegrams; + }) + .catch((err) => { + logger.error("getGroupTelegrams", err); + navigate("/knx/error", { replace: true, data: err }); + }); + this._subscribed = await subscribeKnxTelegrams(this.hass, (telegram) => { + this.telegram_callback(telegram); + }); } private _isGroupRangeAvailable() { @@ -65,6 +93,13 @@ export class KNXProjectView extends LitElement { this._groupRangeAvailable = compare(projectVersion, MIN_XKNXPROJECT_VERSION, ">="); } + protected telegram_callback(telegram: TelegramDict): void { + this._lastTelegrams = { + ...this._lastTelegrams, + [telegram.destination]: telegram, + }; + } + private _columns = memoize((_narrow, _language): DataTableColumnContainer => { const addressWidth = "100px"; const dptWidth = "82px"; @@ -96,6 +131,33 @@ export class KNXProjectView extends LitElement { >${ga.dpt.sub ? "." + ga.dpt.sub.toString().padStart(3, "0") : ""} ` : "", }, + lastValue: { + filterable: true, + title: this.knx.localize("project_view_table_last_value"), + flex: 2, + template: (ga: GroupAddress) => { + const lastTelegram: TelegramDict | undefined = this._lastTelegrams[ga.address]; + if (!lastTelegram) return ""; + const payload = TelegramDictFormatter.payload(lastTelegram); + if (lastTelegram.value == null) return html`${payload}`; + return html`
+ ${TelegramDictFormatter.valueWithUnit(this._lastTelegrams[ga.address])} +
`; + }, + }, + updated: { + title: this.knx.localize("project_view_table_updated"), + flex: 1, + showNarrow: false, + template: (ga: GroupAddress) => { + const lastTelegram: TelegramDict | undefined = this._lastTelegrams[ga.address]; + if (!lastTelegram) return ""; + const tooltip = `${TelegramDictFormatter.dateWithMilliseconds(lastTelegram)}\n\n${lastTelegram.source} ${lastTelegram.source_name}`; + return html`
+ ${relativeTime(new Date(lastTelegram.timestamp), this.hass.locale)} +
`; + }, + }, }; });