even cooler now
This commit is contained in:
10
package-lock.json
generated
10
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -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<API_HA_DeskPosition>().nullable(),
|
||||
ha_temp: z.string().nullable(),
|
||||
tidal_current: z.custom<TidalGetCurrent>().nullable(),
|
||||
grist_personal_goals: z
|
||||
.custom<GristRecord_PersonalGoals>()
|
||||
.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;
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -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<null> {
|
||||
private gristService: GristService;
|
||||
@@ -39,21 +42,34 @@ export class HomepageService extends BaseService<null> {
|
||||
this.wsService = wsService;
|
||||
}
|
||||
|
||||
async sendFullInformationToSocket(socket: WebSocket): Promise<void> {
|
||||
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<ServiceResult<FullInformation | string>> {
|
||||
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<null> {
|
||||
}
|
||||
}
|
||||
|
||||
private async _getAll(): Promise<Iterable<unknown>> {
|
||||
return await Promise.all([
|
||||
this._getDesk(),
|
||||
this._getTemp(),
|
||||
this._getTidal(),
|
||||
this._getGristPG(),
|
||||
]);
|
||||
}
|
||||
|
||||
private async _getDesk(): Promise<API_HA_DeskPosition | null> {
|
||||
const desk = await this.haService.getDeskPosition();
|
||||
return desk.successful
|
||||
@@ -112,26 +137,26 @@ export class HomepageService extends BaseService<null> {
|
||||
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<null> {
|
||||
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<null> {
|
||||
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<null> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
src/index.ts
16
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, {
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
Reference in New Issue
Block a user