From 609938252bc18b5e93663af39c55a19338a116a9 Mon Sep 17 00:00:00 2001 From: Chris Kaczor Date: Fri, 19 Jun 2026 00:06:31 +0000 Subject: [PATCH] Start adding extra views --- WebDisplay/components.d.ts | 1 + WebDisplay/deploy/manifest-internal.yaml | 4 +- WebDisplay/nginx/entrypoint.sh | 3 +- WebDisplay/package.json | 2 +- WebDisplay/pnpm-workspace.yaml | 5 + WebDisplay/src/components/AlarmOverview.vue | 110 ++++++++++++++++++ WebDisplay/src/environment.ts | 4 + .../models/homeAssistant/registryEntity.ts | 4 + WebDisplay/src/pages/kiosk.vue | 89 +++++++++++--- WebDisplay/src/stores/homeAssistantStore.ts | 21 +++- 10 files changed, 220 insertions(+), 23 deletions(-) create mode 100644 WebDisplay/pnpm-workspace.yaml create mode 100644 WebDisplay/src/components/AlarmOverview.vue create mode 100644 WebDisplay/src/models/homeAssistant/registryEntity.ts diff --git a/WebDisplay/components.d.ts b/WebDisplay/components.d.ts index 78853c5..f3290bd 100644 --- a/WebDisplay/components.d.ts +++ b/WebDisplay/components.d.ts @@ -7,6 +7,7 @@ export {} declare module 'vue' { export interface GlobalComponents { + AlarmOverview: typeof import('./src/components/AlarmOverview.vue')['default'] Almanac: typeof import('./src/components/Almanac.vue')['default'] CalendarAgenda: typeof import('./src/components/CalendarAgenda.vue')['default'] CurrentLaundryStatus: typeof import('./src/components/CurrentLaundryStatus.vue')['default'] diff --git a/WebDisplay/deploy/manifest-internal.yaml b/WebDisplay/deploy/manifest-internal.yaml index 0cedf8b..edd437f 100644 --- a/WebDisplay/deploy/manifest-internal.yaml +++ b/WebDisplay/deploy/manifest-internal.yaml @@ -51,7 +51,9 @@ spec: valueFrom: secretKeyRef: name: display-internal-config - key: CALENDAR_EMBED_URL + key: CALENDAR_EMBED_URL + - name: ALARM_INTEGRATION + value: abode restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst diff --git a/WebDisplay/nginx/entrypoint.sh b/WebDisplay/nginx/entrypoint.sh index 8e3b7b6..10c22bf 100644 --- a/WebDisplay/nginx/entrypoint.sh +++ b/WebDisplay/nginx/entrypoint.sh @@ -4,4 +4,5 @@ sed -i -e "s~#API_PREFIX#~$API_PREFIX~g" /usr/share/nginx/html/assets/* sed -i -e "s~#HOME_ASSISTANT_URL#~$HOME_ASSISTANT_URL~g" /usr/share/nginx/html/assets/* sed -i -e "s~#HOME_ASSISTANT_TOKEN#~$HOME_ASSISTANT_TOKEN~g" /usr/share/nginx/html/assets/* sed -i -e "s~#GARAGE_DEVICE#~$GARAGE_DEVICE~g" /usr/share/nginx/html/assets/* -sed -i -e "s~#ALARM_DEVICE#~$ALARM_DEVICE~g" /usr/share/nginx/html/assets/* \ No newline at end of file +sed -i -e "s~#ALARM_DEVICE#~$ALARM_DEVICE~g" /usr/share/nginx/html/assets/* +sed -i -e "s~#ALARM_INTEGRATION#~$ALARM_INTEGRATION~g" /usr/share/nginx/html/assets/* \ No newline at end of file diff --git a/WebDisplay/package.json b/WebDisplay/package.json index 179c1e0..7a40188 100644 --- a/WebDisplay/package.json +++ b/WebDisplay/package.json @@ -1,7 +1,7 @@ { "name": "web-display", "version": "1.0.0", - "packageManager": "pnpm@10.29.3", + "packageManager": "pnpm@11.8.0", "scripts": { "dev": "cross-env NODE_OPTIONS='--no-warnings' vite", "build": "vue-tsc --noEmit && vite build", diff --git a/WebDisplay/pnpm-workspace.yaml b/WebDisplay/pnpm-workspace.yaml new file mode 100644 index 0000000..e902f81 --- /dev/null +++ b/WebDisplay/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +allowBuilds: + '@parcel/watcher': true + core-js: true + esbuild: true + vue-demi: true diff --git a/WebDisplay/src/components/AlarmOverview.vue b/WebDisplay/src/components/AlarmOverview.vue new file mode 100644 index 0000000..6ce61a5 --- /dev/null +++ b/WebDisplay/src/components/AlarmOverview.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/WebDisplay/src/environment.ts b/WebDisplay/src/environment.ts index eee8904..eb602f6 100644 --- a/WebDisplay/src/environment.ts +++ b/WebDisplay/src/environment.ts @@ -18,4 +18,8 @@ export default class Environment { public static getAlarmDevice(): string { return '#ALARM_DEVICE#'; } + + public static getAlarmIntegration(): string { + return '#ALARM_INTEGRATION#'; + } } diff --git a/WebDisplay/src/models/homeAssistant/registryEntity.ts b/WebDisplay/src/models/homeAssistant/registryEntity.ts new file mode 100644 index 0000000..ae78a7d --- /dev/null +++ b/WebDisplay/src/models/homeAssistant/registryEntity.ts @@ -0,0 +1,4 @@ +export interface HomeAssistantRegistryEntity { + entity_id: string; + platform: string; +} diff --git a/WebDisplay/src/pages/kiosk.vue b/WebDisplay/src/pages/kiosk.vue index 5d82676..772ca65 100644 --- a/WebDisplay/src/pages/kiosk.vue +++ b/WebDisplay/src/pages/kiosk.vue @@ -7,6 +7,14 @@ import CalendarAgenda from '@/components/CalendarAgenda.vue'; import LongPressButton from '@/components/LongPressButton.vue'; import PressureTrendArrow from '@/components/PressureTrendArrow.vue'; + import AlarmOverview from '@/components/AlarmOverview.vue'; + + enum KioskPage { + Calendar, + AlarmOverview + } + + const kioskPage = ref(KioskPage.Calendar); const outOfDateDuration = 5000; @@ -233,11 +241,34 @@
- - +
+ + +
+
+ + +
+
+ +
@@ -286,18 +317,25 @@ .kiosk-content { height: 100%; - max-height: calc(100vh - 30px); + max-height: calc(100vh); padding: 10px; - gap: 10px; - display: grid; - grid-template-columns: repeat(3, 1fr); - grid-template-rows: repeat(4, 25%); - grid-auto-flow: row; - grid-template-areas: - 'kiosk-calendar kiosk-national-days kiosk-national-days' - 'kiosk-calendar kiosk-national-days kiosk-national-days' - 'kiosk-calendar kiosk-national-days kiosk-national-days' - 'kiosk-calendar kiosk-national-days kiosk-national-days'; + } + + .kiosk-navigation { + background-color: #121212; + border-radius: 10px; + align-content: center; + padding: 0 10px; + height: 50px; + } + + .kiosk-navigation-icon { + font-size: 2rem; + margin-right: 10px; + } + + .kiosk-navigation-selected { + color: #5e83c7; } .kiosk-time { @@ -362,12 +400,27 @@ font-size: 1.3rem; } + .kiosk-calendar-page { + display: flex; + padding-top: 10px; + gap: 10px; + height: calc(100vh - 70px); + } + + .kiosk-alarm-overview-page { + display: flex; + padding-top: 10px; + gap: 10px; + height: calc(100vh - 70px); + } + .kiosk-calendar { - grid-area: kiosk-calendar; + flex-basis: 20%; } .kiosk-national-days { - grid-area: kiosk-national-days; + flex-grow: 1; + flex-basis: auto; } .warning { diff --git a/WebDisplay/src/stores/homeAssistantStore.ts b/WebDisplay/src/stores/homeAssistantStore.ts index b91e10b..89a605e 100644 --- a/WebDisplay/src/stores/homeAssistantStore.ts +++ b/WebDisplay/src/stores/homeAssistantStore.ts @@ -1,12 +1,14 @@ import { defineStore } from 'pinia'; -import { createConnection, subscribeEntities, createLongLivedTokenAuth, Connection, callService } from 'home-assistant-js-websocket'; +import { createConnection, subscribeEntities, createLongLivedTokenAuth, Connection, callService, HassEntities, HassEntity } from 'home-assistant-js-websocket'; import Environment from '@/environment'; +import { HomeAssistantRegistryEntity } from '@/models/homeAssistant/registryEntity'; export const useHomeAssistantStore = defineStore('home-assistant', { state: () => { return { garageState: null as string | null, houseAlarmState: null as string | null, + alarmEntities: {} as Record, _connection: null as Connection | null }; }, @@ -18,12 +20,21 @@ export const useHomeAssistantStore = defineStore('home-assistant', { const garageDevice = Environment.getGarageDevice(); const alarmDevice = Environment.getAlarmDevice(); + const alarmIntegration = Environment.getAlarmIntegration(); const auth = createLongLivedTokenAuth(Environment.getHomeAssistantUrl(), Environment.getHomeAssistantToken()); this._connection = await createConnection({ auth }); - subscribeEntities(this._connection as Connection, (entities) => { + const homeAssistantRegistryEntries: HomeAssistantRegistryEntity[] = await this._connection.sendMessagePromise({ + type: 'config/entity_registry/list' + }); + + const alarmEntityList = homeAssistantRegistryEntries.filter((entity) => entity.platform === alarmIntegration); + + const alarmEntities: Record = Object.fromEntries(alarmEntityList.map((entity) => [entity.entity_id, entity])); + + subscribeEntities(this._connection as Connection, (entities: HassEntities) => { const garageEntity = entities[garageDevice]; if (garageEntity) { @@ -35,6 +46,12 @@ export const useHomeAssistantStore = defineStore('home-assistant', { if (houseAlarmEntity) { this.$patch({ houseAlarmState: houseAlarmEntity.state }); } + + Object.entries(entities).forEach(([entityId, entity]) => { + if (alarmEntities[entityId]) { + this.$patch((state) => (state.alarmEntities[entityId] = entity)); + } + }); }); setInterval(async () => await this._connection?.ping(), 5000);