homebridge-tuya-without-developer-account 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 (97) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE +20 -0
  3. package/PUBLISHING.md +80 -0
  4. package/README.md +233 -0
  5. package/SUPPORTED_DEVICES.md +206 -0
  6. package/config.schema.json +131 -0
  7. package/dist/cloud/api/TuyaHACloudAPI.js +286 -0
  8. package/dist/cloud/api/TuyaHASharingMQ.js +114 -0
  9. package/dist/cloud/device/TuyaDevice.js +50 -0
  10. package/dist/cloud/device/TuyaHADeviceManager.js +355 -0
  11. package/dist/index.js +7 -0
  12. package/dist/platform.js +397 -0
  13. package/dist/settings.js +18 -0
  14. package/dist/shared/AccessoryFactory.js +276 -0
  15. package/dist/shared/accessories/AccessoryFactory.js +305 -0
  16. package/dist/shared/accessories/AirConditionerAccessory.js +307 -0
  17. package/dist/shared/accessories/AirPurifierAccessory.js +90 -0
  18. package/dist/shared/accessories/AirQualitySensorAccessory.js +30 -0
  19. package/dist/shared/accessories/BaseAccessory.js +406 -0
  20. package/dist/shared/accessories/BlindsAccessory.js +199 -0
  21. package/dist/shared/accessories/CameraAccessory.js +121 -0
  22. package/dist/shared/accessories/CarbonDioxideSensorAccessory.js +52 -0
  23. package/dist/shared/accessories/CarbonMonoxideSensorAccessory.js +52 -0
  24. package/dist/shared/accessories/ContactSensorAccessory.js +30 -0
  25. package/dist/shared/accessories/DehumidifierAccessory.js +68 -0
  26. package/dist/shared/accessories/DiffuserAccessory.js +55 -0
  27. package/dist/shared/accessories/DimmerAccessory.js +94 -0
  28. package/dist/shared/accessories/DoorbellAccessory.js +91 -0
  29. package/dist/shared/accessories/ExtractionHoodAccessory.js +120 -0
  30. package/dist/shared/accessories/FanAccessory.js +129 -0
  31. package/dist/shared/accessories/GarageDoorAccessory.js +69 -0
  32. package/dist/shared/accessories/HeaterAccessory.js +102 -0
  33. package/dist/shared/accessories/HeaterAccessory_old.js +96 -0
  34. package/dist/shared/accessories/HumanPresenceSensorAccessory.js +20 -0
  35. package/dist/shared/accessories/HumidifierAccessory.js +137 -0
  36. package/dist/shared/accessories/IRAirConditionerAccessory.js +278 -0
  37. package/dist/shared/accessories/IRControlHubAccessory.js +49 -0
  38. package/dist/shared/accessories/IRControlHubSubAccessory.js +52 -0
  39. package/dist/shared/accessories/IRGenericAccessory.js +49 -0
  40. package/dist/shared/accessories/LeakSensorAccessory.js +36 -0
  41. package/dist/shared/accessories/LightAccessory.js +36 -0
  42. package/dist/shared/accessories/LightSensorAccessory.js +32 -0
  43. package/dist/shared/accessories/LocationWeatherAccessory.js +72 -0
  44. package/dist/shared/accessories/LockAccessory.js +56 -0
  45. package/dist/shared/accessories/MotionSensorAccessory.js +20 -0
  46. package/dist/shared/accessories/OutletAccessory.js +23 -0
  47. package/dist/shared/accessories/PetFeederAccessory.js +139 -0
  48. package/dist/shared/accessories/SceneAccessory.js +32 -0
  49. package/dist/shared/accessories/SceneSwitchAccessory.js +44 -0
  50. package/dist/shared/accessories/SecuritySystemAccessory.js +30 -0
  51. package/dist/shared/accessories/SmokeSensorAccessory.js +35 -0
  52. package/dist/shared/accessories/SwitchAccessory.js +148 -0
  53. package/dist/shared/accessories/TemperatureHumiditySensorAccessory.js +24 -0
  54. package/dist/shared/accessories/ThermostatAccessory.js +192 -0
  55. package/dist/shared/accessories/TowerRackAccessory.js +157 -0
  56. package/dist/shared/accessories/ValveAccessory.js +45 -0
  57. package/dist/shared/accessories/VibrationSensorAccessory.js +46 -0
  58. package/dist/shared/accessories/WeatherStationAccessory.js +58 -0
  59. package/dist/shared/accessories/WetBulbGlobeTemperatureAccessory.js +23 -0
  60. package/dist/shared/accessories/WhiteNoiseLightAccessory.js +59 -0
  61. package/dist/shared/accessories/WindowAccessory.js +14 -0
  62. package/dist/shared/accessories/WindowCoveringAccessory.js +156 -0
  63. package/dist/shared/accessories/WirelessSwitchAccessory.js +42 -0
  64. package/dist/shared/accessories/characteristic/Active.js +22 -0
  65. package/dist/shared/accessories/characteristic/AirQuality.js +74 -0
  66. package/dist/shared/accessories/characteristic/CurrentRelativeHumidity.js +23 -0
  67. package/dist/shared/accessories/characteristic/CurrentTemperature.js +23 -0
  68. package/dist/shared/accessories/characteristic/CurrentWeather.js +49 -0
  69. package/dist/shared/accessories/characteristic/CurrentWeatherByOpenMeteo.js +49 -0
  70. package/dist/shared/accessories/characteristic/CurrentWetBulbGlobeTemperature.js +48 -0
  71. package/dist/shared/accessories/characteristic/EnergyUsage.js +98 -0
  72. package/dist/shared/accessories/characteristic/Light.js +268 -0
  73. package/dist/shared/accessories/characteristic/LightSensor.js +23 -0
  74. package/dist/shared/accessories/characteristic/LockPhysicalControls.js +21 -0
  75. package/dist/shared/accessories/characteristic/MotionDetected.js +22 -0
  76. package/dist/shared/accessories/characteristic/Name.js +15 -0
  77. package/dist/shared/accessories/characteristic/OccupancyDetected.js +19 -0
  78. package/dist/shared/accessories/characteristic/On.js +25 -0
  79. package/dist/shared/accessories/characteristic/OutletInUse.js +14 -0
  80. package/dist/shared/accessories/characteristic/ProgrammableSwitchEvent.js +89 -0
  81. package/dist/shared/accessories/characteristic/RelativeHumidityDehumidifierThreshold.js +28 -0
  82. package/dist/shared/accessories/characteristic/RotationSpeed.js +78 -0
  83. package/dist/shared/accessories/characteristic/SecuritySystemState.js +74 -0
  84. package/dist/shared/accessories/characteristic/SwingMode.js +21 -0
  85. package/dist/shared/accessories/characteristic/TargetTemperature.js +29 -0
  86. package/dist/shared/accessories/characteristic/TemperatureDisplayUnits.js +25 -0
  87. package/dist/shared/util/ConfigHash.js +79 -0
  88. package/dist/shared/util/FfmpegStreamingProcess.js +126 -0
  89. package/dist/shared/util/InfraredTool.js +392 -0
  90. package/dist/shared/util/Logger.js +42 -0
  91. package/dist/shared/util/TuyaRecordingDelegate.js +22 -0
  92. package/dist/shared/util/TuyaStreamDelegate.js +329 -0
  93. package/dist/shared/util/color.js +23 -0
  94. package/dist/shared/util/util.js +135 -0
  95. package/homebridge-ui/public/index.html +329 -0
  96. package/homebridge-ui/server.js +224 -0
  97. package/package.json +61 -0
