feat: add homeassistant integration (#578)

This commit is contained in:
Manuel
2024-06-10 21:16:39 +02:00
committed by GitHub
parent 19498854fc
commit 2e782ae442
28 changed files with 468 additions and 31 deletions

View File

@@ -0,0 +1,73 @@
import { appendPath } from "@homarr/common";
import { logger } from "@homarr/log";
import { Integration } from "../base/integration";
import { entityStateSchema } from "./homeassistant-types";
export class HomeAssistantIntegration extends Integration {
async getEntityStateAsync(entityId: string) {
try {
const response = await fetch(appendPath(this.integration.url, `/states/${entityId}`), {
headers: {
Authorization: `Bearer ${this.getSecretValue("apiKey")}`,
},
});
const body = (await response.json()) as unknown;
if (!response.ok) {
logger.warn(`Response did not indicate success`);
return {
error: "Response did not indicate success",
};
}
return entityStateSchema.safeParseAsync(body);
} catch (err) {
logger.error(`Failed to fetch from ${this.integration.url}: ${err as string}`);
return {
success: false as const,
error: err,
};
}
}
async triggerAutomationAsync(entityId: string) {
try {
const response = await fetch(appendPath(this.integration.url, "/services/automation/trigger"), {
headers: {
Authorization: `Bearer ${this.getSecretValue("apiKey")}`,
},
body: JSON.stringify({
entity_id: entityId,
}),
method: "POST",
});
return response.ok;
} catch (err) {
logger.error(`Failed to fetch from '${this.integration.url}': ${err as string}`);
return false;
}
}
/**
* Triggers a toggle action for a specific entity.
*
* @param entityId - The ID of the entity to toggle.
* @returns A boolean indicating whether the toggle action was successful.
*/
async triggerToggleAsync(entityId: string) {
try {
const response = await fetch(appendPath(this.integration.url, "/services/homeassistant/toggle"), {
headers: {
Authorization: `Bearer ${this.getSecretValue("apiKey")}`,
},
body: JSON.stringify({
entity_id: entityId,
}),
method: "POST",
});
return response.ok;
} catch (err) {
logger.error(`Failed to fetch from '${this.integration.url}': ${err as string}`);
return false;
}
}
}

View File

@@ -0,0 +1,13 @@
import { z } from "@homarr/validation";
export const entityStateSchema = z.object({
attributes: z.record(
z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(z.union([z.string(), z.number()]))]),
),
entity_id: z.string(),
last_changed: z.string().pipe(z.coerce.date()),
last_updated: z.string().pipe(z.coerce.date()),
state: z.string(),
});
export type EntityState = z.infer<typeof entityStateSchema>;

View File

@@ -1 +1,2 @@
export { PiHoleIntegration } from "./pi-hole/pi-hole-integration";
export { HomeAssistantIntegration } from "./homeassistant/homeassistant-integration";