homebridge-ratgdo 2.1.2 → 2.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/dist/ratgdo-device.d.ts +0 -2
- package/dist/ratgdo-device.js +21 -47
- package/dist/ratgdo-device.js.map +1 -1
- package/dist/ratgdo-options.d.ts +4 -15
- package/dist/ratgdo-options.js +2 -93
- package/dist/ratgdo-options.js.map +1 -1
- package/dist/ratgdo-platform.d.ts +4 -4
- package/dist/ratgdo-platform.js +22 -31
- package/dist/ratgdo-platform.js.map +1 -1
- package/homebridge-ui/public/index.html +20 -1
- package/homebridge-ui/public/lib/featureoptions.js +366 -0
- package/homebridge-ui/public/lib/webUi.mjs +155 -0
- package/homebridge-ui/public/{ratgdo-featureoptions.mjs → lib/webui-featureoptions.mjs} +104 -142
- package/homebridge-ui/server.js +3 -39
- package/package.json +13 -13
- package/dist/ratgdo-mqtt.d.ts +0 -19
- package/dist/ratgdo-mqtt.js +0 -155
- package/dist/ratgdo-mqtt.js.map +0 -1
- package/homebridge-ui/public/lib/featureoptions.mjs +0 -200
- package/homebridge-ui/public/ui.mjs +0 -144
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { API, DynamicPlatformPlugin, HAP, Logging, PlatformAccessory, PlatformConfig } from "homebridge";
|
|
2
|
+
import { FeatureOptions, MqttClient } from "homebridge-plugin-utils";
|
|
2
3
|
import { RatgdoOptions } from "./ratgdo-options.js";
|
|
3
4
|
import { RatgdoAccessory } from "./ratgdo-device.js";
|
|
4
|
-
import { RatgdoMqtt } from "./ratgdo-mqtt.js";
|
|
5
5
|
export declare class RatgdoPlatform implements DynamicPlatformPlugin {
|
|
6
6
|
private readonly accessories;
|
|
7
7
|
readonly api: API;
|
|
8
|
+
private discoveredDevices;
|
|
8
9
|
private espHomeEvents;
|
|
9
|
-
|
|
10
|
+
featureOptions: FeatureOptions;
|
|
10
11
|
config: RatgdoOptions;
|
|
11
12
|
readonly configOptions: string[];
|
|
12
13
|
readonly configuredDevices: {
|
|
@@ -14,12 +15,11 @@ export declare class RatgdoPlatform implements DynamicPlatformPlugin {
|
|
|
14
15
|
};
|
|
15
16
|
readonly hap: HAP;
|
|
16
17
|
readonly log: Logging;
|
|
17
|
-
readonly mqtt:
|
|
18
|
+
readonly mqtt: MqttClient | null;
|
|
18
19
|
constructor(log: Logging, config: PlatformConfig, api: API);
|
|
19
20
|
configureAccessory(accessory: PlatformAccessory): void;
|
|
20
21
|
private configureRatgdo;
|
|
21
22
|
private discoverRatgdoDevice;
|
|
22
23
|
private configureGdo;
|
|
23
|
-
featureOptionDefault(option: string): boolean;
|
|
24
24
|
debug(message: string, ...parameters: unknown[]): void;
|
|
25
25
|
}
|
package/dist/ratgdo-platform.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Bonjour } from "bonjour-service";
|
|
2
|
+
import { FeatureOptions, MqttClient } from "homebridge-plugin-utils";
|
|
2
3
|
import { PLATFORM_NAME, PLUGIN_NAME, RATGDO_AUTODISCOVERY_INTERVAL, RATGDO_HEARTBEAT_DURATION, RATGDO_HEARTBEAT_INTERVAL, RATGDO_MQTT_TOPIC } from "./settings.js";
|
|
3
|
-
import { featureOptionCategories, featureOptions
|
|
4
|
+
import { featureOptionCategories, featureOptions } from "./ratgdo-options.js";
|
|
4
5
|
import EventSource from "eventsource";
|
|
5
6
|
import { RatgdoAccessory } from "./ratgdo-device.js";
|
|
6
|
-
import { RatgdoMqtt } from "./ratgdo-mqtt.js";
|
|
7
7
|
import http from "node:http";
|
|
8
8
|
import net from "node:net";
|
|
9
9
|
import util from "node:util";
|
|
10
10
|
export class RatgdoPlatform {
|
|
11
11
|
accessories;
|
|
12
12
|
api;
|
|
13
|
+
discoveredDevices;
|
|
13
14
|
espHomeEvents;
|
|
14
|
-
|
|
15
|
+
featureOptions;
|
|
15
16
|
config;
|
|
16
17
|
configOptions;
|
|
17
18
|
configuredDevices;
|
|
@@ -21,39 +22,29 @@ export class RatgdoPlatform {
|
|
|
21
22
|
constructor(log, config, api) {
|
|
22
23
|
this.accessories = [];
|
|
23
24
|
this.api = api;
|
|
25
|
+
this.config = {};
|
|
24
26
|
this.configOptions = [];
|
|
25
27
|
this.configuredDevices = {};
|
|
28
|
+
this.discoveredDevices = {};
|
|
26
29
|
this.espHomeEvents = {};
|
|
27
|
-
this.featureOptionDefaults = {};
|
|
28
30
|
this.hap = api.hap;
|
|
29
31
|
this.log = log;
|
|
30
32
|
this.log.debug = this.debug.bind(this);
|
|
31
33
|
this.mqtt = null;
|
|
32
|
-
|
|
33
|
-
for (const category of featureOptionCategories) {
|
|
34
|
-
for (const options of featureOptions[category.name]) {
|
|
35
|
-
this.featureOptionDefaults[(category.name + (options.name.length ? "." + options.name : "")).toLowerCase()] = options.default;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
34
|
+
this.featureOptions = new FeatureOptions(featureOptionCategories, featureOptions, config.options);
|
|
38
35
|
// We can't start without being configured.
|
|
39
36
|
if (!config) {
|
|
40
37
|
return;
|
|
41
38
|
}
|
|
42
39
|
this.config = {
|
|
43
40
|
debug: config.debug === true,
|
|
44
|
-
mqttTopic: config.mqttTopic
|
|
41
|
+
mqttTopic: config.mqttTopic,
|
|
45
42
|
mqttUrl: config.mqttUrl,
|
|
46
43
|
options: config.options
|
|
47
44
|
};
|
|
48
|
-
// If we have feature options, put them into their own array, upper-cased for future reference.
|
|
49
|
-
if (this.config.options) {
|
|
50
|
-
for (const featureOption of this.config.options) {
|
|
51
|
-
this.configOptions.push(featureOption.toLowerCase());
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
45
|
// Initialize MQTT, if needed.
|
|
55
46
|
if (this.config.mqttUrl) {
|
|
56
|
-
this.mqtt = new
|
|
47
|
+
this.mqtt = new MqttClient(this.config.mqttUrl, this.config.mqttTopic ?? RATGDO_MQTT_TOPIC, this.log);
|
|
57
48
|
}
|
|
58
49
|
this.log.debug("Debug logging on. Expect a lot of data.");
|
|
59
50
|
// Fire up the Ratgdo API once Homebridge has loaded all the cached accessories it knows about and called configureAccessory() on each.
|
|
@@ -73,6 +64,8 @@ export class RatgdoPlatform {
|
|
|
73
64
|
this.api.on("shutdown" /* APIEvent.SHUTDOWN */, () => mdns.destroy());
|
|
74
65
|
// Start ESPHome device discovery.
|
|
75
66
|
const mdnsBrowser = mdns.find({ type: "esphomelib" }, this.discoverRatgdoDevice.bind(this));
|
|
67
|
+
// Trigger an initial update of our discovery.
|
|
68
|
+
mdnsBrowser.update();
|
|
76
69
|
// Refresh device discovery regular intervals.
|
|
77
70
|
setInterval(() => mdnsBrowser.update(), RATGDO_AUTODISCOVERY_INTERVAL * 1000);
|
|
78
71
|
}
|
|
@@ -165,7 +158,6 @@ export class RatgdoPlatform {
|
|
|
165
158
|
default:
|
|
166
159
|
ratgdoAccessory.log.error("Unknown door operation detected: %s.", event.current_operation);
|
|
167
160
|
return;
|
|
168
|
-
break;
|
|
169
161
|
}
|
|
170
162
|
ratgdoAccessory.updateState("door", state, (event.position !== undefined) ? event.position * 100 : undefined);
|
|
171
163
|
break;
|
|
@@ -202,6 +194,10 @@ export class RatgdoPlatform {
|
|
|
202
194
|
}
|
|
203
195
|
// Configure a discovered garage door opener.
|
|
204
196
|
configureGdo(address, mac, name, firmwareVersion) {
|
|
197
|
+
// If we've already discovered this device, we're done.
|
|
198
|
+
if (this.discoveredDevices[mac]) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
205
201
|
// Generate this device's unique identifier.
|
|
206
202
|
const uuid = this.hap.uuid.generate(mac);
|
|
207
203
|
// See if we already know about this accessory or if it's truly new.
|
|
@@ -213,8 +209,12 @@ export class RatgdoPlatform {
|
|
|
213
209
|
mac: mac.replace(/:/g, ""),
|
|
214
210
|
name: name
|
|
215
211
|
};
|
|
212
|
+
// Inform the user that we've discovered a device.
|
|
213
|
+
this.log.info("Discovered: %s (address: %s mac: %s ESPHome firmware: v%s).", device.name, device.address, device.mac, device.firmwareVersion);
|
|
214
|
+
// Mark it as discovered.
|
|
215
|
+
this.discoveredDevices[mac] = true;
|
|
216
216
|
// Check to see if the user has disabled the device.
|
|
217
|
-
if (!
|
|
217
|
+
if (!this.featureOptions.test("Device", device.mac)) {
|
|
218
218
|
// If the accessory already exists, let's remove it.
|
|
219
219
|
if (accessory) {
|
|
220
220
|
// Inform the user.
|
|
@@ -231,8 +231,6 @@ export class RatgdoPlatform {
|
|
|
231
231
|
if (this.configuredDevices[uuid]) {
|
|
232
232
|
return null;
|
|
233
233
|
}
|
|
234
|
-
// Inform the user.
|
|
235
|
-
this.log.info("Discovered: %s (address: %s mac: %s ESPHome firmware: v%s).", device.name, device.address, device.mac, device.firmwareVersion);
|
|
236
234
|
// It's a new device - let's add it to HomeKit.
|
|
237
235
|
if (!accessory) {
|
|
238
236
|
accessory = new this.api.platformAccessory(device.name, uuid);
|
|
@@ -240,21 +238,14 @@ export class RatgdoPlatform {
|
|
|
240
238
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
241
239
|
this.accessories.push(accessory);
|
|
242
240
|
}
|
|
241
|
+
// Inform the user.
|
|
242
|
+
this.log.info("Configuring: %s (address: %s mac: %s ESPHome firmware: v%s).", device.name, device.address, device.mac, device.firmwareVersion);
|
|
243
243
|
// Add it to our list of configured devices.
|
|
244
244
|
this.configuredDevices[uuid] = new RatgdoAccessory(this, accessory, device);
|
|
245
245
|
// Refresh the accessory cache.
|
|
246
246
|
this.api.updatePlatformAccessories([accessory]);
|
|
247
247
|
return this.configuredDevices[uuid];
|
|
248
248
|
}
|
|
249
|
-
// Utility to return the default value for a feature option.
|
|
250
|
-
featureOptionDefault(option) {
|
|
251
|
-
const defaultValue = this.featureOptionDefaults[option.toLowerCase()];
|
|
252
|
-
// If it's unknown to us, assume it's true.
|
|
253
|
-
if (defaultValue === undefined) {
|
|
254
|
-
return true;
|
|
255
|
-
}
|
|
256
|
-
return defaultValue;
|
|
257
|
-
}
|
|
258
249
|
// Utility for debug logging.
|
|
259
250
|
debug(message, ...parameters) {
|
|
260
251
|
if (this.config.debug) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ratgdo-platform.js","sourceRoot":"","sources":["../src/ratgdo-platform.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAW,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,yBAAyB,EACtH,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAiB,uBAAuB,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"ratgdo-platform.js","sourceRoot":"","sources":["../src/ratgdo-platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -110,4 +110,23 @@
|
|
|
110
110
|
</li>
|
|
111
111
|
</ul>
|
|
112
112
|
</div>
|
|
113
|
-
<script
|
|
113
|
+
<script type="module">
|
|
114
|
+
|
|
115
|
+
/* Copyright(C) 2017-2024, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
116
|
+
*
|
|
117
|
+
* Plugin webUI.
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
"use strict;"
|
|
121
|
+
|
|
122
|
+
import { webUi } from "./lib/webUi.mjs";
|
|
123
|
+
import { webUiFeatureOptions } from "./lib/webui-featureoptions.mjs";
|
|
124
|
+
|
|
125
|
+
const pluginName = "Ratgdo"
|
|
126
|
+
|
|
127
|
+
// Keep a list of all the feature options and option groups.
|
|
128
|
+
const featureOptions = new webUiFeatureOptions({ sidebar: "Ratgdo Devices", useControllers: false });
|
|
129
|
+
|
|
130
|
+
// Instantiate the webUI.
|
|
131
|
+
new webUi({ featureOptions: featureOptions, homebridge: homebridge, name: "Ratgdo" });
|
|
132
|
+
</script>
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
export class FeatureOptions {
|
|
2
|
+
_categories;
|
|
3
|
+
_configuredOptions;
|
|
4
|
+
_groups;
|
|
5
|
+
_options;
|
|
6
|
+
defaultReturnValue;
|
|
7
|
+
defaults;
|
|
8
|
+
valueOptions;
|
|
9
|
+
// Create a feature option instance.
|
|
10
|
+
constructor(categories, options, configuredOptions) {
|
|
11
|
+
// Initialize our defaults.
|
|
12
|
+
this._categories = [];
|
|
13
|
+
this._configuredOptions = [];
|
|
14
|
+
this._groups = {};
|
|
15
|
+
this._options = {};
|
|
16
|
+
this.defaultReturnValue = false;
|
|
17
|
+
this.defaults = {};
|
|
18
|
+
this.valueOptions = {};
|
|
19
|
+
this.categories = categories ?? [];
|
|
20
|
+
this.configuredOptions = configuredOptions;
|
|
21
|
+
this.options = options ?? {};
|
|
22
|
+
}
|
|
23
|
+
color(option, device) {
|
|
24
|
+
switch (this.scope(option, device)) {
|
|
25
|
+
case "device":
|
|
26
|
+
return "text-info";
|
|
27
|
+
case "controller":
|
|
28
|
+
return "text-success";
|
|
29
|
+
case "global":
|
|
30
|
+
return device ? "text-warning" : "text-info";
|
|
31
|
+
default:
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Return the default value for an option.
|
|
37
|
+
*
|
|
38
|
+
* @param option - Feature option to check.
|
|
39
|
+
*
|
|
40
|
+
* @returns Returns true or false, depending on the option default.
|
|
41
|
+
*/
|
|
42
|
+
defaultValue(option) {
|
|
43
|
+
// Value-centric feature options don't have default values.
|
|
44
|
+
if (this.isValue(option)) {
|
|
45
|
+
return this.defaultReturnValue;
|
|
46
|
+
}
|
|
47
|
+
const value = this.defaults[option.toLowerCase()];
|
|
48
|
+
// If it's unknown to us, assume it's true.
|
|
49
|
+
if (value === undefined) {
|
|
50
|
+
return this.defaultReturnValue;
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Return whether the option explicitly exists in the list of configured options.
|
|
56
|
+
*
|
|
57
|
+
* @param option - Feature option to check.
|
|
58
|
+
* @param id - Optional device or controller scope identifier to check.
|
|
59
|
+
*
|
|
60
|
+
* @returns Returns true if the option has been explicitly configured, false otherwise.
|
|
61
|
+
*/
|
|
62
|
+
exists(option, id) {
|
|
63
|
+
const regex = this.isValue(option) ? this.valueRegex(option, id) : this.optionRegex(option, id);
|
|
64
|
+
return this.configuredOptions.some(x => regex.test(x));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Return a fully formed feature option string.
|
|
68
|
+
*
|
|
69
|
+
* @param category - Feature option category entry or category name string.
|
|
70
|
+
* @param option - Feature option entry of option name string.
|
|
71
|
+
*
|
|
72
|
+
* @returns Returns a fully formed feature option in the form of `category.option`.
|
|
73
|
+
*/
|
|
74
|
+
expandOption(category, option) {
|
|
75
|
+
const categoryName = (typeof category === "string") ? category : category.name;
|
|
76
|
+
const optionName = (typeof option === "string") ? option : option.name;
|
|
77
|
+
if (!categoryName || !categoryName.length) {
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
return (!optionName || !optionName.length) ? categoryName : categoryName + "." + optionName;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse a floating point feature option value.
|
|
84
|
+
*
|
|
85
|
+
* @param value - Value to parse.
|
|
86
|
+
*
|
|
87
|
+
* @returns Returns a floating point number from a string, or `undefined` if it couldn't be parsed.
|
|
88
|
+
*/
|
|
89
|
+
getFloat(value) {
|
|
90
|
+
// We don't have the value configured -- we're done.
|
|
91
|
+
if (value === undefined) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
// Parse the number and return the value.
|
|
95
|
+
return this.parseOptionNumeric(value, parseFloat);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Parse an integer feature option value.
|
|
99
|
+
*
|
|
100
|
+
* @param value - Value to parse.
|
|
101
|
+
*
|
|
102
|
+
* @returns Returns an integer from a string, or `undefined` if it couldn't be parsed.
|
|
103
|
+
*/
|
|
104
|
+
getInteger(value) {
|
|
105
|
+
// We don't have the value configured -- we're done.
|
|
106
|
+
if (value === undefined) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
// Parse the number and return the value.
|
|
110
|
+
return this.parseOptionNumeric(value, parseInt);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Return whether an option has been set in either the device or controller scope context.
|
|
114
|
+
*
|
|
115
|
+
* @param option - Feature option to check.
|
|
116
|
+
*
|
|
117
|
+
* @returns Returns true if the option is set at the device or controller level and false otherwise.
|
|
118
|
+
*/
|
|
119
|
+
isScopeDevice(option, device) {
|
|
120
|
+
const value = this.exists(option, device);
|
|
121
|
+
// Return the value if it's set, or the default value for this option.
|
|
122
|
+
return (value !== undefined) ? value : this.defaultValue(option);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Return whether an option has been set in the global scope context.
|
|
126
|
+
*
|
|
127
|
+
* @param option - Feature option to check.
|
|
128
|
+
*
|
|
129
|
+
* @returns Returns true if the option is set globally and false otherwise.
|
|
130
|
+
*/
|
|
131
|
+
isScopeGlobal(option) {
|
|
132
|
+
const value = this.exists(option);
|
|
133
|
+
// Return the value if it's set, or the default value for this option.
|
|
134
|
+
return (value !== undefined) ? value : this.defaultValue(option);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Return whether an option is value-centric or not.
|
|
138
|
+
*
|
|
139
|
+
* @param option - Feature option entry or string to check.
|
|
140
|
+
*
|
|
141
|
+
* @returns Returns true if it is a value-centric option and false otherwise.
|
|
142
|
+
*/
|
|
143
|
+
isValue(option) {
|
|
144
|
+
return this.valueOptions[option?.toLowerCase()] === true;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Return the scope hierarchy location of an option.
|
|
148
|
+
*
|
|
149
|
+
* @param option - Feature option to check.
|
|
150
|
+
* @param device - Optional device scope identifier.
|
|
151
|
+
* @param controller - Optional controller scope identifier.
|
|
152
|
+
*
|
|
153
|
+
* @returns Returns an object containing the location in the scope hierarchy of an `option` as well as the current value associated with the option.
|
|
154
|
+
*/
|
|
155
|
+
scope(option, device, controller) {
|
|
156
|
+
return this.getOptionInfo(option, device, controller).scope;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Return the current state of a feature option, traversing the scope hierarchy.
|
|
160
|
+
*
|
|
161
|
+
* @param option - Feature option to check.
|
|
162
|
+
* @param device - Optional device scope identifier.
|
|
163
|
+
* @param controller - Optional controller scope identifier.
|
|
164
|
+
*
|
|
165
|
+
* @returns Returns true if the option is enabled, and false otherwise.
|
|
166
|
+
*/
|
|
167
|
+
test(option, device, controller) {
|
|
168
|
+
return this.getOptionInfo(option, device, controller).value;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Return the value associated with a value-centric feature option, traversing the scope hierarchy.
|
|
172
|
+
*
|
|
173
|
+
* @param option - Feature option to check.
|
|
174
|
+
* @param device - Optional device scope identifier.
|
|
175
|
+
* @param controller - Optional controller scope identifier.
|
|
176
|
+
*
|
|
177
|
+
* @returns Returns the current value associated with `option` or `undefined` if none.
|
|
178
|
+
*/
|
|
179
|
+
value(option, device, controller) {
|
|
180
|
+
const getValue = (checkOption, checkId) => {
|
|
181
|
+
const regex = this.valueRegex(checkOption, checkId);
|
|
182
|
+
// Get the option value, if we have one.
|
|
183
|
+
for (const entry of this.configuredOptions) {
|
|
184
|
+
const regexMatch = regex.exec(entry);
|
|
185
|
+
if (regexMatch) {
|
|
186
|
+
return regexMatch[1];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return undefined;
|
|
190
|
+
};
|
|
191
|
+
// Check to see if we have a device-level value first.
|
|
192
|
+
if (device) {
|
|
193
|
+
const value = getValue(option, device);
|
|
194
|
+
if (value) {
|
|
195
|
+
return value;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Now check to see if we have an controller-level value.
|
|
199
|
+
if (controller) {
|
|
200
|
+
const value = getValue(option, controller);
|
|
201
|
+
if (value) {
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Finally, we check for a global-level value.
|
|
206
|
+
return getValue(option);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Return the list of available feature option categories.
|
|
210
|
+
*
|
|
211
|
+
* @returns Returns the current list of available feature option categories.
|
|
212
|
+
*/
|
|
213
|
+
get categories() {
|
|
214
|
+
return this._categories;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Set the list of available feature option categories.
|
|
218
|
+
*
|
|
219
|
+
* @param options - Array of available feature options.
|
|
220
|
+
*/
|
|
221
|
+
set categories(category) {
|
|
222
|
+
this._categories = category;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Return the list of currently configured feature options.
|
|
226
|
+
*
|
|
227
|
+
* @returns Returns the currently configured list of feature options.
|
|
228
|
+
*/
|
|
229
|
+
get configuredOptions() {
|
|
230
|
+
return this._configuredOptions;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Set the list of currently configured feature options.
|
|
234
|
+
*
|
|
235
|
+
* @param options - Array of configured feature options.
|
|
236
|
+
*/
|
|
237
|
+
set configuredOptions(options) {
|
|
238
|
+
this._configuredOptions = options ?? [];
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Return the list of available feature option groups.
|
|
242
|
+
*
|
|
243
|
+
* @returns Returns the current list of available feature option groups.
|
|
244
|
+
*/
|
|
245
|
+
get groups() {
|
|
246
|
+
return this._groups;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Return the list of available feature options.
|
|
250
|
+
*
|
|
251
|
+
* @returns Returns the current list of available feature options.
|
|
252
|
+
*/
|
|
253
|
+
get options() {
|
|
254
|
+
return this._options;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Set the list of available feature options.
|
|
258
|
+
*
|
|
259
|
+
* @param options - Array of available feature options.
|
|
260
|
+
*/
|
|
261
|
+
set options(options) {
|
|
262
|
+
this._options = options ?? {};
|
|
263
|
+
// Regenerate our defaults.
|
|
264
|
+
this.generateDefaults();
|
|
265
|
+
}
|
|
266
|
+
// Build our list of default values for our feature options.
|
|
267
|
+
generateDefaults() {
|
|
268
|
+
this.defaults = {};
|
|
269
|
+
this._groups = {};
|
|
270
|
+
this.valueOptions = {};
|
|
271
|
+
for (const category of this.categories) {
|
|
272
|
+
// Now enumerate all the feature options for a given device and add then to the full list.
|
|
273
|
+
for (const option of this.options[category.name]) {
|
|
274
|
+
// Expand the entry.
|
|
275
|
+
const entry = this.expandOption(category, option);
|
|
276
|
+
// Index the default value.
|
|
277
|
+
this.defaults[entry.toLowerCase()] = option.default;
|
|
278
|
+
// Track value-centric options.
|
|
279
|
+
this.valueOptions[entry.toLowerCase()] = "defaultValue" in option;
|
|
280
|
+
// Cross reference the feature option group it belongs to, if any.
|
|
281
|
+
if (option.group !== undefined) {
|
|
282
|
+
const expandedGroup = category.name + (option.group.length ? ("." + option.group) : "");
|
|
283
|
+
// Initialize the group entry if needed and add the entry.
|
|
284
|
+
(this._groups[expandedGroup] ??= []).push(entry);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Utility function to return the setting of a particular option and it's position in the scoping hierarchy.
|
|
290
|
+
getOptionInfo(option, device, controller) {
|
|
291
|
+
// There are a couple of ways to enable and disable options. The rules of the road are:
|
|
292
|
+
//
|
|
293
|
+
// 1. Explicitly disabling, or enabling an option on the controller propogates to all the devices that are managed by that controller. Why might you want to do this?
|
|
294
|
+
// Because...
|
|
295
|
+
//
|
|
296
|
+
// 2. Explicitly disabling, or enabling an option on a device always override the above. This means that it's possible to disable an option for a controller, and all
|
|
297
|
+
// the devices that are managed by it, and then override that behavior on a single device that it's managing.
|
|
298
|
+
// Check to see if we have a device-level option first.
|
|
299
|
+
if (device && this.exists(option, device)) {
|
|
300
|
+
const value = this.isOptionEnabled(option, device);
|
|
301
|
+
if (value !== undefined) {
|
|
302
|
+
return { scope: "device", value: value };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// Now check to see if we have an controller-level option.
|
|
306
|
+
if (controller && this.exists(option, controller)) {
|
|
307
|
+
const value = this.isOptionEnabled(option, controller);
|
|
308
|
+
if (value !== undefined) {
|
|
309
|
+
return { scope: "controller", value: value };
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Finally, we check for a global-level value.
|
|
313
|
+
if (this.exists(option)) {
|
|
314
|
+
const value = this.isOptionEnabled(option);
|
|
315
|
+
if (value !== undefined) {
|
|
316
|
+
return { scope: "global", value: value };
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// The option hasn't been set at any scope, return our default value.
|
|
320
|
+
return { scope: "none", value: this.defaultValue(option) };
|
|
321
|
+
}
|
|
322
|
+
// Utility to test whether an option is set in a given scope.
|
|
323
|
+
// We return true if an option is enabled, false for disabled, undefined otherwise. For value-centric options, we return true if a value exists.
|
|
324
|
+
isOptionEnabled(option, id) {
|
|
325
|
+
// Deal with value-centric options uniquely.
|
|
326
|
+
if (this.isValue(option)) {
|
|
327
|
+
return this.exists(option, id);
|
|
328
|
+
}
|
|
329
|
+
const regex = this.optionRegex(option, id);
|
|
330
|
+
// Get the option value, if we have one.
|
|
331
|
+
for (const entry of this.configuredOptions) {
|
|
332
|
+
const regexMatch = regex.exec(entry);
|
|
333
|
+
if (regexMatch) {
|
|
334
|
+
return regexMatch[1].toLowerCase() === "enable";
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
// Regular expression test for feature options.
|
|
340
|
+
optionRegex(option, id) {
|
|
341
|
+
// This regular expression is a bit more intricate than you might think it should be due to the need to ensure we capture values at the very end of the option. We
|
|
342
|
+
// also need to escape out our option to ensure we have no inadvertent issues in matching the regular expression.
|
|
343
|
+
return new RegExp("^(Enable|Disable)\\." + option.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + (!id ? "" : "\\." + id) + "$", "gi");
|
|
344
|
+
}
|
|
345
|
+
// Utility function to parse and return a numeric configuration parameter.
|
|
346
|
+
parseOptionNumeric(option, convert) {
|
|
347
|
+
// We don't have the option configured -- we're done.
|
|
348
|
+
if (option === undefined) {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
// Convert it to a number, if needed.
|
|
352
|
+
const convertedValue = convert(option);
|
|
353
|
+
// Let's validate to make sure it's really a number.
|
|
354
|
+
if (isNaN(convertedValue) || (convertedValue < 0)) {
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
// Return the value.
|
|
358
|
+
return convertedValue;
|
|
359
|
+
}
|
|
360
|
+
// Regular expression test for value-centric feature options.
|
|
361
|
+
valueRegex(option, id) {
|
|
362
|
+
// This regular expression is a bit more intricate than you might think it should be due to the need to ensure we capture values at the very end of the option.
|
|
363
|
+
return new RegExp("^Enable\\." + option.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + (!id ? "" : "\\." + id) + "\\.([^\\.]+)$", "gi");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=featureoptions.js.map
|