PySwitchbot 0.68.0__tar.gz → 0.68.1__tar.gz

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 (93) hide show
  1. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/PKG-INFO +1 -1
  2. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/PySwitchbot.egg-info/PKG-INFO +1 -1
  3. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/setup.py +1 -1
  4. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/device.py +6 -0
  5. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/lock.py +6 -0
  6. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_encrypted_device.py +19 -0
  7. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_lock.py +29 -0
  8. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/LICENSE +0 -0
  9. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/MANIFEST.in +0 -0
  10. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/PySwitchbot.egg-info/SOURCES.txt +0 -0
  11. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/PySwitchbot.egg-info/dependency_links.txt +0 -0
  12. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/PySwitchbot.egg-info/requires.txt +0 -0
  13. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/PySwitchbot.egg-info/top_level.txt +0 -0
  14. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/README.md +0 -0
  15. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/pyproject.toml +0 -0
  16. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/setup.cfg +0 -0
  17. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/__init__.py +0 -0
  18. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parser.py +0 -0
  19. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/__init__.py +0 -0
  20. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/air_purifier.py +0 -0
  21. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/blind_tilt.py +0 -0
  22. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/bot.py +0 -0
  23. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/bulb.py +0 -0
  24. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/ceiling_light.py +0 -0
  25. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/contact.py +0 -0
  26. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/curtain.py +0 -0
  27. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/fan.py +0 -0
  28. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/hub2.py +0 -0
  29. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/hub3.py +0 -0
  30. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/hubmini_matter.py +0 -0
  31. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/humidifier.py +0 -0
  32. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/keypad.py +0 -0
  33. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/leak.py +0 -0
  34. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/light_strip.py +0 -0
  35. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/lock.py +0 -0
  36. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/meter.py +0 -0
  37. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/motion.py +0 -0
  38. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/plug.py +0 -0
  39. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/relay_switch.py +0 -0
  40. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/remote.py +0 -0
  41. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/roller_shade.py +0 -0
  42. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/adv_parsers/vacuum.py +0 -0
  43. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/api_config.py +0 -0
  44. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/__init__.py +0 -0
  45. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/air_purifier.py +0 -0
  46. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/evaporative_humidifier.py +0 -0
  47. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/fan.py +0 -0
  48. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/hub2.py +0 -0
  49. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/hub3.py +0 -0
  50. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/light.py +0 -0
  51. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/const/lock.py +0 -0
  52. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/__init__.py +0 -0
  53. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/air_purifier.py +0 -0
  54. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/base_cover.py +0 -0
  55. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/base_light.py +0 -0
  56. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/blind_tilt.py +0 -0
  57. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/bot.py +0 -0
  58. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/bulb.py +0 -0
  59. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/ceiling_light.py +0 -0
  60. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/contact.py +0 -0
  61. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/curtain.py +0 -0
  62. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/evaporative_humidifier.py +0 -0
  63. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/fan.py +0 -0
  64. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/humidifier.py +0 -0
  65. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/keypad.py +0 -0
  66. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/light_strip.py +0 -0
  67. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/meter.py +0 -0
  68. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/motion.py +0 -0
  69. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/plug.py +0 -0
  70. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/relay_switch.py +0 -0
  71. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/roller_shade.py +0 -0
  72. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/devices/vacuum.py +0 -0
  73. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/discovery.py +0 -0
  74. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/enum.py +0 -0
  75. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/helpers.py +0 -0
  76. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/switchbot/models.py +0 -0
  77. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_adv_parser.py +0 -0
  78. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_air_purifier.py +0 -0
  79. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_base_cover.py +0 -0
  80. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_blind_tilt.py +0 -0
  81. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_bulb.py +0 -0
  82. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_ceiling_light.py +0 -0
  83. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_colormode_imports.py +0 -0
  84. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_curtain.py +0 -0
  85. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_evaporative_humidifier.py +0 -0
  86. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_fan.py +0 -0
  87. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_helpers.py +0 -0
  88. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_hub2.py +0 -0
  89. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_hub3.py +0 -0
  90. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_relay_switch.py +0 -0
  91. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_roller_shade.py +0 -0
  92. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_strip_light.py +0 -0
  93. {pyswitchbot-0.68.0 → pyswitchbot-0.68.1}/tests/test_vacuum.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySwitchbot
3
- Version: 0.68.0
3
+ Version: 0.68.1
4
4
  Summary: A library to communicate with Switchbot
5
5
  Home-page: https://github.com/sblibs/pySwitchbot/
