homebridge-kasa-python 2.7.2-beta.2 → 2.7.2-beta.3

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 CHANGED
@@ -153,6 +153,7 @@ Some newer Kasa devices require authentication. These are marked with [*] in the
153
153
  - **KS225**
154
154
  - Hardware: 1.0 (US) / Firmware: 1.0.2[*]
155
155
  - Hardware: 1.0 (US) / Firmware: 1.1.0[*]
156
+ - Hardware: 1.0 (US) / Firmware: 1.1.1[*]
156
157
  - **KS230**
157
158
  - Hardware: 1.0 (US) / Firmware: 1.0.14
158
159
  - Hardware: 2.0 (US) / Firmware: 1.0.11
@@ -183,6 +184,8 @@ Some newer Kasa devices require authentication. These are marked with [*] in the
183
184
  - **KL60**
184
185
  - Hardware: 1.0 (UN) / Firmware: 1.1.4
185
186
  - Hardware: 1.0 (US) / Firmware: 1.1.13
187
+ - **LB100**
188
+ - Hardware: 1.0 (US) / Firmware: 1.8.11
186
189
  - **LB110**
187
190
  - Hardware: 1.0 (US) / Firmware: 1.8.11
188
191
 
@@ -226,6 +229,7 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
226
229
  - Hardware: 1.0.0 (US) / Firmware: 1.3.7
227
230
  - Hardware: 1.0.0 (US) / Firmware: 1.4.0
228
231
  - **P110**
232
+ - Hardware: 1.0 (AU) / Firmware: 1.3.1
229
233
  - Hardware: 1.0 (EU) / Firmware: 1.0.7
230
234
  - Hardware: 1.0 (EU) / Firmware: 1.2.3
231
235
  - Hardware: 1.0 (UK) / Firmware: 1.3.0
@@ -278,10 +282,13 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
278
282
  - **L510E**
279
283
  - Hardware: 3.0 (US) / Firmware: 1.0.5
280
284
  - Hardware: 3.0 (US) / Firmware: 1.1.2
285
+ - **L530B**
286
+ - Hardware: 3.0 (EU) / Firmware: 1.1.9
281
287
  - **L530E**
282
288
  - Hardware: 3.0 (EU) / Firmware: 1.0.6
283
289
  - Hardware: 3.0 (EU) / Firmware: 1.1.0
284
290
  - Hardware: 3.0 (EU) / Firmware: 1.1.6
291
+ - Hardware: 2.0 (TW) / Firmware: 1.1.1
285
292
  - Hardware: 2.0 (US) / Firmware: 1.1.0
286
293
  - **L630**
287
294
  - Hardware: 1.0 (EU) / Firmware: 1.1.2
@@ -300,12 +307,15 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
300
307
  - Hardware: 1.0 (US) / Firmware: 1.1.0
301
308
  - Hardware: 1.0 (US) / Firmware: 1.1.3
302
309
  - **L930-5**
310
+ - Hardware: 1.0 (EU) / Firmware: 1.2.5
303
311
  - Hardware: 1.0 (US) / Firmware: 1.1.2
304
312
 
305
313
  ### Cameras
306
314
 
307
315
  - **C100**
308
316
  - Hardware: 4.0 / Firmware: 1.3.14
317
+ - **C110**
318
+ - Hardware: 2.0 (EU) / Firmware: 1.4.3
309
319
  - **C210**
310
320
  - Hardware: 2.0 / Firmware: 1.3.11
311
321
  - Hardware: 2.0 (EU) / Firmware: 1.4.2
@@ -344,6 +354,7 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
344
354
  ### Hubs
345
355
 
346
356
  - **H100**
357
+ - Hardware: 1.0 (AU) / Firmware: 1.5.23
347
358
  - Hardware: 1.0 (EU) / Firmware: 1.2.3
348
359
  - Hardware: 1.0 (EU) / Firmware: 1.5.10
349
360
  - Hardware: 1.0 (EU) / Firmware: 1.5.5
@@ -362,6 +373,7 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
362
373
  - Hardware: 1.0 (EU) / Firmware: 1.12.0
363
374
  - **T100**
364
375
  - Hardware: 1.0 (EU) / Firmware: 1.12.0
376
+ - Hardware: 1.0 (US) / Firmware: 1.12.0
365
377
  - **T110**
366
378
  - Hardware: 1.0 (EU) / Firmware: 1.8.0