@@ -0,0 +1,397 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TuyaPlatform = void 0;
4
+
5
+ const path = require("path");
6
+ const fs = require("fs");
7
+ const TuyaHACloudAPI = require("./cloud/api/TuyaHACloudAPI").default;
8
+ const TuyaHADeviceManager = require("./cloud/device/TuyaHADeviceManager").default;
9
+ const AccessoryFactory = require("./shared/accessories/AccessoryFactory").default;
10
+ const { sanitizeName } = require("./shared/util/util");
11
+ const { ConfigHash } = require("./shared/util/ConfigHash");
12
+ const { PLUGIN_NAME, PLATFORM_NAME } = require("./settings");
13
+
14
+ function safeUserCode(userCode) {
15
+ return String(userCode || "").replace(/[^a-zA-Z0-9_.-]/g, "_");
16
+ }
17
+
18
+ class TuyaPlatform {
19
+ constructor(log, config, api) {
20
+ this.log = log;
21
+ this.config = config || {};
22
+ this.api = api;
23
+ this.Service = this.api.hap.Service;
24
+ this.Characteristic = this.api.hap.Characteristic;
25
+ this.options = this.config.options || {};
26
+ this.cachedAccessories = [];
27
+ this.accessoryHandlers = [];
28
+
29
+ if (!this.validate()) {
30
+ return;
31
+ }
32
+
33
+ this.log.debug("Finished initializing Tuya QR-only platform");
34
+ this.api.on("didFinishLaunching", async () => {
35
+ this.log.debug("Executed didFinishLaunching callback");
36
+ await this.initDevices();
37
+ });
38
+ }
39
+
40
+ validate() {
41
+ if (!this.config.options || typeof this.config.options !== "object") {
42
+ this.config.options = {};
43
+ this.options = this.config.options;
44
+ }
45
+
46
+ // This fork intentionally supports only Home Assistant-style Tuya QR Cloud Authentication.
47
+ // Old Tuya IoT OpenAPI credentials, local LAN mode, username/password login, and hybrid mode are not accepted.
48
+ this.config.mode = "cloud";
49
+ this.options.projectType = "3";
50
+
51
+ if (!this.options.userCode || String(this.options.userCode).trim().length === 0) {
52
+ this.log.error("[Tuya QR] Missing Tuya User Code. Open Homebridge UI → Plugins → Tuya without developer account for Homebridge → Settings, generate/scan the QR code, then save.");
53
+ return false;
54
+ }
55
+
56
+ if (this.config.local || this.options.accessId || this.options.accessKey || this.options.username || this.options.password || this.options.countryCode || this.options.endpoint) {
57
+ this.log.warn("[Tuya QR] Ignoring legacy Tuya IoT / local configuration. This plugin only uses QR Cloud Authentication.");
58
+ }
59
+
60
+ if (!this.validateDeviceOverrides() || !this.validateSchema()) {
61
+ return false;
62
+ }
63
+
64
+ return true;
65
+ }
66
+
67
+ validateDeviceOverrides() {
68
+ if (!this.options.deviceOverrides) {
69
+ return true;
70
+ }
71
+ const idMap = new Map();
72
+ for (const item of this.options.deviceOverrides) {
73
+ if (!item || !item.id) {
74
+ this.log.error('[Tuya QR] Each device override must include an "id".');
75
+ return false;
76
+ }
77
+ if (idMap.has(item.id)) {
78
+ idMap.get(item.id).push(item);
79
+ } else {
80
+ idMap.set(item.id, [item]);
81
+ }
82
+ }
83
+ for (const items of idMap.values()) {
84
+ if (items.length > 1) {
85
+ this.log.error('[Tuya QR] "deviceOverrides" conflict, "id" must be unique: %o.', items);
86
+ return false;
87
+ }
88
+ }
89
+ return true;
90
+ }
91
+
92
+ validateSchema() {
93
+ if (!this.options.deviceOverrides) {
94
+ return true;
95
+ }
96
+ for (const deviceOverride of this.options.deviceOverrides) {
97
+ if (!deviceOverride.schema) {
98
+ continue;
99
+ }
100
+ const idMap = new Map();
101
+ for (const item of deviceOverride.schema) {
102
+ if (idMap.has(item.code)) {
103
+ idMap.get(item.code).push(item);
104
+ } else {
105
+ idMap.set(item.code, [item]);
106
+ }
107
+ }
108
+ for (const items of idMap.values()) {
109
+ if (items.length > 1) {
110
+ this.log.error('[Tuya QR] "schema" conflict, "code" must be unique: %o.', items);
111
+ return false;
112
+ }
113
+ }
114
+ }
115
+ return true;
116
+ }
117
+
118
+ configureAccessory(accessory) {
119
+ this.log.info("Loading accessory from cache:", accessory.displayName);
120
+ AccessoryFactory.configAccessory(this, accessory);
121
+ this.cachedAccessories.push(accessory);
122
+ }
123
+
124
+ getAuthFile(userCode) {
125
+ return path.join(this.api.user.storagePath(), `tuya-ha-qr-auth.${safeUserCode(userCode)}.json`);
126
+ }
127
+
128
+ async readAuthData(userCode) {
129
+ const file = this.getAuthFile(userCode);
130
+ try {
131
+ const raw = await fs.promises.readFile(file, "utf8");
132
+ const data = JSON.parse(raw);
133
+ if (!data.userCode || !data.endpoint || !data.terminalId || !data.tokenInfo?.access_token || !data.tokenInfo?.refresh_token) {
134
+ this.log.warn("[Tuya QR] Existing auth file is incomplete. Clear authentication in the plugin settings and scan again.");
135
+ return undefined;
136
+ }
137
+ return data;
138
+ } catch {
139
+ return undefined;
140
+ }
141
+ }
142
+
143
+ async writeAuthData(userCode, data) {
144
+ const file = this.getAuthFile(userCode);
145
+ await fs.promises.mkdir(path.dirname(file), { recursive: true });
146
+ await fs.promises.writeFile(file, JSON.stringify(data, null, 2), { mode: 0o600 });
147
+ this.log.info("[Tuya QR] Auth token saved at %s", file);
148
+ }
149
+
150
+ async initDevices() {
151
+ const devices = await this.initQrCloudProject();
152
+ if (!devices || !this.deviceManager) {
153
+ return;
154
+ }
155
+
156
+ this.configHash = new ConfigHash(this.api.user.storagePath(), "tuya-cloud-configs");
157
+
158
+ for (const device of devices) {
159
+ const deviceConfig = this.getDeviceConfig(device);
160
+ if (deviceConfig?.category) {
161
+ this.log.warn("Override %o category from %o to %o", device.name, device.category, deviceConfig.category);
162
+ device.category = deviceConfig.category;
163
+ }
164
+ if (deviceConfig?.unbridged) {
165
+ this.log.warn("Unbridge %o category %o", device.name, device.category);
166
+ device.unbridged = deviceConfig.unbridged;
167
+ }
168
+ const configToHash = {
169
+ deviceId: device.id,
170
+ customCategory: deviceConfig?.category,
171
+ unbridged: deviceConfig?.unbridged ?? false,
172
+ schemaOverrides: deviceConfig?.schema ? JSON.stringify(deviceConfig.schema) : undefined,
173
+ adaptiveLighting: deviceConfig?.adaptiveLighting ?? false,
174
+ };
175
+ const { changed: configChanged } = this.configHash.hasConfigChanged(device.id, configToHash);
176
+ device.configChanged = configChanged;
177
+ if (configChanged) {
178
+ this.log.info(`[Tuya QR] Device config changed for "${device.name}" (${device.id}), will rebuild services`);
179
+ }
180
+ }
181
+
182
+ await this.deviceManager.updateInfraredRemotes(devices);
183
+ this.log.info(`[Tuya QR] Got ${devices.length} device(s) and scene(s).`);
184
+
185
+ const uid = this.deviceManager.api.tokenInfo?.uid || "unknown";
186
+ const file = path.join(this.api.user.persistPath(), `TuyaDeviceList.${uid}.json`);
187
+ this.log.info("Device list saved at %s", file);
188
+ if (!fs.existsSync(this.api.user.persistPath())) {
189
+ await fs.promises.mkdir(this.api.user.persistPath(), { recursive: true });
190
+ }
191
+ await fs.promises.writeFile(file, JSON.stringify(devices, null, 2));
192
+
193
+ for (const device of devices) {
194
+ this.addAccessory(device);
195
+ }
196
+
197
+ const Events = TuyaHADeviceManager.Events;
198
+ this.deviceManager.on(Events.DEVICE_ADD, (device) => this.addAccessory(device));
199
+ this.deviceManager.on(Events.DEVICE_INFO_UPDATE, this.updateAccessoryInfo.bind(this));
200
+ this.deviceManager.on(Events.DEVICE_STATUS_UPDATE, this.updateAccessoryStatus.bind(this));
201
+ this.deviceManager.on(Events.DEVICE_DELETE, this.removeAccessory.bind(this));
202
+
203
+ for (const cachedAccessory of this.cachedAccessories) {
204
+ this.log.warn("Removing unused accessory from cache:", cachedAccessory.displayName);
205
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [cachedAccessory]);
206
+ }
207
+ this.cachedAccessories = [];
208
+ }
209
+
210
+ async initQrCloudProject() {
211
+ const userCode = String(this.options.userCode || "").trim();
212
+ const debugMode = !!(this.options.debug && ((this.options.debugLevel ?? "").length > 0 ? this.options.debugLevel?.includes("api") : true));
213
+
214
+ const authData = await this.readAuthData(userCode);
215
+ if (!authData) {
216
+ this.log.error("[Tuya QR] No saved QR authentication found for this User Code.");
217
+ this.log.error("[Tuya QR] Open Homebridge UI → Plugins → Tuya without developer account for Homebridge → Settings → Generate QR Code, scan it, save, then restart Homebridge.");
218
+ this.log.error("[Tuya QR] Expected auth file: %s", this.getAuthFile(userCode));
219
+ return undefined;
220
+ }
221
+
222
+ const api = new TuyaHACloudAPI(userCode, authData.terminalId, authData.endpoint, authData.tokenInfo, this.log, debugMode);
223
+ const deviceManager = new TuyaHADeviceManager(api, debugMode);
224
+
225
+ this.log.info("[Tuya QR] Fetching home list.");
226
+ const res = await deviceManager.getHomeList();
227
+ if (res.success === false) {
228
+ this.log.error(`[Tuya QR] Fetching home list failed. code=${res.code}, msg=${res.msg}`);
229
+ this.log.error("[Tuya QR] If the token is expired or invalid, clear authentication in the plugin settings and scan again.");
230
+ return undefined;
231
+ }
232
+
233
+ const homeIDList = [];
234
+ for (const { home_id, name } of (res.result || [])) {
235
+ const homeID = String(home_id);
236
+ this.log.info(`[Tuya QR] Got home_id=${homeID}, name=${name}`);
237
+ if (this.options.homeWhitelist && Array.isArray(this.options.homeWhitelist) && this.options.homeWhitelist.length > 0) {
238
+ const whitelist = this.options.homeWhitelist.map(item => String(item));
239
+ if (whitelist.includes(homeID)) {
240
+ this.log.info(`[Tuya QR] Found home_id=${homeID} in whitelist; including devices from this home.`);
241
+ homeIDList.push(homeID);
242
+ } else {
243
+ this.log.info(`[Tuya QR] Did not find home_id=${homeID} in whitelist; excluding devices from this home.`);
244
+ }
245
+ } else {
246
+ homeIDList.push(homeID);
247
+ }
248
+ }
249
+
250
+ if (homeIDList.length === 0) {
251
+ this.log.warn("[Tuya QR] Home list is empty.");
252
+ }
253
+
254
+ this.log.info("[Tuya QR] Fetching device list.");
255
+ deviceManager.ownerIDs = homeIDList.map(homeID => homeID.toString());
256
+ const devices = await deviceManager.updateDevices(homeIDList);
257
+
258
+ this.log.info("[Tuya QR] Fetching scene list.");
259
+ for (const homeID of homeIDList) {
260
+ const scenes = await deviceManager.getSceneList(homeID);
261
+ for (const scene of scenes) {
262
+ this.log.info(`[Tuya QR] Got scene_id=${scene.id}, name=${scene.name}`);
263
+ }
264
+ devices.push(...scenes);
265
+ }
266
+
267
+ await this.writeAuthData(userCode, {
268
+ ...authData,
269
+ endpoint: api.endpoint,
270
+ tokenInfo: api.exportTokenInfo(),
271
+ savedAt: Date.now(),
272
+ });
273
+
274
+ this.deviceManager = deviceManager;
275
+ this.log.info("[Tuya QR] Starting MQTT connection.");
276
+ await deviceManager.startMQ(homeIDList);
277
+
278
+ return devices;
279
+ }
280
+
281
+ getDeviceConfig(device) {
282
+ if (!this.options.deviceOverrides) {
283
+ return undefined;
284
+ }
285
+ const matches = this.options.deviceOverrides.filter(config => {
286
+ const idMatch = config.id === device.id || config.id === device.uuid || config.id === device.product_id || config.id === "global";
287
+ return idMatch;
288
+ });
289
+ return matches.find(config => config.id === device.id || config.id === device.uuid) ||
290
+ matches.find(config => config.id === device.product_id) ||
291
+ matches.find(config => config.id === "global");
292
+ }
293
+
294
+ getDeviceSchemaConfig(device, code) {
295
+ const deviceConfig = this.getDeviceConfig(device);
296
+ if (!deviceConfig || !deviceConfig.schema) {
297
+ return undefined;
298
+ }
299
+ deviceConfig.schema.forEach(item => {
300
+ if (item.oldCode) {
301
+ item.newCode = item.code;
302
+ item.code = item.oldCode;
303
+ item.oldCode = undefined;
304
+ }
305
+ });
306
+ const schemaConfig = deviceConfig.schema.find(item => {
307
+ if (!code) {
308
+ return false;
309
+ }
310
+ const target = code.toString().toLowerCase();
311
+ const legacyCode = item.code?.toString().toLowerCase();
312
+ const migratedCode = item.newCode?.toString().toLowerCase();
313
+ return legacyCode === target || migratedCode === target;
314
+ });
315
+ return schemaConfig;
316
+ }
317
+
318
+ addAccessory(device) {
319
+ const deviceConfig = this.getDeviceConfig(device);
320
+ if (deviceConfig?.category) {
321
+ this.log.warn("Override %o category from %o to %o", device.name, device.category, deviceConfig.category);
322
+ device.category = deviceConfig.category;
323
+ }
324
+ if (deviceConfig?.unbridged) {
325
+ this.log.warn("Unbridge %o category %o", device.name, device.category);
326
+ device.unbridged = deviceConfig.unbridged;
327
+ }
328
+ if (device.category === "hidden") {
329
+ this.log.info("Hide Accessory:", device.name);
330
+ return;
331
+ }
332
+ const uuid = this.api.hap.uuid.generate(device.id);
333
+ const existingAccessory = this.cachedAccessories.find(accessory => accessory.UUID === uuid);
334
+ if (existingAccessory && !device.unbridged) {
335
+ this.log.info("Restoring existing accessory from cache:", existingAccessory.displayName);
336
+ if (!existingAccessory.context || !existingAccessory.context.deviceID) {
337
+ this.log.info("Update accessory context:", existingAccessory.displayName);
338
+ existingAccessory.context.deviceID = device.id;
339
+ this.api.updatePlatformAccessories([existingAccessory]);
340
+ }
341
+ const handler = AccessoryFactory.createAccessory(this, existingAccessory, device);
342
+ this.accessoryHandlers.push(handler);
343
+ const index = this.cachedAccessories.indexOf(existingAccessory);
344
+ if (index >= 0) {
345
+ this.cachedAccessories.splice(index, 1);
346
+ }
347
+ } else {
348
+ this.log.info("Adding new accessory:", device.name);
349
+ const safeName = sanitizeName(device.name) ?? (device.id || "Tuya Device");
350
+ const accessory = new this.api.platformAccessory(safeName, uuid);
351
+ accessory.context.deviceID = device.id;
352
+ const handler = AccessoryFactory.createAccessory(this, accessory, device);
353
+ this.accessoryHandlers.push(handler);
354
+ if (device.unbridged) {
355
+ this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
356
+ } else {
357
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
358
+ }
359
+ AccessoryFactory.configAccessory(this, accessory);
360
+ }
361
+ }
362
+
363
+ updateAccessoryInfo(device, info) {
364
+ const handler = this.getAccessoryHandler(device.id);
365
+ if (!handler) {
366
+ return;
367
+ }
368
+ handler.onDeviceInfoUpdate(info);
369
+ }
370
+
371
+ updateAccessoryStatus(device, status) {
372
+ const handler = this.getAccessoryHandler(device.id);
373
+ if (!handler) {
374
+ return;
375
+ }
376
+ handler.onDeviceStatusUpdate(status);
377
+ }
378
+
379
+ removeAccessory(deviceID) {
380
+ const handler = this.getAccessoryHandler(deviceID);
381
+ if (!handler) {
382
+ return;
383
+ }
384
+ const index = this.accessoryHandlers.indexOf(handler);
385
+ if (index >= 0) {
386
+ this.accessoryHandlers.splice(index, 1);
387
+ }
388
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [handler.accessory]);
389
+ this.log.info("Removing existing accessory from cache:", handler.accessory.displayName);
390
+ }
391
+
392
+ getAccessoryHandler(deviceID) {
393
+ return this.accessoryHandlers.find(handler => handler.device?.id === deviceID);
394
+ }
395
+ }
396
+
397
+ exports.TuyaPlatform = TuyaPlatform;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLUGIN_NAME = exports.PLATFORM_NAME = void 0;
4
+ // eslint-disable-next-line
5
+ // @ts-ignore
6
+ const config_schema_json_1 = require("../config.schema.json");
7
+ // eslint-disable-next-line
8
+ // @ts-ignore
9
+ const package_json_1 = require("../package.json");
10
+ /**
11
+ * This is the name of the platform that users will use to register the plugin in the Homebridge config.json
12
+ */
13
+ exports.PLATFORM_NAME = config_schema_json_1.pluginAlias;
14
+ /**
15
+ * This must match the name of your plugin as defined the package.json
16
+ */
17
+ exports.PLUGIN_NAME = package_json_1.name;
18
+ //# sourceMappingURL=settings.js.map