@homebridge-plugins/homebridge-eufy-security 4.7.1 → 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 (469) 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 -769
  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 -431
  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/LockAccessory.js +0 -142
  295. package/dist/accessories/LockAccessory.js.map +0 -1
  296. package/dist/accessories/MotionSensorAccessory.js +0 -48
  297. package/dist/accessories/MotionSensorAccessory.js.map +0 -1
  298. package/dist/accessories/SmartDropAccessory.js +0 -141
  299. package/dist/accessories/SmartDropAccessory.js.map +0 -1
  300. package/dist/accessories/StationAccessory.js +0 -373
  301. package/dist/accessories/StationAccessory.js.map +0 -1
  302. package/dist/config.js +0 -26
  303. package/dist/config.js.map +0 -1
  304. package/dist/controller/DebugRecordingManager.js +0 -402
  305. package/dist/controller/DebugRecordingManager.js.map +0 -1
  306. package/dist/controller/LocalLivestreamManager.js +0 -371
  307. package/dist/controller/LocalLivestreamManager.js.map +0 -1
  308. package/dist/controller/recordingDelegate.js +0 -252
  309. package/dist/controller/recordingDelegate.js.map +0 -1
  310. package/dist/controller/snapshotDelegate.js +0 -348
  311. package/dist/controller/snapshotDelegate.js.map +0 -1
  312. package/dist/controller/streamingDelegate.js +0 -389
  313. package/dist/controller/streamingDelegate.js.map +0 -1
  314. package/dist/interfaces.js +0 -2
  315. package/dist/interfaces.js.map +0 -1
  316. package/dist/media/Snapshot-Unavailable.png +0 -0
  317. package/dist/media/Snapshot-Unavailable.xcf +0 -0
  318. package/dist/media/Snapshot-black.png +0 -0
  319. package/dist/media/camera-disabled.png +0 -0
  320. package/dist/media/camera-offline.png +0 -0
  321. package/dist/media/media/Snapshot-Unavailable.png +0 -0
  322. package/dist/media/media/Snapshot-Unavailable.xcf +0 -0
  323. package/dist/media/media/Snapshot-black.png +0 -0
  324. package/dist/media/media/camera-disabled.png +0 -0
  325. package/dist/media/media/camera-offline.png +0 -0
  326. package/dist/utils/Talkback.js +0 -162
  327. package/dist/utils/Talkback.js.map +0 -1
  328. package/dist/utils/accessoriesStore.js +0 -207
  329. package/dist/utils/accessoriesStore.js.map +0 -1
  330. package/dist/utils/configTypes.js +0 -36
  331. package/dist/utils/configTypes.js.map +0 -1
  332. package/dist/utils/ffmpeg.js +0 -1111
  333. package/dist/utils/ffmpeg.js.map +0 -1
  334. package/dist/utils/interfaces.js +0 -8
  335. package/dist/utils/interfaces.js.map +0 -1
  336. package/dist/utils/utils.js +0 -224
  337. package/dist/utils/utils.js.map +0 -1
  338. package/dist/version.js +0 -2
  339. package/dist/version.js.map +0 -1
  340. package/homebridge-eufy-security.png +0 -0
  341. package/homebridge-ui/diagnosticsCrypto.js +0 -112
  342. package/homebridge-ui/public/app.js +0 -237
  343. package/homebridge-ui/public/assets/devices/4g_lte_cam_s330_large.png +0 -0
  344. package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
  345. package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C30.png +0 -0
  346. package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C31.png +0 -0
  347. package/homebridge-ui/public/assets/devices/batterydoorbell1080p_large.jpg +0 -0
  348. package/homebridge-ui/public/assets/devices/batterydoorbell2k_large.png +0 -0
  349. package/homebridge-ui/public/assets/devices/batterydoorbell2kdual_large.jpg +0 -0
  350. package/homebridge-ui/public/assets/devices/batterydoorbell_e340_large.png +0 -0
  351. package/homebridge-ui/public/assets/devices/eufy-security-client.png +0 -0
  352. package/homebridge-ui/public/assets/devices/eufyCamS4_large.png +0 -0
  353. package/homebridge-ui/public/assets/devices/eufycam2_large.png +0 -0
  354. package/homebridge-ui/public/assets/devices/eufycam2c_large.jpg +0 -0
  355. package/homebridge-ui/public/assets/devices/eufycam2cpro_large.jpg +0 -0
  356. package/homebridge-ui/public/assets/devices/eufycam2pro_large.jpg +0 -0
  357. package/homebridge-ui/public/assets/devices/eufycam3_large.jpg +0 -0
  358. package/homebridge-ui/public/assets/devices/eufycam3c_large.jpg +0 -0
  359. package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
  360. package/homebridge-ui/public/assets/devices/eufycam_large.jpg +0 -0
  361. package/homebridge-ui/public/assets/devices/eufycame330_large.jpg +0 -0
  362. package/homebridge-ui/public/assets/devices/flood_freeze_sensor_e20_t90F0_large.png +0 -0
  363. package/homebridge-ui/public/assets/devices/floodlight2_large.jpg +0 -0
  364. package/homebridge-ui/public/assets/devices/floodlight2pro_large.jpg +0 -0
  365. package/homebridge-ui/public/assets/devices/floodlight_large.jpg +0 -0
  366. package/homebridge-ui/public/assets/devices/floodlightcame340_large.jpg +0 -0
  367. package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.png +0 -0
  368. package/homebridge-ui/public/assets/devices/homebase2_large.png +0 -0
  369. package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
  370. package/homebridge-ui/public/assets/devices/homebase_large.jpg +0 -0
  371. package/homebridge-ui/public/assets/devices/homebasemini_large.png +0 -0
  372. package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
  373. package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
  374. package/homebridge-ui/public/assets/devices/indoorcamC220_t8419N_large.png +0 -0
  375. package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
  376. package/homebridge-ui/public/assets/devices/indoorcamc120_large.png +0 -0
  377. package/homebridge-ui/public/assets/devices/indoorcammini_large.jpg +0 -0
  378. package/homebridge-ui/public/assets/devices/indoorcamp24_large.png +0 -0
  379. package/homebridge-ui/public/assets/devices/indoorcams350_large.png +0 -0
  380. package/homebridge-ui/public/assets/devices/keypad_large.png +0 -0
  381. package/homebridge-ui/public/assets/devices/minibase_chime_T8023_large.jpg +0 -0
  382. package/homebridge-ui/public/assets/devices/motionsensor_large.png +0 -0
  383. package/homebridge-ui/public/assets/devices/nvr_s4_max_T8N00_large.png +0 -0
  384. package/homebridge-ui/public/assets/devices/pir_sensor_e20_large.png +0 -0
  385. package/homebridge-ui/public/assets/devices/poe_bullet_ptz_cam_s4_T8E00_large.png +0 -0
  386. package/homebridge-ui/public/assets/devices/sensor_large.png +0 -0
  387. package/homebridge-ui/public/assets/devices/siren_sensor_e20_large.png +0 -0
  388. package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.png +0 -0
  389. package/homebridge-ui/public/assets/devices/smartlock_t8500_large.png +0 -0
  390. package/homebridge-ui/public/assets/devices/smartlock_t8500_wifibridge_large.jpg +0 -0
  391. package/homebridge-ui/public/assets/devices/smartlock_t8503_large.png +0 -0
  392. package/homebridge-ui/public/assets/devices/smartlock_t8504_large.jpg +0 -0
  393. package/homebridge-ui/public/assets/devices/smartlock_t8510P_t8520P_large.png +0 -0
  394. package/homebridge-ui/public/assets/devices/smartlock_t85D0_large.png +0 -0
  395. package/homebridge-ui/public/assets/devices/smartlock_t85L0_large.png +0 -0
  396. package/homebridge-ui/public/assets/devices/smartlock_t85P0_large.png +0 -0
  397. package/homebridge-ui/public/assets/devices/smartlock_t85V0_large.png +0 -0
  398. package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8502_large.png +0 -0
  399. package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8506_large.png +0 -0
  400. package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8520_large.png +0 -0
  401. package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_large.png +0 -0
  402. package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_wifibridge_large.jpg +0 -0
  403. package/homebridge-ui/public/assets/devices/smartlock_video_t8530_large.png +0 -0
  404. package/homebridge-ui/public/assets/devices/smartlock_video_t8531_large.png +0 -0
  405. package/homebridge-ui/public/assets/devices/smartlockwifibridge_t8021_large.jpg +0 -0
  406. package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.png +0 -0
  407. package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.png +0 -0
  408. package/homebridge-ui/public/assets/devices/smarttrack_card_t87B2_large.png +0 -0
  409. package/homebridge-ui/public/assets/devices/smarttrack_link_t87B0_large.png +0 -0
  410. package/homebridge-ui/public/assets/devices/smoke_alarm_e10_t90S0_large.png +0 -0
  411. package/homebridge-ui/public/assets/devices/solocamc210_large.jpg +0 -0
  412. package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
  413. package/homebridge-ui/public/assets/devices/solocame20_large.jpg +0 -0
  414. package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
  415. package/homebridge-ui/public/assets/devices/solocame40_large.jpg +0 -0
  416. package/homebridge-ui/public/assets/devices/solocame42_large.png +0 -0
  417. package/homebridge-ui/public/assets/devices/solocaml20_large.jpg +0 -0
  418. package/homebridge-ui/public/assets/devices/solocams220_large.jpg +0 -0
  419. package/homebridge-ui/public/assets/devices/solocams340_large.png +0 -0
  420. package/homebridge-ui/public/assets/devices/solocams40_large.jpg +0 -0
  421. package/homebridge-ui/public/assets/devices/soloindoorcamc24_large.jpg +0 -0
  422. package/homebridge-ui/public/assets/devices/solooutdoorcamc22_large.png +0 -0
  423. package/homebridge-ui/public/assets/devices/solooutdoorcamc24_large.jpg +0 -0
  424. package/homebridge-ui/public/assets/devices/unknown.png +0 -0
  425. package/homebridge-ui/public/assets/devices/walllight_s100_large.png +0 -0
  426. package/homebridge-ui/public/assets/devices/walllight_s120_large.png +0 -0
  427. package/homebridge-ui/public/assets/devices/water_freeze_sensor_t8920_large.png +0 -0
  428. package/homebridge-ui/public/assets/devices/wireddoorbell1080p_large.jpg +0 -0
  429. package/homebridge-ui/public/assets/devices/wireddoorbell2k_large.png +0 -0
  430. package/homebridge-ui/public/assets/devices/wireddoorbelldual_large.jpg +0 -0
  431. package/homebridge-ui/public/assets/icons/attach.svg +0 -1
  432. package/homebridge-ui/public/assets/icons/battery_0.svg +0 -1
  433. package/homebridge-ui/public/assets/icons/battery_1.svg +0 -1
  434. package/homebridge-ui/public/assets/icons/battery_2.svg +0 -1
  435. package/homebridge-ui/public/assets/icons/battery_3.svg +0 -1
  436. package/homebridge-ui/public/assets/icons/battery_4.svg +0 -1
  437. package/homebridge-ui/public/assets/icons/battery_5.svg +0 -1
  438. package/homebridge-ui/public/assets/icons/battery_6.svg +0 -1
  439. package/homebridge-ui/public/assets/icons/copy.svg +0 -1
  440. package/homebridge-ui/public/assets/icons/delete.svg +0 -1
  441. package/homebridge-ui/public/assets/icons/download.svg +0 -1
  442. package/homebridge-ui/public/assets/icons/info.svg +0 -1
  443. package/homebridge-ui/public/assets/icons/refresh.svg +0 -1
  444. package/homebridge-ui/public/assets/icons/satellite_alt.svg +0 -1
  445. package/homebridge-ui/public/assets/icons/solar_power.svg +0 -1
  446. package/homebridge-ui/public/components/device-card.js +0 -174
  447. package/homebridge-ui/public/components/guard-modes.js +0 -88
  448. package/homebridge-ui/public/components/number-input.js +0 -121
  449. package/homebridge-ui/public/components/select.js +0 -73
  450. package/homebridge-ui/public/components/toggle.js +0 -68
  451. package/homebridge-ui/public/services/api.js +0 -250
  452. package/homebridge-ui/public/services/config.js +0 -144
  453. package/homebridge-ui/public/style.css +0 -818
  454. package/homebridge-ui/public/utils/countries.js +0 -73
  455. package/homebridge-ui/public/utils/device-images.js +0 -102
  456. package/homebridge-ui/public/utils/helpers.js +0 -115
  457. package/homebridge-ui/public/views/dashboard.js +0 -226
  458. package/homebridge-ui/public/views/device-detail.js +0 -626
  459. package/homebridge-ui/public/views/diagnostics.js +0 -402
  460. package/homebridge-ui/public/views/login.js +0 -650
  461. package/homebridge-ui/public/views/recordings.js +0 -319
  462. package/homebridge-ui/public/views/settings.js +0 -197
  463. package/homebridge-ui/public/views/unsupported-detail.js +0 -296
  464. package/media/Snapshot-Unavailable.png +0 -0
  465. package/media/Snapshot-Unavailable.xcf +0 -0
  466. package/media/Snapshot-black.png +0 -0
  467. package/media/camera-disabled.png +0 -0
  468. package/media/camera-offline.png +0 -0
  469. package/scripts/decrypt-diagnostics.mjs +0 -257
