This commit is contained in:
2025-12-30 02:57:24 +08:00
parent bd188b9116
commit f18c6d4e3d
6 changed files with 110 additions and 10 deletions

View File

@@ -1,11 +1,15 @@
{
"name": "@kevisual/ha-api",
"version": "0.0.5",
"version": "0.0.6",
"description": "",
"main": "src/index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"app": {
"type": "pm2-system-app",
"entry": "src/index.ts"
},
"files": [
"src"
],

View File

@@ -1,4 +1,4 @@
# 灯光管理
## 灯光管理
该模块提供对Home Assistant中灯光设备的管理功能包括获取灯光列表、搜索特定灯光设备以及控制灯光的开关状态。
@@ -25,3 +25,22 @@ if(searchResult.hasMore) {
console.log('没有找到匹配的灯光设备。');
}
```
## 音箱管理
该模块提供对Home Assistant中音箱设备的管理功能执行文本指令等。
```ts
import { TextHA } from '@kevisual/ha-api';
const tts = new TextHA({
host: 'http://your-home-assistant:8123',
token: 'your-long-lived-access-token',
});
// 获取所有音箱设备
const entities = await text.getSpeakerEntities();
// 执行文本指令
const res2 = await text.executeTextDirective('text.xiaomi_lx06_9e08_execute_text_directive', '关闭阳台灯');
console.log(res2);
```

View File

@@ -4,6 +4,7 @@ export type HACoreOptions = {
token: string;
homeassistantURL?: string;
ttl?: number;
ha?: HACore;
}
/**
* https://developers.home-assistant.io/docs/api/rest/
@@ -14,7 +15,10 @@ export class HACore {
static serviceName = '';
cache: LRUStorage;
constructor(options: HACoreOptions) {
this.token = options?.token;
this.token = options?.token!;
if (!this.token && options.ha) {
this.token = options.ha?.token;
}
this.homeassistantURL = options?.homeassistantURL || 'http://localhost:8123';
this.cache = new LRUStorage({ max: 200, ttl: options?.ttl || 1000 * 60 * 30 }); // 30分钟缓存
}
@@ -91,9 +95,9 @@ export class HACore {
});
return infoList;
}
async runService(opts: { entity_id?: string, name?: string, service?: string, data?: Record<string, any> }) {
async runService(opts: { entity_id?: string, name?: string, serverName?: string, service?: string, data?: Record<string, any> }) {
// e.g., service: 'turn_on', 'turn_off', 'toggle'
const serviceName = (this.constructor as typeof HACore).serviceName;
const serviceName = opts?.serverName || (this.constructor as typeof HACore).serviceName;
let { entity_id, service = '', data } = opts;
if (!entity_id && opts.name) {
const entities = await this.getServiceEntities();
@@ -156,7 +160,7 @@ export const entitiesTypes = [
{ "type": "number", "desc": "可调整的数值控件,有上下限,如温度设定、定时器" }
]
type EntityItem = {
export type EntityItem = {
entity_id: string;
attributes: {
friendly_name?: string;

View File

@@ -1,5 +1,5 @@
import Fuse from "fuse.js";
import { HACore, HACoreOptions, InfoItem } from "./core.ts";
import { HACore, HACoreOptions, InfoItem, EntityItem } from "./core.ts";
export class LightHA extends HACore {
static serviceName = 'light';
constructor(options: HACoreOptions) {
@@ -60,3 +60,47 @@ export class ButtonHA extends HACore {
super(options);
}
}
export class SpeakerHA extends HACore {
static serviceName = 'notify';
constructor(options: HACoreOptions) {
super(options);
}
/**
* 获取音箱实体列表
* @returns
*/
getSpeakerEntities(): Promise<EntityItem[]> {
return this.getEntities((entity: EntityItem) => entity.entity_id.startsWith(`notify.`) && entity.attributes?.friendly_name?.includes?.('音箱'));
}
}
export class TextHA extends HACore {
static serviceName = 'text';
constructor(options: HACoreOptions) {
super(options);
}
/**
* 获取音箱实体列表
* @returns
*/
getSpeakerEntities(): Promise<EntityItem[]> {
return this.getEntities((entity: EntityItem) => entity.entity_id.startsWith(`text.`) && entity.attributes?.friendly_name?.includes?.('音箱'));
}
/**
* 执行文本指令
* @param entity_id
* @param value
* @returns
*/
executeTextDirective(entity_id: string, value: string): Promise<any> {
return this.runService({
entity_id,
service: 'set_value',
data: {
value
}
});
}
}

View File

@@ -1,4 +1,4 @@
import { LightHA, AutoHA, EventHA, ScriptHA, ButtonHA } from "../src/index.ts";
import { LightHA, AutoHA, EventHA, ScriptHA, ButtonHA, HACore, SpeakerHA, TextHA } from "../src/index.ts";
import util from 'node:util';
import dotenv from 'dotenv';
@@ -7,13 +7,15 @@ export const showMore = (obj: any) => {
return util.inspect(obj, { depth: null, colors: true });
}
export const hacore = new LightHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const hacore = new HACore({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const light = new LightHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const auto = new AutoHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const event = new EventHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const script = new ScriptHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const button = new ButtonHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const speaker = new SpeakerHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
export const text = new TextHA({ token: process.env.HAAS_TOKEN || '', homeassistantURL: process.env.HAAS_URL });
// const enti = await hacore.getEntities((item) => item.attributes?.friendly_name?.includes?.('电视'));
// console.log(showMore(enti), enti.length);

27
test/speaker.ts Normal file
View File

@@ -0,0 +1,27 @@
import { speaker, showMore, text } from './common.ts';
// const entities = await speaker.getSpeakerEntities();
const entities = await text.getSpeakerEntities();
console.log(showMore(entities));
console.log(`实体数量: ${entities.length}`);
// const res = await speaker.runService({
// entity_id: 'text.xiaomi_lx06_9e08_execute_text_directive',
// service: 'set_value',
// serverName: 'text',
// data: {
// value: '关闭阳台灯'
// }
// });
// console.log(showMore(res));
const res2 = await text.executeTextDirective('text.xiaomi_lx06_9e08_execute_text_directive', '关闭阳台灯');
console.log(showMore(res2));
const call = { "type": "call_service", "domain": "text", "service": "set_value", "target": { "entity_id": "text.xiaomi_lx06_9e08_execute_text_directive" }, "return_response": false, "service_data": { "value": "关闭阳台灯" }, "id": 101 }