@homebridge-plugins/homebridge-eufy-security 4.7.2 → 5.0.0-beta.0

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 (471) hide show
  1. package/AUTHORS +4 -0
  2. package/CODE_OF_CONDUCT.md +30 -0
  3. package/CONTRIBUTING.md +77 -0
  4. package/README.md +152 -49
  5. package/SECURITY.md +30 -0
  6. package/config.schema.json +92 -3
  7. package/dist/account/ownership.js +290 -0
  8. package/dist/account/ownership.js.map +1 -0
  9. package/dist/account/persistence.js +274 -0
  10. package/dist/account/persistence.js.map +1 -0
  11. package/dist/account/temporary-authentication.js +348 -0
  12. package/dist/account/temporary-authentication.js.map +1 -0
  13. package/dist/configuration.js +167 -0
  14. package/dist/configuration.js.map +1 -0
  15. package/dist/device/member-evidence.js +66 -0
  16. package/dist/device/member-evidence.js.map +1 -0
  17. package/dist/device/member-trust.js +114 -0
  18. package/dist/device/member-trust.js.map +1 -0
  19. package/dist/device/snapshot.js +190 -0
  20. package/dist/device/snapshot.js.map +1 -0
  21. package/dist/diagnostics.js +2218 -0
  22. package/dist/diagnostics.js.map +1 -0
  23. package/dist/homekit/adapter.js +2 -0
  24. package/dist/homekit/adapter.js.map +1 -0
  25. package/dist/homekit/adapters/battery.js +208 -0
  26. package/dist/homekit/adapters/battery.js.map +1 -0
  27. package/dist/homekit/adapters/camera-controls.js +527 -0
  28. package/dist/homekit/adapters/camera-controls.js.map +1 -0
  29. package/dist/homekit/adapters/camera-streaming.js +1515 -0
  30. package/dist/homekit/adapters/camera-streaming.js.map +1 -0
  31. package/dist/homekit/adapters/contact.js +138 -0
  32. package/dist/homekit/adapters/contact.js.map +1 -0
  33. package/dist/homekit/adapters/doorbell.js +57 -0
  34. package/dist/homekit/adapters/doorbell.js.map +1 -0
  35. package/dist/homekit/adapters/information.js +55 -0
  36. package/dist/homekit/adapters/information.js.map +1 -0
  37. package/dist/homekit/adapters/lock.js +489 -0
  38. package/dist/homekit/adapters/lock.js.map +1 -0
  39. package/dist/homekit/adapters/motion.js +100 -0
  40. package/dist/homekit/adapters/motion.js.map +1 -0
  41. package/dist/homekit/adapters/registry.js +26 -0
  42. package/dist/homekit/adapters/registry.js.map +1 -0
  43. package/dist/homekit/adapters/security-system.js +425 -0
  44. package/dist/homekit/adapters/security-system.js.map +1 -0
  45. package/dist/homekit/adapters/siren.js +136 -0
  46. package/dist/homekit/adapters/siren.js.map +1 -0
  47. package/dist/homekit/adapters/smart-light.js +662 -0
  48. package/dist/homekit/adapters/smart-light.js.map +1 -0
  49. package/dist/homekit/coverage-matrix.js +119 -0
  50. package/dist/homekit/coverage-matrix.js.map +1 -0
  51. package/dist/homekit/device-control.js +175 -0
  52. package/dist/homekit/device-control.js.map +1 -0
  53. package/dist/homekit/reconciler.js +319 -0
  54. package/dist/homekit/reconciler.js.map +1 -0
  55. package/dist/homekit/representation.js +23 -0
  56. package/dist/homekit/representation.js.map +1 -0
  57. package/dist/index.js +4 -9
  58. package/dist/index.js.map +1 -1
  59. package/dist/media/contracts.js +2 -0
  60. package/dist/media/contracts.js.map +1 -0
  61. package/dist/media/last-successful-image.js +208 -0
  62. package/dist/media/last-successful-image.js.map +1 -0
  63. package/dist/media/live-stream.js +1003 -0
  64. package/dist/media/live-stream.js.map +1 -0
  65. package/dist/media/recording.js +560 -0
  66. package/dist/media/recording.js.map +1 -0
  67. package/dist/media/session-budget.js +39 -0
  68. package/dist/media/session-budget.js.map +1 -0
  69. package/dist/media/snapshot.js +406 -0
  70. package/dist/media/snapshot.js.map +1 -0
  71. package/dist/media/station-live-sessions.js +101 -0
  72. package/dist/media/station-live-sessions.js.map +1 -0
  73. package/dist/platform.js +97 -809
  74. package/dist/platform.js.map +1 -1
  75. package/dist/runtime/channel.js +375 -0
  76. package/dist/runtime/channel.js.map +1 -0
  77. package/dist/runtime/owner.js +682 -0
  78. package/dist/runtime/owner.js.map +1 -0
  79. package/dist/runtime/sdk-client.js +211 -0
  80. package/dist/runtime/sdk-client.js.map +1 -0
  81. package/dist/runtime/tracker.js +211 -0
  82. package/dist/runtime/tracker.js.map +1 -0
  83. package/dist/settings.js +1 -43
  84. package/dist/settings.js.map +1 -1
  85. package/dist/storage.js +59 -0
  86. package/dist/storage.js.map +1 -0
  87. package/dist/ui/dashboard.js +181 -0
  88. package/dist/ui/dashboard.js.map +1 -0
  89. package/dist/ui/device-image.js +22 -0
  90. package/dist/ui/device-image.js.map +1 -0
  91. package/dist/ui/runtime-channel-client.js +305 -0
  92. package/dist/ui/runtime-channel-client.js.map +1 -0
  93. package/dist/ui/server.js +259 -0
  94. package/dist/ui/server.js.map +1 -0
  95. package/homebridge-ui/public/app.css +1902 -0
  96. package/homebridge-ui/public/assets/devices/clean/clean-T1250.webp +0 -0
  97. package/homebridge-ui/public/assets/devices/clean/clean-T2070.webp +0 -0
  98. package/homebridge-ui/public/assets/devices/clean/clean-T2080.webp +0 -0
  99. package/homebridge-ui/public/assets/devices/clean/clean-T2081.webp +0 -0
  100. package/homebridge-ui/public/assets/devices/clean/clean-T2103.webp +0 -0
  101. package/homebridge-ui/public/assets/devices/clean/clean-T2117.webp +0 -0
  102. package/homebridge-ui/public/assets/devices/clean/clean-T2118.webp +0 -0
  103. package/homebridge-ui/public/assets/devices/clean/clean-T2119.webp +0 -0
  104. package/homebridge-ui/public/assets/devices/clean/clean-T211A.webp +0 -0
  105. package/homebridge-ui/public/assets/devices/clean/clean-T2120.webp +0 -0
  106. package/homebridge-ui/public/assets/devices/clean/clean-T2123.webp +0 -0
  107. package/homebridge-ui/public/assets/devices/clean/clean-T2128.webp +0 -0
  108. package/homebridge-ui/public/assets/devices/clean/clean-T2130.webp +0 -0
  109. package/homebridge-ui/public/assets/devices/clean/clean-T2132.webp +0 -0
  110. package/homebridge-ui/public/assets/devices/clean/clean-T2150.webp +0 -0
  111. package/homebridge-ui/public/assets/devices/clean/clean-T2181.webp +0 -0
  112. package/homebridge-ui/public/assets/devices/clean/clean-T2182.webp +0 -0
  113. package/homebridge-ui/public/assets/devices/clean/clean-T2190.webp +0 -0
  114. package/homebridge-ui/public/assets/devices/clean/clean-T2192.webp +0 -0
  115. package/homebridge-ui/public/assets/devices/clean/clean-T2193.webp +0 -0
  116. package/homebridge-ui/public/assets/devices/clean/clean-T2194.webp +0 -0
  117. package/homebridge-ui/public/assets/devices/clean/clean-T2210.webp +0 -0
  118. package/homebridge-ui/public/assets/devices/clean/clean-T2250.webp +0 -0
  119. package/homebridge-ui/public/assets/devices/clean/clean-T2251.webp +0 -0
  120. package/homebridge-ui/public/assets/devices/clean/clean-T2252.webp +0 -0
  121. package/homebridge-ui/public/assets/devices/clean/clean-T2253.webp +0 -0
  122. package/homebridge-ui/public/assets/devices/clean/clean-T2254.webp +0 -0
  123. package/homebridge-ui/public/assets/devices/clean/clean-T2255.webp +0 -0
  124. package/homebridge-ui/public/assets/devices/clean/clean-T2256.webp +0 -0
  125. package/homebridge-ui/public/assets/devices/clean/clean-T2257.webp +0 -0
  126. package/homebridge-ui/public/assets/devices/clean/clean-T2258.webp +0 -0
  127. package/homebridge-ui/public/assets/devices/clean/clean-T2259.webp +0 -0
  128. package/homebridge-ui/public/assets/devices/clean/clean-T2261.webp +0 -0
  129. package/homebridge-ui/public/assets/devices/clean/clean-T2262.webp +0 -0
  130. package/homebridge-ui/public/assets/devices/clean/clean-T2266.webp +0 -0
  131. package/homebridge-ui/public/assets/devices/clean/clean-T2267.webp +0 -0
  132. package/homebridge-ui/public/assets/devices/clean/clean-T2268.webp +0 -0
  133. package/homebridge-ui/public/assets/devices/clean/clean-T2270.webp +0 -0
  134. package/homebridge-ui/public/assets/devices/clean/clean-T2272.webp +0 -0
  135. package/homebridge-ui/public/assets/devices/clean/clean-T2273.webp +0 -0
  136. package/homebridge-ui/public/assets/devices/clean/clean-T2276.webp +0 -0
  137. package/homebridge-ui/public/assets/devices/clean/clean-T2277.webp +0 -0
  138. package/homebridge-ui/public/assets/devices/clean/clean-T2278.webp +0 -0
  139. package/homebridge-ui/public/assets/devices/clean/clean-T2280.webp +0 -0
  140. package/homebridge-ui/public/assets/devices/clean/clean-T2292.webp +0 -0
  141. package/homebridge-ui/public/assets/devices/clean/clean-T2320.webp +0 -0
  142. package/homebridge-ui/public/assets/devices/clean/clean-T2351.webp +0 -0
  143. package/homebridge-ui/public/assets/devices/clean/clean-T2352.webp +0 -0
  144. package/homebridge-ui/public/assets/devices/clean/clean-T2353.webp +0 -0
  145. package/homebridge-ui/public/assets/devices/life/life-T8L00.webp +0 -0
  146. package/homebridge-ui/public/assets/devices/life/life-T8L01.webp +0 -0
  147. package/homebridge-ui/public/assets/devices/life/life-T8L02.webp +0 -0
  148. package/homebridge-ui/public/assets/devices/life/life-T8L04.webp +0 -0
  149. package/homebridge-ui/public/assets/devices/life/life-T8L10.webp +0 -0
  150. package/homebridge-ui/public/assets/devices/life/life-T8L20.webp +0 -0
  151. package/homebridge-ui/public/assets/devices/life/life-T8L30.webp +0 -0
  152. package/homebridge-ui/public/assets/devices/life/life-T8L40.webp +0 -0
  153. package/homebridge-ui/public/assets/devices/mower/mower-T2801.webp +0 -0
  154. package/homebridge-ui/public/assets/devices/mower/mower-T280B.webp +0 -0
  155. package/homebridge-ui/public/assets/devices/mower/mower-T2880.webp +0 -0
  156. package/homebridge-ui/public/assets/devices/security/security-T7400.webp +0 -0
  157. package/homebridge-ui/public/assets/devices/security/security-T7401.webp +0 -0
  158. package/homebridge-ui/public/assets/devices/security/security-T8001.webp +0 -0
  159. package/homebridge-ui/public/assets/devices/security/security-T8002.webp +0 -0
  160. package/homebridge-ui/public/assets/devices/security/security-T8010.webp +0 -0
  161. package/homebridge-ui/public/assets/devices/security/security-T8021.webp +0 -0
  162. package/homebridge-ui/public/assets/devices/security/security-T8023.webp +0 -0
  163. package/homebridge-ui/public/assets/devices/security/security-T8025.webp +0 -0
  164. package/homebridge-ui/public/assets/devices/security/security-T8030.webp +0 -0
  165. package/homebridge-ui/public/assets/devices/security/security-T8110.webp +0 -0
  166. package/homebridge-ui/public/assets/devices/security/security-T8111.webp +0 -0
  167. package/homebridge-ui/public/assets/devices/security/security-T8112.webp +0 -0
  168. package/homebridge-ui/public/assets/devices/security/security-T8113.webp +0 -0
  169. package/homebridge-ui/public/assets/devices/security/security-T8114.webp +0 -0
  170. package/homebridge-ui/public/assets/devices/security/security-T8122.webp +0 -0
  171. package/homebridge-ui/public/assets/devices/security/security-T8123.webp +0 -0
  172. package/homebridge-ui/public/assets/devices/security/security-T8124.webp +0 -0
  173. package/homebridge-ui/public/assets/devices/security/security-T8130.webp +0 -0
  174. package/homebridge-ui/public/assets/devices/security/security-T8131.webp +0 -0
  175. package/homebridge-ui/public/assets/devices/security/security-T8134.webp +0 -0
  176. package/homebridge-ui/public/assets/devices/security/security-T8140.webp +0 -0
  177. package/homebridge-ui/public/assets/devices/security/security-T8141.webp +0 -0
  178. package/homebridge-ui/public/assets/devices/security/security-T8150.webp +0 -0
  179. package/homebridge-ui/public/assets/devices/security/security-T8151.webp +0 -0
  180. package/homebridge-ui/public/assets/devices/security/security-T8152.webp +0 -0
  181. package/homebridge-ui/public/assets/devices/security/security-T8153.webp +0 -0
  182. package/homebridge-ui/public/assets/devices/security/security-T8160.webp +0 -0
  183. package/homebridge-ui/public/assets/devices/security/security-T8161.webp +0 -0
  184. package/homebridge-ui/public/assets/devices/security/security-T8162.webp +0 -0
  185. package/homebridge-ui/public/assets/devices/security/security-T8170.webp +0 -0
  186. package/homebridge-ui/public/assets/devices/security/security-T8171.webp +0 -0
  187. package/homebridge-ui/public/assets/devices/security/security-T8172.webp +0 -0
  188. package/homebridge-ui/public/assets/devices/security/security-T8173.webp +0 -0
  189. package/homebridge-ui/public/assets/devices/security/security-T8200.webp +0 -0
  190. package/homebridge-ui/public/assets/devices/security/security-T8200X.webp +0 -0
  191. package/homebridge-ui/public/assets/devices/security/security-T8201.webp +0 -0
  192. package/homebridge-ui/public/assets/devices/security/security-T8203.webp +0 -0
  193. package/homebridge-ui/public/assets/devices/security/security-T8210.webp +0 -0
  194. package/homebridge-ui/public/assets/devices/security/security-T8213.webp +0 -0
  195. package/homebridge-ui/public/assets/devices/security/security-T8214.webp +0 -0
  196. package/homebridge-ui/public/assets/devices/security/security-T8222.webp +0 -0
  197. package/homebridge-ui/public/assets/devices/security/security-T8400.webp +0 -0
  198. package/homebridge-ui/public/assets/devices/security/security-T8401.webp +0 -0
  199. package/homebridge-ui/public/assets/devices/security/security-T8410.webp +0 -0
  200. package/homebridge-ui/public/assets/devices/security/security-T8411.webp +0 -0
  201. package/homebridge-ui/public/assets/devices/security/security-T8414.webp +0 -0
  202. package/homebridge-ui/public/assets/devices/security/security-T8416.webp +0 -0
  203. package/homebridge-ui/public/assets/devices/security/security-T8417.webp +0 -0
  204. package/homebridge-ui/public/assets/devices/security/security-T8419.webp +0 -0
  205. package/homebridge-ui/public/assets/devices/security/security-T8419N.webp +0 -0
  206. package/homebridge-ui/public/assets/devices/security/security-T8420.webp +0 -0
  207. package/homebridge-ui/public/assets/devices/security/security-T8420X.webp +0 -0
  208. package/homebridge-ui/public/assets/devices/security/security-T8422.webp +0 -0
  209. package/homebridge-ui/public/assets/devices/security/security-T8423.webp +0 -0
  210. package/homebridge-ui/public/assets/devices/security/security-T8424.webp +0 -0
  211. package/homebridge-ui/public/assets/devices/security/security-T8425.webp +0 -0
  212. package/homebridge-ui/public/assets/devices/security/security-T8441.webp +0 -0
  213. package/homebridge-ui/public/assets/devices/security/security-T8442.webp +0 -0
  214. package/homebridge-ui/public/assets/devices/security/security-T8452.webp +0 -0
  215. package/homebridge-ui/public/assets/devices/security/security-T84A0.webp +0 -0
  216. package/homebridge-ui/public/assets/devices/security/security-T84A1.webp +0 -0
  217. package/homebridge-ui/public/assets/devices/security/security-T8500.webp +0 -0
  218. package/homebridge-ui/public/assets/devices/security/security-T8502.webp +0 -0
  219. package/homebridge-ui/public/assets/devices/security/security-T8503.webp +0 -0
  220. package/homebridge-ui/public/assets/devices/security/security-T8504.webp +0 -0
  221. package/homebridge-ui/public/assets/devices/security/security-T8506.webp +0 -0
  222. package/homebridge-ui/public/assets/devices/security/security-T8510.webp +0 -0
  223. package/homebridge-ui/public/assets/devices/security/security-T8510P.webp +0 -0
  224. package/homebridge-ui/public/assets/devices/security/security-T8520.webp +0 -0
  225. package/homebridge-ui/public/assets/devices/security/security-T8520P.webp +0 -0
  226. package/homebridge-ui/public/assets/devices/security/security-T8530.webp +0 -0
  227. package/homebridge-ui/public/assets/devices/security/security-T8531.webp +0 -0
  228. package/homebridge-ui/public/assets/devices/security/security-T85D0.webp +0 -0
  229. package/homebridge-ui/public/assets/devices/security/security-T85L0.webp +0 -0
  230. package/homebridge-ui/public/assets/devices/security/security-T85P0.webp +0 -0
  231. package/homebridge-ui/public/assets/devices/security/security-T85V0.webp +0 -0
  232. package/homebridge-ui/public/assets/devices/security/security-T8600.webp +0 -0
  233. package/homebridge-ui/public/assets/devices/security/security-T86P2.webp +0 -0
  234. package/homebridge-ui/public/assets/devices/security/security-T8790.webp +0 -0
  235. package/homebridge-ui/public/assets/devices/security/security-T87B0.webp +0 -0
  236. package/homebridge-ui/public/assets/devices/security/security-T87B2.webp +0 -0
  237. package/homebridge-ui/public/assets/devices/security/security-T8900.webp +0 -0
  238. package/homebridge-ui/public/assets/devices/security/security-T8910.webp +0 -0
  239. package/homebridge-ui/public/assets/devices/security/security-T8920.webp +0 -0
  240. package/homebridge-ui/public/assets/devices/security/security-T8960.webp +0 -0
  241. package/homebridge-ui/public/assets/devices/security/security-T8B0.webp +0 -0
  242. package/homebridge-ui/public/assets/devices/security/security-T8E00.webp +0 -0
  243. package/homebridge-ui/public/assets/devices/security/security-T8N00.webp +0 -0
  244. package/homebridge-ui/public/assets/devices/security/security-T8W11C.webp +0 -0
  245. package/homebridge-ui/public/assets/devices/security/security-T90F0.webp +0 -0
  246. package/homebridge-ui/public/assets/devices/security/security-T90M0.webp +0 -0
  247. package/homebridge-ui/public/assets/devices/security/security-T90R0.webp +0 -0
  248. package/homebridge-ui/public/assets/devices/security/security-T90S0.webp +0 -0
  249. package/homebridge-ui/public/assets/icons/inventory.svg +1 -1
  250. package/homebridge-ui/public/assets/icons/troubleshoot.svg +1 -0
  251. package/homebridge-ui/public/assets/icons/warning.svg +1 -1
  252. package/homebridge-ui/public/assets/logo-dark.svg +10 -0
  253. package/homebridge-ui/public/assets/logo.svg +10 -0
  254. package/homebridge-ui/public/i18n/en.json +218 -0
  255. package/homebridge-ui/public/i18n/fr.json +218 -0
  256. package/homebridge-ui/public/index.html +377 -28
  257. package/homebridge-ui/public/js/app.js +1065 -0
  258. package/homebridge-ui/public/js/dashboard.js +385 -0
  259. package/homebridge-ui/public/js/legacy-settings.js +37 -0
  260. package/homebridge-ui/public/js/profile-wizard.js +68 -0
  261. package/homebridge-ui/server.js +2 -1393
  262. package/i18n/runtime/en.json +100 -0
  263. package/media/Snapshot-Unavailable.jpg +0 -0
  264. package/media/Snapshot-black.jpg +0 -0
  265. package/media/camera-disabled.jpg +0 -0
  266. package/media/camera-offline.jpg +0 -0
  267. package/package.json +29 -24
  268. package/.claude/CLAUDE.md +0 -175
  269. package/.claude/PRD.md +0 -241
  270. package/.claude/docs/debug-recording-lessons.md +0 -91
  271. package/.claude/docs/hksv-recording-fix.md +0 -160
  272. package/.claude/skills/architect/SKILL.md +0 -76
  273. package/.claude/skills/developer/SKILL.md +0 -59
  274. package/.claude/skills/new-device-support/SKILL.md +0 -212
  275. package/.claude/skills/new-device-support/check-device.mjs +0 -363
  276. package/.claude/skills/new-device-support/map-properties.mjs +0 -450
  277. package/.claude/skills/new-device-support/verify-device.mjs +0 -272
  278. package/.claude/skills/planner/SKILL.md +0 -100
  279. package/.claude/skills/qa/SKILL.md +0 -79
  280. package/.claude/skills/support/SKILL.md +0 -175
  281. package/.prettierignore +0 -7
  282. package/.prettierrc.json +0 -7
  283. package/FUNDING.yml +0 -1
  284. package/dist/accessories/AutoSyncStationAccessory.js +0 -157
  285. package/dist/accessories/AutoSyncStationAccessory.js.map +0 -1
  286. package/dist/accessories/BaseAccessory.js +0 -261
  287. package/dist/accessories/BaseAccessory.js.map +0 -1
  288. package/dist/accessories/CameraAccessory.js +0 -459
  289. package/dist/accessories/CameraAccessory.js.map +0 -1
  290. package/dist/accessories/Device.js +0 -65
  291. package/dist/accessories/Device.js.map +0 -1
  292. package/dist/accessories/EntrySensorAccessory.js +0 -48
  293. package/dist/accessories/EntrySensorAccessory.js.map +0 -1
  294. package/dist/accessories/GarageDoorAccessory.js +0 -160
  295. package/dist/accessories/GarageDoorAccessory.js.map +0 -1
  296. package/dist/accessories/LockAccessory.js +0 -142
  297. package/dist/accessories/LockAccessory.js.map +0 -1
  298. package/dist/accessories/MotionSensorAccessory.js +0 -48
  299. package/dist/accessories/MotionSensorAccessory.js.map +0 -1
  300. package/dist/accessories/SmartDropAccessory.js +0 -141
  301. package/dist/accessories/SmartDropAccessory.js.map +0 -1
  302. package/dist/accessories/StationAccessory.js +0 -373
  303. package/dist/accessories/StationAccessory.js.map +0 -1
  304. package/dist/config.js +0 -26
  305. package/dist/config.js.map +0 -1
  306. package/dist/controller/DebugRecordingManager.js +0 -402
  307. package/dist/controller/DebugRecordingManager.js.map +0 -1
  308. package/dist/controller/LocalLivestreamManager.js +0 -371
  309. package/dist/controller/LocalLivestreamManager.js.map +0 -1
  310. package/dist/controller/recordingDelegate.js +0 -252
  311. package/dist/controller/recordingDelegate.js.map +0 -1
  312. package/dist/controller/snapshotDelegate.js +0 -348
  313. package/dist/controller/snapshotDelegate.js.map +0 -1
  314. package/dist/controller/streamingDelegate.js +0 -389
  315. package/dist/controller/streamingDelegate.js.map +0 -1
  316. package/dist/interfaces.js +0 -2
  317. package/dist/interfaces.js.map +0 -1
  318. package/dist/media/Snapshot-Unavailable.png +0 -0
  319. package/dist/media/Snapshot-Unavailable.xcf +0 -0
  320. package/dist/media/Snapshot-black.png +0 -0
  321. package/dist/media/camera-disabled.png +0 -0
  322. package/dist/media/camera-offline.png +0 -0
  323. package/dist/media/media/Snapshot-Unavailable.png +0 -0
  324. package/dist/media/media/Snapshot-Unavailable.xcf +0 -0
  325. package/dist/media/media/Snapshot-black.png +0 -0
  326. package/dist/media/media/camera-disabled.png +0 -0
  327. package/dist/media/media/camera-offline.png +0 -0
  328. package/dist/utils/Talkback.js +0 -162
  329. package/dist/utils/Talkback.js.map +0 -1
  330. package/dist/utils/accessoriesStore.js +0 -210
  331. package/dist/utils/accessoriesStore.js.map +0 -1
  332. package/dist/utils/configTypes.js +0 -38
  333. package/dist/utils/configTypes.js.map +0 -1
  334. package/dist/utils/ffmpeg.js +0 -1111
  335. package/dist/utils/ffmpeg.js.map +0 -1
  336. package/dist/utils/interfaces.js +0 -8
  337. package/dist/utils/interfaces.js.map +0 -1
  338. package/dist/utils/utils.js +0 -224
  339. package/dist/utils/utils.js.map +0 -1
  340. package/dist/version.js +0 -2
  341. package/dist/version.js.map +0 -1
  342. package/homebridge-eufy-security.png +0 -0
  343. package/homebridge-ui/diagnosticsCrypto.js +0 -112
  344. package/homebridge-ui/public/app.js +0 -237
  345. package/homebridge-ui/public/assets/devices/4g_lte_cam_s330_large.png +0 -0
  346. package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
  347. package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C30.png +0 -0
  348. package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C31.png +0 -0
  349. package/homebridge-ui/public/assets/devices/batterydoorbell1080p_large.jpg +0 -0
  350. package/homebridge-ui/public/assets/devices/batterydoorbell2k_large.png +0 -0
  351. package/homebridge-ui/public/assets/devices/batterydoorbell2kdual_large.jpg +0 -0
  352. package/homebridge-ui/public/assets/devices/batterydoorbell_e340_large.png +0 -0
  353. package/homebridge-ui/public/assets/devices/eufy-security-client.png +0 -0
  354. package/homebridge-ui/public/assets/devices/eufyCamS4_large.png +0 -0
  355. package/homebridge-ui/public/assets/devices/eufycam2_large.png +0 -0
  356. package/homebridge-ui/public/assets/devices/eufycam2c_large.jpg +0 -0
  357. package/homebridge-ui/public/assets/devices/eufycam2cpro_large.jpg +0 -0
  358. package/homebridge-ui/public/assets/devices/eufycam2pro_large.jpg +0 -0
  359. package/homebridge-ui/public/assets/devices/eufycam3_large.jpg +0 -0
  360. package/homebridge-ui/public/assets/devices/eufycam3c_large.jpg +0 -0
  361. package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
  362. package/homebridge-ui/public/assets/devices/eufycam_large.jpg +0 -0
  363. package/homebridge-ui/public/assets/devices/eufycame330_large.jpg +0 -0
  364. package/homebridge-ui/public/assets/devices/flood_freeze_sensor_e20_t90F0_large.png +0 -0
  365. package/homebridge-ui/public/assets/devices/floodlight2_large.jpg +0 -0
  366. package/homebridge-ui/public/assets/devices/floodlight2pro_large.jpg +0 -0
  367. package/homebridge-ui/public/assets/devices/floodlight_large.jpg +0 -0
  368. package/homebridge-ui/public/assets/devices/floodlightcame340_large.jpg +0 -0
  369. package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.png +0 -0
  370. package/homebridge-ui/public/assets/devices/homebase2_large.png +0 -0
  371. package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
  372. package/homebridge-ui/public/assets/devices/homebase_large.jpg +0 -0
  373. package/homebridge-ui/public/assets/devices/homebasemini_large.png +0 -0
  374. package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
  375. package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
  376. package/homebridge-ui/public/assets/devices/indoorcamC220_t8419N_large.png +0 -0
  377. package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
  378. package/homebridge-ui/public/assets/devices/indoorcamc120_large.png +0 -0
  379. package/homebridge-ui/public/assets/devices/indoorcammini_large.jpg +0 -0
  380. package/homebridge-ui/public/assets/devices/indoorcamp24_large.png +0 -0
  381. package/homebridge-ui/public/assets/devices/indoorcams350_large.png +0 -0
  382. package/homebridge-ui/public/assets/devices/keypad_large.png +0 -0
  383. package/homebridge-ui/public/assets/devices/minibase_chime_T8023_large.jpg +0 -0
  384. package/homebridge-ui/public/assets/devices/motionsensor_large.png +0 -0
  385. package/homebridge-ui/public/assets/devices/nvr_s4_max_T8N00_large.png +0 -0
  386. package/homebridge-ui/public/assets/devices/pir_sensor_e20_large.png +0 -0
  387. package/homebridge-ui/public/assets/devices/poe_bullet_ptz_cam_s4_T8E00_large.png +0 -0
  388. package/homebridge-ui/public/assets/devices/sensor_large.png +0 -0
  389. package/homebridge-ui/public/assets/devices/siren_sensor_e20_large.png +0 -0
  390. package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.png +0 -0
  391. package/homebridge-ui/public/assets/devices/smartlock_t8500_large.png +0 -0
  392. package/homebridge-ui/public/assets/devices/smartlock_t8500_wifibridge_large.jpg +0 -0
  393. package/homebridge-ui/public/assets/devices/smartlock_t8503_large.png +0 -0
  394. package/homebridge-ui/public/assets/devices/smartlock_t8504_large.jpg +0 -0
  395. package/homebridge-ui/public/assets/devices/smartlock_t8510P_t8520P_large.png +0 -0
  396. package/homebridge-ui/public/assets/devices/smartlock_t85D0_large.png +0 -0
  397. package/homebridge-ui/public/assets/devices/smartlock_t85L0_large.png +0 -0
  398. package/homebridge-ui/public/assets/devices/smartlock_t85P0_large.png +0 -0
  399. package/homebridge-ui/public/assets/devices/smartlock_t85V0_large.png +0 -0
  400. package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8502_large.png +0 -0
  401. package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8506_large.png +0 -0
  402. package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8520_large.png +0 -0
  403. package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_large.png +0 -0
  404. package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_wifibridge_large.jpg +0 -0
  405. package/homebridge-ui/public/assets/devices/smartlock_video_t8530_large.png +0 -0
  406. package/homebridge-ui/public/assets/devices/smartlock_video_t8531_large.png +0 -0
  407. package/homebridge-ui/public/assets/devices/smartlockwifibridge_t8021_large.jpg +0 -0
  408. package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.png +0 -0
  409. package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.png +0 -0
  410. package/homebridge-ui/public/assets/devices/smarttrack_card_t87B2_large.png +0 -0
  411. package/homebridge-ui/public/assets/devices/smarttrack_link_t87B0_large.png +0 -0
  412. package/homebridge-ui/public/assets/devices/smoke_alarm_e10_t90S0_large.png +0 -0
  413. package/homebridge-ui/public/assets/devices/solocamc210_large.jpg +0 -0
  414. package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
  415. package/homebridge-ui/public/assets/devices/solocame20_large.jpg +0 -0
  416. package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
  417. package/homebridge-ui/public/assets/devices/solocame40_large.jpg +0 -0
  418. package/homebridge-ui/public/assets/devices/solocame42_large.png +0 -0
  419. package/homebridge-ui/public/assets/devices/solocaml20_large.jpg +0 -0
  420. package/homebridge-ui/public/assets/devices/solocams220_large.jpg +0 -0
  421. package/homebridge-ui/public/assets/devices/solocams340_large.png +0 -0
  422. package/homebridge-ui/public/assets/devices/solocams40_large.jpg +0 -0
  423. package/homebridge-ui/public/assets/devices/soloindoorcamc24_large.jpg +0 -0
  424. package/homebridge-ui/public/assets/devices/solooutdoorcamc22_large.png +0 -0
  425. package/homebridge-ui/public/assets/devices/solooutdoorcamc24_large.jpg +0 -0
  426. package/homebridge-ui/public/assets/devices/unknown.png +0 -0
  427. package/homebridge-ui/public/assets/devices/walllight_s100_large.png +0 -0
  428. package/homebridge-ui/public/assets/devices/walllight_s120_large.png +0 -0
  429. package/homebridge-ui/public/assets/devices/water_freeze_sensor_t8920_large.png +0 -0
  430. package/homebridge-ui/public/assets/devices/wireddoorbell1080p_large.jpg +0 -0
  431. package/homebridge-ui/public/assets/devices/wireddoorbell2k_large.png +0 -0
  432. package/homebridge-ui/public/assets/devices/wireddoorbelldual_large.jpg +0 -0
  433. package/homebridge-ui/public/assets/icons/attach.svg +0 -1
  434. package/homebridge-ui/public/assets/icons/battery_0.svg +0 -1
  435. package/homebridge-ui/public/assets/icons/battery_1.svg +0 -1
  436. package/homebridge-ui/public/assets/icons/battery_2.svg +0 -1
  437. package/homebridge-ui/public/assets/icons/battery_3.svg +0 -1
  438. package/homebridge-ui/public/assets/icons/battery_4.svg +0 -1
  439. package/homebridge-ui/public/assets/icons/battery_5.svg +0 -1
  440. package/homebridge-ui/public/assets/icons/battery_6.svg +0 -1
  441. package/homebridge-ui/public/assets/icons/copy.svg +0 -1
  442. package/homebridge-ui/public/assets/icons/delete.svg +0 -1
  443. package/homebridge-ui/public/assets/icons/download.svg +0 -1
  444. package/homebridge-ui/public/assets/icons/info.svg +0 -1
  445. package/homebridge-ui/public/assets/icons/refresh.svg +0 -1
  446. package/homebridge-ui/public/assets/icons/satellite_alt.svg +0 -1
  447. package/homebridge-ui/public/assets/icons/solar_power.svg +0 -1
  448. package/homebridge-ui/public/components/device-card.js +0 -174
  449. package/homebridge-ui/public/components/guard-modes.js +0 -88
  450. package/homebridge-ui/public/components/number-input.js +0 -121
  451. package/homebridge-ui/public/components/select.js +0 -73
  452. package/homebridge-ui/public/components/toggle.js +0 -68
  453. package/homebridge-ui/public/services/api.js +0 -250
  454. package/homebridge-ui/public/services/config.js +0 -144
  455. package/homebridge-ui/public/style.css +0 -818
  456. package/homebridge-ui/public/utils/countries.js +0 -73
  457. package/homebridge-ui/public/utils/device-images.js +0 -102
  458. package/homebridge-ui/public/utils/helpers.js +0 -115
  459. package/homebridge-ui/public/views/dashboard.js +0 -226
  460. package/homebridge-ui/public/views/device-detail.js +0 -654
  461. package/homebridge-ui/public/views/diagnostics.js +0 -402
  462. package/homebridge-ui/public/views/login.js +0 -650
  463. package/homebridge-ui/public/views/recordings.js +0 -319
  464. package/homebridge-ui/public/views/settings.js +0 -197
  465. package/homebridge-ui/public/views/unsupported-detail.js +0 -296
  466. package/media/Snapshot-Unavailable.png +0 -0
  467. package/media/Snapshot-Unavailable.xcf +0 -0
  468. package/media/Snapshot-black.png +0 -0
  469. package/media/camera-disabled.png +0 -0
  470. package/media/camera-offline.png +0 -0
  471. package/scripts/decrypt-diagnostics.mjs +0 -257