367
379
  - Hardware: 1.0 (EU) / Firmware: 1.9.0
@@ -59,6 +59,7 @@ export const LightBulbs = [
59
59
  'KL135',
60
60
  'KL50',
61
61
  'KL60',
62
+ 'LB100',
62
63
  'LB110',
63
64
  'L510',
64
65
  'L530',
@@ -73,6 +74,7 @@ export const LightBulbs = [
73
74
  ];
74
75
  export const Unsupported = [
75
76
  'C100',
77
+ 'C110',
76
78
  'C210',
77
79
  'C225',
78
80
  'C325WB',
@@ -1 +1 @@
1
- {"version":3,"file":"kasaDevices.js","sourceRoot":"","sources":["../../src/devices/kasaDevices.ts"],"names":[],"mappings":"AA4FA,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;CACR,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,SAAS;IACT,SAAS;IACT,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,MAAM;IACN,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC"}
1
+ {"version":3,"file":"kasaDevices.js","sourceRoot":"","sources":["../../src/devices/kasaDevices.ts"],"names":[],"mappings":"AA4FA,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;CACR,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,SAAS;IACT,SAAS;IACT,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC"}
@@ -114,7 +114,7 @@ async def discover_devices(
114
114
  password: Optional[str] = None,
115
115
  additional_broadcasts: Optional[List[str]] = None,
116
116
  manual_devices: Optional[List[str]] = None,
117
- exlude_mac_addresses: Optional[List[str]] = None,
117
+ exclude_mac_addresses: Optional[List[str]] = None,
118
118
  ) -> Dict[str, Any]:
119
119
  devices = {}
120
120
  devices_to_remove = []
@@ -132,9 +132,11 @@ async def discover_devices(
132
132
  except (UnsupportedDeviceError, AuthenticationError) as e:
133
133
  print(f"{e.__class__.__name__}: {device.host}", file=sys.stderr)
134
134
  devices_to_remove.append(device.host)
135
+ await safe_disconnect(device)
135
136
  except Exception as e:
136
137
  print(f"Error during discovery: {e}", file=sys.stderr)
137
138
  devices_to_remove.append(device.host)
139
+ await safe_disconnect(device)
138
140
 
139
141
  async def discover_on_broadcast(broadcast: str):
140
142
  print(f"Discovering on broadcast: {broadcast}")
@@ -159,6 +161,8 @@ async def discover_devices(
159
161
  devices[host] = device
160
162
  except Exception as e:
161
163
  print(f"Error during manual device discovery: {e}", file=sys.stderr)
164
+ devices_to_remove.append(host)
165
+ await safe_disconnect(device)
162
166
 
163
167
  discover_tasks = [discover_on_broadcast(bc) for bc in broadcasts]
164
168
  manual_discover_tasks = [discover_manual_device(host) for host in (manual_devices or [])]
@@ -171,14 +175,14 @@ async def discover_devices(
171
175
 
172
176
  for host in devices:
173
177
  device = devices[host]
174
- if device.mac in (exlude_mac_addresses or []):
178
+ if device.mac in (exclude_mac_addresses or []):
175
179
  devices_to_remove.append(host)
176
180
 
177
181
  for host in devices_to_remove:
178
182
  device = devices.pop(host, None)
179
183
  if device:
180
184
  print(f"Removing device: {device.alias}")
181
- await device.disconnect()
185
+ await safe_disconnect(device)
182
186
 
183
187
  for host, device_config_dict in device_config_cache.items():
184
188
  device = devices.get(host)
@@ -194,8 +198,7 @@ async def discover_devices(
194
198
  await device.update()
195
199
  except Exception as e:
196
200
  print(f"Error checking device: {e}", file=sys.stderr)
197
- if device:
198
- await device.disconnect()
201
+ await safe_disconnect(device)
199
202
  continue
200
203
 
201
204
  try:
@@ -207,11 +210,11 @@ async def discover_devices(
207
210
  print(f"Skipping device {device.alias} due to Native HomeKit support")
208
211
  if matter_component:
209
212
  print(f"Skipping device {device.alias} due to Matter support")
210
- await device.disconnect()
213
+ await safe_disconnect(device)
211
214
  continue
212
215
  except Exception as e:
213
216
  print(f"Error checking HomeKit and Matter modules: {e}", file=sys.stderr)
214
- await device.disconnect()
217
+ await safe_disconnect(device)
215
218
  continue
216
219
 
217
220
  device_type = device.device_type.value
@@ -223,7 +226,7 @@ async def discover_devices(
223
226
  update_tasks.append(create_device_info(host, device))
224
227
  else:
225
228
  print(f"Skipping unsupported device: {host}")
226
- await device.disconnect()
229
+ await safe_disconnect(device)
227
230
 
228
231
  results = await asyncio.gather(*update_tasks, return_exceptions=True)
229
232
 
@@ -231,26 +234,12 @@ async def discover_devices(
231
234
  host, info = result
232
235
  if isinstance(info, Exception):
233
236
  print(f"Error creating device info for host {host}: {info}", file=sys.stderr)
234
- try:
235
- device_config_dict = device_config_cache.get(host)
236
- if device_config_dict:
237
- device_config = DeviceConfig.from_dict(device_config_dict)
238
- device = await get_or_connect_device(host, device_config)
239
- if device:
240
- await device.disconnect()
241
- device_cache.pop(host, None)
242
- except Exception as e:
243
- print(f"Error disconnecting device: {e}", file=sys.stderr)
237
+ await handle_device_error(host)
244
238
  continue
245
239
  print(f"Device info created for device: {host}")
246
240
  all_device_info[host] = info
247
241
 
248
- for host, device in devices.items():
249
- try:
250
- await device.disconnect()
251
- print(f"Disconnected device: {host}")
252
- except Exception as e:
253
- print(f"Error disconnecting device {host}: {e}", file=sys.stderr)
242
+ await disconnect_all_devices(devices)
254
243
 
255
244
  return all_device_info
256
245
 
@@ -287,21 +276,7 @@ async def get_sys_info(host: str) -> Dict[str, Any]:
287
276
  device_info = custom_serializer(device)
288
277
  return {"sys_info": device_info["sys_info"]}
289
278
  except Exception as e:
290
- try:
291
- if device:
292
- await device.disconnect()
293
- device_cache.pop(host, None)
294
- device_lock = device_lock_cache.get(host, asyncio.Lock())
295
- async with device_lock:
296
- device = await get_or_connect_device(host, device_config)
297
- device_info = custom_serializer(device)
298
- return {"sys_info": device_info["sys_info"]}
299
- except Exception as e:
300
- print(f"GetSysInfo failed: {e}", file=sys.stderr)
301
- if device:
302
- await device.disconnect()
303
- device_cache.pop(host, None)
304
- return {"error": str(e)}
279
+ return await handle_device_error(host, e)
305
280
 
306
281
  async def get_or_connect_device(host: str, device_config: DeviceConfig) -> Device:
307
282
  try:
@@ -313,9 +288,7 @@ async def get_or_connect_device(host: str, device_config: DeviceConfig) -> Devic
313
288
  return device
314
289
  except Exception as e:
315
290
  print(f"Failed to connect to device: {e}", file=sys.stderr)
316
- if device:
317
- await device.disconnect()
318
- device_cache.pop(host, None)
291
+ await safe_disconnect(device)
319
292
  raise
320
293
 
321
294
  async def control_device(
@@ -334,20 +307,7 @@ async def control_device(
334
307
  device = await get_or_connect_device(host, device_config)
335
308
  return await perform_device_action(device, feature, action, value, child_num)
336
309
  except Exception as e:
337
- try:
338
- if device:
339
- await device.disconnect()
340
- device_cache.pop(host, None)
341
- device_lock = device_lock_cache.get(host, asyncio.Lock())
342
- async with device_lock:
343
- device = await get_or_connect_device(host, device_config)
344
- return await perform_device_action(device, feature, action, value, child_num)
345
- except Exception as e:
346
- print(f"ControlDevice failed: {e}", file=sys.stderr)
347
- if device:
348
- await device.disconnect()
349
- device_cache.pop(host, None)
350
- return {"error": str(e)}
310
+ return await handle_device_error(host, e)
351
311
 
352
312
  async def perform_device_action(
353
313
  device: Device,
@@ -421,8 +381,8 @@ async def discover_route():
421
381
  data: Dict[str, Any] = await request.get_json()
422
382
  additional_broadcasts = data.get('additionalBroadcasts', [])
423
383
  manual_devices = data.get('manualDevices', [])
424
- exlude_mac_addresses = data.get('excludeMacAddresses', [])
425
- devices_info = await discover_devices(username, password, additional_broadcasts, manual_devices, exlude_mac_addresses)
384
+ exclude_mac_addresses = data.get('excludeMacAddresses', [])
385
+ devices_info = await discover_devices(username, password, additional_broadcasts, manual_devices, exclude_mac_addresses)
426
386
  return jsonify(devices_info)
427
387
  except Exception as e:
428
388
  print(f"Discover route error: {e}", file=sys.stderr)
@@ -463,4 +423,29 @@ async def cleanup():
463
423
  print("Cleaning up and disconnecting all devices.")
464
424
  await close_all_connections()
465
425
  device_lock_cache.clear()
466
- device_config_cache.clear()
426
+ device_config_cache.clear()
427
+
428
+ async def safe_disconnect(device: Optional[Device]):
429
+ if device:
430
+ try:
431
+ await device.disconnect()
432
+ except Exception as e:
433
+ print(f"Error disconnecting device: {e}", file=sys.stderr)
434
+
435
+ async def handle_device_error(host: str, error: Optional[Exception] = None) -> Dict[str, Any]:
436
+ print(f"Handling device error for host {host}: {error}", file=sys.stderr)
437
+ try:
438
+ device_config_dict = device_config_cache.get(host)
439
+ if device_config_dict:
440
+ device_config = DeviceConfig.from_dict(device_config_dict)
441
+ device = await get_or_connect_device(host, device_config)
442
+ await safe_disconnect(device)
443
+ device_cache.pop(host, None)
444
+ except Exception as e:
445
+ print(f"Error during error handling: {e}", file=sys.stderr)
446
+ return {"error": str(error)}
447
+
448
+ async def disconnect_all_devices(devices: Dict[str, Device]):
449
+ for host, device in devices.items():
450
+ await safe_disconnect(device)
451
+ print(f"Disconnected device: {host}")
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Homebridge Kasa Python",
3
3
  "name": "homebridge-kasa-python",
4
- "version": "2.7.2-beta.2",
4
+ "version": "2.7.2-beta.3",
5
5
  "description": "Plugin that uses Python-Kasa API to communicate with Kasa Devices.",
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "engines": {
16
16
  "homebridge": "^1.8.0 || ^2.0.0-beta.0",
17
- "node": "^18.20.6 || ^20.18.3 || ^22.14.0 || ^23.8.0",
17
+ "node": "^18.20.6 || ^20.18.3 || ^22.14.0 || ^23.9.0",
18
18
  "python": "^3.11.0"
19
19
  },
20
20
  "main": "dist/index.js",
@@ -48,19 +48,19 @@
48
48
  "requirements.txt"
49
49
  ],
50
50
  "devDependencies": {
51
- "@eslint/eslintrc": "^3.2.0",
52
- "@eslint/js": "^9.20.0",
53
- "@types/node": "^22.13.4",
54
- "@typescript-eslint/parser": "^8.24.1",
55
- "@stylistic/eslint-plugin": "^4.0.1",
56
- "eslint": "^9.20.1",
57
- "globals": "^15.15.0",
51
+ "@eslint/eslintrc": "^3.3.0",
52
+ "@eslint/js": "^9.21.0",
53
+ "@types/node": "^22.13.9",
54
+ "@typescript-eslint/parser": "^8.26.0",
55
+ "@stylistic/eslint-plugin": "^4.2.0",
56
+ "eslint": "^9.21.0",
57
+ "globals": "^16.0.0",
58
58
  "homebridge": "^2.0.0-beta.27",
59
59
  "node-persist": "^4.0.4",
60
60
  "nodemon": "^3.1.9",
61
61
  "rimraf": "^6.0.1",
62
62
  "ts-node": "^10.9.2",
63
- "typescript-eslint": "^8.24.1"
63
+ "typescript-eslint": "^8.26.0"
64
64
  },
65
65
  "homepage": "https://github.com/ZeliardM/homebridge-kasa-python#readme",
66
66
  "funding": [
@@ -74,9 +74,9 @@
74
74
  }
75
75
  ],
76
76
  "dependencies": {
77
- "axios": "^1.7.9",
77
+ "axios": "^1.8.2",
78
78
  "ts-essentials": "^10.0.4",
79
- "typescript": "^5.7.3"
79
+ "typescript": "^5.8.2"
80
80
  },
81
81
  "overrides": {
82
82
  "node-persist": "^4.0.4"