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": {
|
"node_modules/@dpu/shared": {
|
||||||
"version": "1.9.6",
|
"version": "1.9.9",
|
||||||
"resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#872d3755d06c8e8c6452d8ab7212b6426d84943b",
|
"resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#d73d98068a779569e3be375f077de1e63f9efa9c",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
@@ -1725,9 +1725,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pino": {
|
"node_modules/pino": {
|
||||||
"version": "10.3.0",
|
"version": "10.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/pino/-/pino-10.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz",
|
||||||
"integrity": "sha512-0GNPNzHXBKw6U/InGe79A3Crzyk9bcSyObF9/Gfo9DLEf5qj5RF50RSjsu0W1rZ6ZqRGdzDFCRBQvi9/rSGPtA==",
|
"integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pinojs/redact": "^0.4.0",
|
"@pinojs/redact": "^0.4.0",
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import type {
|
import {
|
||||||
ComponentUpdate,
|
StatusComponent,
|
||||||
GristRecord_PersonalGoals,
|
type ComponentUpdate,
|
||||||
HA_Update,
|
type GristRecord_PersonalGoals,
|
||||||
HomeAssistantEntity,
|
type HA_Update,
|
||||||
TidalGetCurrent,
|
type HomeAssistantEntity,
|
||||||
|
type TidalGetCurrent,
|
||||||
} from "@dpu/shared";
|
} from "@dpu/shared";
|
||||||
import type { FastifyInstance, FastifyReply } from "fastify";
|
import type { FastifyInstance, FastifyReply } from "fastify";
|
||||||
import type { FastifyRequest } from "fastify/types/request.js";
|
import type { FastifyRequest } from "fastify/types/request.js";
|
||||||
@@ -55,7 +56,7 @@ export async function privateHomepageRoutes(
|
|||||||
}
|
}
|
||||||
const service_result = await hpService.updatePartial([
|
const service_result = await hpService.updatePartial([
|
||||||
{
|
{
|
||||||
component: "grist",
|
component: StatusComponent.GRIST_PERSONAL_GOALS,
|
||||||
data: gristService.transformToPersonalGoals(record),
|
data: gristService.transformToPersonalGoals(record),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -99,7 +100,7 @@ export async function privateHomepageRoutes(
|
|||||||
switch (ha_update.entity_id) {
|
switch (ha_update.entity_id) {
|
||||||
case Config.homeassistant.id_sensor_desk_binary: {
|
case Config.homeassistant.id_sensor_desk_binary: {
|
||||||
updates.push({
|
updates.push({
|
||||||
component: "desk",
|
component: StatusComponent.HA_DESK_POSITION,
|
||||||
data: haService.convertPosResultToApiAnswer(
|
data: haService.convertPosResultToApiAnswer(
|
||||||
haService.convertHaEntityToPosResult(ha_entity),
|
haService.convertHaEntityToPosResult(ha_entity),
|
||||||
),
|
),
|
||||||
@@ -108,7 +109,7 @@ export async function privateHomepageRoutes(
|
|||||||
}
|
}
|
||||||
case Config.homeassistant.id_sensor_roomtemp:
|
case Config.homeassistant.id_sensor_roomtemp:
|
||||||
updates.push({
|
updates.push({
|
||||||
component: "desk",
|
component: StatusComponent.HA_TEMP,
|
||||||
data: ha_entity.state,
|
data: ha_entity.state,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -147,7 +148,7 @@ export async function privateHomepageRoutes(
|
|||||||
const update = request.body as TidalGetCurrent;
|
const update = request.body as TidalGetCurrent;
|
||||||
const service_result = await hpService.updatePartial([
|
const service_result = await hpService.updatePartial([
|
||||||
{
|
{
|
||||||
component: "tidal",
|
component: StatusComponent.TIDAL_CURRENT,
|
||||||
data: update,
|
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;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -8,11 +8,14 @@ import {
|
|||||||
type ServiceResult,
|
type ServiceResult,
|
||||||
type TidalGetCurrent,
|
type TidalGetCurrent,
|
||||||
type WsService,
|
type WsService,
|
||||||
|
createComponentUpdate,
|
||||||
|
StatusComponent,
|
||||||
} from "@dpu/shared";
|
} 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 { GristService } from "../grist/service";
|
||||||
import type { HomeAssistantService } from "../homeassistant/service";
|
import type { HomeAssistantService } from "../homeassistant/service";
|
||||||
import type { TidalService } from "../tidal/service";
|
import type { TidalService } from "../tidal/service";
|
||||||
|
import type { WebSocket } from "ws";
|
||||||
|
|
||||||
export class HomepageService extends BaseService<null> {
|
export class HomepageService extends BaseService<null> {
|
||||||
private gristService: GristService;
|
private gristService: GristService;
|
||||||
@@ -39,21 +42,34 @@ export class HomepageService extends BaseService<null> {
|
|||||||
this.wsService = wsService;
|
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>> {
|
async getFullInformation(): Promise<ServiceResult<FullInformation | string>> {
|
||||||
try {
|
try {
|
||||||
const [desk, temp, tidal, personal_goals] = await Promise.all([
|
const [desk, temp, tidal, personal_goals] = await this._getAll();
|
||||||
this._getDesk(),
|
|
||||||
this._getTemp(),
|
|
||||||
this._getTidal(),
|
|
||||||
this._getGristPG(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return this.getSuccessfulResult(
|
return this.getSuccessfulResult(
|
||||||
this.updateFull({
|
this.updateFull({
|
||||||
ha_desk_position: desk,
|
ha_desk_position: desk as API_HA_DeskPosition,
|
||||||
ha_temp: temp,
|
ha_temp: temp as string,
|
||||||
tidal_current: tidal,
|
tidal_current: tidal as TidalGetCurrent,
|
||||||
grist_personal_goals: personal_goals,
|
grist_personal_goals: personal_goals as GristRecord_PersonalGoals,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} 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> {
|
private async _getDesk(): Promise<API_HA_DeskPosition | null> {
|
||||||
const desk = await this.haService.getDeskPosition();
|
const desk = await this.haService.getDeskPosition();
|
||||||
return desk.successful
|
return desk.successful
|
||||||
@@ -112,26 +137,26 @@ export class HomepageService extends BaseService<null> {
|
|||||||
const updates: ComponentUpdate[] = [];
|
const updates: ComponentUpdate[] = [];
|
||||||
for (const component of components) {
|
for (const component of components) {
|
||||||
switch (component.component) {
|
switch (component.component) {
|
||||||
case "desk": {
|
case StatusComponent.HA_DESK_POSITION: {
|
||||||
this.updateHaDesk(
|
this.updateHaDesk(
|
||||||
(component.data as API_HA_DeskPosition) ?? (await this._getDesk()),
|
(component.data as API_HA_DeskPosition) ?? (await this._getDesk()),
|
||||||
updates,
|
updates,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "temp":
|
case StatusComponent.HA_TEMP:
|
||||||
this.updateHaTemp(
|
this.updateHaTemp(
|
||||||
(component.data as string) ?? (await this._getTemp()),
|
(component.data as string) ?? (await this._getTemp()),
|
||||||
updates,
|
updates,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "tidal":
|
case StatusComponent.TIDAL_CURRENT:
|
||||||
this.updateTidal(
|
this.updateTidal(
|
||||||
(component.data as TidalGetCurrent) ?? (await this._getTidal()),
|
(component.data as TidalGetCurrent) ?? (await this._getTidal()),
|
||||||
updates,
|
updates,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "grist":
|
case StatusComponent.GRIST_PERSONAL_GOALS:
|
||||||
this.updateGristPG(
|
this.updateGristPG(
|
||||||
(component.data as GristRecord_PersonalGoals) ??
|
(component.data as GristRecord_PersonalGoals) ??
|
||||||
(await this._getGristPG()),
|
(await this._getGristPG()),
|
||||||
@@ -159,20 +184,14 @@ export class HomepageService extends BaseService<null> {
|
|||||||
new_ha_desk_position?.is_standing
|
new_ha_desk_position?.is_standing
|
||||||
) {
|
) {
|
||||||
this.lastPoll.ha_desk_position = new_ha_desk_position;
|
this.lastPoll.ha_desk_position = new_ha_desk_position;
|
||||||
updates.push({
|
updates.push(createComponentUpdate(StatusComponent.HA_DESK_POSITION, new_ha_desk_position));
|
||||||
component: "ha_desk_position",
|
|
||||||
data: new_ha_desk_position,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHaTemp(new_ha_temp: string | null, updates: ComponentUpdate[]): void {
|
updateHaTemp(new_ha_temp: string | null, updates: ComponentUpdate[]): void {
|
||||||
if (this.lastPoll.ha_temp !== new_ha_temp) {
|
if (this.lastPoll.ha_temp !== new_ha_temp) {
|
||||||
this.lastPoll.ha_temp = new_ha_temp;
|
this.lastPoll.ha_temp = new_ha_temp;
|
||||||
updates.push({
|
updates.push(createComponentUpdate(StatusComponent.HA_TEMP, new_ha_temp));
|
||||||
component: "ha_temp",
|
|
||||||
data: 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?.volume !== new_tidal_current?.volume
|
||||||
) {
|
) {
|
||||||
this.lastPoll.tidal_current = new_tidal_current;
|
this.lastPoll.tidal_current = new_tidal_current;
|
||||||
updates.push({
|
updates.push(createComponentUpdate(StatusComponent.TIDAL_CURRENT, new_tidal_current));
|
||||||
component: "tidal_current",
|
|
||||||
data: new_tidal_current,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,10 +231,7 @@ export class HomepageService extends BaseService<null> {
|
|||||||
new_grist_personal_goals?.stairs
|
new_grist_personal_goals?.stairs
|
||||||
) {
|
) {
|
||||||
this.lastPoll.grist_personal_goals = new_grist_personal_goals;
|
this.lastPoll.grist_personal_goals = new_grist_personal_goals;
|
||||||
updates.push({
|
updates.push(createComponentUpdate(StatusComponent.GRIST_PERSONAL_GOALS, new_grist_personal_goals));
|
||||||
component: "grist_personal_goals",
|
|
||||||
data: new_grist_personal_goals,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import { HomeAssistantClient } from "./homeassistant/client.js";
|
|||||||
import { privateHomeAssistantRoutes } from "./homeassistant/private-routes.js";
|
import { privateHomeAssistantRoutes } from "./homeassistant/private-routes.js";
|
||||||
import { HomeAssistantService } from "./homeassistant/service.js";
|
import { HomeAssistantService } from "./homeassistant/service.js";
|
||||||
import { privateHomepageRoutes } from "./homepage/private-routes.js";
|
import { privateHomepageRoutes } from "./homepage/private-routes.js";
|
||||||
import { publicHomepageRoutes } from "./homepage/public-routes.js";
|
|
||||||
import { HomepageService } from "./homepage/service.js";
|
import { HomepageService } from "./homepage/service.js";
|
||||||
import { TidalClient } from "./tidal/client.js";
|
import { TidalClient } from "./tidal/client.js";
|
||||||
import { privateTidalRoutes } from "./tidal/private-routes.js";
|
import { privateTidalRoutes } from "./tidal/private-routes.js";
|
||||||
@@ -168,10 +167,7 @@ async function verifyAPIKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register routes
|
// Register routes
|
||||||
await publicServer.register(publicWsRoutes, { wsService });
|
await publicServer.register(publicWsRoutes, { wsService, hpService });
|
||||||
await publicServer.register(publicHomepageRoutes, {
|
|
||||||
hpService,
|
|
||||||
});
|
|
||||||
|
|
||||||
await privateServer.register(privateGristRoutes, { gristService });
|
await privateServer.register(privateGristRoutes, { gristService });
|
||||||
await privateServer.register(privateHomeAssistantRoutes, {
|
await privateServer.register(privateHomeAssistantRoutes, {
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { logInfo, type WsService } from "@dpu/shared";
|
import { logInfo, type WsService } from "@dpu/shared";
|
||||||
import type { FastifyInstance } from "fastify";
|
import type { FastifyInstance } from "fastify";
|
||||||
|
import type { HomepageService } from "../homepage/service";
|
||||||
|
|
||||||
export async function publicWsRoutes(
|
export async function publicWsRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
{
|
{
|
||||||
wsService,
|
wsService,
|
||||||
|
hpService,
|
||||||
}: {
|
}: {
|
||||||
wsService: WsService;
|
wsService: WsService;
|
||||||
|
hpService: HomepageService;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
fastify.get(
|
fastify.get(
|
||||||
"/dpu/events",
|
"/dpu/status/events",
|
||||||
{
|
{
|
||||||
schema: {
|
schema: {
|
||||||
description: "Register for WebSocket events",
|
description: "Register for WebSocket events",
|
||||||
@@ -22,6 +25,7 @@ export async function publicWsRoutes(
|
|||||||
(socket, _request) => {
|
(socket, _request) => {
|
||||||
wsService.addClient(socket);
|
wsService.addClient(socket);
|
||||||
socket.send(JSON.stringify({ type: "message", data: "Connected" }));
|
socket.send(JSON.stringify({ type: "message", data: "Connected" }));
|
||||||
|
hpService.sendFullInformationToSocket(socket)
|
||||||
logInfo(`Connection for client established`);
|
logInfo(`Connection for client established`);
|
||||||
|
|
||||||
socket.on("close", () => {
|
socket.on("close", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user