@mp-consulting/homebridge-unifi-access 1.0.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.
Files changed (74) hide show
  1. package/.claude/settings.local.json +91 -0
  2. package/CHANGELOG.md +13 -0
  3. package/LICENSE.md +22 -0
  4. package/README.md +159 -0
  5. package/config.schema.json +202 -0
  6. package/dist/access-controller.d.ts +41 -0
  7. package/dist/access-controller.js +342 -0
  8. package/dist/access-controller.js.map +1 -0
  9. package/dist/access-device-catalog.d.ts +43 -0
  10. package/dist/access-device-catalog.js +151 -0
  11. package/dist/access-device-catalog.js.map +1 -0
  12. package/dist/access-device.d.ts +68 -0
  13. package/dist/access-device.js +330 -0
  14. package/dist/access-device.js.map +1 -0
  15. package/dist/access-events.d.ts +27 -0
  16. package/dist/access-events.js +152 -0
  17. package/dist/access-events.js.map +1 -0
  18. package/dist/access-options.d.ts +32 -0
  19. package/dist/access-options.js +65 -0
  20. package/dist/access-options.js.map +1 -0
  21. package/dist/access-platform.d.ts +15 -0
  22. package/dist/access-platform.js +74 -0
  23. package/dist/access-platform.js.map +1 -0
  24. package/dist/access-types.d.ts +30 -0
  25. package/dist/access-types.js +42 -0
  26. package/dist/access-types.js.map +1 -0
  27. package/dist/hub/access-hub-api.d.ts +13 -0
  28. package/dist/hub/access-hub-api.js +140 -0
  29. package/dist/hub/access-hub-api.js.map +1 -0
  30. package/dist/hub/access-hub-events.d.ts +2 -0
  31. package/dist/hub/access-hub-events.js +229 -0
  32. package/dist/hub/access-hub-events.js.map +1 -0
  33. package/dist/hub/access-hub-mqtt.d.ts +2 -0
  34. package/dist/hub/access-hub-mqtt.js +137 -0
  35. package/dist/hub/access-hub-mqtt.js.map +1 -0
  36. package/dist/hub/access-hub-services.d.ts +4 -0
  37. package/dist/hub/access-hub-services.js +451 -0
  38. package/dist/hub/access-hub-services.js.map +1 -0
  39. package/dist/hub/access-hub-types.d.ts +145 -0
  40. package/dist/hub/access-hub-types.js +35 -0
  41. package/dist/hub/access-hub-types.js.map +1 -0
  42. package/dist/hub/access-hub-utils.d.ts +20 -0
  43. package/dist/hub/access-hub-utils.js +128 -0
  44. package/dist/hub/access-hub-utils.js.map +1 -0
  45. package/dist/hub/access-hub.d.ts +39 -0
  46. package/dist/hub/access-hub.js +185 -0
  47. package/dist/hub/access-hub.js.map +1 -0
  48. package/dist/hub/index.d.ts +4 -0
  49. package/dist/hub/index.js +7 -0
  50. package/dist/hub/index.js.map +1 -0
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.js +11 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/settings.d.ts +16 -0
  55. package/dist/settings.js +49 -0
  56. package/dist/settings.js.map +1 -0
  57. package/docs/FeatureOptions.md +120 -0
  58. package/docs/MQTT.md +116 -0
  59. package/docs/api_reference.pdf +0 -0
  60. package/docs/media/homebridge-unifi-access.png +0 -0
  61. package/docs/media/homebridge-unifi-access.svg +21 -0
  62. package/eslint.config.mjs +99 -0
  63. package/homebridge-ui/public/app.js +104 -0
  64. package/homebridge-ui/public/index.html +267 -0
  65. package/homebridge-ui/public/modules/constants.js +22 -0
  66. package/homebridge-ui/public/modules/controllers.js +202 -0
  67. package/homebridge-ui/public/modules/discovery.js +89 -0
  68. package/homebridge-ui/public/modules/dom-helpers.js +41 -0
  69. package/homebridge-ui/public/modules/feature-options.js +625 -0
  70. package/homebridge-ui/public/modules/state.js +26 -0
  71. package/homebridge-ui/public/styles.css +533 -0
  72. package/homebridge-ui/server.js +374 -0
  73. package/package.json +83 -0
  74. package/scripts/event-schema-monitor.ts +350 -0
