PySwitchbot 3.0.0__tar.gz → 3.2.0__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 (84) hide show
  1. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/PKG-INFO +14 -1
  2. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/README.md +13 -0
  3. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/pyproject.toml +1 -1
  4. pyswitchbot-3.2.0/switchbot/__version__.py +1 -0
  5. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/air_purifier.py +27 -0
  6. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/bot.py +17 -0
  7. pyswitchbot-3.0.0/switchbot/__version__.py +0 -1
  8. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/LICENSE +0 -0
  9. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/__init__.py +0 -0
  10. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parser.py +0 -0
  11. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/__init__.py +0 -0
  12. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/_sensor_th.py +0 -0
  13. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/air_purifier.py +0 -0
  14. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/art_frame.py +0 -0
  15. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/blind_tilt.py +0 -0
  16. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/bot.py +0 -0
  17. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/bulb.py +0 -0
  18. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/ceiling_light.py +0 -0
  19. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/climate_panel.py +0 -0
  20. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/contact.py +0 -0
  21. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/curtain.py +0 -0
  22. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/fan.py +0 -0
  23. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/hub2.py +0 -0
  24. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/hub3.py +0 -0
  25. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/hubmini_matter.py +0 -0
  26. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/humidifier.py +0 -0
  27. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/keypad.py +0 -0
  28. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/keypad_vision.py +0 -0
  29. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/leak.py +0 -0
  30. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/light_strip.py +0 -0
  31. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/lock.py +0 -0
  32. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/meter.py +0 -0
  33. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/motion.py +0 -0
  34. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/plug.py +0 -0
  35. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/presence_sensor.py +0 -0
  36. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/relay_switch.py +0 -0
  37. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/remote.py +0 -0
  38. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/roller_shade.py +0 -0
  39. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/smart_thermostat_radiator.py +0 -0
  40. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/vacuum.py +0 -0
  41. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/adv_parsers/weather_station.py +0 -0
  42. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/api_config.py +0 -0
  43. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/__init__.py +0 -0
  44. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/air_purifier.py +0 -0
  45. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/climate.py +0 -0
  46. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/evaporative_humidifier.py +0 -0
  47. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/fan.py +0 -0
  48. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/hub2.py +0 -0
  49. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/hub3.py +0 -0
  50. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/light.py +0 -0
  51. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/lock.py +0 -0
  52. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/const/presence_sensor.py +0 -0
  53. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/__init__.py +0 -0
  54. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/art_frame.py +0 -0
  55. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/base_cover.py +0 -0
  56. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/base_light.py +0 -0
  57. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/blind_tilt.py +0 -0
  58. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/bulb.py +0 -0
  59. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/ceiling_light.py +0 -0
  60. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/contact.py +0 -0
  61. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/curtain.py +0 -0
  62. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/device.py +0 -0
  63. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/evaporative_humidifier.py +0 -0
  64. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/fan.py +0 -0
  65. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/humidifier.py +0 -0
  66. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/keypad.py +0 -0
  67. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/keypad_vision.py +0 -0
  68. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/light_strip.py +0 -0
  69. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/lock.py +0 -0
  70. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/meter.py +0 -0
  71. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/meter_pro.py +0 -0
  72. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/motion.py +0 -0
  73. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/plug.py +0 -0
  74. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/relay_switch.py +0 -0
  75. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/roller_shade.py +0 -0
  76. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/smart_thermostat_radiator.py +0 -0
  77. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/universal_remote.py +0 -0
  78. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/devices/vacuum.py +0 -0
  79. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/discovery.py +0 -0
  80. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/enum.py +0 -0
  81. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/helpers.py +0 -0
  82. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/models.py +0 -0
  83. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/oauth.py +0 -0
  84. {pyswitchbot-3.0.0 → pyswitchbot-3.2.0}/switchbot/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySwitchbot
3
- Version: 3.0.0
3
+ Version: 3.2.0
4
4
  Summary: A library to communicate with Switchbot
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -42,6 +42,19 @@ source .venv/bin/activate
42
42
  pip install .
43
43
  ```
44
44
 
45
+ ## Air purifier filter reset
46
+
47
+ After replacing the filter, call `await purifier.reset_filter_usage()` on a
48
+ configured `SwitchbotAirPurifier` instance. The method uses the device's
49
+ encrypted BLE connection, sends the reset command without automatic retries,
50
+ and reads back the used-hours counter. It returns `True` and refreshes the
51
+ cached `filter element working time` only after the device reports zero.
52
+
53
+ Failed commands or an unconfirmed reset raise `SwitchbotOperationError`. If a
54
+ reply is lost, check the device before retrying: the reset may already have
55
+ been applied. This resets the device counter and does not restore its previous
56
+ value.
57
+
45
58
  ## OAuth account access
46
59
 
47
60
  pySwitchbot provides helpers for SwitchBot's authorization-code flow. The
@@ -10,6 +10,19 @@ source .venv/bin/activate
10
10
  pip install .
11
11
  ```
12
12
 