@@ -1,654 +0,0 @@
1
- /**
2
- * Device Detail View — per-device/station settings with progressive disclosure.
3
- * Simple mode shows 3-4 toggles, Advanced expands full options.
4
- */
5
- // eslint-disable-next-line no-unused-vars
6
- const DeviceDetailView = {
7
-
8
- _container: null,
9
- _advancedOpen: false,
10
- _expertOpen: false,
11
-
12
- /**
13
- * @param {HTMLElement} container
14
- * @param {string} type - 'device' or 'station'
15
- * @param {string} id - uniqueId / serial number
16
- */
17
- async render(container, type, id) {
18
- this._container = container;
19
- this._advancedOpen = false;
20
- this._expertOpen = false;
21
- container.innerHTML = '';
22
-
23
- const config = await Config.get();
24
- const { station, device } = this._findAccessory(type, id);
25
-
26
- if (!station && !device) {
27
- container.innerHTML = `
28
- <div class="text-center text-muted py-5">
29
- <p>Device not found.</p>
30
- <button class="btn btn-outline-secondary btn-sm" id="btn-back">Back to Dashboard</button>
31
- </div>`;
32
- container.querySelector('#btn-back').addEventListener('click', () => App.navigate('dashboard'));
33
- return;
34
- }
35
-
36
- // For unsupported standalone stations routed as 'device', the device is null — use station
37
- const accessory = (type === 'station' ? station : device) || station;
38
- const isUnsupported = accessory && accessory.unsupported === true;
39
-
40
- // Redirect unsupported devices to their dedicated view
41
- if (isUnsupported) {
42
- App.navigate('unsupported/' + accessory.uniqueId);
43
- return;
44
- }
45
-
46
- // Keypads have no configurable HomeKit settings — redirect back to dashboard
47
- if (accessory.isKeypad === true) {
48
- App.navigate('dashboard');
49
- return;
50
- }
51
-
52
- // Header with back button + device image
53
- this._renderHeader(container, accessory, type);
54
-
55
- // Main content area
56
- const content = document.createElement('div');
57
-
58
- if (type === 'device' && device) {
59
- const accessoryConfig = type === 'station'
60
- ? Config.getStationConfig(id)
61
- : Config.getDeviceConfig(id);
62
- this._renderDeviceSettings(content, device, accessoryConfig || {}, config);
63
-
64
- // For standalone devices, also show station settings (if station supports security control)
65
- if (device.standalone && station && !station.noSecurityControl) {
66
- const stationConfig = Config.getStationConfig(station.uniqueId) || {};
67
- this._renderStandaloneStationSection(content, station, stationConfig, config);
68
- }
69
- } else if (type === 'station' && station) {
70
- const accessoryConfig = Config.getStationConfig(id);
71
- this._renderStationSettings(content, station, accessoryConfig || {}, config);
72
- }
73
-
74
- container.appendChild(content);
75
-
76
-
77
- },
78
-
79
- // ===== Header =====
80
- _renderHeader(container, accessory, type) {
81
- const header = document.createElement('div');
82
- header.className = 'detail-header';
83
-
84
- const backBtn = document.createElement('button');
85
- backBtn.className = 'btn btn-link p-0';
86
- backBtn.innerHTML = '← Back';
87
- backBtn.style.textDecoration = 'none';
88
- backBtn.addEventListener('click', () => App.navigate('dashboard'));
89
-
90
- const info = document.createElement('div');
91
- info.className = 'detail-header__info';
92
- info.innerHTML = `
93
- <h5>${this._escHtml(accessory.displayName)}</h5>
94
- <small>${accessory.typename || ('Type ' + accessory.type)} · ${accessory.uniqueId}</small>
95
- `;
96
-
97
- header.appendChild(backBtn);
98
-
99
- const img = document.createElement('img');
100
- img.className = 'detail-header__image';
101
- img.src = DeviceImages.getPath(accessory.type);
102
- img.alt = accessory.displayName;
103
- header.appendChild(img);
104
-
105
- header.appendChild(info);
106
- container.appendChild(header);
107
- },
108
-
109
- // ===== Device Settings (Camera/Doorbell/Sensor/Lock) =====
110
- _renderDeviceSettings(content, device, deviceConfig, config) {
111
- const ignoreDevices = config.ignoreDevices || [];
112
- const isIgnored = ignoreDevices.includes(device.uniqueId);
113
-
114
- // ── Enable in HomeKit (always visible) ──
115
- const enableSection = document.createElement('div');
116
- enableSection.className = 'detail-section';
117
-
118
- const enableTitle = document.createElement('div');
119
- enableTitle.className = 'detail-section__title';
120
- enableTitle.textContent = 'Device Settings';
121
- enableSection.appendChild(enableTitle);
122
-
123
- Toggle.render(enableSection, {
124
- id: 'toggle-enable',
125
- label: 'Enable in HomeKit',
126
- help: 'When disabled, this device will not appear in the Home app.',
127
- checked: !isIgnored,
128
- onChange: async (checked) => {
129
- await Config.toggleIgnore(device.uniqueId, !checked, 'device');
130
- const rest = content.querySelector('#device-rest-settings');
131
- if (rest) rest.style.display = checked ? '' : 'none';
132
- },
133
- });
134
-
135
- content.appendChild(enableSection);
136
-
137
- // Wrapper for all settings below Enable toggle — hidden when device is ignored
138
- const restSettings = document.createElement('div');
139
- restSettings.id = 'device-rest-settings';
140
- if (isIgnored) restSettings.style.display = 'none';
141
-
142
- // ── Simple Settings ──
143
- const simpleSection = document.createElement('div');
144
- simpleSection.className = 'detail-section';
145
-
146
- // Camera-specific simple settings
147
- if (device.isCamera) {
148
- Toggle.render(simpleSection, {
149
- id: 'toggle-camera-enable',
150
- label: 'Camera Feed',
151
- help: 'Show camera feed in HomeKit. Disable to expose only sensors.',
152
- checked: deviceConfig.enableCamera !== false,
153
- onChange: async (checked) => {
154
- await Config.updateDeviceConfig(device.uniqueId, { enableCamera: checked });
155
- },
156
- });
157
-
158
- }
159
-
160
- // Garage door toggles (simple settings level)
161
- if (device.isGarageCamera) {
162
- if (device.hasDoor1) {
163
- Toggle.render(simpleSection, {
164
- id: 'toggle-door1',
165
- label: 'Door 1',
166
- help: 'Expose garage door 1 as a GarageDoorOpener in HomeKit.',
167
- checked: deviceConfig.enableDoor1 !== false,
168
- onChange: async (checked) => {
169
- await Config.updateDeviceConfig(device.uniqueId, { enableDoor1: checked });
170
- },
171
- });
172
- }
173
-
174
- if (device.hasDoor2) {
175
- Toggle.render(simpleSection, {
176
- id: 'toggle-door2',
177
- label: 'Door 2',
178
- help: 'Expose garage door 2 as a GarageDoorOpener in HomeKit.',
179
- checked: !!deviceConfig.enableDoor2,
180
- onChange: async (checked) => {
181
- await Config.updateDeviceConfig(device.uniqueId, { enableDoor2: checked });
182
- },
183
- });
184
- }
185
- }
186
-
187
- restSettings.appendChild(simpleSection);
188
-
189
- // ── Advanced Settings (collapsed by default) ──
190
- if (device.isCamera) {
191
- this._renderAdvancedToggle(restSettings, () => {
192
- this._advancedOpen = !this._advancedOpen;
193
- const advSection = content.querySelector('#advanced-section');
194
- if (advSection) advSection.style.display = this._advancedOpen ? 'block' : 'none';
195
- const chevron = content.querySelector('.advanced-toggle__chevron');
196
- if (chevron) chevron.classList.toggle('advanced-toggle__chevron--open', this._advancedOpen);
197
- });
198
-
199
- const advSection = document.createElement('div');
200
- advSection.id = 'advanced-section';
201
- advSection.style.display = 'none';
202
-
203
- // ── Streaming ──
204
- const streamTitle = document.createElement('div');
205
- streamTitle.className = 'detail-section__title';
206
- streamTitle.textContent = 'Streaming';
207
- advSection.appendChild(streamTitle);
208
-
209
- if (device.supportsRTSP) {
210
- Toggle.render(advSection, {
211
- id: 'toggle-rtsp',
212
- label: 'RTSP Streaming',
213
- help: 'Use RTSP stream instead of P2P. Requires the camera to have RTSP enabled in the Eufy app.',
214
- checked: !!deviceConfig.rtsp,
215
- onChange: async (checked) => {
216
- await Config.updateDeviceConfig(device.uniqueId, { rtsp: checked });
217
- },
218
- });
219
- }
220
-
221
- Toggle.render(advSection, {
222
- id: 'toggle-audio',
223
- label: 'Audio',
224
- help: 'Include audio in camera streams and recordings.',
225
- checked: deviceConfig.audio !== false,
226
- onChange: async (checked) => {
227
- await Config.updateDeviceConfig(device.uniqueId, { audio: checked });
228
- },
229
- });
230
-
231
- if (device.supportsTalkback) {
232
- Toggle.render(advSection, {
233
- id: 'toggle-talkback',
234
- label: 'Two-Way Audio',
235
- help: 'Enable talkback / two-way audio in HomeKit.',
236
- checked: !!deviceConfig.talkback,
237
- onChange: async (checked) => {
238
- await Config.updateDeviceConfig(device.uniqueId, { talkback: checked });
239
- },
240
- });
241
- }
242
-
243
- // ── HomeKit Secure Video ──
244
- const hsvTitle = document.createElement('div');
245
- hsvTitle.className = 'detail-section__title';
246
- hsvTitle.textContent = 'HomeKit Secure Video';
247
- advSection.appendChild(hsvTitle);
248
-
249
- NumberInput.render(advSection, {
250
- id: 'num-hsv-duration',
251
- label: 'HSV Recording Duration',
252
- help: 'Maximum recording duration in seconds for HSV clips.',
253
- value: deviceConfig.hsvRecordingDuration || 90,
254
- min: 10,
255
- max: 300,
256
- step: 10,
257
- suffix: 'sec',
258
- onChange: async (val) => {
259
- await Config.updateDeviceConfig(device.uniqueId, { hsvRecordingDuration: val });
260
- },
261
- });
262
-
263
- // ── Snapshots ──
264
- const snapTitle = document.createElement('div');
265
- snapTitle.className = 'detail-section__title';
266
- snapTitle.textContent = 'Snapshots';
267
- advSection.appendChild(snapTitle);
268
-
269
- Select.render(advSection, {
270
- id: 'select-snapshot-method',
271
- label: 'Snapshot Method',
272
- help: 'How to capture snapshots. "Auto" lets the plugin decide the best method.',
273
- options: [
274
- { value: '0', label: 'Auto' },
275
- { value: '1', label: 'From Livestream' },
276
- { value: '2', label: 'From Cloud' },
277
- { value: '3', label: 'Preload on Event' },
278
- ],
279
- value: String(deviceConfig.snapshotHandlingMethod || 0),
280
- onChange: async (val) => {
281
- await Config.updateDeviceConfig(device.uniqueId, { snapshotHandlingMethod: parseInt(val) });
282
- },
283
- });
284
-
285
- Toggle.render(advSection, {
286
- id: 'toggle-delay-snapshot',
287
- label: 'Delay Snapshot Capture',
288
- help: 'Wait briefly before taking a snapshot to get a clearer image.',
289
- checked: !!deviceConfig.delayCameraSnapshot,
290
- onChange: async (checked) => {
291
- await Config.updateDeviceConfig(device.uniqueId, { delayCameraSnapshot: checked });
292
- },
293
- });
294
-
295
- // ── Camera Buttons ──
296
- const btnTitle = document.createElement('div');
297
- btnTitle.className = 'detail-section__title';
298
- btnTitle.textContent = 'Camera Buttons';
299
- advSection.appendChild(btnTitle);
300
-
301
- if (device.DeviceMotionDetection) {
302
- Toggle.render(advSection, {
303
- id: 'toggle-motion',
304
- label: 'Motion Detection Toggle',
305
- help: 'Adds a virtual switch to HomeKit that lets you turn motion detection on or off. The motion sensor itself is always active — this only controls whether detection events are triggered.',
306
- checked: !!deviceConfig.motionButton,
307
- onChange: async (checked) => {
308
- await Config.updateDeviceConfig(device.uniqueId, { motionButton: checked });
309
- },
310
- });
311
- }
312
-
313
- Toggle.render(advSection, {
314
- id: 'toggle-enable-btn',
315
- label: 'Camera Enable Toggle',
316
- help: 'Adds a virtual switch to HomeKit that lets you enable or disable the camera. When the camera is disabled, streaming and recording stop but the device remains registered.',
317
- checked: !!deviceConfig.enableButton,
318
- onChange: async (checked) => {
319
- await Config.updateDeviceConfig(device.uniqueId, { enableButton: checked });
320
- },
321
- });
322
-
323
- if (device.DeviceLight) {
324
- Toggle.render(advSection, {
325
- id: 'toggle-light-btn',
326
- label: 'Spotlight / Floodlight Toggle',
327
- help: 'Adds a virtual switch to HomeKit that lets you turn the camera\'s built-in spotlight or floodlight on and off.',
328
- checked: !!deviceConfig.lightButton,
329
- onChange: async (checked) => {
330
- await Config.updateDeviceConfig(device.uniqueId, { lightButton: checked });
331
- },
332
- });
333
- }
334
-
335
- if (device.DeviceChimeIndoor) {
336
- Toggle.render(advSection, {
337
- id: 'toggle-chime-btn',
338
- label: 'Indoor Chime Toggle',
339
- help: 'Adds a virtual switch to HomeKit that lets you mute or unmute the indoor chime when the doorbell is pressed.',
340
- checked: !!deviceConfig.indoorChimeButton,
341
- onChange: async (checked) => {
342
- await Config.updateDeviceConfig(device.uniqueId, { indoorChimeButton: checked });
343
- },
344
- });
345
- }
346
-
347
- // ── Expert: Video Config ──
348
- this._renderExpertToggle(advSection, () => {
349
- this._expertOpen = !this._expertOpen;
350
- const expertSection = advSection.querySelector('#expert-section');
351
- if (expertSection) expertSection.style.display = this._expertOpen ? 'block' : 'none';
352
- const chevron = advSection.querySelector('#expert-chevron');
353
- if (chevron) chevron.classList.toggle('advanced-toggle__chevron--open', this._expertOpen);
354
- });
355
-
356
- const expertSection = document.createElement('div');
357
- expertSection.id = 'expert-section';
358
- expertSection.style.display = 'none';
359
-
360
- const videoTitle = document.createElement('div');
361
- videoTitle.className = 'detail-section__title';
362
- videoTitle.textContent = 'Video Encoding (Expert)';
363
- expertSection.appendChild(videoTitle);
364
-
365
- const vc = deviceConfig.videoConfig || {};
366
-
367
- NumberInput.render(expertSection, {
368
- id: 'num-maxWidth',
369
- label: 'Max Width',
370
- help: 'Maximum video width in pixels.',
371
- value: vc.maxWidth || 1920,
372
- min: 320, max: 3840, step: 160,
373
- suffix: 'px',
374
- onChange: async (val) => {
375
- const existing = deviceConfig.videoConfig || {};
376
- await Config.updateDeviceConfig(device.uniqueId, { videoConfig: { ...existing, maxWidth: val } });
377
- },
378
- });
379
-
380
- NumberInput.render(expertSection, {
381
- id: 'num-maxHeight',
382
- label: 'Max Height',
383
- help: 'Maximum video height in pixels.',
384
- value: vc.maxHeight || 1080,
385
- min: 240, max: 2160, step: 120,
386
- suffix: 'px',
387
- onChange: async (val) => {
388
- const existing = deviceConfig.videoConfig || {};
389
- await Config.updateDeviceConfig(device.uniqueId, { videoConfig: { ...existing, maxHeight: val } });
390
- },
391
- });
392
-
393
- NumberInput.render(expertSection, {
394
- id: 'num-maxFPS',
395
- label: 'Max FPS',
396
- help: 'Maximum frames per second.',
397
- value: vc.maxFPS || 30,
398
- min: 10, max: 60, step: 5,
399
- onChange: async (val) => {
400
- const existing = deviceConfig.videoConfig || {};
401
- await Config.updateDeviceConfig(device.uniqueId, { videoConfig: { ...existing, maxFPS: val } });
402
- },
403
- });
404
-
405
- NumberInput.render(expertSection, {
406
- id: 'num-maxBitrate',
407
- label: 'Max Bitrate',
408
- help: 'Maximum video bitrate in kbps.',
409
- value: vc.maxBitrate || 1800,
410
- min: 300, max: 8000, step: 100,
411
- suffix: 'kbps',
412
- onChange: async (val) => {
413
- const existing = deviceConfig.videoConfig || {};
414
- await Config.updateDeviceConfig(device.uniqueId, { videoConfig: { ...existing, maxBitrate: val } });
415
- },
416
- });
417
-
418
- advSection.appendChild(expertSection);
419
- restSettings.appendChild(advSection);
420
- }
421
-
422
- content.appendChild(restSettings);
423
- },
424
-
425
- // ===== Station Settings =====
426
- _renderStationSettings(content, station, stationConfig, config) {
427
- const ignoreStations = config.ignoreStations || [];
428
- const isIgnored = ignoreStations.includes(station.uniqueId);
429
-
430
- // Simple
431
- const section = document.createElement('div');
432
- section.className = 'detail-section';
433
-
434
- const title = document.createElement('div');
435
- title.className = 'detail-section__title';
436
- title.textContent = 'Station Settings';
437
- section.appendChild(title);
438
-
439
- Toggle.render(section, {
440
- id: 'toggle-station-enable',
441
- label: 'Enable in HomeKit',
442
- help: 'When disabled, this station\'s security panel will not appear in HomeKit.',
443
- checked: !isIgnored,
444
- onChange: async (checked) => {
445
- await Config.toggleIgnore(station.uniqueId, !checked, 'station');
446
- const rest = content.querySelector('#station-rest-settings');
447
- if (rest) rest.style.display = checked ? '' : 'none';
448
- },
449
- });
450
-
451
- content.appendChild(section);
452
-
453
- // Wrapper for all settings below Enable toggle — hidden when station is ignored
454
- const stationRest = document.createElement('div');
455
- stationRest.id = 'station-rest-settings';
456
- if (isIgnored) stationRest.style.display = 'none';
457
-
458
- // Advanced — Guard Modes Mapping
459
- this._renderAdvancedToggle(stationRest, () => {
460
- this._advancedOpen = !this._advancedOpen;
461
- const advSection = content.querySelector('#advanced-section');
462
- if (advSection) advSection.style.display = this._advancedOpen ? 'block' : 'none';
463
- const chevron = content.querySelector('.advanced-toggle__chevron');
464
- if (chevron) chevron.classList.toggle('advanced-toggle__chevron--open', this._advancedOpen);
465
- });
466
-
467
- const advSection = document.createElement('div');
468
- advSection.id = 'advanced-section';
469
- advSection.style.display = 'none';
470
-
471
- const guardTitle = document.createElement('div');
472
- guardTitle.className = 'detail-section__title';
473
- guardTitle.textContent = 'Guard Mode Mapping';
474
- advSection.appendChild(guardTitle);
475
-
476
- const guardHelp = document.createElement('p');
477
- guardHelp.className = 'text-muted';
478
- guardHelp.style.fontSize = '0.8rem';
479
- guardHelp.textContent = 'Map HomeKit security modes to Eufy guard modes for this station.';
480
- advSection.appendChild(guardHelp);
481
-
482
- GuardModes.render(advSection, {
483
- hkHome: stationConfig.hkHome ?? config.hkHome ?? 1,
484
- hkAway: stationConfig.hkAway ?? config.hkAway ?? 0,
485
- hkNight: stationConfig.hkNight ?? config.hkNight ?? 1,
486
- hkOff: stationConfig.hkOff ?? config.hkOff ?? 63,
487
- onChange: async (modes) => {
488
- await Config.updateStationConfig(station.uniqueId, modes);
489
- },
490
- });
491
-
492
- // Manual Alarm
493
- const alarmTitle = document.createElement('div');
494
- alarmTitle.className = 'detail-section__title mt-3';
495
- alarmTitle.textContent = 'Manual Alarm';
496
- advSection.appendChild(alarmTitle);
497
-
498
- NumberInput.render(advSection, {
499
- id: 'num-alarm-seconds',
500
- label: 'Alarm Duration',
501
- help: 'How long (in seconds) a manually triggered alarm should sound.',
502
- value: stationConfig.manualAlarmSeconds || 30,
503
- min: 5,
504
- max: 300,
505
- step: 5,
506
- suffix: 'sec',
507
- onChange: async (val) => {
508
- await Config.updateStationConfig(station.uniqueId, { manualAlarmSeconds: val });
509
- },
510
- });
511
-
512
- stationRest.appendChild(advSection);
513
- content.appendChild(stationRest);
514
- },
515
-
516
- // ===== Standalone Station Settings (shown in device detail for standalone devices) =====
517
- _renderStandaloneStationSection(content, station, stationConfig, config) {
518
- const ignoreStations = config.ignoreStations || [];
519
- const isIgnored = ignoreStations.includes(station.uniqueId);
520
-
521
- // Divider
522
- const divider = document.createElement('hr');
523
- divider.className = 'my-4';
524
- content.appendChild(divider);
525
-
526
- // Enable toggle section
527
- const section = document.createElement('div');
528
- section.className = 'detail-section';
529
-
530
- const title = document.createElement('div');
531
- title.className = 'detail-section__title';
532
- title.textContent = 'Security Panel';
533
- section.appendChild(title);
534
-
535
- const helpText = document.createElement('p');
536
- helpText.className = 'text-muted';
537
- helpText.style.fontSize = '0.8rem';
538
- helpText.textContent = 'This device acts as its own station. Configure the security panel independently from the device.';
539
- section.appendChild(helpText);
540
-
541
- Toggle.render(section, {
542
- id: 'toggle-station-enable',
543
- label: 'Enable Security Panel',
544
- help: 'When disabled, the security panel will not appear in HomeKit. The device itself remains active.',
545
- checked: !isIgnored,
546
- onChange: async (checked) => {
547
- await Config.toggleIgnore(station.uniqueId, !checked, 'station');
548
- const rest = content.querySelector('#standalone-station-rest');
549
- if (rest) rest.style.display = checked ? '' : 'none';
550
- },
551
- });
552
-
553
- content.appendChild(section);
554
-
555
- // Rest of station settings (hidden when disabled)
556
- const stationRest = document.createElement('div');
557
- stationRest.id = 'standalone-station-rest';
558
- if (isIgnored) stationRest.style.display = 'none';
559
-
560
- // Guard Mode Mapping
561
- const guardSection = document.createElement('div');
562
- guardSection.className = 'detail-section';
563
-
564
- const guardTitle = document.createElement('div');
565
- guardTitle.className = 'detail-section__title';
566
- guardTitle.textContent = 'Guard Mode Mapping';
567
- guardSection.appendChild(guardTitle);
568
-
569
- const guardHelp = document.createElement('p');
570
- guardHelp.className = 'text-muted';
571
- guardHelp.style.fontSize = '0.8rem';
572
- guardHelp.textContent = 'Map HomeKit security modes to Eufy guard modes.';
573
- guardSection.appendChild(guardHelp);
574
-
575
- GuardModes.render(guardSection, {
576
- hkHome: stationConfig.hkHome ?? config.hkHome ?? 1,
577
- hkAway: stationConfig.hkAway ?? config.hkAway ?? 0,
578
- hkNight: stationConfig.hkNight ?? config.hkNight ?? 1,
579
- hkOff: stationConfig.hkOff ?? config.hkOff ?? 63,
580
- onChange: async (modes) => {
581
- await Config.updateStationConfig(station.uniqueId, modes);
582
- },
583
- });
584
-
585
- // Manual Alarm
586
- const alarmTitle = document.createElement('div');
587
- alarmTitle.className = 'detail-section__title mt-3';
588
- alarmTitle.textContent = 'Manual Alarm';
589
- guardSection.appendChild(alarmTitle);
590
-
591
- NumberInput.render(guardSection, {
592
- id: 'num-station-alarm-seconds',
593
- label: 'Alarm Duration',
594
- help: 'How long (in seconds) a manually triggered alarm should sound.',
595
- value: stationConfig.manualAlarmSeconds || 30,
596
- min: 5,
597
- max: 300,
598
- step: 5,
599
- suffix: 'sec',
600
- onChange: async (val) => {
601
- await Config.updateStationConfig(station.uniqueId, { manualAlarmSeconds: val });
602
- },
603
- });
604
-
605
- stationRest.appendChild(guardSection);
606
- content.appendChild(stationRest);
607
- },
608
-
609
- // ===== Helpers =====
610
-
611
- _findAccessory(type, id) {
612
- const stations = App.state.stations || [];
613
- let foundStation = null;
614
- let foundDevice = null;
615
-
616
- for (const s of stations) {
617
- if (s.uniqueId === id) foundStation = s;
618
- for (const d of s.devices || []) {
619
- if (d.uniqueId === id) {
620
- foundDevice = d;
621
- foundStation = s;
622
- }
623
- }
624
- }
625
-
626
- return { station: foundStation, device: foundDevice };
627
- },
628
-
629
- _renderAdvancedToggle(container, onClick) {
630
- const btn = document.createElement('button');
631
- btn.className = 'advanced-toggle';
632
- btn.innerHTML = `
633
- <span class="advanced-toggle__chevron">▶</span>
634
- Advanced Settings
635
- `;
636
- btn.addEventListener('click', onClick);
637
- container.appendChild(btn);
638
- },
639
-
640
- _renderExpertToggle(container, onClick) {
641
- const btn = document.createElement('button');
642
- btn.className = 'advanced-toggle';
643
- btn.innerHTML = `
644
- <span class="advanced-toggle__chevron" id="expert-chevron">▶</span>
645
- Video Encoding (Expert)
646
- `;
647
- btn.addEventListener('click', onClick);
648
- container.appendChild(btn);
649
- },
650
-
651
- _escHtml(str) {
652
- return Helpers.escHtml(str);
653
- },
654
- };