@digital-alchemy/hass 24.9.3 → 24.9.5
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/README.md +3 -0
- package/dist/dynamic.d.ts +1 -1
- package/dist/dynamic.js +7 -2
- package/dist/dynamic.js.map +1 -1
- package/dist/extensions/area.extension.d.ts +2 -12
- package/dist/extensions/area.extension.js +20 -26
- package/dist/extensions/area.extension.js.map +1 -1
- package/dist/extensions/backup.extension.d.ts +2 -7
- package/dist/extensions/backup.extension.js +5 -8
- package/dist/extensions/backup.extension.js.map +1 -1
- package/dist/extensions/call-proxy.extension.d.ts +1 -1
- package/dist/extensions/call-proxy.extension.js +3 -22
- package/dist/extensions/call-proxy.extension.js.map +1 -1
- package/dist/extensions/config.extension.d.ts +2 -6
- package/dist/extensions/config.extension.js +21 -25
- package/dist/extensions/config.extension.js.map +1 -1
- package/dist/extensions/conversation.extension.d.ts +2 -6
- package/dist/extensions/conversation.extension.js +5 -8
- package/dist/extensions/conversation.extension.js.map +1 -1
- package/dist/extensions/device.extension.d.ts +2 -5
- package/dist/extensions/device.extension.js +16 -22
- package/dist/extensions/device.extension.js.map +1 -1
- package/dist/extensions/entity.extension.d.ts +2 -61
- package/dist/extensions/entity.extension.js +42 -83
- package/dist/extensions/entity.extension.js.map +1 -1
- package/dist/extensions/events.extension.d.ts +3 -11
- package/dist/extensions/events.extension.js +8 -11
- package/dist/extensions/events.extension.js.map +1 -1
- package/dist/extensions/fetch-api.extension.d.ts +12 -4
- package/dist/extensions/fetch-api.extension.js +23 -35
- package/dist/extensions/fetch-api.extension.js.map +1 -1
- package/dist/extensions/floor.extension.d.ts +2 -9
- package/dist/extensions/floor.extension.js +17 -23
- package/dist/extensions/floor.extension.js.map +1 -1
- package/dist/extensions/id-by.extension.js +15 -20
- package/dist/extensions/id-by.extension.js.map +1 -1
- package/dist/extensions/index.d.ts +1 -0
- package/dist/extensions/index.js +16 -18
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/internal.extension.d.ts +18 -0
- package/dist/extensions/internal.extension.js +102 -0
- package/dist/extensions/internal.extension.js.map +1 -0
- package/dist/extensions/label.extension.d.ts +2 -9
- package/dist/extensions/label.extension.js +17 -23
- package/dist/extensions/label.extension.js.map +1 -1
- package/dist/extensions/reference.extension.d.ts +2 -12
- package/dist/extensions/reference.extension.js +19 -25
- package/dist/extensions/reference.extension.js.map +1 -1
- package/dist/extensions/registry.extension.d.ts +2 -7
- package/dist/extensions/registry.extension.js +1 -4
- package/dist/extensions/registry.extension.js.map +1 -1
- package/dist/extensions/websocket-api.extension.d.ts +3 -78
- package/dist/extensions/websocket-api.extension.js +82 -165
- package/dist/extensions/websocket-api.extension.js.map +1 -1
- package/dist/extensions/zone.extension.d.ts +2 -7
- package/dist/extensions/zone.extension.js +15 -21
- package/dist/extensions/zone.extension.js.map +1 -1
- package/dist/hass.module.d.ts +47 -36
- package/dist/hass.module.js +70 -70
- package/dist/hass.module.js.map +1 -1
- package/dist/helpers/backup.helper.js +1 -2
- package/dist/helpers/constants.helper.js +15 -18
- package/dist/helpers/constants.helper.js.map +1 -1
- package/dist/helpers/device.helper.js +2 -5
- package/dist/helpers/device.helper.js.map +1 -1
- package/dist/helpers/entity-state.helper.d.ts +3 -8
- package/dist/helpers/entity-state.helper.js +1 -8
- package/dist/helpers/entity-state.helper.js.map +1 -1
- package/dist/helpers/features.helper.js +79 -85
- package/dist/helpers/features.helper.js.map +1 -1
- package/dist/helpers/fetch/calendar.js +1 -2
- package/dist/helpers/fetch/configuration.js +2 -5
- package/dist/helpers/fetch/configuration.js.map +1 -1
- package/dist/helpers/fetch/index.js +5 -8
- package/dist/helpers/fetch/index.js.map +1 -1
- package/dist/helpers/fetch/server-log.js +1 -2
- package/dist/helpers/fetch/server-log.js.map +1 -1
- package/dist/helpers/fetch/service-list.js +1 -2
- package/dist/helpers/fetch/weather-forecasts.js +1 -2
- package/dist/helpers/fetch/weather-forecasts.js.map +1 -1
- package/dist/helpers/fetch.helper.d.ts +162 -0
- package/dist/helpers/fetch.helper.js +161 -0
- package/dist/helpers/fetch.helper.js.map +1 -0
- package/dist/helpers/id-by.helper.js +1 -2
- package/dist/helpers/index.d.ts +2 -1
- package/dist/helpers/index.js +13 -15
- package/dist/helpers/index.js.map +1 -1
- package/dist/helpers/interfaces.helper.d.ts +228 -0
- package/dist/helpers/interfaces.helper.js +10 -0
- package/dist/helpers/interfaces.helper.js.map +1 -0
- package/dist/helpers/manifest.helper.d.ts +0 -1
- package/dist/helpers/manifest.helper.js +0 -1
- package/dist/helpers/notify.helper.d.ts +13 -5
- package/dist/helpers/notify.helper.js +1 -2
- package/dist/helpers/registry.js +7 -10
- package/dist/helpers/registry.js.map +1 -1
- package/dist/helpers/utility.helper.d.ts +6 -1
- package/dist/helpers/utility.helper.js +9 -13
- package/dist/helpers/utility.helper.js.map +1 -1
- package/dist/helpers/websocket.helper.d.ts +1 -2
- package/dist/helpers/websocket.helper.js +1 -2
- package/dist/index.js +5 -8
- package/dist/index.js.map +1 -1
- package/dist/mock_assistant/extensions/area.extension.d.ts +8 -0
- package/dist/mock_assistant/extensions/area.extension.js +51 -0
- package/dist/mock_assistant/extensions/area.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/config.extension.d.ts +14 -0
- package/dist/mock_assistant/extensions/config.extension.js +29 -0
- package/dist/mock_assistant/extensions/config.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/device.extension.d.ts +8 -0
- package/dist/mock_assistant/extensions/device.extension.js +33 -0
- package/dist/mock_assistant/extensions/device.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/entity-registry.extension.d.ts +13 -0
- package/dist/mock_assistant/extensions/entity-registry.extension.js +28 -0
- package/dist/mock_assistant/extensions/entity-registry.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/entity.extension.d.ts +30 -0
- package/dist/mock_assistant/extensions/entity.extension.js +77 -0
- package/dist/mock_assistant/extensions/entity.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/events.extension.d.ts +1 -1
- package/dist/mock_assistant/extensions/events.extension.js +3 -6
- package/dist/mock_assistant/extensions/events.extension.js.map +1 -1
- package/dist/mock_assistant/extensions/fetch.extension.d.ts +1 -0
- package/dist/mock_assistant/extensions/fetch.extension.js +4 -0
- package/dist/mock_assistant/extensions/fetch.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/fixtures.extension.d.ts +1 -1
- package/dist/mock_assistant/extensions/fixtures.extension.js +29 -33
- package/dist/mock_assistant/extensions/fixtures.extension.js.map +1 -1
- package/dist/mock_assistant/extensions/floor.extension.d.ts +8 -0
- package/dist/mock_assistant/extensions/floor.extension.js +51 -0
- package/dist/mock_assistant/extensions/floor.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/index.d.ts +10 -0
- package/dist/mock_assistant/extensions/index.js +12 -5
- package/dist/mock_assistant/extensions/index.js.map +1 -1
- package/dist/mock_assistant/extensions/label.extension.d.ts +8 -0
- package/dist/mock_assistant/extensions/label.extension.js +51 -0
- package/dist/mock_assistant/extensions/label.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/services.extension.d.ts +12 -0
- package/dist/mock_assistant/extensions/services.extension.js +20 -0
- package/dist/mock_assistant/extensions/services.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/websocket-api.extension.d.ts +15 -0
- package/dist/mock_assistant/extensions/websocket-api.extension.js +68 -0
- package/dist/mock_assistant/extensions/websocket-api.extension.js.map +1 -0
- package/dist/mock_assistant/extensions/zone.extension.d.ts +8 -0
- package/dist/mock_assistant/extensions/zone.extension.js +51 -0
- package/dist/mock_assistant/extensions/zone.extension.js.map +1 -0
- package/dist/mock_assistant/helpers/fixtures.js +1 -2
- package/dist/mock_assistant/helpers/index.d.ts +0 -1
- package/dist/mock_assistant/helpers/index.js +1 -5
- package/dist/mock_assistant/helpers/index.js.map +1 -1
- package/dist/mock_assistant/index.js +3 -6
- package/dist/mock_assistant/index.js.map +1 -1
- package/dist/mock_assistant/main.js +11 -15
- package/dist/mock_assistant/main.js.map +1 -1
- package/dist/mock_assistant/mock-assistant.module.d.ts +156 -3
- package/dist/mock_assistant/mock-assistant.module.js +56 -11
- package/dist/mock_assistant/mock-assistant.module.js.map +1 -1
- package/dist/quickboot.module.js +5 -8
- package/dist/quickboot.module.js.map +1 -1
- package/dist/testing/area.spec.js +106 -194
- package/dist/testing/area.spec.js.map +1 -1
- package/dist/testing/backup.spec.js +97 -139
- package/dist/testing/backup.spec.js.map +1 -1
- package/dist/testing/config.spec.js +79 -153
- package/dist/testing/config.spec.js.map +1 -1
- package/dist/testing/device.spec.js +35 -69
- package/dist/testing/device.spec.js.map +1 -1
- package/dist/testing/entity.spec.js +94 -149
- package/dist/testing/entity.spec.js.map +1 -1
- package/dist/testing/events.spec.js +33 -57
- package/dist/testing/events.spec.js.map +1 -1
- package/dist/testing/fetch-api.spec.js +242 -427
- package/dist/testing/fetch-api.spec.js.map +1 -1
- package/dist/testing/fixtures.spec.d.ts +1 -0
- package/dist/testing/fixtures.spec.js +150 -0
- package/dist/testing/fixtures.spec.js.map +1 -0
- package/dist/testing/floor.spec.js +106 -194
- package/dist/testing/floor.spec.js.map +1 -1
- package/dist/testing/id-by.spec.js +68 -107
- package/dist/testing/id-by.spec.js.map +1 -1
- package/dist/testing/label.spec.js +106 -194
- package/dist/testing/label.spec.js.map +1 -1
- package/dist/testing/ref-by.spec.js +155 -219
- package/dist/testing/ref-by.spec.js.map +1 -1
- package/dist/testing/websocket.spec.d.ts +1 -8
- package/dist/testing/websocket.spec.js +35 -50
- package/dist/testing/websocket.spec.js.map +1 -1
- package/dist/testing/workflow.spec.js +82 -81
- package/dist/testing/workflow.spec.js.map +1 -1
- package/dist/testing/zone.spec.js +61 -113
- package/dist/testing/zone.spec.js.map +1 -1
- package/package.json +62 -44
- package/scripts/mock-assistant.sh +5 -0
- package/scripts/run-e2e.sh +7 -0
- package/scripts/test.sh +2 -0
- package/src/dynamic.ts +4254 -0
- package/src/extensions/area.extension.ts +118 -0
- package/src/extensions/backup.extension.ts +63 -0
- package/src/extensions/call-proxy.extension.ts +113 -0
- package/src/extensions/config.extension.ts +119 -0
- package/src/extensions/conversation.extension.ts +46 -0
- package/src/extensions/device.extension.ts +56 -0
- package/src/extensions/entity.extension.ts +344 -0
- package/src/extensions/events.extension.ts +25 -0
- package/src/extensions/fetch-api.extension.ts +269 -0
- package/src/extensions/floor.extension.ts +76 -0
- package/src/extensions/id-by.extension.ts +157 -0
- package/src/extensions/index.ts +16 -0
- package/src/extensions/internal.extension.ts +145 -0
- package/src/extensions/label.extension.ts +83 -0
- package/src/extensions/reference.extension.ts +330 -0
- package/src/extensions/registry.extension.ts +44 -0
- package/src/extensions/websocket-api.extension.ts +554 -0
- package/src/extensions/zone.extension.ts +69 -0
- package/src/hass.module.ts +217 -0
- package/src/helpers/backup.helper.ts +11 -0
- package/src/helpers/constants.helper.ts +30 -0
- package/src/helpers/device.helper.ts +25 -0
- package/src/helpers/entity-state.helper.ts +171 -0
- package/src/helpers/features.helper.ts +580 -0
- package/src/helpers/fetch/calendar.ts +54 -0
- package/src/helpers/fetch/configuration.ts +75 -0
- package/src/helpers/fetch/index.ts +5 -0
- package/src/helpers/fetch/server-log.ts +28 -0
- package/src/helpers/fetch/service-list.ts +64 -0
- package/src/helpers/fetch/weather-forecasts.ts +86 -0
- package/src/helpers/fetch.helper.ts +328 -0
- package/src/helpers/id-by.helper.ts +53 -0
- package/src/helpers/index.ts +13 -0
- package/src/helpers/interfaces.helper.ts +340 -0
- package/src/helpers/manifest.helper.ts +0 -0
- package/src/helpers/notify.helper.ts +302 -0
- package/src/helpers/registry.ts +281 -0
- package/src/helpers/utility.helper.ts +147 -0
- package/src/helpers/websocket.helper.ts +117 -0
- package/src/index.ts +5 -0
- package/src/mock_assistant/extensions/area.extension.ts +62 -0
- package/src/mock_assistant/extensions/config.extension.ts +33 -0
- package/src/mock_assistant/extensions/device.extension.ts +44 -0
- package/src/mock_assistant/extensions/entity-registry.extension.ts +41 -0
- package/src/mock_assistant/extensions/entity.extension.ts +114 -0
- package/src/mock_assistant/extensions/events.extension.ts +37 -0
- package/src/mock_assistant/extensions/fetch.extension.ts +3 -0
- package/src/mock_assistant/extensions/fixtures.extension.ts +79 -0
- package/src/mock_assistant/extensions/floor.extension.ts +64 -0
- package/src/mock_assistant/extensions/index.ts +12 -0
- package/src/mock_assistant/extensions/label.extension.ts +64 -0
- package/src/mock_assistant/extensions/services.extension.ts +25 -0
- package/src/mock_assistant/extensions/websocket-api.extension.ts +84 -0
- package/src/mock_assistant/extensions/zone.extension.ts +65 -0
- package/src/mock_assistant/helpers/fixtures.ts +22 -0
- package/src/mock_assistant/helpers/index.ts +1 -0
- package/src/mock_assistant/index.ts +3 -0
- package/src/mock_assistant/main.ts +46 -0
- package/src/mock_assistant/mock-assistant.module.ts +90 -0
- package/src/quickboot.module.ts +23 -0
- package/src/testing/area.spec.ts +189 -0
- package/src/testing/backup.spec.ts +157 -0
- package/src/testing/config.spec.ts +188 -0
- package/src/testing/device.spec.ts +89 -0
- package/src/testing/entity.spec.ts +171 -0
- package/src/testing/events.spec.ts +78 -0
- package/src/testing/fetch-api.spec.ts +410 -0
- package/src/testing/fixtures.spec.ts +158 -0
- package/src/testing/floor.spec.ts +186 -0
- package/src/testing/id-by.spec.ts +140 -0
- package/src/testing/label.spec.ts +186 -0
- package/src/testing/ref-by.spec.ts +300 -0
- package/src/testing/websocket.spec.ts +63 -0
- package/src/testing/workflow.spec.ts +195 -0
- package/src/testing/zone.spec.ts +109 -0
- package/dist/helpers/metrics.helper.d.ts +0 -29
- package/dist/helpers/metrics.helper.js +0 -62
- package/dist/helpers/metrics.helper.js.map +0 -1
- package/dist/mock_assistant/helpers/utils.d.ts +0 -4
- package/dist/mock_assistant/helpers/utils.js +0 -57
- package/dist/mock_assistant/helpers/utils.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { TRawEntityIds } from "../../dynamic";
|
|
4
|
+
import { EntityRegistryItem } from "../../helpers";
|
|
5
|
+
|
|
6
|
+
export function MockEntityRegistryExtension({ mock_assistant, hass }: TServiceParams) {
|
|
7
|
+
let entityRegistry = new Map<TRawEntityIds, EntityRegistryItem<TRawEntityIds>>();
|
|
8
|
+
|
|
9
|
+
hass.entity.registry.list = async () => [...entityRegistry.values()];
|
|
10
|
+
|
|
11
|
+
const sendUpdate = () =>
|
|
12
|
+
mock_assistant.socket.sendMessage({
|
|
13
|
+
event: { event_type: "entity_registry_updated" },
|
|
14
|
+
type: "event",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
mock_assistant.socket.onMessage<{ entity_id: TRawEntityIds }>(
|
|
18
|
+
"config/entity_registry/get",
|
|
19
|
+
message => {
|
|
20
|
+
mock_assistant.socket.sendMessage({
|
|
21
|
+
id: message.id,
|
|
22
|
+
result: entityRegistry.get(message.entity_id),
|
|
23
|
+
type: "result",
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
/**
|
|
30
|
+
* does not imply sendUpdate
|
|
31
|
+
*/
|
|
32
|
+
loadFixtures(incoming: EntityRegistryItem<TRawEntityIds>[]) {
|
|
33
|
+
entityRegistry = new Map(incoming.map(i => [i.entity_id, i]));
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* emit entity_registry_updated
|
|
38
|
+
*/
|
|
39
|
+
sendUpdate,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { deepExtend, InternalError, is, sleep, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { TRawEntityIds } from "../../dynamic";
|
|
4
|
+
import { ENTITY_STATE, PICK_ENTITY } from "../../helpers";
|
|
5
|
+
|
|
6
|
+
export function MockEntityExtension({
|
|
7
|
+
hass,
|
|
8
|
+
internal,
|
|
9
|
+
context,
|
|
10
|
+
logger,
|
|
11
|
+
config,
|
|
12
|
+
mock_assistant,
|
|
13
|
+
}: TServiceParams) {
|
|
14
|
+
let entities = new Map<TRawEntityIds, ENTITY_STATE<TRawEntityIds>>();
|
|
15
|
+
|
|
16
|
+
const origGetAll = hass.fetch.getAllEntities;
|
|
17
|
+
|
|
18
|
+
hass.fetch.getAllEntities = async () => [...entities.values()];
|
|
19
|
+
|
|
20
|
+
function setupState(incoming: SetupStateOptions) {
|
|
21
|
+
if (internal.boot.completedLifecycleEvents.has("PreInit")) {
|
|
22
|
+
logger.error(`run [setupState] as part of the .setup command of your test`);
|
|
23
|
+
throw new InternalError(context, "LATE_SETUP", "Must call setupState before preInit");
|
|
24
|
+
}
|
|
25
|
+
const list = Object.keys(incoming) as PICK_ENTITY[];
|
|
26
|
+
list.forEach((key: PICK_ENTITY) => {
|
|
27
|
+
const data = entities.get(key);
|
|
28
|
+
entities.set(key, {
|
|
29
|
+
...data,
|
|
30
|
+
state: incoming[key].state,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function emitChange<ENTITY extends PICK_ENTITY>(
|
|
36
|
+
entity: ENTITY,
|
|
37
|
+
update: PartialUpdate<ENTITY>,
|
|
38
|
+
) {
|
|
39
|
+
const old_state = entities.get(entity);
|
|
40
|
+
if (hass.socket.connectionState !== "connected") {
|
|
41
|
+
throw new InternalError(context, "EARLY_CHANGE", "Websocket does not identify as connected");
|
|
42
|
+
}
|
|
43
|
+
if (!old_state) {
|
|
44
|
+
throw new InternalError(
|
|
45
|
+
context,
|
|
46
|
+
"MISSING_ENTITY",
|
|
47
|
+
"Cannot find existing entity for old_state",
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const new_state = deepExtend({}, old_state);
|
|
51
|
+
if ("state" in update) {
|
|
52
|
+
new_state.state = update.state;
|
|
53
|
+
}
|
|
54
|
+
if (!is.empty(update.attributes)) {
|
|
55
|
+
new_state.attributes = deepExtend(new_state.attributes, update.attributes);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
mock_assistant.socket.sendMessage({
|
|
59
|
+
event: {
|
|
60
|
+
data: { new_state, old_state },
|
|
61
|
+
event_type: "state_changed",
|
|
62
|
+
},
|
|
63
|
+
type: "event",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// allow changes to propagate properly
|
|
67
|
+
await sleep(config.mock_assistant.EMIT_SLEEP);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
emitChange,
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
loadFixtures(incoming: ENTITY_STATE<TRawEntityIds>[]) {
|
|
80
|
+
if (!is.empty(entities)) {
|
|
81
|
+
// this should not be possible, the dependency resolution order of tests SHOULD prevent
|
|
82
|
+
// if you get this error, let me know how
|
|
83
|
+
throw new InternalError(
|
|
84
|
+
context,
|
|
85
|
+
"FIXTURES_ALREADY_LOADED",
|
|
86
|
+
"There is data in the entity fixtures already, order of operations wrong",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
entities = new Map(incoming.map(i => [i.entity_id, i]));
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @internal
|
|
94
|
+
*
|
|
95
|
+
* restores code references, only used for testing internals
|
|
96
|
+
*/
|
|
97
|
+
monkeyReset() {
|
|
98
|
+
hass.fetch.getAllEntities = origGetAll;
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Does not emit update event
|
|
103
|
+
*
|
|
104
|
+
* Intended for test setup
|
|
105
|
+
*/
|
|
106
|
+
setupState,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
type PartialUpdate<ENTITY extends PICK_ENTITY> = Partial<
|
|
111
|
+
Pick<ENTITY_STATE<ENTITY>, "state" | "attributes">
|
|
112
|
+
>;
|
|
113
|
+
|
|
114
|
+
type SetupStateOptions = Partial<{ [ENTITY in PICK_ENTITY]: PartialUpdate<ENTITY> }>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sleep, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { ANY_ENTITY, ENTITY_STATE, EntityUpdateEvent } from "../../helpers";
|
|
4
|
+
|
|
5
|
+
const SUPER_SHORT = 1;
|
|
6
|
+
|
|
7
|
+
export function MockEvents({ mock_assistant, hass }: TServiceParams) {
|
|
8
|
+
let id = 1000;
|
|
9
|
+
|
|
10
|
+
async function emitEvent(event: string, data: object) {
|
|
11
|
+
id++;
|
|
12
|
+
await hass.socket.onMessage({
|
|
13
|
+
event: {
|
|
14
|
+
data,
|
|
15
|
+
event_type: event,
|
|
16
|
+
} as EntityUpdateEvent,
|
|
17
|
+
id: id,
|
|
18
|
+
type: "event",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function emitEntityUpdate<ENTITY extends ANY_ENTITY>(
|
|
23
|
+
entity: ENTITY,
|
|
24
|
+
new_state: Partial<ENTITY_STATE<ENTITY>>,
|
|
25
|
+
) {
|
|
26
|
+
const old_state = mock_assistant.fixtures.byId(entity);
|
|
27
|
+
new_state = mock_assistant.fixtures.replace(entity, new_state);
|
|
28
|
+
await emitEvent("state_changed", { new_state, old_state });
|
|
29
|
+
// help ensure all the async flows settle
|
|
30
|
+
await sleep(SUPER_SHORT);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
emitEntityUpdate,
|
|
35
|
+
emitEvent,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { BootstrapException, is, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
|
|
4
|
+
import { ANY_ENTITY, ENTITY_STATE } from "../../helpers";
|
|
5
|
+
import { ScannerCacheData } from "../helpers";
|
|
6
|
+
|
|
7
|
+
type StateOptions = Partial<{
|
|
8
|
+
[entity in ANY_ENTITY]: Partial<ENTITY_STATE<entity>>;
|
|
9
|
+
}>;
|
|
10
|
+
|
|
11
|
+
// this naming pattern is confusing sometimes
|
|
12
|
+
// don't think about it too much
|
|
13
|
+
export function MockFixtures({
|
|
14
|
+
lifecycle,
|
|
15
|
+
config,
|
|
16
|
+
internal,
|
|
17
|
+
context,
|
|
18
|
+
mock_assistant,
|
|
19
|
+
}: TServiceParams) {
|
|
20
|
+
// This file DELIBERATELY breaks some rules
|
|
21
|
+
// Setup actions that depend on config are not NORMALLY expected to run inside constructor
|
|
22
|
+
|
|
23
|
+
const { FIXTURES_FILE } = config.mock_assistant;
|
|
24
|
+
if (!existsSync(FIXTURES_FILE)) {
|
|
25
|
+
throw new BootstrapException(
|
|
26
|
+
context,
|
|
27
|
+
"MISSING_FIXTURES_FILE",
|
|
28
|
+
`${FIXTURES_FILE} does not exist`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
if (is.empty(config.hass.TOKEN)) {
|
|
32
|
+
// prevents throwing errors
|
|
33
|
+
internal.boilerplate.configuration.set("hass", "TOKEN", "--");
|
|
34
|
+
}
|
|
35
|
+
const data = JSON.parse(readFileSync(FIXTURES_FILE, "utf8")) as ScannerCacheData;
|
|
36
|
+
mock_assistant.device.loadFixtures(data.devices);
|
|
37
|
+
mock_assistant.floor.loadFixtures(data.floors);
|
|
38
|
+
mock_assistant.area.loadFixtures(data.areas);
|
|
39
|
+
mock_assistant.label.loadFixtures(data.labels);
|
|
40
|
+
mock_assistant.config.loadFixtures(data.config);
|
|
41
|
+
mock_assistant.entity.loadFixtures(data.entities);
|
|
42
|
+
mock_assistant.entity_registry.loadFixtures(data.entity_registry);
|
|
43
|
+
mock_assistant.services.loadFixtures(data.services);
|
|
44
|
+
// TODO zones are not currently included in fixtures
|
|
45
|
+
// more of a completion thing than them having any particular use
|
|
46
|
+
//
|
|
47
|
+
// mock_assistant.zone.set(data.);
|
|
48
|
+
|
|
49
|
+
function setState(options: StateOptions) {
|
|
50
|
+
lifecycle.onPreInit(() => {
|
|
51
|
+
const entities = Object.keys(options) as ANY_ENTITY[];
|
|
52
|
+
entities.forEach(i => replace(i, options[i]));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function byId(entity: ANY_ENTITY) {
|
|
57
|
+
return mock_assistant.fixtures.data.entities.find(i => i.entity_id === entity);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function replace<ENTITY extends ANY_ENTITY>(
|
|
61
|
+
entity: ENTITY,
|
|
62
|
+
new_state: Partial<ENTITY_STATE<ENTITY>>,
|
|
63
|
+
): ENTITY_STATE<ENTITY> {
|
|
64
|
+
const old_state = byId(entity);
|
|
65
|
+
const { data } = mock_assistant.fixtures;
|
|
66
|
+
data.entities = data.entities.filter(i => i.entity_id !== entity);
|
|
67
|
+
|
|
68
|
+
const updated = { ...old_state, ...new_state } as ENTITY_STATE<ENTITY>;
|
|
69
|
+
mock_assistant.fixtures.data.entities.push(updated);
|
|
70
|
+
return updated;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
byId,
|
|
75
|
+
data,
|
|
76
|
+
replace,
|
|
77
|
+
setState,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { TFloorId } from "../../dynamic";
|
|
4
|
+
import { FloorDetails } from "../../helpers";
|
|
5
|
+
|
|
6
|
+
export function MockFloorExtension({ mock_assistant }: TServiceParams) {
|
|
7
|
+
let floors = new Map<TFloorId, FloorDetails>();
|
|
8
|
+
|
|
9
|
+
mock_assistant.socket.onMessage("config/floor_registry/list", message => {
|
|
10
|
+
mock_assistant.socket.sendMessage({
|
|
11
|
+
id: message.id,
|
|
12
|
+
result: [...floors.values()],
|
|
13
|
+
type: "result",
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
mock_assistant.socket.onMessage<{ floor_id: TFloorId }>(
|
|
18
|
+
"config/floor_registry/delete",
|
|
19
|
+
message => {
|
|
20
|
+
floors.delete(message.floor_id);
|
|
21
|
+
sendUpdate();
|
|
22
|
+
mock_assistant.socket.sendMessage({
|
|
23
|
+
id: message.id,
|
|
24
|
+
result: null,
|
|
25
|
+
type: "result",
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
mock_assistant.socket.onMessage<FloorDetails>("config/floor_registry/create", message => {
|
|
31
|
+
message.floor_id = message.name as TFloorId;
|
|
32
|
+
floors.set(message.floor_id as TFloorId, message);
|
|
33
|
+
sendUpdate();
|
|
34
|
+
mock_assistant.socket.sendMessage({
|
|
35
|
+
id: message.id,
|
|
36
|
+
result: null,
|
|
37
|
+
type: "result",
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
mock_assistant.socket.onMessage<FloorDetails>("config/floor_registry/update", message => {
|
|
41
|
+
floors.set(message.floor_id as TFloorId, message);
|
|
42
|
+
sendUpdate();
|
|
43
|
+
mock_assistant.socket.sendMessage({
|
|
44
|
+
id: message.id,
|
|
45
|
+
result: null,
|
|
46
|
+
type: "result",
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const sendUpdate = () =>
|
|
51
|
+
mock_assistant.socket.sendMessage({
|
|
52
|
+
event: { event_type: "floor_registry_updated" },
|
|
53
|
+
type: "event",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
/**
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
60
|
+
loadFixtures(incoming: FloorDetails[]) {
|
|
61
|
+
floors = new Map(incoming.map(i => [i.floor_id, i]));
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./area.extension";
|
|
2
|
+
export * from "./config.extension";
|
|
3
|
+
export * from "./device.extension";
|
|
4
|
+
export * from "./entity.extension";
|
|
5
|
+
export * from "./entity-registry.extension";
|
|
6
|
+
export * from "./events.extension";
|
|
7
|
+
export * from "./fixtures.extension";
|
|
8
|
+
export * from "./floor.extension";
|
|
9
|
+
export * from "./label.extension";
|
|
10
|
+
export * from "./services.extension";
|
|
11
|
+
export * from "./websocket-api.extension";
|
|
12
|
+
export * from "./zone.extension";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { TLabelId } from "../../dynamic";
|
|
4
|
+
import { LabelDefinition } from "../../helpers";
|
|
5
|
+
|
|
6
|
+
export function MockLabelExtension({ mock_assistant }: TServiceParams) {
|
|
7
|
+
let labels = new Map<TLabelId, LabelDefinition>();
|
|
8
|
+
|
|
9
|
+
mock_assistant.socket.onMessage("config/label_registry/list", message => {
|
|
10
|
+
mock_assistant.socket.sendMessage({
|
|
11
|
+
id: message.id,
|
|
12
|
+
result: [...labels.values()],
|
|
13
|
+
type: "result",
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
mock_assistant.socket.onMessage<{ label_id: TLabelId }>(
|
|
18
|
+
"config/label_registry/delete",
|
|
19
|
+
message => {
|
|
20
|
+
labels.delete(message.label_id);
|
|
21
|
+
sendUpdate();
|
|
22
|
+
mock_assistant.socket.sendMessage({
|
|
23
|
+
id: message.id,
|
|
24
|
+
result: null,
|
|
25
|
+
type: "result",
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
mock_assistant.socket.onMessage<LabelDefinition>("config/label_registry/create", message => {
|
|
31
|
+
message.label_id = message.name as TLabelId;
|
|
32
|
+
labels.set(message.label_id as TLabelId, message);
|
|
33
|
+
sendUpdate();
|
|
34
|
+
mock_assistant.socket.sendMessage({
|
|
35
|
+
id: message.id,
|
|
36
|
+
result: null,
|
|
37
|
+
type: "result",
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
mock_assistant.socket.onMessage<LabelDefinition>("config/label_registry/update", message => {
|
|
41
|
+
labels.set(message.label_id as TLabelId, message);
|
|
42
|
+
sendUpdate();
|
|
43
|
+
mock_assistant.socket.sendMessage({
|
|
44
|
+
id: message.id,
|
|
45
|
+
result: null,
|
|
46
|
+
type: "result",
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const sendUpdate = () =>
|
|
51
|
+
mock_assistant.socket.sendMessage({
|
|
52
|
+
event: { event_type: "label_registry_updated" },
|
|
53
|
+
type: "event",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
/**
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
60
|
+
loadFixtures(incoming: LabelDefinition[]) {
|
|
61
|
+
labels = new Map(incoming.map(i => [i.label_id, i]));
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { HassServiceDTO } from "../../helpers";
|
|
4
|
+
|
|
5
|
+
export function MockServices({ hass }: TServiceParams) {
|
|
6
|
+
let services: HassServiceDTO[];
|
|
7
|
+
|
|
8
|
+
const origList = hass.fetch.listServices;
|
|
9
|
+
hass.fetch.listServices = async () => services;
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
loadFixtures(incoming: HassServiceDTO[]) {
|
|
16
|
+
services = incoming;
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
monkeyReset() {
|
|
22
|
+
hass.fetch.listServices = origList;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { START, TBlackHole, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
import EventEmitter from "events";
|
|
3
|
+
import { PartialDeep, WritableDeep } from "type-fest";
|
|
4
|
+
import WS from "ws";
|
|
5
|
+
|
|
6
|
+
import { SocketMessageDTO } from "../../helpers";
|
|
7
|
+
|
|
8
|
+
const CONNECTION_CLOSED = 0;
|
|
9
|
+
// const CONNECTION_OPEN = 1;
|
|
10
|
+
// const CONNECTION_FAILED = 2;
|
|
11
|
+
const UNLIMITED = 0;
|
|
12
|
+
|
|
13
|
+
export const INTERNAL_MESSAGE = "INTERNAL_MESSAGE";
|
|
14
|
+
|
|
15
|
+
export function MockWebsocketAPI({ hass, config, lifecycle }: TServiceParams) {
|
|
16
|
+
const connection = new EventEmitter() as WritableDeep<WS>;
|
|
17
|
+
connection.setMaxListeners(UNLIMITED);
|
|
18
|
+
lifecycle.onShutdownStart(() => {
|
|
19
|
+
connection.removeAllListeners();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
connection.readyState = CONNECTION_CLOSED;
|
|
23
|
+
let id = START;
|
|
24
|
+
connection.close = () => {
|
|
25
|
+
connection.readyState = CONNECTION_CLOSED;
|
|
26
|
+
};
|
|
27
|
+
// connection.send = (...data) =>
|
|
28
|
+
|
|
29
|
+
hass.socket.createConnection = () => {
|
|
30
|
+
setImmediate(() => {
|
|
31
|
+
if (!config.mock_assistant.PASS_AUTH) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
sendMessage({ type: "auth_ok" });
|
|
35
|
+
});
|
|
36
|
+
return connection;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
connection.send = (data: string) => {
|
|
40
|
+
const payload = JSON.parse(data) as { type: string; id: number };
|
|
41
|
+
connection.emit(INTERNAL_MESSAGE, payload);
|
|
42
|
+
switch (payload.type) {
|
|
43
|
+
case "ping": {
|
|
44
|
+
sendMessage({ id: id++, type: "pong" });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
case "auth": {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
default: {
|
|
51
|
+
setImmediate(() => {
|
|
52
|
+
sendMessage({
|
|
53
|
+
id: payload.id,
|
|
54
|
+
result: null,
|
|
55
|
+
type: "result",
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function sendMessage(data: PartialDeep<SocketMessageDTO>) {
|
|
63
|
+
setImmediate(() => {
|
|
64
|
+
connection.emit("message", JSON.stringify(data));
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
connection: connection as WS,
|
|
70
|
+
onMessage<DATA extends object>(
|
|
71
|
+
type: string,
|
|
72
|
+
callback: (data: DATA & MessageData) => TBlackHole,
|
|
73
|
+
) {
|
|
74
|
+
connection.on(INTERNAL_MESSAGE, (data: DATA & MessageData) => {
|
|
75
|
+
if (data.type === type) {
|
|
76
|
+
callback(data as DATA & MessageData);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
sendMessage,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type MessageData = { id: number; type: string };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { TZoneId } from "../../dynamic";
|
|
4
|
+
import { ZoneDetails } from "../../helpers";
|
|
5
|
+
|
|
6
|
+
export function MockZoneExtension({ mock_assistant }: TServiceParams) {
|
|
7
|
+
let zones = new Map<TZoneId, ZoneDetails>();
|
|
8
|
+
|
|
9
|
+
mock_assistant.socket.onMessage("config/zone_registry/list", message => {
|
|
10
|
+
mock_assistant.socket.sendMessage({
|
|
11
|
+
id: message.id,
|
|
12
|
+
result: [...zones.values()],
|
|
13
|
+
type: "result",
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
mock_assistant.socket.onMessage<{ zone_id: TZoneId }>("config/zone_registry/delete", message => {
|
|
18
|
+
zones.delete(message.zone_id);
|
|
19
|
+
sendUpdate();
|
|
20
|
+
mock_assistant.socket.sendMessage({
|
|
21
|
+
id: message.id,
|
|
22
|
+
result: null,
|
|
23
|
+
type: "result",
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
mock_assistant.socket.onMessage<ZoneDetails>(
|
|
28
|
+
"config/zone_registry/create",
|
|
29
|
+
(message: ZoneDetails) => {
|
|
30
|
+
message.id = message.name as TZoneId;
|
|
31
|
+
zones.set(message.id as TZoneId, message);
|
|
32
|
+
sendUpdate();
|
|
33
|
+
mock_assistant.socket.sendMessage({
|
|
34
|
+
id: message.id,
|
|
35
|
+
result: null,
|
|
36
|
+
type: "result",
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
mock_assistant.socket.onMessage<ZoneDetails>("config/zone_registry/update", message => {
|
|
42
|
+
zones.set(message.id as TZoneId, message);
|
|
43
|
+
sendUpdate();
|
|
44
|
+
mock_assistant.socket.sendMessage({
|
|
45
|
+
id: message.id,
|
|
46
|
+
result: null,
|
|
47
|
+
type: "result",
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const sendUpdate = () =>
|
|
52
|
+
mock_assistant.socket.sendMessage({
|
|
53
|
+
event: { event_type: "zone_registry_updated" },
|
|
54
|
+
type: "event",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
loadFixtures(incoming: ZoneDetails[]) {
|
|
62
|
+
zones = new Map(incoming.map(i => [i.id, i]));
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ANY_ENTITY,
|
|
3
|
+
AreaDetails,
|
|
4
|
+
DeviceDetails,
|
|
5
|
+
ENTITY_STATE,
|
|
6
|
+
EntityRegistryItem,
|
|
7
|
+
FloorDetails,
|
|
8
|
+
HassConfig,
|
|
9
|
+
HassServiceDTO as HassServiceDefinition,
|
|
10
|
+
LabelDefinition,
|
|
11
|
+
} from "../../helpers";
|
|
12
|
+
|
|
13
|
+
export type ScannerCacheData = {
|
|
14
|
+
areas: AreaDetails[];
|
|
15
|
+
config: HassConfig;
|
|
16
|
+
devices: DeviceDetails[];
|
|
17
|
+
entities: ENTITY_STATE<ANY_ENTITY>[];
|
|
18
|
+
entity_registry: EntityRegistryItem<ANY_ENTITY>[];
|
|
19
|
+
floors: FloorDetails[];
|
|
20
|
+
labels: LabelDefinition[];
|
|
21
|
+
services: HassServiceDefinition[];
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./fixtures";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { CreateApplication, TServiceParams } from "@digital-alchemy/core";
|
|
3
|
+
import { writeFileSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { cwd } from "process";
|
|
6
|
+
|
|
7
|
+
import { LIB_HASS } from "..";
|
|
8
|
+
import { ScannerCacheData } from "./helpers";
|
|
9
|
+
|
|
10
|
+
const writeFixtures = CreateApplication({
|
|
11
|
+
configuration: {
|
|
12
|
+
FIXTURES_FILE: {
|
|
13
|
+
default: join(cwd(), "fixtures.json"),
|
|
14
|
+
description: [],
|
|
15
|
+
type: "string",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
libraries: [LIB_HASS],
|
|
19
|
+
name: "mock_assistant",
|
|
20
|
+
services: {
|
|
21
|
+
Write({ hass, lifecycle, config }: TServiceParams) {
|
|
22
|
+
lifecycle.onReady(async () => {
|
|
23
|
+
writeFileSync(
|
|
24
|
+
config.mock_assistant.FIXTURES_FILE,
|
|
25
|
+
JSON.stringify(
|
|
26
|
+
{
|
|
27
|
+
areas: hass.area.current,
|
|
28
|
+
config: await hass.fetch.getConfig(),
|
|
29
|
+
devices: hass.device.current,
|
|
30
|
+
entities: hass.entity.listEntities().map(i => hass.entity.getCurrentState(i)),
|
|
31
|
+
entity_registry: hass.entity.registry.current,
|
|
32
|
+
floors: hass.floor.current,
|
|
33
|
+
labels: hass.label.current,
|
|
34
|
+
services: await hass.fetch.listServices(),
|
|
35
|
+
} as ScannerCacheData,
|
|
36
|
+
undefined,
|
|
37
|
+
" ",
|
|
38
|
+
),
|
|
39
|
+
"utf8",
|
|
40
|
+
);
|
|
41
|
+
process.exit();
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
setImmediate(async () => writeFixtures.bootstrap());
|