Skip to content

Commit

Permalink
feat(BusMonitor): Add first working version of KNX Bus Monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
marvin-w committed Apr 17, 2022
1 parent d9645a0 commit 3b3c335
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 47 deletions.
7 changes: 6 additions & 1 deletion custom_components/knx_panel/const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
"""Constants for KNX Panel."""
from typing import Final
from typing import Awaitable, Callable, Final

from xknx.telegram import Telegram

KNX_DOMAIN: Final = "knx"

AsyncMessageCallbackType = Callable[[Telegram], Awaitable[None]]
MessageCallbackType = Callable[[Telegram], None]
144 changes: 108 additions & 36 deletions custom_components/knx_panel/knx_ui.js

Large diffs are not rendered by default.

58 changes: 57 additions & 1 deletion custom_components/knx_panel/websocket.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
"""KNX Websocket API."""
from __future__ import annotations

from typing import Callable

from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant
import voluptuous as vol
from xknx.telegram import Telegram

from .const import KNX_DOMAIN
from .const import KNX_DOMAIN, AsyncMessageCallbackType, MessageCallbackType


def register_websocket_api(hass: HomeAssistant) -> None:
"""Register the KNX Websocket API."""
websocket_api.async_register_command(hass, ws_info)
websocket_api.async_register_command(hass, ws_subscribe_telegram)


@websocket_api.websocket_command(
Expand All @@ -32,3 +38,53 @@ async def ws_info(
"current_address": str(xknx.current_address),
},
)


@websocket_api.websocket_command(
{
vol.Required("type"): "knx_panel/subscribe_telegrams",
}
)
@websocket_api.async_response
async def ws_subscribe_telegram(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict,
) -> None:
"""Handle get info command."""

async def forward_telegrams(telegram: Telegram):
"""Forward events to websocket."""
connection.send_message(
websocket_api.event_message(
msg["id"],
{
"destination_address": str(telegram.destination_address),
"payload": str(telegram.payload),
"source_address": str(telegram.source_address),
"direction": str(telegram.direction),
"timestamp": str(telegram.timestamp),
},
)
)

connection.subscriptions[msg["id"]] = await async_subscribe_telegrams(
hass, forward_telegrams
)

connection.send_message(websocket_api.result_message(msg["id"]))


async def async_subscribe_telegrams(
hass: HomeAssistant, callback: AsyncMessageCallbackType | MessageCallbackType
) -> Callable[[], None]:
"""Subscribe to telegram received callback."""
xknx = hass.data[KNX_DOMAIN].xknx

def async_remove():
"""Remove callback."""
xknx.telegram_queue.unregister_telegram_received_cb(callback)

xknx.telegram_queue.register_telegram_received_cb(callback)

return async_remove
11 changes: 9 additions & 2 deletions frontend/src/knx_ui.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { NavigationService } from "@services/navigation.service";
import { NavigationEntry, Route } from "@typing/navigation";
import { HomeAssistantComponentLoader } from "@util/load-ha";
import { KNXBusMonitor } from "@views/bus_monitor";
import { KNXOverview } from "@views/overview";
import { HomeAssistant, navigate } from "custom-card-helpers";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { KNXOverview } from "./views/overview";

@customElement("knx-custom-panel")
export class KNXCustomPanel extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;

private loadedViews = KNXOverview; // We need this so that the compiler also compiles our views...
private loadedViews = [KNXOverview, KNXBusMonitor]; // We need this so that the compiler also compiles our views...
private navigationService: NavigationService = new NavigationService();