6
6
  Author: Daniel Hjelseth Hoyer
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySwitchbot
3
- Version: 0.68.0
3
+ Version: 0.68.1
4
4
  Summary: A library to communicate with Switchbot
5
5
  Home-page: https://github.com/sblibs/pySwitchbot/
6
6
  Author: Daniel Hjelseth Hoyer
@@ -20,7 +20,7 @@ setup(
20
20
  "cryptography>=39.0.0",
21
21
  "pyOpenSSL>=23.0.0",
22
22
  ],
23
- version="0.68.0",
23
+ version="0.68.1",
24
24
  description="A library to communicate with Switchbot",
25
25
  long_description=long_description,
26
26
  long_description_content_type="text/markdown",
@@ -955,6 +955,12 @@ class SwitchbotEncryptedDevice(SwitchbotDevice):
955
955
  if len(data) == 0:
956
956
  return b""
957
957
  if self._iv is None:
958
+ if self._expected_disconnect:
959
+ _LOGGER.debug(
960
+ "%s: Cannot decrypt, IV is None during expected disconnect",
961
+ self.name,
962
+ )
963
+ return b""
958
964
  raise RuntimeError("Cannot decrypt: IV is None")
959
965
  decryptor = self._get_cipher().decryptor()
960
966
  return decryptor.update(data) + decryptor.finalize()
@@ -214,6 +214,12 @@ class SwitchbotLock(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
214
214
 
215
215
  def _notification_handler(self, _sender: int, data: bytearray) -> None:
216
216
  if self._notifications_enabled and self._check_command_result(data, 0, {0xF}):
217
+ if self._expected_disconnect:
218
+ _LOGGER.debug(
219
+ "%s: Ignoring lock notification during expected disconnect",
220
+ self.name,
221
+ )
222
+ return
217
223
  self._update_lock_status(data)
218
224
  else:
219
225
  super()._notification_handler(_sender, data)
@@ -365,3 +365,22 @@ async def test_empty_data_encryption_decryption() -> None:
365
365
  # Test empty decryption
366
366
  decrypted = device._decrypt(bytearray())
367
367
  assert decrypted == b""
368
+
369
+
370
+ @pytest.mark.asyncio
371
+ async def test_decrypt_with_none_iv_during_disconnect() -> None:
372
+ """Test that decryption returns empty bytes when IV is None during expected disconnect."""
373
+ device = create_encrypted_device()
374
+
375
+ # Simulate disconnection in progress
376
+ device._expected_disconnect = True
377
+ device._iv = None
378
+
379
+ # Should return empty bytes instead of raising
380
+ result = device._decrypt(bytearray(b"encrypted_data"))
381
+ assert result == b""
382
+
383
+ # Verify it still raises when not disconnecting
384
+ device._expected_disconnect = False
385
+ with pytest.raises(RuntimeError, match="Cannot decrypt: IV is None"):
386
+ device._decrypt(bytearray(b"encrypted_data"))
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  from unittest.mock import AsyncMock, Mock, patch
2
3
 
3
4
  import pytest
@@ -478,6 +479,34 @@ def test_notification_handler_not_enabled(model: str):
478
479
  mock_super.assert_called_once()
479
480
 
480
481
 
482
+ @pytest.mark.parametrize(
483
+ "model",
484
+ [
485
+ SwitchbotModel.LOCK,
486
+ SwitchbotModel.LOCK_LITE,
487
+ SwitchbotModel.LOCK_PRO,
488
+ SwitchbotModel.LOCK_ULTRA,
489
+ ],
490
+ )
491
+ def test_notification_handler_during_disconnect(
492
+ model: str, caplog: pytest.LogCaptureFixture
493
+ ) -> None:
494
+ """Test _notification_handler during expected disconnect."""
495
+ device = create_device_for_command_testing(model)
496
+ device._notifications_enabled = True
497
+ device._expected_disconnect = True
498
+ data = bytearray(b"\x0f\x00\x00\x00\x80\x00\x00\x00\x00\x00")
499
+ with (
500
+ patch.object(device, "_update_lock_status") as mock_update,
501
+ caplog.at_level(logging.DEBUG),
502
+ ):
503
+ device._notification_handler(0, data)
504
+ # Should not update lock status during disconnect
505
+ mock_update.assert_not_called()
506
+ # Should log debug message
507
+ assert "Ignoring lock notification during expected disconnect" in caplog.text
508
+
509
+
481
510
  @pytest.mark.parametrize(
482
511
  "model",
483
512
  [
File without changes
File without changes
File without changes
File without changes