Skip to content

Commit

Permalink
misc tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
zoe-codez committed Apr 22, 2024
1 parent 56d3e73 commit 6c0fe5f
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 70 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@digital-alchemy/hass",
"repository": "https://github.com/Digital-Alchemy-TS/hass",
"homepage": "https://docs.digital-alchemy.app/Hass",
"version": "0.3.14",
"version": "0.3.16",
"scripts": {
"build": "rm -rf dist/; tsc",
"lint": "eslint src",
Expand Down
73 changes: 62 additions & 11 deletions src/extensions/area.extension.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { TServiceParams } from "@digital-alchemy/core";
import {
eachSeries,
InternalError,
TServiceParams,
} from "@digital-alchemy/core";

import { TAreaId } from "../dynamic";
import { AreaCreate, AreaDetails, EARLY_ON_READY } from "../helpers";
import {
AREA_REGISTRY_UPDATED,
AreaCreate,
AreaDetails,
EARLY_ON_READY,
ENTITY_REGISTRY_UPDATED,
PICK_ENTITY,
} from "../helpers";

export function Area({
hass,
context,
config,
logger,
event,
lifecycle,
}: TServiceParams) {
hass.socket.onConnect(async () => {
Expand All @@ -26,22 +38,58 @@ export function Area({
async exec() {
hass.area.current = await hass.area.list();
logger.debug(`area registry updated`);
event.emit(AREA_REGISTRY_UPDATED);
},
});
});

return {
async apply(area: TAreaId, entities: PICK_ENTITY[]) {
const out = { updated: [] as PICK_ENTITY[] };
await eachSeries(entities, async (entity: PICK_ENTITY) => {
const details = hass.entity.registry.current.find(
item => item.entity_id === entity,
);
if (!details) {
throw new InternalError(
context,
"UNKNOWN_ENTITY",
`Cannot find ${entity} in entity registry`,
);
}
if (details.area_id === area) {
return;
}
await new Promise<void>(async done => {
event.once(ENTITY_REGISTRY_UPDATED, done);
logger.trace({ area, entity }, `setting area`);
out.updated.push(entity);
await hass.socket.sendMessage({
area_id: area,
entity_id: entity,
type: "config/entity_registry/update",
});
});
});
return out;
},
async create(details: AreaCreate) {
await hass.socket.sendMessage({
type: "config/area_registry/create",
...details,
return await new Promise<void>(async done => {
event.once(AREA_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
type: "config/area_registry/create",
...details,
});
});
},
current: [] as AreaDetails[],
async delete(area_id: TAreaId) {
await hass.socket.sendMessage({
area_id,
type: "config/area_registry/delete",
return await new Promise<void>(async done => {
event.once(AREA_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
area_id,
type: "config/area_registry/delete",
});
});
},
async list() {
Expand All @@ -50,9 +98,12 @@ export function Area({
});
},
async update(details: AreaDetails) {
await hass.socket.sendMessage({
type: "config/area_registry/update",
...details,
return await new Promise<void>(async done => {
event.once(AREA_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
type: "config/area_registry/update",
...details,
});
});
},
};
Expand Down
23 changes: 20 additions & 3 deletions src/extensions/backup.extension.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
import { HALF, SECOND, sleep, TServiceParams } from "@digital-alchemy/core";
import { HALF, is, SECOND, sleep, TServiceParams } from "@digital-alchemy/core";

import { BackupResponse, HomeAssistantBackup } from "../helpers";
import {
BackupResponse,
HomeAssistantBackup,
SignRequestResponse,
} from "../helpers";

export function Backup({ logger, hass }: TServiceParams) {
async function download(slug: string, destination: string): Promise<void> {
const result = await hass.socket.sendMessage<SignRequestResponse>({
path: `/api/backup/download/${slug}`,
type: "auth/sign_path",
});
if (!is.object(result) || !("path" in result)) {
return;
}
await hass.fetch.download(destination, {
url: result.path,
});
}

async function generate(): Promise<HomeAssistantBackup> {
let current = await list();
// const originalLength = current.backups.length;
Expand Down Expand Up @@ -41,5 +58,5 @@ export function Backup({ logger, hass }: TServiceParams) {
await hass.socket.sendMessage({ slug, type: "backup/remove" }, false);
}

return { generate, list, remove };
return { download, generate, list, remove };
}
46 changes: 29 additions & 17 deletions src/extensions/entity.extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Get } from "type-fest";
import {
ALL_DOMAINS,
EditLabelOptions,
ENTITY_REGISTRY_UPDATED,
ENTITY_STATE,
EntityHistoryDTO,
EntityHistoryResult,
Expand Down Expand Up @@ -77,6 +78,7 @@ export function EntityManager({
hass,
config,
lifecycle,
event,
context,
internal,
}: TServiceParams) {
Expand All @@ -93,8 +95,8 @@ export function EntityManager({

// * Local event emitter for coordination of socket events
// Other libraries will internally take advantage of this eventemitter
const event = new EventEmitter();
event.setMaxListeners(UNLIMITED);
const ENTITY_EVENTS = new EventEmitter();
ENTITY_EVENTS.setMaxListeners(UNLIMITED);
let init = false;

// #MARK: getCurrentState
Expand Down Expand Up @@ -150,11 +152,11 @@ export function EntityManager({
get: (_, property: Extract<keyof ByIdProxy<ENTITY_ID>, string>) => {
if (property === "onUpdate") {
return (callback: TAnyFunction) =>
event.on(entity_id, async (a, b) => callback(a, b));
ENTITY_EVENTS.on(entity_id, async (a, b) => callback(a, b));
}
if (property === "once") {
return (callback: TAnyFunction) =>
event.once(entity_id, async (a, b) => callback(a, b));
ENTITY_EVENTS.once(entity_id, async (a, b) => callback(a, b));
}
if (property === "entity_id") {
return entity_id;
Expand All @@ -164,8 +166,10 @@ export function EntityManager({
}
if (property === "nextState") {
return new Promise<ENTITY_STATE<ENTITY_ID>>(done => {
event.once(entity_id, (entity: ENTITY_STATE<ENTITY_ID>) =>
done(entity as ENTITY_STATE<ENTITY_ID>),
ENTITY_EVENTS.once(
entity_id,
(entity: ENTITY_STATE<ENTITY_ID>) =>
done(entity satisfies ENTITY_STATE<ENTITY_ID>),
);
});
}
Expand Down Expand Up @@ -329,7 +333,7 @@ export function EntityManager({
async entity =>
await EntityUpdateReceiver(
entity.entity_id,
entity as ENTITY_STATE<PICK_ENTITY>,
entity satisfies ENTITY_STATE<PICK_ENTITY>,
internal.utils.object.get(oldState, entity.entity_id),
),
);
Expand All @@ -340,7 +344,7 @@ export function EntityManager({
// #MARK: is.entity
// Actually tie the type casting to real state
is.entity = (entityId: PICK_ENTITY): entityId is PICK_ENTITY =>
is.undefined(internal.utils.object.get(MASTER_STATE, entityId));
!is.undefined(internal.utils.object.get(MASTER_STATE, entityId));

// #MARK: EntityUpdateReceiver
function EntityUpdateReceiver<ENTITY extends PICK_ENTITY = PICK_ENTITY>(
Expand All @@ -360,7 +364,7 @@ export function EntityManager({
}
internal.utils.object.set(MASTER_STATE, entity_id, new_state);
if (!hass.socket.pauseMessages) {
event.emit(entity_id, new_state, old_state);
ENTITY_EVENTS.emit(entity_id, new_state, old_state);
}
}

Expand All @@ -376,10 +380,13 @@ export function EntityManager({
logger.debug({ name: entity }, `already has label {%s}`, label);
return;
}
await hass.socket.sendMessage({
entity_id: entity,
labels: [...current.labels, label],
type: UPDATE_REGISTRY,
return await new Promise<void>(async done => {
event.once(ENTITY_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
entity_id: entity,
labels: [...current.labels, label],
type: UPDATE_REGISTRY,
});
});
}

Expand All @@ -402,10 +409,13 @@ export function EntityManager({
return;
}
logger.debug({ name: entity }, `removing label [%s]`, label);
await hass.socket.sendMessage({
entity_id: entity,
labels: current.labels.filter(i => i !== label),
type: UPDATE_REGISTRY,
return await new Promise<void>(async done => {
event.once(ENTITY_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
entity_id: entity,
labels: current.labels.filter(i => i !== label),
type: UPDATE_REGISTRY,
});
});
}

Expand All @@ -427,6 +437,7 @@ export function EntityManager({
async exec() {
logger.debug("entity registry updated");
hass.entity.registry.current = await hass.entity.registry.list();
event.emit(ENTITY_REGISTRY_UPDATED);
},
});
});
Expand Down Expand Up @@ -560,6 +571,7 @@ export function EntityManager({
};
}

// mental note: stop changing this from string
declare module "@digital-alchemy/core" {
export interface IsIt {
entity(entity: string): entity is PICK_ENTITY;
Expand Down
36 changes: 26 additions & 10 deletions src/extensions/floor.extension.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { is, TServiceParams } from "@digital-alchemy/core";

import { TFloorId } from "../dynamic";
import { EARLY_ON_READY, FloorCreate, FloorDetails } from "../helpers";
import {
EARLY_ON_READY,
FLOOR_REGISTRY_UPDATED,
FloorCreate,
FloorDetails,
} from "../helpers";

export function Floor({
hass,
config,
context,
event,
logger,
lifecycle,
}: TServiceParams) {
Expand All @@ -26,6 +32,7 @@ export function Floor({
async exec() {
hass.floor.current = await hass.floor.list();
logger.debug(`floor registry updated`);
event.emit(FLOOR_REGISTRY_UPDATED);
},
});
});
Expand All @@ -35,16 +42,22 @@ export function Floor({

return {
async create(details: FloorCreate) {
await hass.socket.sendMessage({
type: "config/floor_registry/create",
...details,
return await new Promise<void>(async done => {
event.once(FLOOR_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
type: "config/floor_registry/create",
...details,
});
});
},
current: [] as FloorDetails[],
async delete(floor_id: TFloorId) {
await hass.socket.sendMessage({
floor_id,
type: "config/floor_registry/delete",
return await new Promise<void>(async done => {
event.once(FLOOR_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
floor_id,
type: "config/floor_registry/delete",
});
});
},
async list() {
Expand All @@ -53,9 +66,12 @@ export function Floor({
});
},
async update(details: FloorDetails) {
await hass.socket.sendMessage({
type: "config/floor_registry/update",
...details,
return await new Promise<void>(async done => {
event.once(FLOOR_REGISTRY_UPDATED, done);
await hass.socket.sendMessage({
type: "config/floor_registry/update",
...details,
});
});
},
};
Expand Down
Loading

0 comments on commit 6c0fe5f

Please sign in to comment.