protected firstUpdated() {
Expand Down Expand Up @@ -68,6 +69,12 @@ export class KNXCustomPanel extends LitElement {
></knx-overview>
`;
case NavigationEntry.BUS_MONITOR:
return html`
<knx-bus-monitor
.hass=${this.hass}
.narrow=${this.narrow}
></knx-bus-monitor>
`;
default:
return html`
<ha-card header="404">
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/services/websocket.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { KnxInfo } from "@typing/websocket";
import { KNXInfo, KNXTelegram } from "@typing/websocket";
import { HomeAssistant } from "custom-card-helpers";

export const getKnxInfo = (hass: HomeAssistant): Promise<KnxInfo> =>
export const getKnxInfo = (hass: HomeAssistant): Promise<KNXInfo> =>
hass.callWS({
type: "knx_panel/info",
});

export const subscribeKnxTelegrams = (
hass: HomeAssistant,
callback: (telegram: KNXTelegram) => void
) =>
hass.connection.subscribeMessage<KNXTelegram>(callback, {
type: "knx_panel/subscribe_telegrams",
});
10 changes: 9 additions & 1 deletion frontend/src/types/websocket.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
export interface KnxInfo {
export interface KNXInfo {
version: string;
connected: boolean;
current_address: string;
}

export interface KNXTelegram {
destination_address: string;
source_address: string;
payload: any;
direction: string;
timestamp: Date;
}
64 changes: 64 additions & 0 deletions frontend/src/views/bus_monitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { subscribeKnxTelegrams } from "@services/websocket.service";
import { KNXTelegram } from "@typing/websocket";
import { HomeAssistant } from "custom-card-helpers";
import { css, html, LitElement, TemplateResult } from "lit";
import { state } from "lit-element";
import { customElement, property } from "lit/decorators.js";

@customElement("knx-bus-monitor")
export class KNXBusMonitor extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
@state() private telegrams: KNXTelegram[] = [];
@state() private subscribed?: () => void;

public disconnectedCallback() {
super.disconnectedCallback();
if (this.subscribed) {
this.subscribed();
this.subscribed = undefined;
}
}

protected async firstUpdated() {
if (!this.subscribed) {
this.subscribed = await subscribeKnxTelegrams(this.hass, (message) =>
this.telegram_callback(message)
);
this.telegrams = [];
}
}

protected telegram_callback(telegram: KNXTelegram): void {
this.telegrams.push(telegram);
this.requestUpdate();
}

protected render(): TemplateResult | void {
return html`
<ha-card class="knx-info" header="KNX Bus Monitor">
${this.telegrams.map(
(telegram) => html`
<div class="telegram">
<div>${telegram.destination_address}</div>
<div>${telegram.source_address}</div>
<div>${telegram.payload}</div>
<div>${telegram.direction}</div>
<div>${telegram.timestamp}</div>
</div>
`
)}
</ha-card>
`;
}

static get styles() {
return css`
.telegram {
display: flex;
flex-direction: row;
justify-content: space-between;
}
`;
}
}
4 changes: 2 additions & 2 deletions frontend/src/views/overview.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getKnxInfo } from "@services/websocket.service";
import { KnxInfo } from "@typing/websocket";
import { KNXInfo } from "@typing/websocket";
import { HomeAssistant } from "custom-card-helpers";
import { css, html, LitElement, TemplateResult } from "lit";
import { state } from "lit-element";
Expand All @@ -9,7 +9,7 @@ import { customElement, property } from "lit/decorators.js";
export class KNXOverview extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
@state() private knxInfo: KnxInfo | null = null;
@state() private knxInfo: KNXInfo | null = null;

protected firstUpdated() {
getKnxInfo(this.hass).then((knxInfo) => {
Expand Down
3 changes: 2 additions & 1 deletion frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"paths": {
"@util/*": ["util/*"],
"@services/*": ["services/*"],
"@typing/*": ["types/*"]
"@typing/*": ["types/*"],
"@views/*": ["views/*"]
},
"noEmit": true,
"noUnusedParameters": true,
Expand Down
11 changes: 10 additions & 1 deletion frontend/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@
"no-console": {
"severity": "warning",
"options": ["debug", "info", "log", "time", "timeEnd", "trace"]
}
},
"trailing-comma": [true, {
"singleline": "never",
"multiline": {
"objects": "always",
"arrays": "always",
"functions": "never",
"typeLiterals": "ignore"
}
}]
},
"jsRules": {
"max-line-length": {
Expand Down

0 comments on commit 3b3c335

Please sign in to comment.