@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,157 @@
|
|
|
1
|
+
import { is, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TAreaId,
|
|
5
|
+
TDeviceId,
|
|
6
|
+
TFloorId,
|
|
7
|
+
TLabelId,
|
|
8
|
+
TPlatformId,
|
|
9
|
+
TUniqueId,
|
|
10
|
+
TUniqueIDMapping,
|
|
11
|
+
} from "../dynamic";
|
|
12
|
+
import {
|
|
13
|
+
ALL_DOMAINS,
|
|
14
|
+
ANY_ENTITY,
|
|
15
|
+
EntityRegistryItem,
|
|
16
|
+
IDByInterface,
|
|
17
|
+
PICK_ENTITY,
|
|
18
|
+
PICK_FROM_AREA,
|
|
19
|
+
PICK_FROM_DEVICE,
|
|
20
|
+
PICK_FROM_FLOOR,
|
|
21
|
+
PICK_FROM_LABEL,
|
|
22
|
+
PICK_FROM_PLATFORM,
|
|
23
|
+
} from "../helpers";
|
|
24
|
+
|
|
25
|
+
const check = <RAW extends ANY_ENTITY>(raw: RAW[], domains: ALL_DOMAINS[]) => {
|
|
26
|
+
if (!is.empty(domains)) {
|
|
27
|
+
raw = raw.filter(entity => is.domain(entity, domains));
|
|
28
|
+
}
|
|
29
|
+
return raw;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export function IDByExtension({ hass, logger }: TServiceParams): IDByInterface {
|
|
33
|
+
// * byDomain
|
|
34
|
+
function byDomain<DOMAIN extends ALL_DOMAINS>(domain: DOMAIN) {
|
|
35
|
+
const MASTER_STATE = hass.entity._masterState();
|
|
36
|
+
return Object.keys(MASTER_STATE[domain] ?? {}).map(
|
|
37
|
+
id => `${domain}.${id}` as PICK_ENTITY<DOMAIN>,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// * unique_id
|
|
42
|
+
function unique_id<
|
|
43
|
+
UNIQUE_ID extends TUniqueId,
|
|
44
|
+
ENTITY_ID extends Extract<TUniqueIDMapping[UNIQUE_ID], ANY_ENTITY> = Extract<
|
|
45
|
+
TUniqueIDMapping[UNIQUE_ID],
|
|
46
|
+
ANY_ENTITY
|
|
47
|
+
>,
|
|
48
|
+
>(unique_id: UNIQUE_ID): ENTITY_ID {
|
|
49
|
+
hass.entity.warnEarly("byUniqueId");
|
|
50
|
+
const entity = hass.entity.registry.current.find(
|
|
51
|
+
i => i.unique_id === unique_id,
|
|
52
|
+
) as EntityRegistryItem<ENTITY_ID>;
|
|
53
|
+
if (!entity) {
|
|
54
|
+
logger.error({ name: unique_id, unique_id }, `could not find an entity`);
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
return entity?.entity_id;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// * label
|
|
61
|
+
function label<LABEL extends TLabelId, DOMAIN extends ALL_DOMAINS>(
|
|
62
|
+
label: LABEL,
|
|
63
|
+
...domains: DOMAIN[]
|
|
64
|
+
) {
|
|
65
|
+
hass.entity.warnEarly("label");
|
|
66
|
+
return check(
|
|
67
|
+
hass.entity.registry.current
|
|
68
|
+
.filter(i => i.labels.includes(label))
|
|
69
|
+
.map(i => i.entity_id as PICK_FROM_LABEL<LABEL, DOMAIN>),
|
|
70
|
+
domains,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// * area
|
|
75
|
+
function area<AREA extends TAreaId, DOMAIN extends ALL_DOMAINS>(
|
|
76
|
+
area: AREA,
|
|
77
|
+
...domains: DOMAIN[]
|
|
78
|
+
) {
|
|
79
|
+
hass.entity.warnEarly("area");
|
|
80
|
+
|
|
81
|
+
// find entities are associated with the area directly
|
|
82
|
+
const fromEntity = hass.entity.registry.current
|
|
83
|
+
.filter(i => i.area_id === area)
|
|
84
|
+
.map(i => i.entity_id);
|
|
85
|
+
|
|
86
|
+
// identify devices
|
|
87
|
+
const devices = new Set(
|
|
88
|
+
hass.device.current.filter(device => device.area_id === area).map(i => i.id),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// extract entities associated with device, that have not been assigned to a room
|
|
92
|
+
const fromDevice = hass.entity.registry.current
|
|
93
|
+
.filter(entity => devices.has(entity.device_id) && is.empty(entity.area_id))
|
|
94
|
+
.map(i => i.entity_id);
|
|
95
|
+
|
|
96
|
+
return check(
|
|
97
|
+
// merge lists
|
|
98
|
+
is.unique([...fromEntity, ...fromDevice]),
|
|
99
|
+
domains,
|
|
100
|
+
) as PICK_FROM_AREA<AREA, DOMAIN>[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// * device
|
|
104
|
+
function device<DEVICE extends TDeviceId, DOMAIN extends ALL_DOMAINS>(
|
|
105
|
+
device: DEVICE,
|
|
106
|
+
...domains: DOMAIN[]
|
|
107
|
+
): PICK_FROM_DEVICE<DEVICE, DOMAIN>[] {
|
|
108
|
+
hass.entity.warnEarly("device");
|
|
109
|
+
return check(
|
|
110
|
+
hass.entity.registry.current
|
|
111
|
+
.filter(i => i.device_id === device)
|
|
112
|
+
.map(i => i.entity_id as PICK_FROM_DEVICE<DEVICE, DOMAIN>),
|
|
113
|
+
domains,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// * floor
|
|
118
|
+
function floor<FLOOR extends TFloorId, DOMAIN extends ALL_DOMAINS>(
|
|
119
|
+
floor: FLOOR,
|
|
120
|
+
...domains: DOMAIN[]
|
|
121
|
+
): PICK_FROM_FLOOR<FLOOR, DOMAIN>[] {
|
|
122
|
+
hass.entity.warnEarly("floor");
|
|
123
|
+
const areas = new Set<TAreaId>(
|
|
124
|
+
hass.area.current.filter(i => i.floor_id === floor).map(i => i.area_id),
|
|
125
|
+
);
|
|
126
|
+
return check(
|
|
127
|
+
hass.entity.registry.current
|
|
128
|
+
.filter(i => areas.has(i.area_id))
|
|
129
|
+
.map(i => i.entity_id as PICK_FROM_FLOOR<FLOOR, DOMAIN>),
|
|
130
|
+
domains,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// * platform
|
|
135
|
+
function platform<PLATFORM extends TPlatformId, DOMAIN extends ALL_DOMAINS>(
|
|
136
|
+
platform: PLATFORM,
|
|
137
|
+
...domains: DOMAIN[]
|
|
138
|
+
): PICK_FROM_PLATFORM<PLATFORM, DOMAIN>[] {
|
|
139
|
+
hass.entity.warnEarly("platform");
|
|
140
|
+
return check(
|
|
141
|
+
hass.entity.registry.current
|
|
142
|
+
.filter(i => i.platform === platform)
|
|
143
|
+
.map(i => i.entity_id as PICK_FROM_PLATFORM<PLATFORM, DOMAIN>),
|
|
144
|
+
domains,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
area,
|
|
150
|
+
device,
|
|
151
|
+
domain: byDomain,
|
|
152
|
+
floor,
|
|
153
|
+
label,
|
|
154
|
+
platform,
|
|
155
|
+
unique_id,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./area.extension";
|
|
2
|
+
export * from "./backup.extension";
|
|
3
|
+
export * from "./call-proxy.extension";
|
|
4
|
+
export * from "./config.extension";
|
|
5
|
+
export * from "./device.extension";
|
|
6
|
+
export * from "./entity.extension";
|
|
7
|
+
export * from "./events.extension";
|
|
8
|
+
export * from "./fetch-api.extension";
|
|
9
|
+
export * from "./floor.extension";
|
|
10
|
+
export * from "./id-by.extension";
|
|
11
|
+
export * from "./internal.extension";
|
|
12
|
+
export * from "./label.extension";
|
|
13
|
+
export * from "./reference.extension";
|
|
14
|
+
export * from "./registry.extension";
|
|
15
|
+
export * from "./websocket-api.extension";
|
|
16
|
+
export * from "./zone.extension";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { FIRST, InternalError, is, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
import { createWriteStream } from "fs";
|
|
3
|
+
import { pipeline } from "stream";
|
|
4
|
+
import { promisify } from "util";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
buildFilterString,
|
|
8
|
+
DownloadOptions,
|
|
9
|
+
FetchArguments,
|
|
10
|
+
FetcherOptions,
|
|
11
|
+
FetchProcessTypes,
|
|
12
|
+
FetchWith,
|
|
13
|
+
MaybeHttpError,
|
|
14
|
+
TFetchBody,
|
|
15
|
+
} from "../helpers";
|
|
16
|
+
|
|
17
|
+
const streamPipeline = promisify(pipeline);
|
|
18
|
+
|
|
19
|
+
export function FetchInternals({ logger, context: parentContext }: TServiceParams) {
|
|
20
|
+
return ({ headers: base_headers, baseUrl: base_url, context: logContext }: FetcherOptions) => {
|
|
21
|
+
const capabilities: string[] = [];
|
|
22
|
+
|
|
23
|
+
if (!is.empty(capabilities)) {
|
|
24
|
+
logger.trace({ capabilities, name: logContext }, `initialized fetcher`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function checkForHttpErrors<T extends unknown = unknown>(maybeError: MaybeHttpError): T {
|
|
28
|
+
if (
|
|
29
|
+
is.object(maybeError) &&
|
|
30
|
+
maybeError !== null &&
|
|
31
|
+
is.number(maybeError.statusCode) &&
|
|
32
|
+
is.string(maybeError.error)
|
|
33
|
+
) {
|
|
34
|
+
// Log the error if needed
|
|
35
|
+
logger.error({ error: maybeError, name: logContext }, maybeError.message);
|
|
36
|
+
|
|
37
|
+
// Throw a FetchRequestError
|
|
38
|
+
// throw new FetchRequestError(maybeError);
|
|
39
|
+
throw new InternalError(logContext || parentContext, maybeError.error, maybeError.message);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return maybeError as T;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// #MARK: fetchHandleResponse
|
|
46
|
+
async function fetchHandleResponse<T extends unknown = unknown>(
|
|
47
|
+
process: FetchProcessTypes,
|
|
48
|
+
response: Response,
|
|
49
|
+
): Promise<T> {
|
|
50
|
+
if (process === false || process === "raw") {
|
|
51
|
+
return response as T;
|
|
52
|
+
}
|
|
53
|
+
const text = await response.text();
|
|
54
|
+
if (process === "text") {
|
|
55
|
+
return text as unknown as T;
|
|
56
|
+
}
|
|
57
|
+
if (!["{", "["].includes(text.charAt(FIRST))) {
|
|
58
|
+
if (["OK"].includes(text)) {
|
|
59
|
+
logger.debug({ name: logContext, text }, "full response text");
|
|
60
|
+
} else {
|
|
61
|
+
// It's probably a coding error error, and not something a user did.
|
|
62
|
+
// Will try to keep the array up to date if any other edge cases pop up
|
|
63
|
+
logger.warn({ name: logContext, text }, `unexpected api Response`);
|
|
64
|
+
}
|
|
65
|
+
return text as T;
|
|
66
|
+
}
|
|
67
|
+
const parsed = JSON.parse(text);
|
|
68
|
+
return checkForHttpErrors<T>(parsed);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function fetchCreateUrl({ rawUrl, url, ...fetchWith }: FetchWith): string {
|
|
72
|
+
let out = url || "";
|
|
73
|
+
if (!rawUrl) {
|
|
74
|
+
const base = fetchWith.baseUrl || fetchWrapper.base_url;
|
|
75
|
+
out = base + url;
|
|
76
|
+
}
|
|
77
|
+
if (!is.empty(fetchWith.params)) {
|
|
78
|
+
out = `${out}?${buildFilterString(fetchWith)}`;
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// #MARK: execFetch
|
|
84
|
+
async function exec<T, BODY extends TFetchBody = undefined>({
|
|
85
|
+
body,
|
|
86
|
+
headers = {},
|
|
87
|
+
method = "get",
|
|
88
|
+
process,
|
|
89
|
+
...fetchWith
|
|
90
|
+
}: Partial<FetchArguments<BODY>>) {
|
|
91
|
+
const contentType = is.object(body) ? { "Content-Type": "application/json" } : {};
|
|
92
|
+
const result = await global.fetch(fetchCreateUrl(fetchWith), {
|
|
93
|
+
body: is.object(body) ? JSON.stringify(body) : body,
|
|
94
|
+
headers: {
|
|
95
|
+
...contentType,
|
|
96
|
+
...fetchWrapper.base_headers,
|
|
97
|
+
...headers,
|
|
98
|
+
},
|
|
99
|
+
method,
|
|
100
|
+
});
|
|
101
|
+
return await fetchHandleResponse<T>(process, result);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function download({
|
|
105
|
+
destination,
|
|
106
|
+
body,
|
|
107
|
+
headers = {},
|
|
108
|
+
method = "get",
|
|
109
|
+
...fetchWith
|
|
110
|
+
}: DownloadOptions) {
|
|
111
|
+
const url: string = await fetchCreateUrl(fetchWith);
|
|
112
|
+
const response = await fetch(url, {
|
|
113
|
+
body: is.object(body) ? JSON.stringify(body) : body,
|
|
114
|
+
headers: { ...fetchWrapper.base_headers, ...headers },
|
|
115
|
+
method,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const stream = createWriteStream(destination);
|
|
119
|
+
await streamPipeline(response.body, stream);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// #MARK: return object
|
|
123
|
+
const fetchWrapper = {
|
|
124
|
+
base_headers,
|
|
125
|
+
base_url,
|
|
126
|
+
download,
|
|
127
|
+
exec,
|
|
128
|
+
/**
|
|
129
|
+
* @deprecated set base_url directly
|
|
130
|
+
*/
|
|
131
|
+
setBaseUrl: (url: string) => (fetchWrapper.base_url = url),
|
|
132
|
+
/**
|
|
133
|
+
* @deprecated set base_headers directly
|
|
134
|
+
*/
|
|
135
|
+
setHeaders: (headers: Record<string, string>) => (fetchWrapper.base_headers = headers),
|
|
136
|
+
};
|
|
137
|
+
return fetchWrapper;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type TFetch = <T, BODY extends object = object>(
|
|
142
|
+
fetchWith: Partial<FetchArguments<BODY>>,
|
|
143
|
+
) => Promise<T>;
|
|
144
|
+
|
|
145
|
+
export type TDownload = (fetchWith: DownloadOptions) => Promise<void>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { debounce, TServiceParams } from "@digital-alchemy/core";
|
|
2
|
+
|
|
3
|
+
import { TLabelId } from "../dynamic";
|
|
4
|
+
import {
|
|
5
|
+
EARLY_ON_READY,
|
|
6
|
+
HassLabelService,
|
|
7
|
+
LABEL_REGISTRY_UPDATED,
|
|
8
|
+
LabelDefinition,
|
|
9
|
+
LabelOptions,
|
|
10
|
+
} from "../helpers";
|
|
11
|
+
|
|
12
|
+
export function Label({
|
|
13
|
+
hass,
|
|
14
|
+
config,
|
|
15
|
+
logger,
|
|
16
|
+
lifecycle,
|
|
17
|
+
event,
|
|
18
|
+
context,
|
|
19
|
+
}: TServiceParams): HassLabelService {
|
|
20
|
+
hass.socket.onConnect(async () => {
|
|
21
|
+
let loading = new Promise<void>(async done => {
|
|
22
|
+
hass.label.current = await hass.label.list();
|
|
23
|
+
loading = undefined;
|
|
24
|
+
done();
|
|
25
|
+
});
|
|
26
|
+
lifecycle.onReady(async () => loading && (await loading), EARLY_ON_READY);
|
|
27
|
+
|
|
28
|
+
hass.socket.subscribe({
|
|
29
|
+
context,
|
|
30
|
+
event_type: "label_registry_updated",
|
|
31
|
+
async exec() {
|
|
32
|
+
await debounce(LABEL_REGISTRY_UPDATED, config.hass.EVENT_DEBOUNCE_MS);
|
|
33
|
+
hass.label.current = await hass.label.list();
|
|
34
|
+
logger.debug(`label registry updated`);
|
|
35
|
+
event.emit(LABEL_REGISTRY_UPDATED);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
async function create(details: LabelOptions) {
|
|
41
|
+
return await new Promise<void>(async done => {
|
|
42
|
+
event.once(LABEL_REGISTRY_UPDATED, done);
|
|
43
|
+
await hass.socket.sendMessage({
|
|
44
|
+
type: "config/label_registry/create",
|
|
45
|
+
...details,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function deleteLabel(label_id: TLabelId) {
|
|
51
|
+
return await new Promise<void>(async done => {
|
|
52
|
+
event.once(LABEL_REGISTRY_UPDATED, done);
|
|
53
|
+
await hass.socket.sendMessage({
|
|
54
|
+
label_id,
|
|
55
|
+
type: "config/label_registry/delete",
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function list() {
|
|
61
|
+
return await hass.socket.sendMessage<LabelDefinition[]>({
|
|
62
|
+
type: "config/label_registry/list",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function update(details: LabelDefinition) {
|
|
67
|
+
return await new Promise<void>(async done => {
|
|
68
|
+
event.once(LABEL_REGISTRY_UPDATED, done);
|
|
69
|
+
await hass.socket.sendMessage({
|
|
70
|
+
type: "config/label_registry/update",
|
|
71
|
+
...details,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
create,
|
|
78
|
+
current: [] as LabelDefinition[],
|
|
79
|
+
delete: deleteLabel,
|
|
80
|
+
list,
|
|
81
|
+
update,
|
|
82
|
+
};
|
|
83
|
+
}
|