diff --git a/package-lock.json b/package-lock.json index 806b51b..4b40128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,8 +31,8 @@ } }, "node_modules/@dpu/shared": { - "version": "1.9.6", - "resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#872d3755d06c8e8c6452d8ab7212b6426d84943b", + "version": "1.9.9", + "resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#d73d98068a779569e3be375f077de1e63f9efa9c", "dependencies": { "@types/ws": "^8.18.1", "axios": "^1.7.9", @@ -1725,9 +1725,9 @@ } }, "node_modules/pino": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.0.tgz", - "integrity": "sha512-0GNPNzHXBKw6U/InGe79A3Crzyk9bcSyObF9/Gfo9DLEf5qj5RF50RSjsu0W1rZ6ZqRGdzDFCRBQvi9/rSGPtA==", + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", "license": "MIT", "dependencies": { "@pinojs/redact": "^0.4.0", diff --git a/src/homepage/private-routes.ts b/src/homepage/private-routes.ts index 5c88b6c..b2e1bc1 100644 --- a/src/homepage/private-routes.ts +++ b/src/homepage/private-routes.ts @@ -1,9 +1,10 @@ -import type { - ComponentUpdate, - GristRecord_PersonalGoals, - HA_Update, - HomeAssistantEntity, - TidalGetCurrent, +import { + StatusComponent, + type ComponentUpdate, + type GristRecord_PersonalGoals, + type HA_Update, + type HomeAssistantEntity, + type TidalGetCurrent, } from "@dpu/shared"; import type { FastifyInstance, FastifyReply } from "fastify"; import type { FastifyRequest } from "fastify/types/request.js"; @@ -55,7 +56,7 @@ export async function privateHomepageRoutes( } const service_result = await hpService.updatePartial([ { - component: "grist", + component: StatusComponent.GRIST_PERSONAL_GOALS, data: gristService.transformToPersonalGoals(record), }, ]); @@ -99,7 +100,7 @@ export async function privateHomepageRoutes( switch (ha_update.entity_id) { case Config.homeassistant.id_sensor_desk_binary: { updates.push({ - component: "desk", + component: StatusComponent.HA_DESK_POSITION, data: haService.convertPosResultToApiAnswer( haService.convertHaEntityToPosResult(ha_entity), ), @@ -108,7 +109,7 @@ export async function privateHomepageRoutes( } case Config.homeassistant.id_sensor_roomtemp: updates.push({ - component: "desk", + component: StatusComponent.HA_TEMP, data: ha_entity.state, }); break; @@ -147,7 +148,7 @@ export async function privateHomepageRoutes( const update = request.body as TidalGetCurrent; const service_result = await hpService.updatePartial([ { - component: "tidal", + component: StatusComponent.TIDAL_CURRENT, data: update, }, ]); diff --git a/src/homepage/public-routes.ts b/src/homepage/public-routes.ts deleted file mode 100644 index 9ff085f..0000000 --- a/src/homepage/public-routes.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { - API_HA_DeskPosition, - GristRecord_PersonalGoals, - TidalGetCurrent, -} from "@dpu/shared"; -import type { FastifyInstance } from "fastify"; -import { z } from "zod"; -import type { HomepageService } from "./service.js"; - -export async function publicHomepageRoutes( - fastify: FastifyInstance, - { - hpService, - }: { - hpService: HomepageService; - }, -) { - fastify.get( - "/homepage/status", - { - schema: { - description: "Get all current information for dpu status page", - tags: ["homepage"], - response: { - 200: z.object({ - ha_desk_position: z.custom().nullable(), - ha_temp: z.string().nullable(), - tidal_current: z.custom().nullable(), - grist_personal_goals: z - .custom() - .nullable(), - }), - 418: z.object({ - error: z.string(), - }), - }, - }, - }, - async (_request, reply) => { - const service_result = await hpService.getFullInformation(); - - if (!service_result.successful) { - reply.code(418); - return { error: service_result.result }; - } - - return service_result.result; - }, - ); -} diff --git a/src/homepage/service.ts b/src/homepage/service.ts index ed2a2ad..381a541 100644 --- a/src/homepage/service.ts +++ b/src/homepage/service.ts @@ -1,18 +1,21 @@ import { - type API_HA_DeskPosition, - BaseService, - type ComponentUpdate, - type FullInformation, - type GristRecord_PersonalGoals, - type HomeAssistantDeskPositionResult, - type ServiceResult, - type TidalGetCurrent, - type WsService, + type API_HA_DeskPosition, + BaseService, + type ComponentUpdate, + type FullInformation, + type GristRecord_PersonalGoals, + type HomeAssistantDeskPositionResult, + type ServiceResult, + type TidalGetCurrent, + type WsService, + createComponentUpdate, + StatusComponent, } from "@dpu/shared"; -import { logInfo } from "@dpu/shared/dist/logger.js"; +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"; +import type { WebSocket } from "ws"; export class HomepageService extends BaseService { private gristService: GristService; @@ -39,21 +42,34 @@ export class HomepageService extends BaseService { this.wsService = wsService; } + async sendFullInformationToSocket(socket: WebSocket): Promise { + try { + const [desk, temp, tidal, personal_goals] = await this._getAll(); + const updates: ComponentUpdate[] = [ + createComponentUpdate(StatusComponent.HA_DESK_POSITION, desk), + createComponentUpdate(StatusComponent.HA_TEMP, temp), + createComponentUpdate(StatusComponent.TIDAL_CURRENT, tidal), + createComponentUpdate(StatusComponent.GRIST_PERSONAL_GOALS, personal_goals) + ]; + socket.send(JSON.stringify({ + type: "update", + data: updates + })) + } catch (error) { + logWarning("error getting all information for socket update.", error); + } + } + async getFullInformation(): Promise> { try { - const [desk, temp, tidal, personal_goals] = await Promise.all([ - this._getDesk(), - this._getTemp(), - this._getTidal(), - this._getGristPG(), - ]); + const [desk, temp, tidal, personal_goals] = await this._getAll(); return this.getSuccessfulResult( this.updateFull({ - ha_desk_position: desk, - ha_temp: temp, - tidal_current: tidal, - grist_personal_goals: personal_goals, + ha_desk_position: desk as API_HA_DeskPosition, + ha_temp: temp as string, + tidal_current: tidal as TidalGetCurrent, + grist_personal_goals: personal_goals as GristRecord_PersonalGoals, }), ); } catch (error) { @@ -61,6 +77,15 @@ export class HomepageService extends BaseService { } } + private async _getAll(): Promise> { + return await Promise.all([ + this._getDesk(), + this._getTemp(), + this._getTidal(), + this._getGristPG(), + ]); + } + private async _getDesk(): Promise { const desk = await this.haService.getDeskPosition(); return desk.successful @@ -112,26 +137,26 @@ export class HomepageService extends BaseService { const updates: ComponentUpdate[] = []; for (const component of components) { switch (component.component) { - case "desk": { + case StatusComponent.HA_DESK_POSITION: { this.updateHaDesk( (component.data as API_HA_DeskPosition) ?? (await this._getDesk()), updates, ); break; } - case "temp": + case StatusComponent.HA_TEMP: this.updateHaTemp( (component.data as string) ?? (await this._getTemp()), updates, ); break; - case "tidal": + case StatusComponent.TIDAL_CURRENT: this.updateTidal( (component.data as TidalGetCurrent) ?? (await this._getTidal()), updates, ); break; - case "grist": + case StatusComponent.GRIST_PERSONAL_GOALS: this.updateGristPG( (component.data as GristRecord_PersonalGoals) ?? (await this._getGristPG()), @@ -159,20 +184,14 @@ export class HomepageService extends BaseService { 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, - }); + updates.push(createComponentUpdate(StatusComponent.HA_DESK_POSITION, new_ha_desk_position)); } } 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, - }); + updates.push(createComponentUpdate(StatusComponent.HA_TEMP, new_ha_temp)); } } @@ -187,10 +206,7 @@ export class HomepageService extends BaseService { 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, - }); + updates.push(createComponentUpdate(StatusComponent.TIDAL_CURRENT, new_tidal_current)); } } @@ -215,10 +231,7 @@ export class HomepageService extends BaseService { 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, - }); + updates.push(createComponentUpdate(StatusComponent.GRIST_PERSONAL_GOALS, new_grist_personal_goals)); } } } diff --git a/src/index.ts b/src/index.ts index f2664b5..d48ea98 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,17 +3,17 @@ import { logError } from "@dpu/shared/dist/logger.js"; import fastifyCors, { type FastifyCorsOptions } from "@fastify/cors"; import fastifySwagger, { type SwaggerOptions } from "@fastify/swagger"; import fastifySwaggerUi, { - type FastifySwaggerUiOptions, + type FastifySwaggerUiOptions, } from "@fastify/swagger-ui"; import fastifyWebsocket from "@fastify/websocket"; import type { FastifyReply, FastifyRequest } from "fastify"; import Fastify from "fastify"; import fastifyAxios, { type FastifyAxiosOptions } from "fastify-axios"; import { - jsonSchemaTransform, - serializerCompiler, - validatorCompiler, - type ZodTypeProvider, + jsonSchemaTransform, + serializerCompiler, + validatorCompiler, + type ZodTypeProvider, } from "fastify-type-provider-zod"; import type { OpenAPIV3 } from "openapi-types"; import { SwaggerTheme, SwaggerThemeNameEnum } from "swagger-themes"; @@ -26,7 +26,6 @@ import { HomeAssistantClient } from "./homeassistant/client.js"; import { privateHomeAssistantRoutes } from "./homeassistant/private-routes.js"; import { HomeAssistantService } from "./homeassistant/service.js"; import { privateHomepageRoutes } from "./homepage/private-routes.js"; -import { publicHomepageRoutes } from "./homepage/public-routes.js"; import { HomepageService } from "./homepage/service.js"; import { TidalClient } from "./tidal/client.js"; import { privateTidalRoutes } from "./tidal/private-routes.js"; @@ -168,10 +167,7 @@ async function verifyAPIKey( } // Register routes -await publicServer.register(publicWsRoutes, { wsService }); -await publicServer.register(publicHomepageRoutes, { - hpService, -}); +await publicServer.register(publicWsRoutes, { wsService, hpService }); await privateServer.register(privateGristRoutes, { gristService }); await privateServer.register(privateHomeAssistantRoutes, { diff --git a/src/websocket/public-routes.ts b/src/websocket/public-routes.ts index 050a68c..96130e1 100644 --- a/src/websocket/public-routes.ts +++ b/src/websocket/public-routes.ts @@ -1,16 +1,19 @@ import { logInfo, type WsService } from "@dpu/shared"; import type { FastifyInstance } from "fastify"; +import type { HomepageService } from "../homepage/service"; export async function publicWsRoutes( fastify: FastifyInstance, { wsService, + hpService, }: { wsService: WsService; + hpService: HomepageService; }, ) { fastify.get( - "/dpu/events", + "/dpu/status/events", { schema: { description: "Register for WebSocket events", @@ -22,6 +25,7 @@ export async function publicWsRoutes( (socket, _request) => { wsService.addClient(socket); socket.send(JSON.stringify({ type: "message", data: "Connected" })); + hpService.sendFullInformationToSocket(socket) logInfo(`Connection for client established`); socket.on("close", () => {