@@ -1,371 +0,0 @@
1
- import { PassThrough } from 'stream';
2
- import { Deferred } from '../utils/utils.js';
3
- import { PREBUFFER_DURATION_MS, PREBUFFER_ESTIMATED_BYTE_RATE } from '../settings.js';
4
- const P2P_TIMEOUT_MS = 15_000;
5
- const DUPLICATE_STREAM_GUARD_S = 5;
6
- const MAX_RETRIES = 3;
7
- const BASE_RETRY_DELAY_MS = 2_000;
8
- const MAX_RETRY_DELAY_MS = 10_000;
9
- /** Grace period before actually stopping a P2P stream after the last consumer releases. */
10
- const STOP_GRACE_MS = 5_000;
11
- /**
12
- * Fixed-capacity ring buffer that stores raw P2P video chunks (H.264 NALUs).
13
- *
14
- * When a P2P stream is pre-warmed on motion detection, data flows but has no
15
- * consumer. This buffer captures the last {@link PREBUFFER_DURATION_MS} of
16
- * video so that when HKSV requests a recording, the buffered data can be
17
- * drained into FFmpeg's input immediately — eliminating the probe/analysis
18
- * delay that normally occurs while FFmpeg waits for the first bytes.
19
- */
20
- class StreamBuffer {
21
- chunks = [];
22
- totalBytes = 0;
23
- maxBytes;
24
- constructor(durationMs, byteRate) {
25
- this.maxBytes = Math.ceil(durationMs * byteRate);
26
- }
27
- push(chunk) {
28
- this.chunks.push(chunk);
29
- this.totalBytes += chunk.length;
30
- while (this.totalBytes > this.maxBytes && this.chunks.length > 0) {
31
- const removed = this.chunks.shift();
32
- this.totalBytes -= removed.length;
33
- }
34
- }
35
- /** Return all buffered chunks and reset. */
36
- drain() {
37
- const buffered = this.chunks;
38
- this.chunks = [];
39
- this.totalBytes = 0;
40
- return buffered;
41
- }
42
- get isEmpty() {
43
- return this.chunks.length === 0;
44
- }
45
- get byteLength() {
46
- return this.totalBytes;
47
- }
48
- }
49
- export class LocalLivestreamManager {
50
- stationStream = null;
51
- pending = null;
52
- retryCount = 0;
53
- stopGraceTimer = null;
54
- /** Number of consumers currently holding a forked copy of the stream. */
55
- activeConsumers = 0;
56
- /** Trigger that started (or will start) the current P2P stream. */
57
- streamTrigger = 'livestream';
58
- /** Ring buffer for raw video data captured during pre-warm (no consumers). */
59
- videoBuffer = null;
60
- /** Listener reference for cleaning up the buffer tap on the video stream. */
61
- bufferListener = null;
62
- /** The videostream the buffer listener is attached to (for reliable cleanup). */
63
- bufferedVideoStream = null;
64
- eufyClient;
65
- log;
66
- serialNumber;
67
- debugRecordingManager;
68
- debugEnabled;
69
- constructor(camera) {
70
- this.eufyClient = camera.platform.eufyClient;
71
- this.serialNumber = camera.device.getSerial();
72
- this.log = camera.log;
73
- this.debugEnabled = camera.platform.config.debugLivestream ?? false;
74
- this.debugRecordingManager = camera.platform.debugRecordingManager ?? null;
75
- this.log.debug(`LocalLivestreamManager initialized for ${camera.device.getName()} (serial: ${this.serialNumber})`);
76
- this.eufyClient.on('station livestream start', this.onStationLivestreamStart);
77
- this.eufyClient.on('station livestream stop', this.onStationLivestreamStop);
78
- }
79
- /** Destroy active streams and reset state. */
80
- destroyStreams() {
81
- this.stopBuffering();
82
- // Stop raw debug recording before destroying streams
83
- this.debugRecordingManager?.stopRawRecording(this.serialNumber);
84
- if (this.stationStream) {
85
- this.stationStream.audiostream.unpipe();
86
- this.stationStream.audiostream.destroy();
87
- this.stationStream.videostream.unpipe();
88
- this.stationStream.videostream.destroy();
89
- this.stationStream = null;
90
- this.activeConsumers = 0;
91
- }
92
- }
93
- /**
94
- * Start capturing raw video chunks into the ring buffer.
95
- * Called when a stream is established with no consumers (pre-warm scenario).
96
- * The buffer is drained into the first consumer fork via {@link forkStream}.
97
- */
98
- startBuffering(videostream) {
99
- this.stopBuffering();
100
- this.videoBuffer = new StreamBuffer(PREBUFFER_DURATION_MS, PREBUFFER_ESTIMATED_BYTE_RATE);
101
- this.bufferListener = (chunk) => this.videoBuffer?.push(chunk);
102
- this.bufferedVideoStream = videostream;
103
- videostream.on('data', this.bufferListener);
104
- this.log.debug(`Prebuffer started (max ${PREBUFFER_DURATION_MS}ms / ${((PREBUFFER_DURATION_MS * PREBUFFER_ESTIMATED_BYTE_RATE) / 1024).toFixed(0)} KB).`);
105
- }
106
- /** Stop buffering and detach the listener from the video stream. */
107
- stopBuffering() {
108
- if (this.bufferListener && this.bufferedVideoStream) {
109
- this.bufferedVideoStream.removeListener('data', this.bufferListener);
110
- }
111
- this.bufferListener = null;
112
- this.bufferedVideoStream = null;
113
- this.videoBuffer = null;
114
- }
115
- /**
116
- * Return a forked copy of the active livestream, or start a new one.
117
- * Each caller gets its own PassThrough fork so that when one consumer's
118
- * FFmpeg exits and destroys its input, the underlying P2P stream survives
119
- * for other consumers. A consumer count tracks active forks so the P2P
120
- * session is only stopped when the last consumer calls stopLocalLiveStream().
121
- */
122
- async getLocalLiveStream(trigger) {
123
- if (this.stopGraceTimer) {
124
- clearTimeout(this.stopGraceTimer);
125
- this.stopGraceTimer = null;
126
- this.log.debug('Cancelled deferred stop — reusing active stream.');
127
- }
128
- if (!this.stationStream) {
129
- if (trigger)
130
- this.streamTrigger = trigger;
131
- await this.startLocalLiveStream();
132
- }
133
- if (!this.stationStream) {
134
- throw new Error('Livestream failed to start.');
135
- }
136
- const runtime = ((Date.now() - this.stationStream.createdAt) / 1000).toFixed(1);
137
- this.activeConsumers++;
138
- this.log.debug(`Providing forked stream (consumers: ${this.activeConsumers}, ` + `stream age: ${runtime}s).`);
139
- return this.forkStream(this.stationStream);
140
- }
141
- /**
142
- * Create PassThrough forks of the video and audio streams. The forks
143
- * automatically unpipe when closed so the originals stay healthy.
144
- *
145
- * If a prebuffer has accumulated (from a pre-warmed stream with no consumers),
146
- * the buffered video data is drained into the fork first so that FFmpeg
147
- * receives data immediately without waiting for new P2P frames.
148
- */
149
- forkStream(source) {
150
- const videoFork = new PassThrough();
151
- const audioFork = new PassThrough();
152
- // Drain any prebuffered video data into the fork before piping live data.
153
- // This eliminates FFmpeg's probe delay by providing immediate input.
154
- // Backpressure note: at 4s / ~1 MB the PassThrough internal buffer
155
- // handles this comfortably. If PREBUFFER_DURATION_MS is increased
156
- // significantly, consider making this drain async with drain events.
157
- if (this.videoBuffer && !this.videoBuffer.isEmpty) {
158
- const buffered = this.videoBuffer.drain();
159
- const totalBytes = buffered.reduce((sum, c) => sum + c.length, 0);
160
- this.log.debug(`Draining ${buffered.length} prebuffered chunks (${(totalBytes / 1024).toFixed(1)} KB) into video fork.`);
161
- for (const chunk of buffered) {
162
- videoFork.write(chunk);
163
- }
164
- }
165
- // Stop buffering — live data now flows directly to the consumer.
166
- this.stopBuffering();
167
- source.videostream.pipe(videoFork);
168
- source.audiostream.pipe(audioFork);
169
- videoFork.on('close', () => source.videostream.unpipe(videoFork));
170
- audioFork.on('close', () => source.audiostream.unpipe(audioFork));
171
- return {
172
- videostream: videoFork,
173
- audiostream: audioFork,
174
- metadata: source.metadata,
175
- };
176
- }
177
- /** True when a P2P livestream is currently active or starting. */
178
- isStreamActive() {
179
- return this.stationStream !== null || this.pending !== null;
180
- }
181
- /** Session ID for the current debug recording pair (raw + processed). */
182
- getSessionId() {
183
- return this.stationStream?.sessionId ?? null;
184
- }
185
- /**
186
- * Pre-warm the P2P livestream without creating a consumer fork.
187
- * The stream will be kept alive by the STOP_GRACE_MS timer once established.
188
- * If a consumer calls getLocalLiveStream() while the stream is warm,
189
- * it will reuse the existing connection instantly.
190
- */
191
- async preWarmStream() {
192
- if (this.isStreamActive()) {
193
- return;
194
- }
195
- this.streamTrigger = 'hksv';
196
- await this.startLocalLiveStream();
197
- // Stream is now active but has zero consumers.
198
- // Schedule a grace-period stop so it doesn't run forever if unused.
199
- if (this.activeConsumers === 0 && !this.stopGraceTimer) {
200
- this.log.debug(`Pre-warmed stream has no consumers — scheduling ${STOP_GRACE_MS / 1000}s grace stop.`);
201
- this.stopGraceTimer = setTimeout(() => {
202
- this.stopGraceTimer = null;
203
- if (this.activeConsumers > 0) {
204
- return;
205
- }
206
- this.log.debug('Pre-warm grace period expired — stopping stream.');
207
- this.forceStopLocalLiveStream();
208
- }, STOP_GRACE_MS);
209
- }
210
- }
211
- /**
212
- * Requests a P2P livestream from the eufy station and waits for the
213
- * 'station livestream start' event. If a start is already in progress,
214
- * the caller piggy-backs on the existing promise instead of issuing a
215
- * duplicate request.
216
- */
217
- startLocalLiveStream() {
218
- if (this.pending) {
219
- this.log.debug('Livestream already starting — waiting on existing request.');
220
- return this.pending.deferred.promise;
221
- }
222
- this.log.debug(`Starting station livestream for serial: ${this.serialNumber}...`);
223
- const deferred = new Deferred();
224
- this.issueP2PRequest(deferred);
225
- return deferred.promise;
226
- }
227
- /**
228
- * Issue a P2P start request with a timeout. Used for both initial
229
- * attempts and retries (reusing the same deferred).
230
- */
231
- issueP2PRequest(deferred) {
232
- const timer = setTimeout(() => {
233
- this.log.error(`Livestream timeout: no P2P stream event within ${P2P_TIMEOUT_MS / 1000}s` +
234
- ` for serial ${this.serialNumber}.`);
235
- this.settlePending('reject', new Error('Livestream timeout — check eufy-lib.log for P2P errors.'));
236
- }, P2P_TIMEOUT_MS);
237
- this.pending = { deferred, timer };
238
- this.eufyClient.startStationLivestream(this.serialNumber).catch((err) => {
239
- this.log.error(`startStationLivestream failed: ${err}`);
240
- this.settlePending('reject', err);
241
- });
242
- }
243
- settlePending(action, payload) {
244
- const p = this.pending;
245
- if (!p)
246
- return;
247
- clearTimeout(p.timer);
248
- if (action === 'resolve') {
249
- this.retryCount = 0;
250
- this.pending = null;
251
- p.deferred.resolve(payload);
252
- return;
253
- }
254
- // Failure path — retry with exponential backoff if attempts remain
255
- if (this.retryCount < MAX_RETRIES) {
256
- const delay = Math.min(BASE_RETRY_DELAY_MS * Math.pow(2, this.retryCount) + Math.random() * 1000, MAX_RETRY_DELAY_MS);
257
- this.retryCount++;
258
- this.log.warn(`P2P connection failed. Retrying in ${(delay / 1000).toFixed(1)}s` +
259
- ` (attempt ${this.retryCount + 1}/${MAX_RETRIES + 1})...`);
260
- // Keep pending alive during backoff so new callers piggyback
261
- p.timer = setTimeout(() => {
262
- this.log.debug(`Retrying station livestream for serial: ${this.serialNumber}` +
263
- ` (attempt ${this.retryCount + 1}/${MAX_RETRIES + 1})...`);
264
- this.issueP2PRequest(p.deferred);
265
- }, delay);
266
- }
267
- else {
268
- this.retryCount = 0;
269
- this.pending = null;
270
- this.log.error(`Livestream failed after ${MAX_RETRIES + 1} attempts.`);
271
- p.deferred.reject(payload instanceof Error ? payload : new Error(String(payload)));
272
- this.forceStopLocalLiveStream();
273
- }
274
- }
275
- /**
276
- * Signal that a consumer is done with its forked stream. When the last
277
- * consumer releases, the P2P session is stopped after a short grace period
278
- * to allow a subsequent consumer (e.g. a livestream right after a snapshot)
279
- * to reuse the session without a stop/start cycle.
280
- */
281
- stopLocalLiveStream() {
282
- this.activeConsumers = Math.max(0, this.activeConsumers - 1);
283
- this.log.debug(`Consumer released (remaining: ${this.activeConsumers}).`);
284
- if (this.activeConsumers > 0) {
285
- return;
286
- }
287
- // Last consumer — schedule a deferred stop
288
- if (this.stopGraceTimer)
289
- return;
290
- this.log.debug(`Deferring stream stop by ${STOP_GRACE_MS / 1000}s to allow reuse.`);
291
- this.stopGraceTimer = setTimeout(() => {
292
- this.stopGraceTimer = null;
293
- if (this.activeConsumers > 0) {
294
- this.log.debug('Grace period expired but new consumer(s) present — not stopping.');
295
- return;
296
- }
297
- this.log.debug('Grace period expired — stopping stream now.');
298
- this.forceStopLocalLiveStream();
299
- }, STOP_GRACE_MS);
300
- }
301
- /** Unconditionally tear down the P2P session and all state. */
302
- forceStopLocalLiveStream() {
303
- this.log.debug('Stopping station livestream.');
304
- if (this.stopGraceTimer) {
305
- clearTimeout(this.stopGraceTimer);
306
- this.stopGraceTimer = null;
307
- }
308
- this.retryCount = 0;
309
- if (this.pending) {
310
- clearTimeout(this.pending.timer);
311
- this.pending = null;
312
- }
313
- this.eufyClient.stopStationLivestream(this.serialNumber).catch((err) => {
314
- this.log.warn(`stopStationLivestream failed: ${err}`);
315
- });
316
- this.destroyStreams();
317
- }
318
- /** True when the event belongs to this camera instance. */
319
- isOwnDevice(device) {
320
- return device.getSerial() === this.serialNumber;
321
- }
322
- onStationLivestreamStop = (_station, device) => {
323
- if (!this.isOwnDevice(device))
324
- return;
325
- this.log.debug(`Station livestream for ${device.getName()} has stopped.`);
326
- this.destroyStreams();
327
- };
328
- onStationLivestreamStart = (station, device, metadata, videostream, audiostream) => {
329
- if (!this.isOwnDevice(device))
330
- return;
331
- // Guard against duplicate events fired in quick succession.
332
- if (this.stationStream) {
333
- const elapsed = (Date.now() - this.stationStream.createdAt) / 1000;
334
- if (elapsed < DUPLICATE_STREAM_GUARD_S) {
335
- this.log.warn('Duplicate livestream event received — ignoring.');
336
- return;
337
- }
338
- }
339
- // Tear down any prior stream before storing the new one.
340
- this.destroyStreams();
341
- this.log.debug(`${station.getName()} P2P livestream for ${device.getName()} started.`);
342
- this.log.debug('Stream metadata:', JSON.stringify(metadata));
343
- const sessionId = new Date().toISOString().replace(/[:.]/g, '-');
344
- const trigger = this.streamTrigger;
345
- this.streamTrigger = 'livestream'; // reset for next stream
346
- this.stationStream = { videostream, audiostream, metadata, createdAt: Date.now(), sessionId, trigger };
347
- // Start prebuffering video data. If a consumer is already waiting (pending
348
- // resolve), forkStream will drain the buffer immediately. If this is a
349
- // pre-warm with no consumers, the buffer accumulates until one arrives.
350
- this.startBuffering(videostream);
351
- // Start raw debug recording if enabled — captures the P2P feed before any FFmpeg processing.
352
- // Piping source→fork is deferred until startRawRecording resolves (TCP servers
353
- // listening, FFmpeg spawned). This prevents buffered data from bursting into
354
- // FFmpeg all at once, which would cause incorrect timestamps and ~0s duration.
355
- if (this.debugEnabled && this.debugRecordingManager) {
356
- const rawVideoFork = new PassThrough();
357
- const rawAudioFork = new PassThrough();
358
- this.debugRecordingManager
359
- .startRawRecording(this.serialNumber, rawVideoFork, rawAudioFork, metadata, sessionId, trigger)
360
- .then(() => {
361
- videostream.pipe(rawVideoFork);
362
- audiostream.pipe(rawAudioFork);
363
- rawVideoFork.on('close', () => videostream.unpipe(rawVideoFork));
364
- rawAudioFork.on('close', () => audiostream.unpipe(rawAudioFork));
365
- })
366
- .catch((err) => this.log.warn(`Raw debug recording failed to start: ${err}`));
367
- }
368
- this.settlePending('resolve', this.stationStream);
369
- };
370
- }
371
- //# sourceMappingURL=LocalLivestreamManager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LocalLivestreamManager.js","sourceRoot":"","sources":["../../src/controller/LocalLivestreamManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAY,MAAM,QAAQ,CAAC;AAG/C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAqBtF,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAClC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,2FAA2F;AAC3F,MAAM,aAAa,GAAG,KAAK,CAAC;AAE5B;;;;;;;;GAQG;AACH,MAAM,YAAY;IACR,MAAM,GAAa,EAAE,CAAC;IACtB,UAAU,GAAG,CAAC,CAAC;IACN,QAAQ,CAAS;IAElC,YAAY,UAAkB,EAAE,QAAgB;QAC9C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,CAAC,KAAa;QAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;QAChC,OAAO,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAG,CAAC;YACrC,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;QACpC,CAAC;IACH,CAAC;IAED,4CAA4C;IAC5C,KAAK;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,sBAAsB;IACzB,aAAa,GAAwB,IAAI,CAAC;IAC1C,OAAO,GAAyE,IAAI,CAAC;IACrF,UAAU,GAAG,CAAC,CAAC;IACf,cAAc,GAA0B,IAAI,CAAC;IACrD,yEAAyE;IACjE,eAAe,GAAG,CAAC,CAAC;IAC5B,mEAAmE;IAC3D,aAAa,GAAkB,YAAY,CAAC;IAEpD,8EAA8E;IACtE,WAAW,GAAwB,IAAI,CAAC;IAChD,6EAA6E;IACrE,cAAc,GAAqC,IAAI,CAAC;IAChE,iFAAiF;IACzE,mBAAmB,GAAoB,IAAI,CAAC;IAEnC,UAAU,CAAe;IACzB,GAAG,CAAkB;IACrB,YAAY,CAAS;IACrB,qBAAqB,CAA+B;IACpD,YAAY,CAAU;IAEvC,YAAY,MAAuB;QACjC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC7C,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QAC9C,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,IAAI,KAAK,CAAC;QACpE,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC,QAAQ,CAAC,qBAAqB,IAAI,IAAI,CAAC;QAE3E,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,0CAA0C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QAEnH,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,0BAA0B,EAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC9E,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,yBAAyB,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC9E,CAAC;IAED,8CAA8C;IACtC,cAAc;QACpB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,qDAAqD;QACrD,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChE,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,WAAqB;QAC1C,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,IAAI,YAAY,CAAC,qBAAqB,EAAE,6BAA6B,CAAC,CAAC;QAC1F,IAAI,CAAC,cAAc,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,CAAC,mBAAmB,GAAG,WAAW,CAAC;QACvC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,0BAA0B,qBAAqB,QAAQ,CAAC,CAAC,qBAAqB,GAAG,6BAA6B,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAC1I,CAAC;IACJ,CAAC;IAED,oEAAoE;IAC5D,aAAa;QACnB,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACpD,IAAI,CAAC,mBAAmB,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAChC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,kBAAkB,CAAC,OAAuB;QACrD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAClC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,OAAO;gBAAE,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;YAC1C,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChF,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,uCAAuC,IAAI,CAAC,eAAe,IAAI,GAAG,eAAe,OAAO,KAAK,CAAC,CAAC;QAE9G,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;;OAOG;IACK,UAAU,CAAC,MAAoB;QACrC,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC;QAEpC,0EAA0E;QAC1E,qEAAqE;QACrE,mEAAmE;QACnE,kEAAkE;QAClE,qEAAqE;QACrE,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAClE,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,YAAY,QAAQ,CAAC,MAAM,wBAAwB,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CACzG,CAAC;YACF,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;gBAC7B,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,iEAAiE;QACjE,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAClE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAElE,OAAO;YACL,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,SAAS;YACtB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC;IACJ,CAAC;IAED,kEAAkE;IAC3D,cAAc;QACnB,OAAO,IAAI,CAAC,aAAa,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;IAC9D,CAAC;IAED,yEAAyE;IAClE,YAAY;QACjB,OAAO,IAAI,CAAC,aAAa,EAAE,SAAS,IAAI,IAAI,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,aAAa;QACxB,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC5B,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAClC,+CAA+C;QAC/C,oEAAoE;QACpE,IAAI,IAAI,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACvD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,mDAAmD,aAAa,GAAG,IAAI,eAAe,CAAC,CAAC;YACvG,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;gBACpC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC3B,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;oBAC7B,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;gBACnE,IAAI,CAAC,wBAAwB,EAAE,CAAC;YAClC,CAAC,EAAE,aAAa,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,oBAAoB;QAC1B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;YAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;QACvC,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2CAA2C,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC;QAElF,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAkB,CAAC;QAChD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACK,eAAe,CAAC,QAAkC;QACxD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,kDAAkD,cAAc,GAAG,IAAI,GAAG;gBACxE,eAAe,IAAI,CAAC,YAAY,GAAG,CACtC,CAAC;YACF,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC,CAAC;QACrG,CAAC,EAAE,cAAc,CAAC,CAAC;QAEnB,IAAI,CAAC,OAAO,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAEnC,IAAI,CAAC,UAAU,CAAC,sBAAsB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACtE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kCAAkC,GAAG,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;IASO,aAAa,CAAC,MAA4B,EAAE,OAAgB;QAClE,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QACvB,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAEtB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAyB,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,IAAI,IAAI,CAAC,UAAU,GAAG,WAAW,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,EACzE,kBAAkB,CACnB,CAAC;YACF,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,sCAAsC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;gBAChE,aAAa,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,MAAM,CAC5D,CAAC;YACF,6DAA6D;YAC7D,CAAC,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACxB,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,2CAA2C,IAAI,CAAC,YAAY,EAAE;oBAC5D,aAAa,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,MAAM,CAC5D,CAAC;gBACF,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC,EAAE,KAAK,CAAC,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2BAA2B,WAAW,GAAG,CAAC,YAAY,CAAC,CAAC;YACvE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACnF,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,mBAAmB;QACxB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC;QAE1E,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,2CAA2C;QAC3C,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO;QAChC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,4BAA4B,aAAa,GAAG,IAAI,mBAAmB,CAAC,CAAC;QACpF,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YACpC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC3B,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;gBACnF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC9D,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAClC,CAAC,EAAE,aAAa,CAAC,CAAC;IACpB,CAAC;IAED,+DAA+D;IACvD,wBAAwB;QAC9B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC/C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAClC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACrE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,2DAA2D;IACnD,WAAW,CAAC,MAAc;QAChC,OAAO,MAAM,CAAC,SAAS,EAAE,KAAK,IAAI,CAAC,YAAY,CAAC;IAClD,CAAC;IAEO,uBAAuB,GAAG,CAAC,QAAiB,EAAE,MAAc,EAAQ,EAAE;QAC5E,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QACtC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC1E,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC,CAAC;IAEM,wBAAwB,GAAG,CACjC,OAAgB,EAChB,MAAc,EACd,QAAwB,EACxB,WAAqB,EACrB,WAAqB,EACf,EAAE;QACR,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;YAAE,OAAO;QAEtC,4DAA4D;QAC5D,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;YACnE,IAAI,OAAO,GAAG,wBAAwB,EAAE,CAAC;gBACvC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;gBACjE,OAAO;YACT,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,uBAAuB,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACvF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE7D,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC,CAAC,wBAAwB;QAC3D,IAAI,CAAC,aAAa,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;QAEvG,2EAA2E;QAC3E,uEAAuE;QACvE,wEAAwE;QACxE,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QAEjC,6FAA6F;QAC7F,+EAA+E;QAC/E,6EAA6E;QAC7E,+EAA+E;QAC/E,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YACpD,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC;YACvC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC;YACvC,IAAI,CAAC,qBAAqB;iBACvB,iBAAiB,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC;iBAC9F,IAAI,CAAC,GAAG,EAAE;gBACT,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC/B,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC/B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;gBACjE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;YACnE,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC,CAAC;QAClF,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACpD,CAAC,CAAC;CACH"}
@@ -1,252 +0,0 @@
1
- import { PropertyName } from 'eufy-security-client';
2
- import { FFmpeg, FFmpegParameters } from '../utils/ffmpeg.js';
3
- import { CHAR, SERV, isRtspReady, applyP2PAudioFormat, log, ffmpegLoggerFactory } from '../utils/utils.js';
4
- const MAX_RECORDING_MINUTES = 1; // should never be used
5
- /** Max time (ms) to wait for the next fMP4 box before considering the stream stalled. */
6
- const SEGMENT_HEARTBEAT_TIMEOUT_MS = 10_000;
7
- /** Minimum moof+mdat fragments before honouring motion-stopped to avoid ultra-short recordings. */
8
- const MIN_FRAGMENTS_BEFORE_STOP = 2;
9
- const HKSVQuitReason = [
10
- 'Normal',
11
- 'Not allowed',
12
- 'Busy',
13
- 'Cancelled',
14
- 'Unsupported',
15
- 'Unexpected Failure',
16
- 'Timeout',
17
- 'Bad data',
18
- 'Protocol error',
19
- 'Invalid Configuration',
20
- ];
21
- export class RecordingDelegate {
22
- platform;
23
- accessory;
24
- camera;
25
- cameraConfig;
26
- localLivestreamManager;
27
- snapshotDlg;
28
- configuration;
29
- forceStopTimeout;
30
- closeReason;
31
- handlingStreamingRequest = false;
32
- controller;
33
- session;
34
- /** Delay before extracting a snapshot from a running HKSV recording (ms). */
35
- static RECORDING_SNAPSHOT_DELAY_MS = 2_000;
36
- constructor(platform, accessory, camera, cameraConfig, localLivestreamManager, snapshotDlg) {
37
- this.platform = platform;
38
- this.accessory = accessory;
39
- this.camera = camera;
40
- this.cameraConfig = cameraConfig;
41
- this.localLivestreamManager = localLivestreamManager;
42
- this.snapshotDlg = snapshotDlg;
43
- }
44
- setController(controller) {
45
- this.controller = controller;
46
- }
47
- isRecording() {
48
- return this.handlingStreamingRequest;
49
- }
50
- resetMotionSensor() {
51
- const motionDetected = this.accessory.getService(SERV.MotionSensor)?.getCharacteristic(CHAR.MotionDetected).value;
52
- if (motionDetected) {
53
- this.accessory.getService(SERV.MotionSensor)?.getCharacteristic(CHAR.MotionDetected).updateValue(false);
54
- }
55
- }
56
- clearForceStopTimeout() {
57
- if (this.forceStopTimeout) {
58
- clearTimeout(this.forceStopTimeout);
59
- this.forceStopTimeout = undefined;
60
- }
61
- }
62
- isMotionDetected() {
63
- return !!this.accessory.getService(SERV.MotionSensor)?.getCharacteristic(CHAR.MotionDetected).value;
64
- }
65
- async configureInputSource(videoParams, audioParams) {
66
- if (isRtspReady(this.camera, this.cameraConfig)) {
67
- const url = this.camera.getPropertyValue(PropertyName.DeviceRTSPStreamUrl);
68
- log.debug(this.camera.getName(), 'RTSP URL: ' + url);
69
- videoParams.setInputSource(url);
70
- audioParams.setInputSource(url);
71
- }
72
- else {
73
- const streamData = await this.localLivestreamManager.getLocalLiveStream('hksv');
74
- await videoParams.setInputStream(streamData.videostream);
75
- applyP2PAudioFormat(audioParams, streamData.metadata.audioCodec);
76
- await audioParams.setInputStream(streamData.audiostream);
77
- }
78
- }
79
- async *handleRecordingStreamRequest() {
80
- this.handlingStreamingRequest = true;
81
- this.closeReason = undefined;
82
- log.info(this.camera.getName(), 'requesting recording for HomeKit Secure Video.');
83
- try {
84
- if (!this.configuration) {
85
- log.error(this.camera.getName(), 'No recording configuration available. Aborting.');
86
- yield { data: Buffer.alloc(0), isLast: true };
87
- return;
88
- }
89
- const audioEnabled = this.cameraConfig.audio !== false &&
90
- this.controller?.recordingManagement?.recordingManagementService.getCharacteristic(CHAR.RecordingAudioActive)
91
- .value;
92
- log.debug(this.camera.getName(), `HKSV audio recording: ${audioEnabled ? 'enabled' : 'disabled'}.`);
93
- const videoConfig = this.cameraConfig.videoConfig ?? {};
94
- const videoParams = await FFmpegParameters.forVideoRecording(videoConfig.debug);
95
- const audioParams = await FFmpegParameters.forAudioRecording(videoConfig.debug);
96
- videoParams.setupForRecording(videoConfig, this.configuration);
97
- audioParams.setupForRecording(videoConfig, this.configuration);
98
- await this.configureInputSource(videoParams, audioParams);
99
- // Opportunistically capture a snapshot from the HKSV recording stream
100
- setTimeout(() => {
101
- this.snapshotDlg.captureSnapshotFromActiveLivestream().catch((error) => {
102
- log.debug(this.camera.getName(), 'Snapshot capture from HKSV recording failed: ' + error);
103
- });
104
- }, RecordingDelegate.RECORDING_SNAPSHOT_DELAY_MS);
105
- const ffmpeg = new FFmpeg(`[${this.camera.getName()}] [HSV Recording Process]`, audioEnabled ? [videoParams, audioParams] : videoParams, ffmpegLoggerFactory.forCamera(this.camera.getSerial()));
106
- ffmpeg.on('error', (error) => {
107
- log.debug(this.camera.getName(), 'HKSV recording FFmpeg error: ' + error);
108
- });
109
- this.session = await ffmpeg.startFragmentedMP4Session();
110
- const maxDuration = Math.min(this.cameraConfig.hsvRecordingDuration ?? MAX_RECORDING_MINUTES * 60, this.platform.config.CameraMaxLivestreamDuration);
111
- if (maxDuration > 0) {
112
- this.forceStopTimeout = setTimeout(() => {
113
- log.warn(this.camera.getName(), `Recording force-stopped after ${maxDuration}s.`);
114
- this.resetMotionSensor();
115
- }, maxDuration * 1000);
116
- }
117
- yield* this.generateFragments(this.session.generator);
118
- }
119
- catch (error) {
120
- if (!this.handlingStreamingRequest &&
121
- this.closeReason &&
122
- this.closeReason === 3 /* HDSProtocolSpecificErrorReason.CANCELLED */) {
123
- log.debug(this.camera.getName(), 'Recording encountered an error but that is expected, as the recording was canceled beforehand. Error: ' +
124
- error);
125
- }
126
- else {
127
- log.error(this.camera.getName(), 'Error while recording: ' + error);
128
- }
129
- }
130
- finally {
131
- this.logCloseReason();
132
- this.clearForceStopTimeout();
133
- this.resetMotionSensor();
134
- this.localLivestreamManager.stopLocalLiveStream();
135
- }
136
- }
137
- logCloseReason() {
138
- if (!this.closeReason) {
139
- return;
140
- }
141
- if (this.closeReason === 3 /* HDSProtocolSpecificErrorReason.CANCELLED */) {
142
- log.debug(this.camera.getName(), 'The recording process was canceled by the HomeKit Controller.');
143
- }
144
- else if (this.closeReason !== 0 /* HDSProtocolSpecificErrorReason.NORMAL */) {
145
- log.warn(this.camera.getName(), `The recording process was aborted by HSV with reason "${HKSVQuitReason[this.closeReason]}"`);
146
- }
147
- }
148
- /**
149
- * Assembles fragmented MP4 boxes into HKSV-compatible recording packets.
150
- * Yields an initialization segment (ftyp+moov), then paired moof+mdat fragments.
151
- */
152
- async *generateFragments(generator) {
153
- const cameraName = this.camera.getName();
154
- let initPending = [];
155
- let moofBuffer = null;
156
- let isInit = true;
157
- let fragmentCount = 0;
158
- let sentLast = false;
159
- let heartbeatTimer;
160
- const resetHeartbeat = () => {
161
- if (heartbeatTimer)
162
- clearTimeout(heartbeatTimer);
163
- heartbeatTimer = setTimeout(() => {
164
- log.error(cameraName, `No HKSV data received for ${SEGMENT_HEARTBEAT_TIMEOUT_MS / 1000}s — stream appears stalled. Ending recording.`);
165
- this.handlingStreamingRequest = false;
166
- this.session?.socket?.destroy();
167
- }, SEGMENT_HEARTBEAT_TIMEOUT_MS);
168
- };
169
- resetHeartbeat();
170
- try {
171
- for await (const { header, type, data } of generator) {
172
- if (!this.handlingStreamingRequest) {
173
- log.debug(cameraName, 'Recording was ended prematurely.');
174
- break;
175
- }
176
- resetHeartbeat();
177
- if (isInit) {
178
- initPending.push(header, data);
179
- if (type === 'moov') {
180
- const fragment = Buffer.concat(initPending);
181
- initPending = [];
182
- isInit = false;
183
- log.debug(cameraName, `HKSV: Sending initialization segment, size: ${fragment.length}`);
184
- yield { data: fragment, isLast: false };
185
- }
186
- continue;
187
- }
188
- if (type === 'moof') {
189
- moofBuffer = Buffer.concat([header, data]);
190
- }
191
- else if (type === 'mdat' && moofBuffer) {
192
- const fragment = Buffer.concat([moofBuffer, header, data]);
193
- moofBuffer = null;
194
- fragmentCount++;
195
- const motionStopped = !this.isMotionDetected() && fragmentCount >= MIN_FRAGMENTS_BEFORE_STOP;
196
- const isLast = motionStopped || !this.handlingStreamingRequest;
197
- log.debug(cameraName, `HKSV: Fragment #${fragmentCount}, size: ${fragment.length}${isLast ? ' (final)' : ''}`);
198
- yield { data: fragment, isLast };
199
- if (isLast) {
200
- sentLast = true;
201
- log.debug(cameraName, motionStopped
202
- ? 'Ending recording session due to motion stopped.'
203
- : 'Ending recording session due to stream close.');
204
- break;
205
- }
206
- }
207
- }
208
- if (!sentLast && !isInit) {
209
- log.warn(cameraName, `HKSV: Recording ended after ${fragmentCount} fragment(s) without signalling end-of-stream to HomeKit.`);
210
- }
211
- }
212
- finally {
213
- if (heartbeatTimer)
214
- clearTimeout(heartbeatTimer);
215
- }
216
- }
217
- updateRecordingActive(active) {
218
- log.info(this.camera.getName(), `HKSV recording ${active ? 'enabled' : 'disabled'} by HomeKit.`);
219
- }
220
- updateRecordingConfiguration(configuration) {
221
- this.configuration = configuration;
222
- }
223
- closeRecordingStream(streamId, reason) {
224
- log.info(this.camera.getName(), 'Closing recording process');
225
- this.closeReason = reason;
226
- this.handlingStreamingRequest = false;
227
- if (this.session) {
228
- log.debug(this.camera.getName(), 'Stopping recording session.');
229
- const isCancelled = reason === 3 /* HDSProtocolSpecificErrorReason.CANCELLED */;
230
- if (isCancelled) {
231
- this.session.socket?.destroy();
232
- this.session.ffmpeg?.stop();
233
- }
234
- else {
235
- this.session.ffmpeg?.stop();
236
- const socket = this.session.socket;
237
- setTimeout(() => socket?.destroy(), 2_500);
238
- }
239
- this.session = undefined;
240
- }
241
- else {
242
- log.warn('Recording session could not be closed gracefully.');
243
- }
244
- this.clearForceStopTimeout();
245
- this.resetMotionSensor();
246
- }
247
- acknowledgeStream(streamId) {
248
- log.debug('end of recording acknowledged!');
249
- this.closeRecordingStream(streamId, undefined);
250
- }
251
- }
252
- //# sourceMappingURL=recordingDelegate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"recordingDelegate.js","sourceRoot":"","sources":["../../src/controller/recordingDelegate.ts"],"names":[],"mappings":"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"}