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 @@
+
+
+
+
+
+
+
+
+
+ {{ alarmEntity.attributes.friendly_name }}
+
+
+ {{ translateAlarmState(alarmEntity.state) }}
+
+
+
+
+
+ {{ alarmEntity.attributes.friendly_name }}
+
+
+ {{ translateAlarmState(alarmEntity.state) }}
+
+
+
+
+
+
+
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);