light_strip.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. from __future__ import annotations
  2. from typing import Any
  3. from bleak.backends.device import BLEDevice
  4. from ..const import SwitchbotModel
  5. from ..const.light import ColorMode, RGBICStripLightColorMode, StripLightColorMode
  6. from .base_light import SwitchbotSequenceBaseLight
  7. from .device import SwitchbotEncryptedDevice
  8. # Private mapping from device-specific color modes to original ColorMode enum
  9. _STRIP_LIGHT_COLOR_MODE_MAP = {
  10. StripLightColorMode.RGB: ColorMode.RGB,
  11. StripLightColorMode.SCENE: ColorMode.EFFECT,
  12. StripLightColorMode.MUSIC: ColorMode.EFFECT,
  13. StripLightColorMode.CONTROLLER: ColorMode.EFFECT,
  14. StripLightColorMode.COLOR_TEMP: ColorMode.COLOR_TEMP,
  15. StripLightColorMode.UNKNOWN: ColorMode.OFF,
  16. }
  17. _RGBICWW_STRIP_LIGHT_COLOR_MODE_MAP = {
  18. RGBICStripLightColorMode.SEGMENTED: ColorMode.EFFECT,
  19. RGBICStripLightColorMode.RGB: ColorMode.RGB,
  20. RGBICStripLightColorMode.SCENE: ColorMode.EFFECT,
  21. RGBICStripLightColorMode.MUSIC: ColorMode.EFFECT,
  22. RGBICStripLightColorMode.CONTROLLER: ColorMode.EFFECT,
  23. RGBICStripLightColorMode.COLOR_TEMP: ColorMode.COLOR_TEMP,
  24. RGBICStripLightColorMode.UNKNOWN: ColorMode.OFF,
  25. }
  26. LIGHT_STRIP_CONTROL_HEADER = "570F4901"
  27. COMMON_EFFECTS = {
  28. "christmas": [
  29. "570F49070200033C01",
  30. "570F490701000600009902006D0EFF0021",
  31. "570F490701000603009902006D0EFF0021",
  32. ],
  33. "halloween": ["570F49070200053C04", "570F490701000300FF6A009E00ED00EA0F"],
  34. "sunset": [
  35. "570F49070200033C3C",
  36. "570F490701000900FF9000ED8C04DD5800",
  37. "570F490701000903FF2E008E0B004F0500",
  38. "570F4907010009063F0010270056140033",
  39. ],
  40. "vitality": [
  41. "570F49070200053C02",
  42. "570F490701000600C5003FD9530AEC9800",
  43. "570F490701000603FFDF0000895500468B",
  44. ],
  45. "flashing": [
  46. "570F49070200053C02",
  47. "570F4907010006000000FF00FF00FF0000",
  48. "570F490701000603FFFF0000FFFFA020F0",
  49. ],
  50. "strobe": ["570F49070200043C02", "570F490701000300FF00E19D70FFFF0515"],
  51. "fade": [
  52. "570F49070200043C04",
  53. "570F490701000500FF5481FF00E19D70FF",
  54. "570F490701000503FF0515FF7FEB",
  55. ],
  56. "smooth": [
  57. "570F49070200033C02",
  58. "570F4907010007000036FC00F6FF00ED13",
  59. "570F490701000703F6FF00FF8300FF0800",
  60. "570F490701000706FF00E1",
  61. ],
  62. "forest": [
  63. "570F49070200033C06",
  64. "570F490701000400006400228B223CB371",
  65. "570F49070100040390EE90",
  66. ],
  67. "ocean": [
  68. "570F49070200033C06",
  69. "570F4907010007004400FF0061FF007BFF",
  70. "570F490701000703009DFF00B2FF00CBFF",
  71. "570F49070100070600E9FF",
  72. ],
  73. "autumn": [
  74. "570F49070200043C05",
  75. "570F490701000700D10035922D13A16501",
  76. "570F490701000703AB9100DD8C00F4AA29",
  77. "570F490701000706E8D000",
  78. ],
  79. "cool": [
  80. "570F49070200043C04",
  81. "570F490701000600001A63006C9A00468B",
  82. "570F490701000603009DA50089BE4378B6",
  83. ],
  84. "flow": [
  85. "570F49070200033C02",
  86. "570F490701000600FF00D8E100FFAA00FF",
  87. "570F4907010006037F00FF5000FF1900FF",
  88. ],
  89. "relax": [
  90. "570F49070200033C03",
  91. "570F490701000400FF8C00FF7200FF1D00",
  92. "570F490701000403FF5500",
  93. ],
  94. "modern": [
  95. "570F49070200043C03",
  96. "570F49070100060089231A5F8969829E5A",
  97. "570F490701000603BCB05EEDBE5AFF9D60",
  98. ],
  99. "rose": [
  100. "570F49070200043C04",
  101. "570F490701000500FF1969BC215F7C0225",
  102. "570F490701000503600C2B35040C",
  103. ],
  104. }
  105. RGBIC_EFFECTS = {
  106. "romance": [
  107. "570F490D01350100FF10EE",
  108. "570F490D0363",
  109. ],
  110. "energy": [
  111. "570F490D01000300ED070F34FF14FFE114",
  112. "570F490D03FA",
  113. ],
  114. "heartbeat": [
  115. "570F490D01020400FFDEADFE90FDFF9E3D",
  116. "570F490D01020403FCBAFD",
  117. "570F490D03FA",
  118. ],
  119. "party": [
  120. "570F490D01030400FF8A47FF524DFF4DEE",
  121. "570F490D010304034DFF8C",
  122. "570F490D03FA",
  123. ],
  124. "dynamic": [
  125. "570F490D010403004DFFFB4DFF4FFFBF4D",
  126. "570F490D03FA",
  127. ],
  128. "mystery": [
  129. "570F490D01050300F660F6F6D460C6F660",
  130. "570F490D03FA",
  131. ],
  132. "lightning": [
  133. "570F490D01340100FFD700",
  134. "570F490D03FA",
  135. ],
  136. "rock": [
  137. "570F490D01090300B0F6606864FCFFBC3D",
  138. "570F490D03FA",
  139. ],
  140. "starlight": [
  141. "570F490D010A0100FF8C00",
  142. "570F490D0363",
  143. ],
  144. "valentine_day": [
  145. "570F490D010C0300FDE0FFFFCC8AD7FF8A",
  146. "570F490D03FA",
  147. ],
  148. "dream": [
  149. "570F490D010E0300A3E5FF73F019FFA8E5",
  150. "570F490D03FA",
  151. ],
  152. "alarm": [
  153. "570F490D013E0100FF0000",
  154. "570F490D03FA",
  155. ],
  156. "fireworks": [
  157. "570F490D01110300FFAA33FFE233FF5CDF",
  158. "570F490D03FA",
  159. ],
  160. "waves": [
  161. "570F490D013D01001E90FF",
  162. "570F490D03FA",
  163. ],
  164. "christmas": [
  165. "570F490D01380400DC143C228B22DAA520",
  166. "570F490D0363",
  167. "570F490D0138040332CD32",
  168. "570F490D0363",
  169. ],
  170. "rainbow": [
  171. "570F490D01160600FF0000FF7F00FFFF00",
  172. "570F490D03FA",
  173. "570F490D0116060300FF000000FF9400D3",
  174. "570F490D03FA",
  175. ],
  176. "game": [
  177. "570F490D011A0400D05CFF668FFFFFEFD5",
  178. "570F490D0363",
  179. "570F490D011A0403FFC55C",
  180. "570F490D0363",
  181. ],
  182. "halloween": [
  183. "570F490D01320300FF8C009370DB32CD32",
  184. "570F490D0364",
  185. ],
  186. "meditation": [
  187. "570F490D013502001E90FF9370DB",
  188. "570F490D0364",
  189. ],
  190. "starlit_sky": [
  191. "570F490D010D010099C8FF",
  192. "570F490D0364",
  193. ],
  194. "sleep": [
  195. "570F490D01370300FF8C002E4E3E3E3E5E",
  196. "570F490D0364",
  197. ],
  198. "movie": [
  199. "570F490D013602001919704B0082",
  200. "570F490D0364",
  201. ],
  202. "sunrise": [
  203. "570F490D013F0200FFD700FF4500",
  204. "570F490D03FA",
  205. "570F490D03FA",
  206. ],
  207. "sunset": [
  208. "570F490D01390300FF4500FFA500483D8B",
  209. "570F490D0363",
  210. "570F490D0363",
  211. ],
  212. "new_year": [
  213. "570F490D013F0300FF0000FFD700228B22",
  214. "570F490D0364",
  215. ],
  216. "cherry_blossom": [
  217. "570F490D01400200FFB3C1FF69B4",
  218. "570F490D0364",
  219. ],
  220. }
  221. class SwitchbotLightStrip(SwitchbotSequenceBaseLight):
  222. """Representation of a Switchbot light strip."""
  223. _effect_dict = COMMON_EFFECTS
  224. _turn_on_command = f"{LIGHT_STRIP_CONTROL_HEADER}01"
  225. _turn_off_command = f"{LIGHT_STRIP_CONTROL_HEADER}02"
  226. _set_rgb_command = f"{LIGHT_STRIP_CONTROL_HEADER}12{{}}"
  227. _set_color_temp_command = f"{LIGHT_STRIP_CONTROL_HEADER}11{{}}"
  228. _set_brightness_command = f"{LIGHT_STRIP_CONTROL_HEADER}14{{}}"
  229. _get_basic_info_command = ["570003", "570f4A01"]
  230. @property
  231. def color_modes(self) -> set[ColorMode]:
  232. """Return the supported color modes."""
  233. return {ColorMode.RGB}
  234. @property
  235. def color_mode(self) -> ColorMode:
  236. """Return the current color mode."""
  237. device_mode = StripLightColorMode(self._get_adv_value("color_mode") or 10)
  238. return _STRIP_LIGHT_COLOR_MODE_MAP.get(device_mode, ColorMode.OFF)
  239. async def get_basic_info(self) -> dict[str, Any] | None:
  240. """Get device basic settings."""
  241. if not (
  242. res := await self._get_multi_commands_results(self._get_basic_info_command)
  243. ):
  244. return None
  245. _version_info, _data = res
  246. self._state["r"] = _data[3]
  247. self._state["g"] = _data[4]
  248. self._state["b"] = _data[5]
  249. self._state["cw"] = int.from_bytes(_data[7:9], "big")
  250. return {
  251. "isOn": bool(_data[1] & 0b10000000),
  252. "brightness": _data[2] & 0b01111111,
  253. "r": self._state["r"],
  254. "g": self._state["g"],
  255. "b": self._state["b"],
  256. "cw": self._state["cw"],
  257. "color_mode": _data[10] & 0b00001111,
  258. "firmware": _version_info[2] / 10.0,
  259. }
  260. class SwitchbotStripLight3(SwitchbotEncryptedDevice, SwitchbotLightStrip):
  261. """Support for switchbot strip light3 and floor lamp."""
  262. def __init__(
  263. self,
  264. device: BLEDevice,
  265. key_id: str,
  266. encryption_key: str,
  267. interface: int = 0,
  268. model: SwitchbotModel = SwitchbotModel.STRIP_LIGHT_3,
  269. **kwargs: Any,
  270. ) -> None:
  271. super().__init__(device, key_id, encryption_key, model, interface, **kwargs)
  272. @classmethod
  273. async def verify_encryption_key(
  274. cls,
  275. device: BLEDevice,
  276. key_id: str,
  277. encryption_key: str,
  278. model: SwitchbotModel = SwitchbotModel.STRIP_LIGHT_3,
  279. **kwargs: Any,
  280. ) -> bool:
  281. return await super().verify_encryption_key(
  282. device, key_id, encryption_key, model, **kwargs
  283. )
  284. @property
  285. def color_modes(self) -> set[ColorMode]:
  286. """Return the supported color modes."""
  287. return {ColorMode.RGB, ColorMode.COLOR_TEMP}
  288. class SwitchbotRgbicLight(SwitchbotEncryptedDevice, SwitchbotLightStrip):
  289. """Support for Switchbot RGBIC lights."""
  290. _effect_dict = RGBIC_EFFECTS
  291. def __init__(
  292. self,
  293. device: BLEDevice,
  294. key_id: str,
  295. encryption_key: str,
  296. interface: int = 0,
  297. model: SwitchbotModel = SwitchbotModel.RGBICWW_STRIP_LIGHT,
  298. **kwargs: Any,
  299. ) -> None:
  300. super().__init__(device, key_id, encryption_key, model, interface, **kwargs)
  301. @classmethod
  302. async def verify_encryption_key(
  303. cls,
  304. device: BLEDevice,
  305. key_id: str,
  306. encryption_key: str,
  307. model: SwitchbotModel = SwitchbotModel.RGBICWW_STRIP_LIGHT,
  308. **kwargs: Any,
  309. ) -> bool:
  310. return await super().verify_encryption_key(
  311. device, key_id, encryption_key, model, **kwargs
  312. )
  313. @property
  314. def color_modes(self) -> set[ColorMode]:
  315. """Return the supported color modes."""
  316. return {ColorMode.RGB, ColorMode.COLOR_TEMP}
  317. @property
  318. def color_mode(self) -> ColorMode:
  319. """Return the current color mode."""
  320. device_mode = RGBICStripLightColorMode(self._get_adv_value("color_mode") or 10)
  321. return _RGBICWW_STRIP_LIGHT_COLOR_MODE_MAP.get(device_mode, ColorMode.OFF)