@@ -0,0 +1,99 @@
1
+ /* Copyright(C) 2026, Mickael Palma. All rights reserved.
2
+ *
3
+ * eslint.config.mjs: Linting defaults for Homebridge plugins.
4
+ */
5
+ import eslintJs from "@eslint/js";
6
+ import hbPluginUtils from "homebridge-plugin-utils/build/eslint-rules.mjs";
7
+ import ts from "typescript-eslint";
8
+ import tsParser from "@typescript-eslint/parser";
9
+
10
+ export default ts.config(
11
+
12
+ { ignores: ["dist"] },
13
+
14
+ eslintJs.configs.recommended,
15
+
16
+ {
17
+
18
+ files: ["src/**.ts"],
19
+ rules: {
20
+
21
+ ...hbPluginUtils.rules.ts
22
+ }
23
+ },
24
+
25
+ {
26
+
27
+ files: [ "homebridge-ui/public/**/*.js", "homebridge-ui/server.js", "eslint.config.mjs" ],
28
+ rules: {
29
+
30
+ ...hbPluginUtils.rules.js
31
+ }
32
+ },
33
+
34
+ {
35
+
36
+ files: [ "src/**.ts", "homebridge-ui/*.js", "homebridge-ui/public/**/*.js", "eslint.config.mjs" ],
37
+
38
+ languageOptions: {
39
+
40
+ ecmaVersion: "latest",
41
+ parser: tsParser,
42
+ parserOptions: {
43
+
44
+ ecmaVersion: "latest",
45
+
46
+ projectService: {
47
+
48
+ allowDefaultProject: [ "eslint.config.mjs", "homebridge-ui/*.js", "homebridge-ui/public/*.js", "homebridge-ui/public/modules/*.js" ],
49
+ defaultProject: "./tsconfig.json",
50
+ maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 20 // eslint-disable-line camelcase
51
+ }
52
+ },
53
+
54
+ sourceType: "module"
55
+ },
56
+
57
+ linterOptions: {
58
+
59
+ reportUnusedDisableDirectives: "error"
60
+ },
61
+
62
+ plugins: {
63
+
64
+ ...hbPluginUtils.plugins
65
+ },
66
+
67
+ rules: {
68
+
69
+ ...hbPluginUtils.rules.common
70
+ }
71
+ },
72
+
73
+ {
74
+
75
+ files: [ "homebridge-ui/public/*.js", "homebridge-ui/public/modules/*.js" ],
76
+
77
+ languageOptions: {
78
+
79
+ globals: {
80
+
81
+ ...hbPluginUtils.globals.ui
82
+ }
83
+ }
84
+ },
85
+
86
+ {
87
+
88
+ files: ["homebridge-ui/server.js"],
89
+
90
+ languageOptions: {
91
+
92
+ globals: {
93
+
94
+ console: "readonly",
95
+ fetch: "readonly"
96
+ }
97
+ }
98
+ }
99
+ );
@@ -0,0 +1,104 @@
1
+ /* @mp-consulting/homebridge-unifi-access Custom UI. */
2
+ import { $, showScreen } from "./modules/dom-helpers.js";
3
+ import { getControllers, state } from "./modules/state.js";
4
+ import { handleSetupSubmit, openAddController, renderControllers } from "./modules/controllers.js";
5
+ import { PLUGIN_NAME } from "./modules/constants.js";
6
+ import { handleDiscover } from "./modules/discovery.js";
7
+ import { renderOptions } from "./modules/feature-options.js";
8
+
9
+ // Search & toolbar.
10
+ let searchTimeout = null;
11
+
12
+ $("optionsSearch").addEventListener("input", () => {
13
+
14
+
15
+ clearTimeout(searchTimeout);
16
+ searchTimeout = setTimeout(() => renderOptions(), 300);
17
+ });
18
+
19
+ $("clearSearchBtn").addEventListener("click", () => {
20
+
21
+
22
+ $("optionsSearch").value = "";
23
+ renderOptions();
24
+ });
25
+
26
+ $("scopeSelect").addEventListener("change", () => renderOptions());
27
+ $("modifiedOnlyToggle").addEventListener("change", () => renderOptions());
28
+
29
+ // Event listeners.
30
+ $("discoverBtn").addEventListener("click", handleDiscover);
31
+ $("manualEntryBtn").addEventListener("click", () => openAddController());
32
+ $("cancelDiscoveryBtn").addEventListener("click", () => {
33
+
34
+
35
+ showScreen("controllersScreen");
36
+ renderControllers();
37
+ });
38
+ $("addControllerBtn").addEventListener("click", () => {
39
+
40
+
41
+ if(getControllers().length) {
42
+
43
+
44
+ showScreen("discoveryScreen");
45
+ $("cancelDiscoveryBtn").style.display = "inline-block";
46
+ } else {
47
+
48
+
49
+ showScreen("discoveryScreen");
50
+ }
51
+ });
52
+ $("setupForm").addEventListener("submit", handleSetupSubmit);
53
+ $("cancelSetupBtn").addEventListener("click", () => {
54
+
55
+
56
+ if(getControllers().length) {
57
+
58
+
59
+ showScreen("controllersScreen");
60
+ renderControllers();
61
+ } else {
62
+
63
+
64
+ showScreen("discoveryScreen");
65
+ }
66
+ });
67
+ $("backFromOptionsBtn").addEventListener("click", () => {
68
+
69
+
70
+ showScreen("controllersScreen");
71
+ renderControllers();
72
+ });
73
+ $("backFromSupportBtn").addEventListener("click", () => {
74
+
75
+
76
+ showScreen("controllersScreen");
77
+ renderControllers();
78
+ });
79
+ $("supportBtn").addEventListener("click", () => showScreen("supportScreen"));
80
+
81
+ // Initialization.
82
+ state.pluginConfig = await homebridge.getPluginConfig();
83
+
84
+ if(!state.pluginConfig.length) {
85
+
86
+
87
+ state.pluginConfig = [{ name: PLUGIN_NAME }];
88
+ await homebridge.updatePluginConfig(state.pluginConfig);
89
+ }
90
+
91
+ state.pluginConfig[0].name ||= PLUGIN_NAME;
92
+
93
+ // Show the right screen.
94
+ if(getControllers().length) {
95
+
96
+
97
+ showScreen("controllersScreen");
98
+ renderControllers();
99
+ } else {
100
+
101
+
102
+ showScreen("discoveryScreen");
103
+ $("cancelDiscoveryBtn").style.display = "none";
104
+ }
@@ -0,0 +1,267 @@
1
+ <link rel="stylesheet" href="styles.css">
2
+
3
+ <div id="app" class="container">
4
+ <div class="text-center mb-3">
5
+ <img src="https://raw.githubusercontent.com/mp-consulting/homebridge-unifi-access/main/docs/media/homebridge-unifi-access.svg" alt="homebridge-unifi-access logo" style="max-width: 200px;" />
6
+ <hr>
7
+ </div>
8
+
9
+ <!-- Screen: Discovery -->
10
+ <div id="discoveryScreen">
11
+ <h5><i class="fas fa-search"></i> Discover Your Controller</h5>
12
+ <p class="text-muted">Scan your network for UniFi Access controllers, or enter the address manually.</p>
13
+
14
+ <div class="alert alert-info mb-3">
15
+ <i class="fas fa-info-circle"></i> Ensure your UniFi console is powered on and connected to the same network.
16
+ </div>
17
+
18
+ <div class="row g-2 mb-3">
19
+ <div class="col-12">
20
+ <button id="discoverBtn" class="btn btn-secondary">
21
+ <span id="discoverSpinner" class="spinner-border spinner-border-sm" style="display: none;"></span>
22
+ <span id="discoverBtnText"><i class="fas fa-search"></i> Discover Controllers</span>
23
+ </button>
24
+ <button id="manualEntryBtn" class="btn btn-outline-primary">
25
+ <i class="fas fa-keyboard"></i> Manual Entry
26
+ </button>
27
+ <button id="cancelDiscoveryBtn" class="btn btn-primary" style="display: none;">Cancel</button>
28
+ </div>
29
+ </div>
30
+
31
+ <div id="deviceList" style="display: none;">
32
+ <div id="deviceListContainer"></div>
33
+ </div>
34
+ </div>
35
+
36
+ <!-- Screen: Setup Controller (Add/Edit) -->
37
+ <div id="setupScreen">
38
+ <h5><i class="fas fa-shield-alt"></i> <span id="setupTitle">Add UniFi Access Controller</span></h5>
39
+ <p class="text-muted" id="setupSubtitle">Enter your UniFi Access controller details and login credentials.</p>
40
+
41
+ <form id="setupForm" novalidate>
42
+ <div class="mb-3 row">
43
+ <label for="inputAddress" class="col-sm-3 col-form-label"><i class="fas fa-server"></i> Controller</label>
44
+ <div class="col-sm-9">
45
+ <input type="text" class="form-control" id="inputAddress" placeholder="Hostname or IP (e.g. unvr.local)" required>
46
+ <small class="form-text text-muted">The address of your UniFi Access controller.</small>
47
+ </div>
48
+ </div>
49
+ <div class="mb-3 row">
50
+ <label for="inputUsername" class="col-sm-3 col-form-label"><i class="fas fa-user"></i> Username</label>
51
+ <div class="col-sm-9">
52
+ <input type="text" class="form-control" id="inputUsername" autocomplete="username" placeholder="Local user account username" required>
53
+ </div>
54
+ </div>
55
+ <div class="mb-3 row">
56
+ <label for="inputPassword" class="col-sm-3 col-form-label"><i class="fas fa-lock"></i> Password</label>
57
+ <div class="col-sm-9">
58
+ <input type="password" class="form-control" id="inputPassword" autocomplete="current-password" placeholder="Local user account password" required>
59
+ </div>
60
+ </div>
61
+
62
+ <div id="setupError" class="alert alert-danger" style="display: none;">
63
+ <i class="fas fa-exclamation-circle"></i> <span id="setupErrorText"></span>
64
+ </div>
65
+
66
+ <div class="alert alert-info">
67
+ <i class="fas fa-info-circle"></i>
68
+ <strong>Local account required.</strong> Ubiquiti.com/UI.com accounts are not supported. Create one via the <em>Admins & Users</em> tab in your UniFi console.
69
+ </div>
70
+
71
+ <hr>
72
+ <div class="col-12">
73
+ <button id="saveControllerBtn" class="btn btn-success" type="submit">
74
+ <i class="fas fa-save"></i> Save Controller
75
+ </button>
76
+ <button id="cancelSetupBtn" class="btn btn-secondary" type="button">Cancel</button>
77
+ </div>
78
+ </form>
79
+ </div>
80
+
81
+ <!-- Screen: Controllers List (Main) -->
82
+ <div id="controllersScreen">
83
+ <h5><i class="fas fa-network-wired"></i> Configured Controllers</h5>
84
+ <div id="noControllersMessage" class="alert alert-info mb-3">
85
+ <i class="fas fa-info-circle"></i> No controllers configured yet. Add one to get started.
86
+ </div>
87
+ <ul id="controllersList" class="list-group mb-3"></ul>
88
+ <div class="d-flex gap-2">
89
+ <button id="addControllerBtn" class="btn btn-primary">
90
+ <i class="fas fa-plus"></i> Add Controller
91
+ </button>
92
+ <button id="supportBtn" class="btn btn-outline-secondary">
93
+ <i class="fas fa-life-ring"></i> Support
94
+ </button>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- Screen: Feature Options (split layout) -->
99
+ <div id="featureOptionsScreen">
100
+ <div class="d-flex justify-content-between align-items-center mb-3">
101
+ <h5 class="mb-0"><i class="fas fa-sliders-h"></i> Feature Options</h5>
102
+ <button id="backFromOptionsBtn" class="btn btn-secondary btn-sm">
103
+ <i class="fas fa-arrow-left"></i> Back
104
+ </button>
105
+ </div>
106
+
107
+ <div class="row">
108
+ <!-- Left sidebar: scope -->
109
+ <div class="col-sm-4">
110
+ <div class="scope-sidebar">
111
+ <!-- Scope selector -->
112
+ <div class="card mb-3">
113
+ <div class="card-body py-2">
114
+ <label class="form-label mb-1 text-muted"><small><i class="fas fa-layer-group"></i> Scope</small></label>
115
+ <select class="form-select form-select-sm" id="scopeSelect"></select>
116
+ </div>
117
+ </div>
118
+
119
+ <!-- Visual cascade -->
120
+ <div class="card mb-3">
121
+ <div class="card-body py-3" id="scopeCascade">
122
+ <div class="scope-cascade">
123
+ <div class="scope-level" data-scope="global">
124
+ <div class="scope-dot"><i class="fas fa-globe-americas"></i></div>
125
+ <div class="scope-text">
126
+ <div class="scope-label">Global</div>
127
+ <div class="scope-hint">All devices</div>
128
+ </div>
129
+ </div>
130
+ <div class="scope-connector"><div class="scope-connector-line"></div></div>
131
+ <div class="scope-level" data-scope="controller">
132
+ <div class="scope-dot"><i class="fas fa-server"></i></div>
133
+ <div class="scope-text">
134
+ <div class="scope-label">Controller</div>
135
+ <div class="scope-hint">Overrides global</div>
136
+ </div>
137
+ </div>
138
+ <div class="scope-connector"><div class="scope-connector-line"></div></div>
139
+ <div class="scope-level" data-scope="device">
140
+ <div class="scope-dot"><i class="fas fa-microchip"></i></div>
141
+ <div class="scope-text">
142
+ <div class="scope-label">Device</div>
143
+ <div class="scope-hint">Final value</div>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </div>
149
+
150
+ <!-- Device info panel -->
151
+ <div id="deviceInfoPanel" class="card mb-3" style="display: none;">
152
+ <div class="card-body py-2">
153
+ <div class="mb-2"><small class="text-muted d-block">Model</small><strong id="infoModel"></strong></div>
154
+ <div class="mb-2"><small class="text-muted d-block">MAC</small><code id="infoMac" style="font-size:0.75rem"></code></div>
155
+ <div class="mb-2"><small class="text-muted d-block">IP</small><code id="infoIp"></code></div>
156
+ <div><small class="text-muted d-block">Status</small><span id="infoStatus"></span></div>
157
+ </div>
158
+ </div>
159
+
160
+ <!-- Legend -->
161
+ <div class="card mb-3">
162
+ <div class="card-body py-2">
163
+ <small class="text-muted d-block mb-2"><i class="fas fa-palette"></i> Legend</small>
164
+ <div class="d-flex flex-column gap-1" style="font-size: 0.75rem;">
165
+ <div class="d-flex align-items-center gap-2">
166
+ <span class="scope-legend-bar" style="background: #ffc107;"></span> Set at global
167
+ </div>
168
+ <div class="d-flex align-items-center gap-2">
169
+ <span class="scope-legend-bar" style="background: #198754;"></span> Set at controller
170
+ </div>
171
+ <div class="d-flex align-items-center gap-2">
172
+ <span class="scope-legend-bar" style="background: #0dcaf0;"></span> Set at device
173
+ </div>
174
+ </div>
175
+ </div>
176
+ </div>
177
+
178
+ </div>
179
+ </div>
180
+
181
+ <!-- Right main: options -->
182
+ <div class="col-sm-8">
183
+ <!-- Search & filter -->
184
+ <div class="d-flex align-items-center gap-2 mb-3">
185
+ <div class="input-group flex-grow-1">
186
+ <span class="input-group-text"><i class="fas fa-search"></i></span>
187
+ <input type="text" class="form-control" placeholder="Search options..." id="optionsSearch">
188
+ <button class="btn btn-outline-secondary" type="button" id="clearSearchBtn"><i class="fas fa-times"></i></button>
189
+ </div>
190
+ <div class="form-check form-switch mb-0 flex-shrink-0" style="min-width: 110px;">
191
+ <input class="form-check-input" type="checkbox" id="modifiedOnlyToggle">
192
+ <label class="form-check-label text-muted text-nowrap" for="modifiedOnlyToggle"><small>Modified <span id="modifiedSummary"></span></small></label>
193
+ </div>
194
+ </div>
195
+
196
+ <!-- Loading -->
197
+ <div id="optionsLoading" class="text-center my-4">
198
+ <div class="spinner-border text-primary" role="status">
199
+ <span class="visually-hidden">Loading...</span>
200
+ </div>
201
+ <p class="mt-2 text-muted">Loading options...</p>
202
+ </div>
203
+
204
+ <!-- Options container -->
205
+ <div id="optionsContainer" class="mb-3"></div>
206
+
207
+ <!-- Unsaved changes notice -->
208
+ <div class="alert alert-warning mb-3" id="unsavedChanges" style="display: none;">
209
+ <i class="fas fa-exclamation-triangle"></i> You have unsaved changes. Click <strong>Save</strong> in Homebridge to apply.
210
+ </div>
211
+ </div>
212
+ </div>
213
+ </div>
214
+
215
+ <!-- Screen: Support -->
216
+ <div id="supportScreen">
217
+ <div class="d-flex justify-content-between align-items-center mb-3">
218
+ <h5 class="mb-0"><i class="fas fa-life-ring"></i> Support</h5>
219
+ <button id="backFromSupportBtn" class="btn btn-secondary btn-sm">
220
+ <i class="fas fa-arrow-left"></i> Back
221
+ </button>
222
+ </div>
223
+
224
+ <div class="card mb-3">
225
+ <div class="card-header bg-transparent"><i class="fas fa-heart"></i> About This Plugin</div>
226
+ <div class="card-body">
227
+ <p class="card-text mb-0">If you find this plugin useful, please consider <a target="_blank" href="https://github.com/mp-consulting/homebridge-unifi-access">starring the project on GitHub</a>.</p>
228
+ </div>
229
+ </div>
230
+
231
+ <div class="card mb-3">
232
+ <div class="card-header bg-transparent"><i class="fas fa-book"></i> Getting Started</div>
233
+ <div class="list-group list-group-flush">
234
+ <a href="https://github.com/mp-consulting/homebridge-unifi-access/blob/main/README.md#installation" target="_blank" class="list-group-item list-group-item-action">
235
+ <i class="fas fa-download text-primary"></i> <strong>Installation</strong>
236
+ <small class="text-muted d-block">Installing this plugin, including system requirements.</small>
237
+ </a>
238
+ <a href="https://github.com/mp-consulting/homebridge-unifi-access/blob/main/docs/FeatureOptions.md" target="_blank" class="list-group-item list-group-item-action">
239
+ <i class="fas fa-sliders-h text-primary"></i> <strong>Feature Options</strong>
240
+ <small class="text-muted d-block">Granular options to configure at a controller or device level.</small>
241
+ </a>
242
+ <a href="https://github.com/mp-consulting/homebridge-unifi-access/blob/main/docs/MQTT.md" target="_blank" class="list-group-item list-group-item-action">
243
+ <i class="fas fa-broadcast-tower text-primary"></i> <strong>MQTT</strong>
244
+ <small class="text-muted d-block">How to configure MQTT support.</small>
245
+ </a>
246
+ <a href="https://github.com/mp-consulting/homebridge-unifi-access/blob/main/CHANGELOG.md" target="_blank" class="list-group-item list-group-item-action">
247
+ <i class="fas fa-history text-primary"></i> <strong>Changelog</strong>
248
+ <small class="text-muted d-block">Changes and release history.</small>
249
+ </a>
250
+ </div>
251
+ </div>
252
+
253
+ <div class="card mb-3">
254
+ <div class="card-header bg-transparent"><i class="fas fa-life-ring"></i> Get Help</div>
255
+ <div class="list-group list-group-flush">
256
+ <a href="https://discord.gg/QXqfHEW" target="_blank" class="list-group-item list-group-item-action">
257
+ <i class="fab fa-discord text-primary"></i> <strong>Discord Support Channel</strong>
258
+ </a>
259
+ <a href="https://github.com/mp-consulting/homebridge-unifi-access/issues/new/choose" target="_blank" class="list-group-item list-group-item-action">
260
+ <i class="fab fa-github text-primary"></i> <strong>Create a Developer Support Request</strong>
261
+ </a>
262
+ </div>
263
+ </div>
264
+ </div>
265
+ </div>
266
+
267
+ <script type="module" src="app.js"></script>
@@ -0,0 +1,22 @@
1
+ export const SCREENS = [ "discoveryScreen", "setupScreen", "controllersScreen", "featureOptionsScreen", "supportScreen" ];
2
+ export const PLUGIN_NAME = "UniFi Access";
3
+
4
+ export const CATEGORY_ICONS = {
5
+
6
+
7
+ AccessMethod: "fa-fingerprint",
8
+ Controller: "fa-server",
9
+ Device: "fa-microchip",
10
+ Hub: "fa-door-open",
11
+ Log: "fa-file-alt"
12
+ };
13
+
14
+ export const CATEGORY_COLORS = {
15
+
16
+
17
+ AccessMethod: "#fd7e14",
18
+ Controller: "#6f42c1",
19
+ Device: "#0d6efd",
20
+ Hub: "#20c997",
21
+ Log: "#6c757d"
22
+ };