generated from homebridge/homebridge-plugin-template
-
-
Notifications
You must be signed in to change notification settings - Fork 49
/
helpers.ts
117 lines (104 loc) · 3.8 KB
/
helpers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { Characteristic, Service, WithUUID } from 'homebridge';
import { ExposesEntry, exposesHasFeatures, exposesHasNumericRangeProperty } from './z2mModels';
export function errorToString(e: unknown): string {
if (typeof e === 'string') {
return e;
}
if (e instanceof Error) {
return e.message; // works, `e` narrowed to Error
}
return JSON.stringify(e);
}
export function getDiffFromArrays<T>(a: T[], b: T[]): T[] {
return a.filter((x) => !b.includes(x)).concat(b.filter((x) => !a.includes(x)));
}
export function getOrAddCharacteristic(service: Service, characteristic: WithUUID<{ new (): Characteristic }>): Characteristic {
return service.getCharacteristic(characteristic) || service.addCharacteristic(characteristic);
}
export function roundToDecimalPlaces(input: number, decimalPlaces: number): number {
if (decimalPlaces !== Math.round(decimalPlaces) || decimalPlaces < 1 || decimalPlaces > 10) {
throw new Error(`decimalPlaces must be a whole number between 1 and 10, not ${decimalPlaces}`);
}
const maxDecimals = Math.pow(10, decimalPlaces);
return Math.round((input + Number.EPSILON) * maxDecimals) / maxDecimals;
}
export function copyExposesRangeToCharacteristic(exposes: ExposesEntry, characteristic: Characteristic): boolean {
if (exposesHasNumericRangeProperty(exposes)) {
characteristic.setProps({
minValue: exposes.value_min,
maxValue: exposes.value_max,
minStep: exposes.value_step ?? 1,
});
return true;
}
return false;
}
export function groupByEndpoint<Entry extends ExposesEntry>(entries: Entry[]): Map<string | undefined, Entry[]> {
const endpointMap = new Map<string | undefined, Entry[]>();
entries.forEach((entry) => {
const collection = endpointMap.get(entry.endpoint);
if (!collection) {
endpointMap.set(entry.endpoint, [entry]);
} else {
collection.push(entry);
}
});
return endpointMap;
}
export function getAllEndpoints(entries: ExposesEntry[], parentEndpoint?: string): (string | undefined)[] {
const endpoints = new Set<string | undefined>();
entries.forEach((entry) => {
const endpoint = entry.endpoint ?? parentEndpoint;
if (endpoint !== undefined || entry.property !== undefined) {
endpoints.add(endpoint);
}
if (exposesHasFeatures(entry)) {
getAllEndpoints(entry.features, endpoint).forEach((e) => {
endpoints.add(e);
});
}
});
const result = Array.from(endpoints);
// Sort so that `undefined` is always the first and the rest is sorted alphabetically.
result.sort((a, b) => {
if (a === undefined) {
return -1;
}
if (b === undefined) {
return 1;
}
return a.localeCompare(b);
});
return result;
}
export function sanitizeAndFilterExposesEntries(
input: ExposesEntry[],
filter?: (entry: ExposesEntry) => boolean,
valueFilter?: (entry: ExposesEntry) => string[],
parentEndpoint?: string | undefined
): ExposesEntry[] {
return input
.filter((e) => filter === undefined || filter(e))
.map((e) => sanitizeAndFilterExposesEntry(e, filter, valueFilter, parentEndpoint));
}
function sanitizeAndFilterExposesEntry(
input: ExposesEntry,
filter?: (entry: ExposesEntry) => boolean,
valueFilter?: (entry: ExposesEntry) => string[],
parentEndpoint?: string | undefined
): ExposesEntry {
const output: ExposesEntry = {
...input,
};
if (output.endpoint === undefined && parentEndpoint !== undefined) {
// Make sure features inherit the endpoint from their parent, if it is not defined explicitly.
output.endpoint = parentEndpoint;
}
if (exposesHasFeatures(output)) {
output.features = sanitizeAndFilterExposesEntries(output.features, filter, valueFilter, output.endpoint);
}
if (Array.isArray(output.values) && valueFilter !== undefined) {
output.values = valueFilter(output);
}
return output;
}