From 8948470baac3b1a906a273228600e3d210a08a0e Mon Sep 17 00:00:00 2001 From: Darius Date: Fri, 6 Feb 2026 21:28:48 +0100 Subject: [PATCH] update for partial polling, add grist --- package-lock.json | 4 +- src/grist/service.ts | 4 +- src/homepage/service.ts | 229 ++++++++++++++++++++++++++++++---------- 3 files changed, 180 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index f18c106..9e3f3d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,8 +28,8 @@ } }, "node_modules/@dpu/shared": { - "version": "1.8.1", - "resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#27dc6f2b1214b8e2aff65de510caea402c2f88db", + "version": "1.8.4", + "resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#ff4248961b97a84bfdbeed85cd83b007332378ac", "dependencies": { "@types/ws": "^8.18.1", "axios": "^1.7.9", diff --git a/src/grist/service.ts b/src/grist/service.ts index 820df76..0e24750 100644 --- a/src/grist/service.ts +++ b/src/grist/service.ts @@ -35,13 +35,13 @@ export class GristService extends BaseService { } } - getTodayAsId(date = new Date()) { + private getTodayAsId(date = new Date()) { const start = new Date(date.getFullYear(), 0, 0); const diff = date.getTime() - start.getTime(); return Math.floor(diff / 86400000); } - transformToPersonalGoals( + private transformToPersonalGoals( obj: Record, ): GristRecord_PersonalGoals { return { diff --git a/src/homepage/service.ts b/src/homepage/service.ts index 89a3682..3976f00 100644 --- a/src/homepage/service.ts +++ b/src/homepage/service.ts @@ -1,28 +1,40 @@ import { + type API_HA_DeskPosition, BaseService, + type ComponentUpdate, type FullInformation, + type GristRecord_PersonalGoals, type HomeAssistantDeskPositionResult, type ServiceResult, type TidalGetCurrent, type WsService, } from "@dpu/shared"; import { logInfo, logWarning } from "@dpu/shared/dist/logger.js"; +import type { GristService } from "../grist/service"; import type { HomeAssistantService } from "../homeassistant/service"; import type { TidalService } from "../tidal/service"; export class HomepageService extends BaseService { + private gristService: GristService; private haService: HomeAssistantService; private tidalService: TidalService; private wsService: WsService; - private pollingInterval: ReturnType | null = null; - private lastPoll: FullInformation | null = null; + private pollingIntervals: ReturnType[] = []; + private lastPoll: FullInformation = { + ha_desk_position: null, + ha_temp: null, + tidal_current: null, + grist_personal_goals: null, + }; constructor( + gristService: GristService, haService: HomeAssistantService, tidalService: TidalService, wsService: WsService, ) { super(null); + this.gristService = gristService; this.haService = haService; this.tidalService = tidalService; this.wsService = wsService; @@ -31,23 +43,21 @@ export class HomepageService extends BaseService { async getFullInformation(): Promise> { try { - const [desk, temp, song] = await Promise.all([ - this.haService.getDeskPosition(), - this.haService.getTemperatureText(), - this.tidalService.getSong(), + const [desk, temp, tidal, personal_goals] = await Promise.all([ + this._getDesk(), + this._getTemp(), + this._getTidal(), + this._getGristPG(), ]); - const result = { - ha_desk_position: desk.successful - ? this.haService.convertPosResultToApiAnswer( - desk.result as HomeAssistantDeskPositionResult, - ) - : null, - ha_temp: temp.successful ? temp.result : null, - tidal_current: song ? (song.result as TidalGetCurrent) : null, - }; - - return this.getSuccessfulResult(this.updateLastPoll(result)); + return this.getSuccessfulResult( + this.updateFull({ + ha_desk_position: desk, + ha_temp: temp, + tidal_current: tidal, + grist_personal_goals: personal_goals, + }), + ); } catch { const error_message = "error getting all information"; logWarning(error_message); @@ -55,34 +65,39 @@ export class HomepageService extends BaseService { } } - updateLastPoll(newPoll: FullInformation) { - const updates = []; - if ( - this.lastPoll?.ha_desk_position?.is_standing !== - newPoll.ha_desk_position?.is_standing - ) { - updates.push({ - component: "ha_desk_position", - data: newPoll.ha_desk_position, - }); - } + private async _getDesk(): Promise { + const desk = await this.haService.getDeskPosition(); + return desk.successful + ? this.haService.convertPosResultToApiAnswer( + desk.result as HomeAssistantDeskPositionResult, + ) + : null; + } - if (this.lastPoll?.ha_temp !== newPoll.ha_temp) { - updates.push({ - component: "ha_temp", - data: newPoll.ha_temp, - }); - } + private async _getTemp(): Promise { + const temp = await this.haService.getTemperatureText(); + return temp.successful ? temp.result : null; + } - if ( - this.lastPoll?.tidal_current?.title !== newPoll.tidal_current?.title || - this.lastPoll?.tidal_current?.status !== newPoll.tidal_current?.status - ) { - updates.push({ - component: "tidal_current", - data: newPoll.tidal_current, - }); - } + private async _getTidal(): Promise { + const tidal = await this.tidalService.getSong(); + return tidal ? (tidal.result as TidalGetCurrent) : null; + } + + private async _getGristPG(): Promise { + const personal_goals = await this.gristService.getToday(); + return personal_goals.successful + ? (personal_goals.result as GristRecord_PersonalGoals) + : null; + } + + updateFull(newPoll: FullInformation): FullInformation { + const updates: ComponentUpdate[] = []; + + this.updateHaDesk(newPoll.ha_desk_position, updates); + this.updateHaTemp(newPoll.ha_temp, updates); + this.updateTidal(newPoll.tidal_current, updates); + this.updateGristPG(newPoll.grist_personal_goals, updates); if (updates.length > 0) { logInfo("Updating clients"); @@ -92,16 +107,117 @@ export class HomepageService extends BaseService { }); } - this.lastPoll = newPoll; return newPoll; } + async updatePartial(components: string[]): Promise { + const updates: ComponentUpdate[] = []; + for (const component of components) { + switch (component) { + case "desk": { + this.updateHaDesk(await this._getDesk(), updates); + break; + } + case "temp": + this.updateHaTemp(await this._getTemp(), updates); + break; + case "tidal": + this.updateTidal(await this._getTidal(), updates); + break; + case "grist": + this.updateGristPG(await this._getGristPG(), updates); + break; + default: + } + } + + this.wsService.broadcast({ + type: "update", + data: updates, + }); + } + + private updateHaDesk( + new_ha_desk_position: API_HA_DeskPosition | null, + updates: ComponentUpdate[], + ): void { + if ( + this.lastPoll.ha_desk_position?.is_standing !== + new_ha_desk_position?.is_standing + ) { + this.lastPoll.ha_desk_position = new_ha_desk_position; + updates.push({ + component: "ha_desk_position", + data: new_ha_desk_position, + }); + } + } + + private updateHaTemp( + new_ha_temp: string | null, + updates: ComponentUpdate[], + ): void { + if (this.lastPoll.ha_temp !== new_ha_temp) { + this.lastPoll.ha_temp = new_ha_temp; + updates.push({ + component: "ha_temp", + data: new_ha_temp, + }); + } + } + + private updateTidal( + new_tidal_current: TidalGetCurrent | null, + updates: ComponentUpdate[], + ): void { + if ( + this.lastPoll.tidal_current?.title !== new_tidal_current?.title || + this.lastPoll.tidal_current?.artists !== new_tidal_current?.artists || + this.lastPoll.tidal_current?.status !== new_tidal_current?.status || + this.lastPoll.tidal_current?.volume !== new_tidal_current?.volume + ) { + this.lastPoll.tidal_current = new_tidal_current; + updates.push({ + component: "tidal_current", + data: new_tidal_current, + }); + } + } + + private updateGristPG( + new_grist_personal_goals: GristRecord_PersonalGoals | null, + updates: ComponentUpdate[], + ): void { + if ( + this.lastPoll.grist_personal_goals?.went_outside !== + new_grist_personal_goals?.went_outside || + this.lastPoll.grist_personal_goals?.standing !== + new_grist_personal_goals?.standing || + this.lastPoll.grist_personal_goals?.steps !== + new_grist_personal_goals?.steps || + this.lastPoll.grist_personal_goals?.pushups !== + new_grist_personal_goals?.pushups || + this.lastPoll.grist_personal_goals?.squats !== + new_grist_personal_goals?.squats || + this.lastPoll.grist_personal_goals?.leg_raises !== + new_grist_personal_goals?.leg_raises || + this.lastPoll.grist_personal_goals?.stairs !== + new_grist_personal_goals?.stairs + ) { + this.lastPoll.grist_personal_goals = new_grist_personal_goals; + updates.push({ + component: "grist_personal_goals", + data: new_grist_personal_goals, + }); + } + } + listenForClientChange(): void { this.wsService.onClientChange((clients: number) => { if (clients === 0) { this.stopPolling(); } else { - if (!this.pollingInterval) { + if (this.pollingIntervals.length === 0) { this.startPolling(); } } @@ -110,17 +226,24 @@ export class HomepageService extends BaseService { startPolling(): void { logInfo("Polling started"); - this.pollingInterval = setInterval(() => { - logInfo("Polling now"); - this.getFullInformation(); - }, 30000); + + const config: [string[], number][] = [ + [["tidal"], 20_000], + [["desk"], 60_000], + [["temp", "grist"], 600_000], + ]; + + this.pollingIntervals = config.map(([components, interval]) => + setInterval(() => { + logInfo(`Polling ${components.join(", ")}`); + this.updatePartial(components); + }, interval), + ); } stopPolling(): void { logInfo("Polling ended"); - if (this.pollingInterval) { - clearInterval(this.pollingInterval); - this.pollingInterval = null; - } + this.pollingIntervals.forEach(clearInterval); + this.pollingIntervals = []; } }