wled_module.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. from typing import List, Optional, Dict, Any
  2. class WledSegment:
  3. """
  4. WLED分段控制类
  5. 用于控制LED灯条的分段效果,包括位置、颜色、特效等参数
  6. """
  7. def __init__(self, start: int = 0, stop: int = 150, segment_id: int = 0,
  8. group: int = 5, on: bool = True, colors: list = None,
  9. effect: int = 6, speed: int = 230, intensity: int = 255,
  10. palette: int = 0, reverse: bool = False, selected: bool = True):
  11. """
  12. 初始化WLED分段
  13. Args:
  14. start: 分段起始灯珠编号
  15. stop: 分段结束灯珠编号(不包含此编号)
  16. segment_id: 分段ID,用于唯一标识
  17. group: 分组数量,每N个灯珠为1组运行特效
  18. on: 分段开关状态
  19. colors: 颜色配置,3个颜色通道[主色, 辅助色, 第三色]
  20. effect: 特效ID
  21. speed: 特效速度 (0-255)
  22. intensity: 特效强度 (0-255)
  23. palette: 调色板ID
  24. reverse: 方向反转
  25. selected: 分段选中状态
  26. """
  27. self.start = start
  28. self.stop = stop
  29. self.id = segment_id
  30. self.grp = group
  31. self.on = on
  32. self.col = colors or [[0, 0, 255], [0, 0, 0], [0, 0, 0]] # 默认蓝色主色
  33. self.fx = effect
  34. self.sx = speed
  35. self.ix = intensity
  36. self.pal = palette
  37. self.rev = reverse
  38. self.sel = selected
  39. def to_dict(self) -> dict:
  40. """
  41. 将分段配置转换为字典格式,用于API调用
  42. Returns:
  43. dict: 分段配置字典
  44. """
  45. return {
  46. "start": self.start,
  47. "stop": self.stop,
  48. "id": self.id,
  49. "grp": self.grp,
  50. "on": self.on,
  51. "col": self.col,
  52. "fx": self.fx,
  53. "sx": self.sx,
  54. "ix": self.ix,
  55. "pal": self.pal,
  56. "rev": self.rev,
  57. "sel": self.sel
  58. }
  59. def set_color(self, primary_color: tuple, secondary_color: tuple = (0, 0, 0),
  60. tertiary_color: tuple = (0, 0, 0)):
  61. """
  62. 设置分段颜色
  63. Args:
  64. primary_color: 主色 RGB元组
  65. secondary_color: 辅助色 RGB元组
  66. tertiary_color: 第三色 RGB元组
  67. """
  68. self.col = [list(primary_color), list(secondary_color), list(tertiary_color)]
  69. def set_effect(self, effect_id: int, speed: int = None, intensity: int = None):
  70. """
  71. 设置分段特效
  72. Args:
  73. effect_id: 特效ID
  74. speed: 特效速度 (0-255)
  75. intensity: 特效强度 (0-255)
  76. """
  77. self.fx = effect_id
  78. if speed is not None:
  79. self.sx = max(0, min(255, speed))
  80. if intensity is not None:
  81. self.ix = max(0, min(255, intensity))
  82. def set_position(self, start: int, stop: int):
  83. """
  84. 设置分段位置
  85. Args:
  86. start: 起始灯珠编号
  87. stop: 结束灯珠编号(不包含)
  88. """
  89. self.start = start
  90. self.stop = stop
  91. def set_group_size(self, group_size: int):
  92. """
  93. 设置分组大小
  94. Args:
  95. group_size: 每组的灯珠数量
  96. """
  97. self.grp = group_size
  98. def toggle(self):
  99. """切换分段开关状态"""
  100. self.on = not self.on
  101. def select(self):
  102. """选中此分段"""
  103. self.sel = True
  104. def deselect(self):
  105. """取消选中此分段"""
  106. self.sel = False
  107. def reverse(self):
  108. """切换方向反转状态"""
  109. self.rev = not self.rev
  110. def __str__(self) -> str:
  111. """返回分段的字符串表示"""
  112. return f"WLED Segment {self.id}: LEDs {self.start}-{self.stop-1}, " \
  113. f"Effect {self.fx}, Color {self.col[0]}, {'ON' if self.on else 'OFF'}"
  114. class WledState:
  115. """
  116. WLED设备状态控制类
  117. 用于管理WLED设备的全局状态,包括开关、亮度、过渡时间等参数
  118. """
  119. def __init__(self, on: bool = True, brightness: int = 255, transition: int = 10,
  120. segments: list = None):
  121. """
  122. 初始化WLED设备状态
  123. Args:
  124. on: 设备总开关,True=开启,False=关闭(全局生效,分段开关需配合此值)
  125. brightness: 全局亮度,取值 0-255,255=最大亮度(所有分段的亮度均基于此值)
  126. transition: 过渡时间,单位 100ms,10=1秒(颜色/特效切换时的平滑过渡时长)
  127. segments: 分段数组,存放多个独立控制的灯珠段
  128. """
  129. self.on = on
  130. self.bri = max(0, min(255, brightness)) # 限制亮度范围 0-255
  131. self.transition = max(0, transition) # 过渡时间不能为负数
  132. self.seg = segments or [] # 分段数组,默认为空列表
  133. def add_segment(self, segment: WledSegment):
  134. """
  135. 添加一个分段到设备状态中
  136. Args:
  137. segment: wled_segment对象
  138. """
  139. self.seg.append(segment)
  140. def remove_segment(self, segment_id: int):
  141. """
  142. 根据ID移除分段
  143. Args:
  144. segment_id: 要移除的分段ID
  145. """
  146. self.seg = [seg for seg in self.seg if seg.id != segment_id]
  147. def get_segment(self, segment_id: int) -> Optional[WledSegment]:
  148. """
  149. 根据ID获取分段
  150. Args:
  151. segment_id: 分段ID
  152. Returns:
  153. wled_segment对象,如果未找到返回None
  154. """
  155. for seg in self.seg:
  156. if seg.id == segment_id:
  157. return seg
  158. return None
  159. def set_global_brightness(self, brightness: int):
  160. """
  161. 设置全局亮度
  162. Args:
  163. brightness: 亮度值 0-255
  164. """
  165. self.bri = max(0, min(255, brightness))
  166. def set_transition_time(self, transition: int):
  167. """
  168. 设置过渡时间
  169. Args:
  170. transition: 过渡时间,单位 100ms
  171. """
  172. self.transition = max(0, transition)
  173. def toggle_power(self):
  174. """切换设备总开关状态"""
  175. self.on = not self.on
  176. def turn_on(self):
  177. """开启设备"""
  178. self.on = True
  179. def turn_off(self):
  180. """关闭设备"""
  181. self.on = False
  182. def to_dict(self) -> dict:
  183. """
  184. 将设备状态转换为字典格式,用于API调用
  185. Returns:
  186. dict: 设备状态字典,符合WLED API格式
  187. """
  188. return {
  189. "on": self.on,
  190. "bri": self.bri,
  191. "transition": self.transition,
  192. "seg": [segment.to_dict() for segment in self.seg]
  193. }
  194. def from_dict(self, state_dict: dict):
  195. """
  196. 从字典格式加载设备状态
  197. Args:
  198. state_dict: 包含设备状态的字典
  199. """
  200. self.on = state_dict.get("on", True)
  201. self.bri = state_dict.get("bri", 255)
  202. self.transition = state_dict.get("transition", 10)
  203. # 清空现有分段
  204. self.seg = []
  205. # 加载分段数据
  206. segments_data = state_dict.get("seg", [])
  207. for seg_data in segments_data:
  208. segment = WledSegment(
  209. start=seg_data.get("start", 0),
  210. stop=seg_data.get("stop", 150),
  211. segment_id=seg_data.get("id", 0),
  212. group=seg_data.get("grp", 5),
  213. on=seg_data.get("on", True),
  214. colors=seg_data.get("col", [[0, 0, 255], [0, 0, 0], [0, 0, 0]]),
  215. effect=seg_data.get("fx", 6),
  216. speed=seg_data.get("sx", 230),
  217. intensity=seg_data.get("ix", 255),
  218. palette=seg_data.get("pal", 0),
  219. reverse=seg_data.get("rev", False),
  220. selected=seg_data.get("sel", True)
  221. )
  222. self.add_segment(segment)
  223. def get_segments_count(self) -> int:
  224. """获取分段数量"""
  225. return len(self.seg)
  226. def get_total_leds(self) -> int:
  227. """获取总LED数量(基于最后一个分段的结束位置)"""
  228. if not self.seg:
  229. return 0
  230. return max(seg.stop for seg in self.seg)
  231. def clone(self) -> 'WledState':
  232. """
  233. 深度克隆WledState对象
  234. Returns:
  235. WledState: 克隆的新对象
  236. """
  237. # 创建新的WledState对象
  238. cloned_state = WledState(
  239. on=self.on,
  240. brightness=self.bri,
  241. transition=self.transition
  242. )
  243. # 深度克隆所有分段
  244. for segment in self.seg:
  245. cloned_segment = WledSegment(
  246. start=segment.start,
  247. stop=segment.stop,
  248. segment_id=segment.id,
  249. group=segment.grp,
  250. on=segment.on,
  251. colors=[color[:] for color in segment.col], # 深拷贝颜色数组
  252. effect=segment.fx,
  253. speed=segment.sx,
  254. intensity=segment.ix,
  255. palette=segment.pal,
  256. reverse=segment.rev,
  257. selected=segment.sel
  258. )
  259. cloned_state.add_segment(cloned_segment)
  260. return cloned_state
  261. def merge_segments(self) -> 'WledState':
  262. """
  263. 合并所有分段为一个完整的分段,用于控制整条灯带
  264. Returns:
  265. WledState: 合并后的状态对象
  266. """
  267. if not self.seg:
  268. return self.clone()
  269. # 计算总LED数量
  270. total_leds = self.get_total_leds()
  271. # 创建合并后的状态
  272. merged_state = WledState(
  273. on=self.on,
  274. brightness=self.bri,
  275. transition=self.transition
  276. )
  277. # 创建单个分段覆盖整个灯带
  278. merged_segment = WledSegment(
  279. start=0,
  280. stop=total_leds,
  281. segment_id=0,
  282. group=self.seg[0].grp if self.seg else 5,
  283. on=True,
  284. colors=[[0, 0, 255], [0, 0, 0], [0, 0, 0]], # 默认蓝色
  285. effect=6, # 默认彩虹特效
  286. speed=230,
  287. intensity=255,
  288. palette=0,
  289. reverse=False,
  290. selected=True
  291. )
  292. merged_state.add_segment(merged_segment)
  293. return merged_state
  294. def __str__(self) -> str:
  295. """返回设备状态的字符串表示"""
  296. status = "ON" if self.on else "OFF"
  297. return f"WLED State: {status}, Brightness: {self.bri}, " \
  298. f"Transition: {self.transition}ms, Segments: {len(self.seg)}"