13
+ ## Air purifier filter reset
14
+
15
+ After replacing the filter, call `await purifier.reset_filter_usage()` on a
16
+ configured `SwitchbotAirPurifier` instance. The method uses the device's
17
+ encrypted BLE connection, sends the reset command without automatic retries,
18
+ and reads back the used-hours counter. It returns `True` and refreshes the
19
+ cached `filter element working time` only after the device reports zero.
20
+
21
+ Failed commands or an unconfirmed reset raise `SwitchbotOperationError`. If a
22
+ reply is lost, check the device before retrying: the reset may already have
23
+ been applied. This resets the device counter and does not restore its previous
24
+ value.
25
+
13
26
  ## OAuth account access
14
27
 
15
28
  pySwitchbot provides helpers for SwitchBot's authorization-code flow. The
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "PySwitchbot"
3
- version = "3.0.0"
3
+ version = "3.2.0"
4
4
  description = "A library to communicate with Switchbot"
5
5
  authors = ["Daniel Hjelseth Hoyer"]
6
6
  license = "MIT"
@@ -0,0 +1 @@
1
+ __version__ = "3.2.0"
@@ -33,6 +33,8 @@ DEVICE_GET_BASIC_SETTINGS_KEY = "570f4d81"
33
33
  COMMAND_SET_PERCENTAGE = f"{COMMAND_HEAD}02{{percentage:02x}}"
34
34
  READ_LED_SETTINGS_COMMAND = "570f4d05"
35
35
  READ_LED_STATUS_COMMAND = "570f4d07"
36
+ RESET_FILTER_USAGE_COMMAND = f"{COMMAND_HEAD}09"
37
+ READ_FILTER_USAGE_COMMAND = "570f4d09"
36
38
 
37
39
 
38
40
  class SwitchbotAirPurifier(SwitchbotSequenceBaseLight, SwitchbotEncryptedDevice):
@@ -147,6 +149,31 @@ class SwitchbotAirPurifier(SwitchbotSequenceBaseLight, SwitchbotEncryptedDevice)
147
149
  return data | {"pm25": pm25}
148
150
  return data
149
151
 
152
+ async def reset_filter_usage(self) -> bool:
153
+ """Reset filter usage, returning True only after a verified zero readback."""
154
+ result = await self._send_command(RESET_FILTER_USAGE_COMMAND, retry=0)
155
+ if not self._check_command_result(result, 0, {1}):
156
+ raise SwitchbotOperationError("Filter usage reset was rejected")
157
+
158
+ result = await self._send_command(READ_FILTER_USAGE_COMMAND)
159
+ if not result or len(result) < 3:
160
+ raise SwitchbotOperationError(
161
+ "Reset was sent, but filter usage could not be verified. "
162
+ "Check the device before retrying"
163
+ )
164
+ if not self._check_command_result(result, 0, {1}):
165
+ raise SwitchbotOperationError("Filter usage read was rejected")
166
+ used_hours = _UNPACK_UINT16_BE(result, 1)[0]
167
+ if used_hours != 0:
168
+ raise SwitchbotOperationError(
169
+ f"Reset was sent, but the device still reports {used_hours} used hours. "
170
+ "Check the device before retrying"
171
+ )
172
+
173
+ self._update_parsed_data({"filter element working time": used_hours})
174
+ self._fire_callbacks()
175
+ return True
176
+
150
177
  @update_after_operation
151
178
  async def set_preset_mode(self, preset_mode: str) -> bool:
152
179
  """Send command to set air purifier preset_mode."""
@@ -9,6 +9,7 @@ from .device import (
9
9
  DEVICE_SET_EXTENDED_KEY,
10
10
  DEVICE_SET_MODE_KEY,
11
11
  SwitchbotDeviceOverrideStateDuringConnection,
12
+ SwitchbotOperationError,
12
13
  update_after_operation,
13
14
  )
14
15
 
@@ -90,6 +91,18 @@ class Switchbot(SwitchbotDeviceOverrideStateDuringConnection):
90
91
  result = await self._send_command(DEVICE_SET_MODE_KEY + strength_key + mode_key)
91
92
  return self._check_command_result(result, 0, {1})
92
93
 
94
+ async def set_inverse_direction(self, inverse: bool) -> bool:
95
+ """Set the Bot's inverse direction while preserving its other mode settings."""
96
+ if not (settings := await self.get_basic_info()):
97
+ raise SwitchbotOperationError(
98
+ f"{self.name}: Unable to get current Bot mode settings"
99
+ )
100
+ return await self.set_switch_mode(
101
+ switch_mode=settings["switchMode"],
102
+ strength=settings["strength"],
103
+ inverse=inverse,
104
+ )
105
+
93
106
  @update_after_operation
94
107
  async def set_long_press(self, duration: int = 0) -> bool:
95
108
  """Set bot long press duration."""
@@ -121,3 +134,7 @@ class Switchbot(SwitchbotDeviceOverrideStateDuringConnection):
121
134
  if self._inverse:
122
135
  return not value
123
136
  return value
137
+
138
+ def inverse_direction(self) -> bool | None:
139
+ """Return the cached inverse direction setting."""
140
+ return self._get_adv_value("inverseDirection")
@@ -1 +0,0 @@
1
- __version__ = "3.0.0"
File without changes