@digital-alchemy/hass 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/dynamic.d.ts +1126 -0
- package/dist/dynamic.js +153 -0
- package/dist/dynamic.js.map +1 -0
- package/dist/extensions/call-proxy.extension.d.ts +4 -0
- package/dist/extensions/call-proxy.extension.js +88 -0
- package/dist/extensions/call-proxy.extension.js.map +1 -0
- package/dist/extensions/config.extension.d.ts +2 -0
- package/dist/extensions/config.extension.js +53 -0
- package/dist/extensions/config.extension.js.map +1 -0
- package/dist/extensions/entity-manager.extension.d.ts +61 -0
- package/dist/extensions/entity-manager.extension.js +212 -0
- package/dist/extensions/entity-manager.extension.js.map +1 -0
- package/dist/extensions/fetch-api.extension.d.ts +29 -0
- package/dist/extensions/fetch-api.extension.js +174 -0
- package/dist/extensions/fetch-api.extension.js.map +1 -0
- package/dist/extensions/index.d.ts +6 -0
- package/dist/extensions/index.js +10 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/utilities.extension.d.ts +9 -0
- package/dist/extensions/utilities.extension.js +43 -0
- package/dist/extensions/utilities.extension.js.map +1 -0
- package/dist/extensions/websocket-api.extension.d.ts +39 -0
- package/dist/extensions/websocket-api.extension.js +363 -0
- package/dist/extensions/websocket-api.extension.js.map +1 -0
- package/dist/hass.module.d.ts +80 -0
- package/dist/hass.module.js +83 -0
- package/dist/hass.module.js.map +1 -0
- package/dist/helpers/backup.helper.d.ts +11 -0
- package/dist/helpers/backup.helper.js +3 -0
- package/dist/helpers/backup.helper.js.map +1 -0
- package/dist/helpers/constants.helper.d.ts +54 -0
- package/dist/helpers/constants.helper.js +63 -0
- package/dist/helpers/constants.helper.js.map +1 -0
- package/dist/helpers/entity-state.helper.d.ts +45 -0
- package/dist/helpers/entity-state.helper.js +9 -0
- package/dist/helpers/entity-state.helper.js.map +1 -0
- package/dist/helpers/fetch/calendar.d.ts +54 -0
- package/dist/helpers/fetch/calendar.js +3 -0
- package/dist/helpers/fetch/calendar.js.map +1 -0
- package/dist/helpers/fetch/configuration.d.ts +34 -0
- package/dist/helpers/fetch/configuration.js +3 -0
- package/dist/helpers/fetch/configuration.js.map +1 -0
- package/dist/helpers/fetch/index.d.ts +4 -0
- package/dist/helpers/fetch/index.js +8 -0
- package/dist/helpers/fetch/index.js.map +1 -0
- package/dist/helpers/fetch/server-log.d.ts +10 -0
- package/dist/helpers/fetch/server-log.js +20 -0
- package/dist/helpers/fetch/server-log.js.map +1 -0
- package/dist/helpers/fetch/service-list.d.ts +51 -0
- package/dist/helpers/fetch/service-list.js +3 -0
- package/dist/helpers/fetch/service-list.js.map +1 -0
- package/dist/helpers/index.d.ts +7 -0
- package/dist/helpers/index.js +11 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/metrics.helper.d.ts +13 -0
- package/dist/helpers/metrics.helper.js +30 -0
- package/dist/helpers/metrics.helper.js.map +1 -0
- package/dist/helpers/utility.helper.d.ts +53 -0
- package/dist/helpers/utility.helper.js +30 -0
- package/dist/helpers/utility.helper.js.map +1 -0
- package/dist/helpers/websocket.helper.d.ts +129 -0
- package/dist/helpers/websocket.helper.js +3 -0
- package/dist/helpers/websocket.helper.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/dist/dynamic.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ENTITY_SETUP = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* ## THIS FILE IS INTENDED TO BE REPLACED
|
|
6
|
+
*
|
|
7
|
+
* ! IF YOU STILL SEE THIS IN YOUR `node_modules`, run `npx type-writer`
|
|
8
|
+
*
|
|
9
|
+
* The purpose it to represent the configuration of Home Assistant
|
|
10
|
+
*
|
|
11
|
+
* - entities, with their available attributes & states
|
|
12
|
+
* - services, and what parameters they take
|
|
13
|
+
*
|
|
14
|
+
* This information is TYPES ONLY, and is used to add type safety to
|
|
15
|
+
* methods exported from this library through the use of utility types that
|
|
16
|
+
* take advantage of this information
|
|
17
|
+
*
|
|
18
|
+
* A post-install hook will regenerate these with real values.
|
|
19
|
+
*
|
|
20
|
+
* The service definition is the switch, light, scene domains from a previously generated file.
|
|
21
|
+
* These are required to make typescript happy for internal library definitions
|
|
22
|
+
*/
|
|
23
|
+
exports.ENTITY_SETUP = {
|
|
24
|
+
binary_sensor: {
|
|
25
|
+
is_day: {
|
|
26
|
+
attributes: {
|
|
27
|
+
friendly_name: "Is day",
|
|
28
|
+
},
|
|
29
|
+
context: {
|
|
30
|
+
id: "01HNZ7RV5ZRHF4R6EVTX210Z82",
|
|
31
|
+
parent_id: null,
|
|
32
|
+
user_id: null,
|
|
33
|
+
},
|
|
34
|
+
entity_id: "binary_sensor.is_day",
|
|
35
|
+
last_changed: "2024-02-06T12:55:00.031067+00:00",
|
|
36
|
+
last_updated: "2024-02-06T12:55:00.031067+00:00",
|
|
37
|
+
state: "on",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
button: {
|
|
41
|
+
click_me: {
|
|
42
|
+
attributes: {
|
|
43
|
+
friendly_name: "Click me",
|
|
44
|
+
},
|
|
45
|
+
context: {
|
|
46
|
+
id: "01HNZ7RV5ZRHF4R6EVTX210Z83",
|
|
47
|
+
parent_id: null,
|
|
48
|
+
user_id: null,
|
|
49
|
+
},
|
|
50
|
+
entity_id: "button.click_me",
|
|
51
|
+
last_changed: "2024-02-06T12:55:00.031068+00:00",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
calendar: {
|
|
55
|
+
personal: {
|
|
56
|
+
attributes: {
|
|
57
|
+
friendly_name: "Personal",
|
|
58
|
+
offset_reached: false,
|
|
59
|
+
},
|
|
60
|
+
context: {
|
|
61
|
+
id: "01HJYK0H8P96SCF35ZVZGXKRT0",
|
|
62
|
+
parent_id: null,
|
|
63
|
+
user_id: null,
|
|
64
|
+
},
|
|
65
|
+
entity_id: "calendar.personal",
|
|
66
|
+
last_changed: "2023-12-31T00:00:06.145302+00:00",
|
|
67
|
+
last_updated: "2023-12-31T00:05:06.454423+00:00",
|
|
68
|
+
state: "off",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
light: {
|
|
72
|
+
womp: {
|
|
73
|
+
attributes: {
|
|
74
|
+
brightness: 255,
|
|
75
|
+
color_mode: "color_temp",
|
|
76
|
+
color_temp: 253,
|
|
77
|
+
color_temp_kelvin: 3952,
|
|
78
|
+
dynamics: "none",
|
|
79
|
+
friendly_name: "Womp",
|
|
80
|
+
hs_color: [26.835, 35.746],
|
|
81
|
+
max_color_temp_kelvin: 6535,
|
|
82
|
+
max_mireds: 500,
|
|
83
|
+
min_color_temp_kelvin: 2000,
|
|
84
|
+
min_mireds: 153,
|
|
85
|
+
mode: "normal",
|
|
86
|
+
rgb_color: [255, 204, 163],
|
|
87
|
+
supported_color_modes: ["color_temp", "xy"],
|
|
88
|
+
supported_features: 40,
|
|
89
|
+
xy_color: [0.424, 0.366],
|
|
90
|
+
},
|
|
91
|
+
context: {
|
|
92
|
+
id: "01HK0TW9610XX5C5EZWE6ZEWJ0",
|
|
93
|
+
parent_id: null,
|
|
94
|
+
user_id: "72b5dc1d14484f9bb54df2de3ab95773",
|
|
95
|
+
},
|
|
96
|
+
entity_id: "light.womp",
|
|
97
|
+
last_changed: "2023-12-31T16:23:21.270862+00:00",
|
|
98
|
+
last_updated: "2023-12-31T21:01:05.179072+00:00",
|
|
99
|
+
state: "on",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
scene: {
|
|
103
|
+
bedroom_auto: {
|
|
104
|
+
attributes: {
|
|
105
|
+
friendly_name: "Bedroom Auto",
|
|
106
|
+
},
|
|
107
|
+
context: {
|
|
108
|
+
id: "01HK02X46S76A2C7JJMENBHF55",
|
|
109
|
+
parent_id: null,
|
|
110
|
+
user_id: "72b5dc1d14484f9bb54df2de3ab95773",
|
|
111
|
+
},
|
|
112
|
+
entity_id: "scene.bedroom_auto",
|
|
113
|
+
last_changed: "2023-12-31T14:02:06.428935+00:00",
|
|
114
|
+
last_updated: "2023-12-31T14:02:06.428935+00:00",
|
|
115
|
+
state: "2023-12-31T14:02:06.428760+00:00",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
sensor: {
|
|
119
|
+
loft_current_scene: {
|
|
120
|
+
attributes: {
|
|
121
|
+
friendly_name: "Loft current scene",
|
|
122
|
+
managed_by: "home-automation",
|
|
123
|
+
scene: "high",
|
|
124
|
+
},
|
|
125
|
+
context: {
|
|
126
|
+
id: "01HNZE7KCPMNXAK1N6G9MWC5M4",
|
|
127
|
+
parent_id: null,
|
|
128
|
+
user_id: null,
|
|
129
|
+
},
|
|
130
|
+
entity_id: "sensor.loft_current_scene",
|
|
131
|
+
last_changed: "2024-02-06T14:47:55.030369+00:00",
|
|
132
|
+
last_updated: "2024-02-06T14:47:55.030369+00:00",
|
|
133
|
+
state: "High",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
switch: {
|
|
137
|
+
guest_mode: {
|
|
138
|
+
attributes: {
|
|
139
|
+
friendly_name: "Guest mode",
|
|
140
|
+
},
|
|
141
|
+
context: {
|
|
142
|
+
id: "01HK1AAJ4PW4SNPBFV35EDTJME",
|
|
143
|
+
parent_id: null,
|
|
144
|
+
user_id: "72b5dc1d14484f9bb54df2de3ab95773",
|
|
145
|
+
},
|
|
146
|
+
entity_id: "switch.guest_mode",
|
|
147
|
+
last_changed: "2024-01-01T01:25:47.375385+00:00",
|
|
148
|
+
last_updated: "2024-01-01T01:31:01.142980+00:00",
|
|
149
|
+
state: "off",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=dynamic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic.js","sourceRoot":"","sources":["../src/dynamic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CallProxy = void 0;
|
|
4
|
+
const core_1 = require("@digital-alchemy/core");
|
|
5
|
+
const process_1 = require("process");
|
|
6
|
+
const __1 = require("..");
|
|
7
|
+
const FAILED_LOAD_DELAY = 5;
|
|
8
|
+
const MAX_ATTEMPTS = 50;
|
|
9
|
+
const FAILED = 1;
|
|
10
|
+
const NOT_A_DOMAIN = new Set(["then"]);
|
|
11
|
+
function CallProxy({ logger, lifecycle, context, hass, config, }) {
|
|
12
|
+
let domains;
|
|
13
|
+
let services;
|
|
14
|
+
/**
|
|
15
|
+
* Describe the current services, and build up a proxy api based on that.
|
|
16
|
+
*
|
|
17
|
+
* This API matches the api at the time the this function is run, which may be different from any generated typescript definitions from the past.
|
|
18
|
+
*/
|
|
19
|
+
lifecycle.onBootstrap(async () => {
|
|
20
|
+
if (!config.hass.AUTO_SCAN_CALL_PROXY) {
|
|
21
|
+
logger.debug(`skip service populate`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
logger.debug(`runtime populate service interfaces`);
|
|
25
|
+
await loadServiceList();
|
|
26
|
+
});
|
|
27
|
+
function getDomain(domain) {
|
|
28
|
+
if (!domains || !domains?.includes(domain)) {
|
|
29
|
+
if (!NOT_A_DOMAIN.has(domain)) {
|
|
30
|
+
logger.error({ domain }, `unknown domain`);
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const domainItem = services.find(i => i.domain === domain);
|
|
35
|
+
if (!domainItem) {
|
|
36
|
+
throw new core_1.InternalError(context, "HALLUCINATED_DOMAIN", `Cannot access call_service#${domain}. Home Assistant doesn't list it as a real domain.`);
|
|
37
|
+
}
|
|
38
|
+
return Object.fromEntries(Object.entries(domainItem.services).map(([key]) => [
|
|
39
|
+
key,
|
|
40
|
+
async (parameters) => await sendMessage(`${domain}.${key}`, {
|
|
41
|
+
...parameters,
|
|
42
|
+
}),
|
|
43
|
+
]));
|
|
44
|
+
}
|
|
45
|
+
async function loadServiceList(recursion = core_1.START) {
|
|
46
|
+
logger.info(`fetching service list`);
|
|
47
|
+
services = await hass.fetch.listServices();
|
|
48
|
+
if (core_1.is.empty(services)) {
|
|
49
|
+
if (recursion > MAX_ATTEMPTS) {
|
|
50
|
+
logger.fatal(`Failed to load service list from Home Assistant. Validate configuration`);
|
|
51
|
+
(0, process_1.exit)(FAILED);
|
|
52
|
+
}
|
|
53
|
+
logger.warn("failed to retrieve {service} list. Retrying {%s}/[%s]", recursion, MAX_ATTEMPTS);
|
|
54
|
+
await (0, core_1.sleep)(FAILED_LOAD_DELAY * core_1.SECOND);
|
|
55
|
+
await loadServiceList(recursion + core_1.INCREMENT);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
domains = services.map(i => i.domain);
|
|
59
|
+
services.forEach(value => {
|
|
60
|
+
logger.trace({ services: Object.keys(value.services) }, `loaded domain [%s]`, value.domain);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Prefer sending via socket, if available.
|
|
65
|
+
*/
|
|
66
|
+
async function sendMessage(serviceName, service_data) {
|
|
67
|
+
if (!hass.socket.getConnectionActive()) {
|
|
68
|
+
return await hass.fetch.callService(serviceName, service_data);
|
|
69
|
+
}
|
|
70
|
+
const [domain, service] = serviceName.split(".");
|
|
71
|
+
// User can just not await this call if they don't care about the "waitForChange"
|
|
72
|
+
return await hass.socket.sendMessage({
|
|
73
|
+
domain,
|
|
74
|
+
service,
|
|
75
|
+
service_data,
|
|
76
|
+
type: __1.HASSIO_WS_COMMAND.call_service,
|
|
77
|
+
}, true);
|
|
78
|
+
}
|
|
79
|
+
function buildCallProxy() {
|
|
80
|
+
return new Proxy({}, {
|
|
81
|
+
get: (_, domain) => getDomain(domain),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return buildCallProxy();
|
|
85
|
+
}
|
|
86
|
+
exports.CallProxy = CallProxy;
|
|
87
|
+
exports.default = CallProxy;
|
|
88
|
+
//# sourceMappingURL=call-proxy.extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-proxy.extension.js","sourceRoot":"","sources":["../../src/extensions/call-proxy.extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Configure = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-magic-numbers */
|
|
5
|
+
const core_1 = require("@digital-alchemy/core");
|
|
6
|
+
const process_1 = require("process");
|
|
7
|
+
const __1 = require("..");
|
|
8
|
+
function Configure({ logger, lifecycle, hass, config, internal, }) {
|
|
9
|
+
/**
|
|
10
|
+
* Check for environment defined tokens provided by Home Assistant
|
|
11
|
+
*
|
|
12
|
+
* If available, override defaults to match
|
|
13
|
+
*/
|
|
14
|
+
lifecycle.onPreInit(() => {
|
|
15
|
+
const token = process_1.env.HASSIO_TOKEN || process_1.env.SUPERVISOR_TOKEN;
|
|
16
|
+
if (core_1.is.empty(token)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
logger.debug(`auto configuring from addon environment`);
|
|
20
|
+
internal.config.set("hass", "BASE_URL", process_1.env.HASS_SERVER || "http://supervisor/core");
|
|
21
|
+
internal.config.set("hass", "TOKEN", token);
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Request by someone to validate the provided credentials are valid
|
|
25
|
+
*
|
|
26
|
+
* Send a test request, and provide feedback on what happened
|
|
27
|
+
*/
|
|
28
|
+
lifecycle.onPostConfig(async () => {
|
|
29
|
+
if (!config.hass.VALIDATE_CONFIGURATION) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
core_1.ZCC.logger.setLogLevel("trace");
|
|
33
|
+
logger.info(`validating credentials`);
|
|
34
|
+
try {
|
|
35
|
+
const result = await hass.fetch.checkCredentials();
|
|
36
|
+
if (core_1.is.object(result)) {
|
|
37
|
+
// * all good
|
|
38
|
+
logger.info(result.message);
|
|
39
|
+
(0, process_1.exit)(1);
|
|
40
|
+
}
|
|
41
|
+
// * bad token
|
|
42
|
+
logger.error(String(result));
|
|
43
|
+
(0, process_1.exit)(0);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// * bad BASE_URL
|
|
47
|
+
logger.error({ error }, "failed to send request");
|
|
48
|
+
(0, process_1.exit)(0);
|
|
49
|
+
}
|
|
50
|
+
}, __1.PostConfigPriorities.VALIDATE);
|
|
51
|
+
}
|
|
52
|
+
exports.Configure = Configure;
|
|
53
|
+
//# sourceMappingURL=config.extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.extension.js","sourceRoot":"","sources":["../../src/extensions/config.extension.ts"],"names":[],"mappings":";;;AAAA,wDAAwD;AACxD,gDAAgE;AAChE,qCAAoC;AAEpC,0BAA0C;AAC1C,SAAgB,SAAS,CAAC,EACxB,MAAM,EACN,SAAS,EACT,IAAI,EACJ,MAAM,EACN,QAAQ,GACO;IACf;;;;OAIG;IACH,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE;QACvB,MAAM,KAAK,GAAG,aAAG,CAAC,YAAY,IAAI,aAAG,CAAC,gBAAgB,CAAC;QACvD,IAAI,SAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACxD,QAAQ,CAAC,MAAM,CAAC,GAAG,CACjB,MAAM,EACN,UAAU,EACV,aAAG,CAAC,WAAW,IAAI,wBAAwB,CAC5C,CAAC;QACF,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH;;;;OAIG;IACH,SAAS,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;QAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACxC,OAAO;QACT,CAAC;QACD,UAAG,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;YACnD,IAAI,SAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,aAAa;gBACb,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC5B,IAAA,cAAI,EAAC,CAAC,CAAC,CAAC;YACV,CAAC;YACD,cAAc;YACd,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7B,IAAA,cAAI,EAAC,CAAC,CAAC,CAAC;QACV,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,iBAAiB;YACjB,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,wBAAwB,CAAC,CAAC;YAClD,IAAA,cAAI,EAAC,CAAC,CAAC,CAAC;QACV,CAAC;IACH,CAAC,EAAE,wBAAoB,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC;AArDD,8BAqDC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TBlackHole, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
import { ENTITY_STATE, EntityHistoryDTO, EntityHistoryResult, PICK_ENTITY } from "..";
|
|
3
|
+
export declare const ENTITY_UPDATE_RECEIVER: unique symbol;
|
|
4
|
+
export type ByIdProxy<ENTITY_ID extends PICK_ENTITY> = ENTITY_STATE<ENTITY_ID> & {
|
|
5
|
+
entity_id: ENTITY_ID;
|
|
6
|
+
/**
|
|
7
|
+
* Run callback
|
|
8
|
+
*/
|
|
9
|
+
onUpdate: (callback: (state: NonNullable<ENTITY_STATE<ENTITY_ID>>) => TBlackHole) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Run callback once, for next update
|
|
12
|
+
*/
|
|
13
|
+
once: (callback: (state: NonNullable<ENTITY_STATE<ENTITY_ID>>) => TBlackHole) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Will resolve with the next state of the next value. No time limit
|
|
16
|
+
*/
|
|
17
|
+
nextState: () => Promise<ENTITY_STATE<ENTITY_ID>>;
|
|
18
|
+
};
|
|
19
|
+
export declare function EntityManager({ logger, hass, lifecycle }: TServiceParams): {
|
|
20
|
+
/**
|
|
21
|
+
* Internal library use only
|
|
22
|
+
*/
|
|
23
|
+
[ENTITY_UPDATE_RECEIVER]: <ENTITY extends PICK_ENTITY = PICK_ENTITY>(entity_id: PICK_ENTITY, new_state: ENTITY_STATE<ENTITY>, old_state: ENTITY_STATE<ENTITY>) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Retrieves a proxy object for a specified entity. This proxy object
|
|
26
|
+
* provides current values and event hooks for the entity.
|
|
27
|
+
*/
|
|
28
|
+
byId: <ENTITY_ID extends PICK_ENTITY>(entity_id: ENTITY_ID) => ByIdProxy<ENTITY_ID>;
|
|
29
|
+
/**
|
|
30
|
+
* Lists all entities within a specified domain. This is useful for
|
|
31
|
+
* domain-specific operations or queries.
|
|
32
|
+
*/
|
|
33
|
+
findByDomain: <DOMAIN extends "binary_sensor" | "button" | "calendar" | "light" | "scene" | "sensor" | "switch">(domain: DOMAIN) => ByIdProxy<PICK_ENTITY>[];
|
|
34
|
+
/**
|
|
35
|
+
* Retrieves the current state of a given entity. This method returns
|
|
36
|
+
* raw data, offering a direct view of the entity's state at a given moment.
|
|
37
|
+
*/
|
|
38
|
+
getCurrentState: <ENTITY_ID_1 extends PICK_ENTITY>(entity_id: ENTITY_ID_1) => NonNullable<ENTITY_STATE<ENTITY_ID_1>>;
|
|
39
|
+
/**
|
|
40
|
+
* Retrieves the historical state data of entities over a specified time
|
|
41
|
+
* period. Useful for analysis or tracking changes over time.
|
|
42
|
+
*/
|
|
43
|
+
history: <ENTITES extends PICK_ENTITY[]>(payload: Omit<EntityHistoryDTO<ENTITES>, "type">) => Promise<{
|
|
44
|
+
[k: string]: EntityHistoryResult[];
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Provides a simple listing of all entity IDs. Useful for enumeration
|
|
48
|
+
* and quick reference to all available entities.
|
|
49
|
+
*/
|
|
50
|
+
listEntities: () => PICK_ENTITY[];
|
|
51
|
+
/**
|
|
52
|
+
* Initiates a refresh of the current entity states. Useful for ensuring
|
|
53
|
+
* synchronization with the latest state data from Home Assistant.
|
|
54
|
+
*/
|
|
55
|
+
refresh: (recursion?: number) => Promise<void>;
|
|
56
|
+
};
|
|
57
|
+
declare module "@digital-alchemy/core" {
|
|
58
|
+
interface IsIt {
|
|
59
|
+
entity(entity: PICK_ENTITY): entity is PICK_ENTITY;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityManager = exports.ENTITY_UPDATE_RECEIVER = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@digital-alchemy/core");
|
|
6
|
+
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
|
|
7
|
+
const events_1 = tslib_1.__importDefault(require("events"));
|
|
8
|
+
const process_1 = require("process");
|
|
9
|
+
const __1 = require("..");
|
|
10
|
+
exports.ENTITY_UPDATE_RECEIVER = Symbol.for("entityUpdateReceiver");
|
|
11
|
+
const MAX_ATTEMPTS = 50;
|
|
12
|
+
const FAILED_LOAD_DELAY = 5;
|
|
13
|
+
const UNLIMITED = 0;
|
|
14
|
+
const RECENT = 5;
|
|
15
|
+
function EntityManager({ logger, hass, lifecycle }) {
|
|
16
|
+
// # Local vars
|
|
17
|
+
/**
|
|
18
|
+
* MASTER_STATE.switch.desk_light = {entity_id,state,attributes,...}
|
|
19
|
+
*/
|
|
20
|
+
let MASTER_STATE = {};
|
|
21
|
+
const ENTITY_PROXIES = new Map();
|
|
22
|
+
let lastRefresh;
|
|
23
|
+
// * Local event emitter for coordination of socket events
|
|
24
|
+
// Other libraries will internally take advantage of this eventemitter
|
|
25
|
+
const event = new events_1.default();
|
|
26
|
+
event.setMaxListeners(UNLIMITED);
|
|
27
|
+
let init = false;
|
|
28
|
+
// # Methods
|
|
29
|
+
// ## Retrieve raw state object for entity
|
|
30
|
+
function getCurrentState(entity_id) {
|
|
31
|
+
return core_1.ZCC.utils.object.get(MASTER_STATE, entity_id);
|
|
32
|
+
}
|
|
33
|
+
// ## Proxy version of the logic
|
|
34
|
+
function proxyGetLogic(entity, property) {
|
|
35
|
+
if (!init) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const valid = ["state", "attributes", "last"].some(i => property.startsWith(i));
|
|
39
|
+
if (!valid) {
|
|
40
|
+
logger.error({ entity, property }, `invalid property lookup`);
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const current = getCurrentState(entity);
|
|
44
|
+
const defaultValue = (property === "state" ? undefined : {});
|
|
45
|
+
if (!current) {
|
|
46
|
+
logger.error({ defaultValue, name: entity, property }, `proxyGetLogic cannot find entity`);
|
|
47
|
+
}
|
|
48
|
+
return core_1.ZCC.utils.object.get(current, property) || defaultValue;
|
|
49
|
+
}
|
|
50
|
+
// ## Retrieve a proxy by id
|
|
51
|
+
function byId(entity_id) {
|
|
52
|
+
if (!ENTITY_PROXIES.has(entity_id)) {
|
|
53
|
+
ENTITY_PROXIES.set(entity_id, new Proxy({ entity_id }, {
|
|
54
|
+
// things that shouldn't be needed: this extract
|
|
55
|
+
get: (_, property) => {
|
|
56
|
+
if (property === "onUpdate") {
|
|
57
|
+
return (callback) => event.on(entity_id, async (a, b) => callback(a, b));
|
|
58
|
+
}
|
|
59
|
+
if (property === "once") {
|
|
60
|
+
return (callback) => event.once(entity_id, async (a, b) => callback(a, b));
|
|
61
|
+
}
|
|
62
|
+
if (property === "entity_id") {
|
|
63
|
+
return entity_id;
|
|
64
|
+
}
|
|
65
|
+
if (property === "nextState") {
|
|
66
|
+
return new Promise(done => {
|
|
67
|
+
event.once(entity_id, (entity) => done(entity));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return proxyGetLogic(entity_id, property);
|
|
71
|
+
},
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
return ENTITY_PROXIES.get(entity_id);
|
|
75
|
+
}
|
|
76
|
+
// ## Retrieve entity history (via socket)
|
|
77
|
+
async function history(payload) {
|
|
78
|
+
logger.trace({ payload }, `looking up entity history`);
|
|
79
|
+
const result = (await hass.socket.sendMessage({
|
|
80
|
+
...payload,
|
|
81
|
+
end_time: (0, dayjs_1.default)(payload.end_time).toISOString(),
|
|
82
|
+
start_time: (0, dayjs_1.default)(payload.start_time).toISOString(),
|
|
83
|
+
type: __1.HASSIO_WS_COMMAND.history_during_period,
|
|
84
|
+
}));
|
|
85
|
+
const entities = Object.keys(result);
|
|
86
|
+
return Object.fromEntries(entities.map((entity_id) => {
|
|
87
|
+
const key = entity_id;
|
|
88
|
+
const states = result[entity_id];
|
|
89
|
+
const value = states.map(data => {
|
|
90
|
+
return {
|
|
91
|
+
attributes: data.a,
|
|
92
|
+
date: new Date(data.lu * core_1.SECOND),
|
|
93
|
+
state: data.s,
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
return [key, value];
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
// ## Build a string array of all known entity ids
|
|
100
|
+
function listEntities() {
|
|
101
|
+
return Object.keys(MASTER_STATE).flatMap(domain => Object.keys(MASTER_STATE[domain]).map(id => `${domain}.${id}`));
|
|
102
|
+
}
|
|
103
|
+
// ## Gather all entity proxies for a domain
|
|
104
|
+
function findByDomain(domain) {
|
|
105
|
+
return Object.keys(MASTER_STATE[domain] ?? {}).map(i => byId(`${domain}.${i}`));
|
|
106
|
+
}
|
|
107
|
+
// ## Load all entity state information from hass
|
|
108
|
+
async function refresh(recursion = core_1.START) {
|
|
109
|
+
const now = (0, dayjs_1.default)();
|
|
110
|
+
if (lastRefresh) {
|
|
111
|
+
const diff = lastRefresh.diff(now, "ms");
|
|
112
|
+
if (diff >= RECENT * core_1.SECOND) {
|
|
113
|
+
logger.warn({ diff }, `multiple refreshes in close time`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
lastRefresh = now;
|
|
117
|
+
// - Fetch list of entities
|
|
118
|
+
const states = await hass.fetch.getAllEntities();
|
|
119
|
+
// - Keep retrying until max failures reached
|
|
120
|
+
if (core_1.is.empty(states)) {
|
|
121
|
+
if (recursion > MAX_ATTEMPTS) {
|
|
122
|
+
logger.fatal(`failed to load service list from Home Assistant. Validate configuration`);
|
|
123
|
+
(0, process_1.exit)();
|
|
124
|
+
}
|
|
125
|
+
logger.warn("failed to retrieve entity list. Retrying {%s}/[%s]", recursion, MAX_ATTEMPTS);
|
|
126
|
+
await (0, core_1.sleep)(FAILED_LOAD_DELAY * core_1.SECOND);
|
|
127
|
+
await refresh(recursion + core_1.INCREMENT);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// - Preserve old state for comparison
|
|
131
|
+
const oldState = MASTER_STATE;
|
|
132
|
+
MASTER_STATE = {};
|
|
133
|
+
const emitUpdates = [];
|
|
134
|
+
// - Go through all entities, setting the state
|
|
135
|
+
// ~ If this is a refresh (not an initial boot), track what changed so events can be emitted
|
|
136
|
+
states.forEach(entity => {
|
|
137
|
+
// ? Set first, ensure data is populated
|
|
138
|
+
// `nextTick` will fire AFTER loop finishes
|
|
139
|
+
core_1.ZCC.utils.object.set(MASTER_STATE, entity.entity_id, entity, core_1.is.undefined(core_1.ZCC.utils.object.get(oldState, entity.entity_id)));
|
|
140
|
+
if (!init) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const old = core_1.ZCC.utils.object.get(oldState, entity.entity_id);
|
|
144
|
+
if (core_1.is.equal(old, entity)) {
|
|
145
|
+
logger.trace({ name: entity.entity_id }, `no change on refresh`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
emitUpdates.push(entity);
|
|
149
|
+
});
|
|
150
|
+
// Attempt to not blow up the system?
|
|
151
|
+
// TODO: does this gain anything? is a debounce needed somewhere else instead?
|
|
152
|
+
setImmediate(async () => {
|
|
153
|
+
await (0, core_1.each)(emitUpdates, async (entity) => await EntityUpdateReceiver(entity.entity_id, entity, core_1.ZCC.utils.object.get(oldState, entity.entity_id)));
|
|
154
|
+
});
|
|
155
|
+
init = true;
|
|
156
|
+
}
|
|
157
|
+
// ## is.entity definition
|
|
158
|
+
// Actually tie the type casting to real state
|
|
159
|
+
core_1.is.entity = (entityId) => core_1.is.undefined(core_1.ZCC.utils.object.get(MASTER_STATE, entityId));
|
|
160
|
+
// ## Receiver function for incoming entity updates
|
|
161
|
+
function EntityUpdateReceiver(entity_id, new_state, old_state) {
|
|
162
|
+
if (new_state === null) {
|
|
163
|
+
logger.warn({ name: entity_id }, `removing deleted entity from {MASTER_STATE}`);
|
|
164
|
+
core_1.ZCC.utils.object.del(MASTER_STATE, entity_id);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
core_1.ZCC.utils.object.set(MASTER_STATE, entity_id, new_state);
|
|
168
|
+
event.emit(entity_id, new_state, old_state);
|
|
169
|
+
}
|
|
170
|
+
lifecycle.onPostConfig(async () => {
|
|
171
|
+
logger.debug(`pre populate {MASTER_STATE}`);
|
|
172
|
+
await refresh();
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
/**
|
|
176
|
+
* Internal library use only
|
|
177
|
+
*/
|
|
178
|
+
[exports.ENTITY_UPDATE_RECEIVER]: EntityUpdateReceiver,
|
|
179
|
+
/**
|
|
180
|
+
* Retrieves a proxy object for a specified entity. This proxy object
|
|
181
|
+
* provides current values and event hooks for the entity.
|
|
182
|
+
*/
|
|
183
|
+
byId,
|
|
184
|
+
/**
|
|
185
|
+
* Lists all entities within a specified domain. This is useful for
|
|
186
|
+
* domain-specific operations or queries.
|
|
187
|
+
*/
|
|
188
|
+
findByDomain,
|
|
189
|
+
/**
|
|
190
|
+
* Retrieves the current state of a given entity. This method returns
|
|
191
|
+
* raw data, offering a direct view of the entity's state at a given moment.
|
|
192
|
+
*/
|
|
193
|
+
getCurrentState,
|
|
194
|
+
/**
|
|
195
|
+
* Retrieves the historical state data of entities over a specified time
|
|
196
|
+
* period. Useful for analysis or tracking changes over time.
|
|
197
|
+
*/
|
|
198
|
+
history,
|
|
199
|
+
/**
|
|
200
|
+
* Provides a simple listing of all entity IDs. Useful for enumeration
|
|
201
|
+
* and quick reference to all available entities.
|
|
202
|
+
*/
|
|
203
|
+
listEntities,
|
|
204
|
+
/**
|
|
205
|
+
* Initiates a refresh of the current entity states. Useful for ensuring
|
|
206
|
+
* synchronization with the latest state data from Home Assistant.
|
|
207
|
+
*/
|
|
208
|
+
refresh,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
exports.EntityManager = EntityManager;
|
|
212
|
+
//# sourceMappingURL=entity-manager.extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-manager.extension.js","sourceRoot":"","sources":["../../src/extensions/entity-manager.extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FilteredFetchArguments, TFetch, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
import { CalendarEvent, CalendarFetchOptions, CheckConfigResult, ENTITY_STATE, HassConfig, HassServiceDTO, HomeAssistantServerLogItem, PICK_ENTITY, PICK_SERVICE, PICK_SERVICE_PARAMETERS } from "..";
|
|
3
|
+
type SendBody<STATE extends string | number = string, ATTRIBUTES extends object = object> = {
|
|
4
|
+
attributes?: ATTRIBUTES;
|
|
5
|
+
state?: STATE;
|
|
6
|
+
};
|
|
7
|
+
export declare function FetchAPI({ logger, lifecycle, context, config, }: TServiceParams): {
|
|
8
|
+
calendarSearch: ({ calendar, start, end, }: CalendarFetchOptions) => Promise<CalendarEvent[]>;
|
|
9
|
+
callService: <SERVICE extends PICK_SERVICE>(serviceName: SERVICE, data: PICK_SERVICE_PARAMETERS<SERVICE>) => Promise<ENTITY_STATE<PICK_ENTITY>[]>;
|
|
10
|
+
checkConfig: () => Promise<CheckConfigResult>;
|
|
11
|
+
checkCredentials: () => Promise<{
|
|
12
|
+
message: string;
|
|
13
|
+
} | string>;
|
|
14
|
+
download: (destination: string, fetchWith: FilteredFetchArguments) => Promise<void>;
|
|
15
|
+
fetch: TFetch;
|
|
16
|
+
fetchEntityCustomizations: <T extends Record<never, unknown> = Record<"local" | "global", Record<string, string>>>(entityId: string | string[]) => Promise<T>;
|
|
17
|
+
fetchEntityHistory: <ENTITY extends PICK_ENTITY = PICK_ENTITY, T_1 extends ENTITY_STATE<ENTITY> = ENTITY_STATE<ENTITY>>(entity_id: ENTITY, from: Date, to: Date, extra?: {
|
|
18
|
+
minimal_response?: "";
|
|
19
|
+
}) => Promise<T_1[]>;
|
|
20
|
+
fireEvent: <DATA extends object = object>(event: string, data?: DATA) => Promise<void>;
|
|
21
|
+
getAllEntities: () => Promise<ENTITY_STATE<PICK_ENTITY>[]>;
|
|
22
|
+
getConfig: () => Promise<HassConfig>;
|
|
23
|
+
getLogs: () => Promise<HomeAssistantServerLogItem[]>;
|
|
24
|
+
getRawLogs: () => Promise<string>;
|
|
25
|
+
listServices: () => Promise<HassServiceDTO[]>;
|
|
26
|
+
updateEntity: <STATE extends string | number = string, ATTRIBUTES extends object = object>(entity_id: PICK_ENTITY, { attributes, state }: SendBody<STATE, ATTRIBUTES>) => Promise<void>;
|
|
27
|
+
webhook: (name: string, data?: object) => Promise<void>;
|
|
28
|
+
};
|
|
29
|
+
export {};
|