@camera.ui/server 0.0.70 → 0.0.71-dev.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 (1328) hide show
  1. package/CLAUDE.md +91 -0
  2. package/README.md +0 -24
  3. package/cupdate.config.txt +0 -1
  4. package/dist/interface/assets/404-CIsBB4A0.js +1 -0
  5. package/dist/interface/assets/About-CkxZb9D-.js +1 -0
  6. package/dist/interface/assets/Adminpanel-BrZ55JBx.js +1 -0
  7. package/dist/interface/assets/Automation-BKhuIS2v.js +2 -0
  8. package/dist/interface/assets/Automation-Csu8t0D7.css +1 -0
  9. package/dist/interface/assets/Automations-CzdnqGGU.js +1 -0
  10. package/dist/interface/assets/Camera-BhCDJE7I.css +1 -0
  11. package/dist/interface/assets/Camera-CU3aKdBR.js +2 -0
  12. package/dist/interface/assets/CameraConsole-D7KxwRxQ.js +7 -0
  13. package/dist/interface/assets/Cameras-807mspcl.css +1 -0
  14. package/dist/interface/assets/Cameras-DJcAfGpU.js +656 -0
  15. package/dist/interface/assets/Camview-ArBQ3nES.js +1 -0
  16. package/dist/interface/assets/Camview-Dd7DwMHG.css +1 -0
  17. package/dist/interface/assets/Config-D2ftkjl2.js +2 -0
  18. package/dist/interface/assets/Config-JgftUZFe.css +1 -0
  19. package/dist/interface/assets/ConfigActionCameraControl-94iyzBzJ.js +1 -0
  20. package/dist/interface/assets/ConfigActionDelay-DKhE0Xr8.js +1 -0
  21. package/dist/interface/assets/ConfigActionHttp-BbfN1UGF.js +1 -0
  22. package/dist/interface/assets/ConfigActionImageInput-P39gRfld.js +1 -0
  23. package/dist/interface/assets/ConfigActionNotification-CuDDnksK.js +1 -0
  24. package/dist/interface/assets/ConfigActionOutput-BIHvC1Z5.js +1 -0
  25. package/dist/interface/assets/ConfigActionPlugin-CDA53LwA.js +1 -0
  26. package/dist/interface/assets/ConfigActionSensor-BBkfWT_r.js +1 -0
  27. package/dist/interface/assets/ConfigActionSnapshot-C5enxVcl.js +1 -0
  28. package/dist/interface/assets/ConfigActionVariable-CVaOMoOi.js +1 -0
  29. package/dist/interface/assets/ConfigConditionIfElse-DiIOUqA5.js +1 -0
  30. package/dist/interface/assets/ConfigConditionSensorState-DBktbA8F.js +1 -0
  31. package/dist/interface/assets/ConfigConditionSwitch-DWqcQ3Ip.js +1 -0
  32. package/dist/interface/assets/ConfigConditionTime-BEaHclqa.js +1 -0
  33. package/dist/interface/assets/ConfigTriggerDetection-CRnZR91p.js +1 -0
  34. package/dist/interface/assets/ConfigTriggerGeofence-DODdJBZW.js +1 -0
  35. package/dist/interface/assets/ConfigTriggerManual-V8-5hrdl.js +1 -0
  36. package/dist/interface/assets/ConfigTriggerSchedule-CqID85d1.js +1 -0
  37. package/dist/interface/assets/ConfigTriggerSensor-DR6ifBrK.js +1 -0
  38. package/dist/interface/assets/ConfigTriggerSystem-K1ohOW18.js +1 -0
  39. package/dist/interface/assets/ConfigTriggerWebhook-Cmwu5IU4.js +1 -0
  40. package/dist/interface/assets/Console-IC7AOnvc.js +6 -0
  41. package/dist/interface/assets/CuiActionButton-Ba5wT-4n.js +1 -0
  42. package/dist/interface/assets/CuiAvatar-BtMXnhxd.css +1 -0
  43. package/dist/interface/assets/CuiAvatar-Bu4NixiB.js +1 -0
  44. package/dist/interface/assets/CuiBBoxPlayground-Cmbd4_qG.js +1 -0
  45. package/dist/interface/assets/CuiBBoxPlayground-EFkdOBvq.css +1 -0
  46. package/dist/interface/assets/CuiBottomSheet-BN5exkJm.js +1 -0
  47. package/dist/interface/assets/CuiBottomSheet-CHspaYgP.js +1 -0
  48. package/dist/interface/assets/CuiBottomSheet-DxQ6D_RM.css +1 -0
  49. package/dist/interface/assets/CuiCameraCard-C7eDwhgw.js +1 -0
  50. package/dist/interface/assets/CuiCameraCard-dNsAwlKS.css +1 -0
  51. package/dist/interface/assets/CuiCameraPipCard-C8Pg7xT9.js +1 -0
  52. package/dist/interface/assets/CuiCameraPipCard-D3o29_wc.css +1 -0
  53. package/dist/interface/assets/CuiCameraRecordings-CQHbo-_J.js +1 -0
  54. package/dist/interface/assets/CuiCameraRecordings-DM_o0Lya.css +1 -0
  55. package/dist/interface/assets/CuiCameraShares-DNuCgk4b.js +1 -0
  56. package/dist/interface/assets/CuiCameraSnapshot-BpUMwSoR.js +1 -0
  57. package/dist/interface/assets/CuiCameraTable-DQffvTtY.js +2 -0
  58. package/dist/interface/assets/CuiFloatingButton-RaxwbGht.js +1 -0
  59. package/dist/interface/assets/CuiImage-60jwFIqc.js +1 -0
  60. package/dist/interface/assets/CuiImage-Bxf7z2N4.css +1 -0
  61. package/dist/interface/assets/CuiMarkdownContent-M5v8bBmS.js +1 -0
  62. package/dist/interface/assets/CuiMenu-B4CHT2F_.js +1 -0
  63. package/dist/interface/assets/CuiMenu-BWUfWLQP.css +1 -0
  64. package/dist/interface/assets/CuiPluginCard-5ItfIe1Z.js +2 -0
  65. package/dist/interface/assets/CuiPluginCard-CTTsEM9M.css +1 -0
  66. package/dist/interface/assets/CuiPluginOAuthButton-BJRU2JBX.js +2 -0
  67. package/dist/interface/assets/CuiQRCode-CNeepRQw.js +1 -0
  68. package/dist/interface/assets/CuiQRCode-DfUba6JB.css +1 -0
  69. package/dist/interface/assets/CuiRecordingsGrid-CKHFeJlJ.js +1 -0
  70. package/dist/interface/assets/CuiRecordingsGrid-CZIZiEuT.css +1 -0
  71. package/dist/interface/assets/CuiSchema--yMBD996.css +1 -0
  72. package/dist/interface/assets/CuiSchema-CTRLO0uq.js +1 -0
  73. package/dist/interface/assets/CuiTopNavbarItem-CgaR_X1z.js +1 -0
  74. package/dist/interface/assets/CuiTopNavbarItem-w54CrODK.css +1 -0
  75. package/dist/interface/assets/CuiTopbarSlot-BDZoZ_yn.js +1 -0
  76. package/dist/interface/assets/Faces-JoBk1Mcv.js +1 -0
  77. package/dist/interface/assets/FirstSteps-CSMvd_p0.js +1 -0
  78. package/dist/interface/assets/Instances-DwNihvsL.js +1 -0
  79. package/dist/interface/assets/Menu-CUnOgtD5.js +1 -0
  80. package/dist/interface/assets/OAuthDeviceFlow-aUHpE7wP.js +1 -0
  81. package/dist/interface/assets/Plugin-DoxdkvWR.css +1 -0
  82. package/dist/interface/assets/Plugin-LjpUwn17.js +1 -0
  83. package/dist/interface/assets/PluginConsole-CvDWPKOs.js +7 -0
  84. package/dist/interface/assets/PluginSchema-DL7Bfd_U.js +1 -0
  85. package/dist/interface/assets/Plugins-B207FOsG.js +2 -0
  86. package/dist/interface/assets/Plugins-BPt1RSKT.css +1 -0
  87. package/dist/interface/assets/Recordings-Bt_GlPOK.css +1 -0
  88. package/dist/interface/assets/Recordings-adHTSogQ.js +1 -0
  89. package/dist/interface/assets/Settings-bwLTNAxX.css +1 -0
  90. package/dist/interface/assets/Settings-iBjUbXTH.js +1 -0
  91. package/dist/interface/assets/SettingsAccount-Ce0UnkLb.js +1 -0
  92. package/dist/interface/assets/SettingsAccount-DXKQY4Iz.css +1 -0
  93. package/dist/interface/assets/SettingsAccount-f2wkt4kx.js +1 -0
  94. package/dist/interface/assets/SettingsAppearance-2TfnSgkI.js +1 -0
  95. package/dist/interface/assets/SettingsAppearance-Dca237An.js +1 -0
  96. package/dist/interface/assets/SettingsBackup-Bh5x-GU_.js +1 -0
  97. package/dist/interface/assets/SettingsNotifications-BVmhorXq.js +2 -0
  98. package/dist/interface/assets/SettingsRecordings-dPUm5hma.js +1 -0
  99. package/dist/interface/assets/SettingsRemote-BcVzn2m3.js +1 -0
  100. package/dist/interface/assets/SettingsRemote-CjVK9pGg.css +1 -0
  101. package/dist/interface/assets/SettingsSystem-Dz76BUJ-.js +2 -0
  102. package/dist/interface/assets/SettingsUsers-Dzj--Rmf.js +1 -0
  103. package/dist/interface/assets/Terminal-BAMMh8Px.js +4 -0
  104. package/dist/interface/assets/Terminal-CrOfQJ-O.css +1 -0
  105. package/dist/interface/assets/VariableInput-D_-qKfZK.js +1 -0
  106. package/dist/interface/assets/VariableSuggestions-Br4yDsLZ.js +1 -0
  107. package/dist/interface/assets/VersionsHandler-CfNT3Yke.js +7 -0
  108. package/dist/interface/assets/Workers-D3jFWBjm.js +1 -0
  109. package/dist/interface/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
  110. package/dist/interface/assets/ace-BRyQJK-L.js +1 -0
  111. package/dist/interface/assets/ace.config-fXRdG20S.js +1 -0
  112. package/dist/interface/assets/alert-outline-D3FCIX7_.js +1 -0
  113. package/dist/interface/assets/api-BaywoTCE.js +2 -0
  114. package/dist/interface/assets/api-Cna9Poda.css +2 -0
  115. package/dist/interface/assets/api-DvuXV3Xb.js +1 -0
  116. package/dist/interface/assets/auth-Cu-pUvKk.js +1 -0
  117. package/dist/interface/assets/automation-CbEPnAW4.js +1 -0
  118. package/dist/interface/assets/automations-Bj3wF0wR.js +1 -0
  119. package/dist/interface/assets/automations-C6ssihoC.js +1 -0
  120. package/dist/interface/assets/back-filled-CvLD0CND.js +1 -0
  121. package/dist/interface/assets/backup-DK5aZBLo.js +1 -0
  122. package/dist/interface/assets/bell-outline-JZZKpcfS.js +1 -0
  123. package/dist/interface/assets/camera-preview-C7GT5VHo.png +0 -0
  124. package/dist/interface/assets/cameras-DQ28quQb.js +1 -0
  125. package/dist/interface/assets/cameras.schema-CDeB5JeE.js +1 -0
  126. package/dist/interface/assets/cctv-SQFfbBnL.js +1 -0
  127. package/dist/interface/assets/check-BQQidcYi.js +1 -0
  128. package/dist/interface/assets/chevron-down-Dd1qHXVA.js +1 -0
  129. package/dist/interface/assets/chevron-right-DOmJR2OL.js +1 -0
  130. package/dist/interface/assets/circular-connection-nKCVm4QI.js +1 -0
  131. package/dist/interface/assets/close-Dhjo4o57.js +1 -0
  132. package/dist/interface/assets/close-WdhW_91X.js +1 -0
  133. package/dist/interface/assets/close-circle-i5PrRG0X.js +1 -0
  134. package/dist/interface/assets/close-rounded-6nzLVPw0.js +1 -0
  135. package/dist/interface/assets/cloud-check-DeN6leiB.js +1 -0
  136. package/dist/interface/assets/cloud-outline-BHjUiP9q.js +1 -0
  137. package/dist/interface/assets/cloud-outline-BQddJElX.js +1 -0
  138. package/dist/interface/assets/cloudHandoff-DxhttWWd.js +1 -0
  139. package/dist/interface/assets/cog-Batjj1se.js +1 -0
  140. package/dist/interface/assets/copy-16-filled-DuAEBVEX.js +1 -0
  141. package/dist/interface/assets/copy-BeuZDsJN.js +1 -0
  142. package/dist/interface/assets/delete-DvMWXBFV.js +1 -0
  143. package/dist/interface/assets/dist-CcCNy5h7.js +1 -0
  144. package/dist/interface/assets/download-Cna5QEEj.js +1 -0
  145. package/dist/interface/assets/esm-B4Pd2w1t.js +1 -0
  146. package/dist/interface/assets/esm-B4l8-ACY.js +1 -0
  147. package/dist/interface/assets/esm-BE98HKPg.js +1 -0
  148. package/dist/interface/assets/esm-BNSLSv2m.js +1 -0
  149. package/dist/interface/assets/esm-BnT9fzsT.js +1 -0
  150. package/dist/interface/assets/esm-C-uLCRX1.js +1 -0
  151. package/dist/interface/assets/esm-C6JCcz6o.js +1 -0
  152. package/dist/interface/assets/esm-D5_rxfjE.js +1 -0
  153. package/dist/interface/assets/esm-D6ymjVa1.js +1 -0
  154. package/dist/interface/assets/esm-D8teZoG1.js +1 -0
  155. package/dist/interface/assets/esm-DnSGrmvg.js +1 -0
  156. package/dist/interface/assets/esm-DqkQVzkL.js +1 -0
  157. package/dist/interface/assets/esm-tnu6qUMk.js +1 -0
  158. package/dist/interface/assets/eventIcons-2hVCNchU.css +1 -0
  159. package/dist/interface/assets/eventIcons-DVykqtE5.js +1 -0
  160. package/dist/interface/assets/face-recognition-5Yp1IcUb.js +1 -0
  161. package/dist/interface/assets/github-37yEERpu.js +1 -0
  162. package/dist/interface/assets/grid-fill-BGU3gqir.js +1 -0
  163. package/dist/interface/assets/hasPermission-DIF0bX8u.js +1 -0
  164. package/dist/interface/assets/home-sSF_NnOu.js +1 -0
  165. package/dist/interface/assets/information-outline-fu18_QSH.js +1 -0
  166. package/dist/interface/assets/instances-DGPhZWRw.js +1 -0
  167. package/dist/interface/assets/lightbulb-outline-DWc53kV7.js +1 -0
  168. package/dist/interface/assets/locale-Bm1nXzqV.js +1 -0
  169. package/dist/interface/assets/main-BqVSZVz1.css +1 -0
  170. package/dist/interface/assets/main-D1gFWXGG.js +3 -0
  171. package/dist/interface/assets/microphone-ChDR4mkG.js +1 -0
  172. package/dist/interface/assets/native-Cq3ra8E-.js +1 -0
  173. package/dist/interface/assets/native-DfLBhmBo.js +1 -0
  174. package/dist/interface/assets/nodeDefinitions-BLSMZueH.js +1 -0
  175. package/dist/interface/assets/notifications-DNRzOl89.js +1 -0
  176. package/dist/interface/assets/play-solid-B_749j1A.js +1 -0
  177. package/dist/interface/assets/plugin-C1NakF2p.js +1 -0
  178. package/dist/interface/assets/plugins-DzRwEcA4.js +1 -0
  179. package/dist/interface/assets/plus-B5eEboLZ.js +1 -0
  180. package/dist/interface/assets/plus-Dis0MPt8.js +1 -0
  181. package/dist/interface/assets/power-CxGfHa98.js +1 -0
  182. package/dist/interface/assets/ring-resize-fOkdAS5R.js +1 -0
  183. package/dist/interface/assets/rolldown-runtime-CMxvf4Kt.js +1 -0
  184. package/dist/interface/assets/round-alt-arrow-left-bold-ekP_ATNV.js +1 -0
  185. package/dist/interface/assets/round-restart-alt-BWTTuG_j.js +1 -0
  186. package/dist/interface/assets/round-restart-alt-CJgRaJjF.css +1 -0
  187. package/dist/interface/assets/router-CuAn6JZ_.css +1 -0
  188. package/dist/interface/assets/router-DGyFln7e.js +2 -0
  189. package/dist/interface/assets/routerState-DMVeYr60.js +1 -0
  190. package/dist/interface/assets/search-YdrT6au7.js +1 -0
  191. package/dist/interface/assets/server-BWxbeZzY.js +1 -0
  192. package/dist/interface/assets/settings-D2-mWioF.js +1 -0
  193. package/dist/interface/assets/shares-BLuBJftj.js +1 -0
  194. package/dist/interface/assets/shield-check-DFR-xg-g.js +1 -0
  195. package/dist/interface/assets/terminal-BYi6cqd4.js +1 -0
  196. package/dist/interface/assets/theme-D08Upl8q.js +1 -0
  197. package/dist/interface/assets/trash-2-Du7oioNA.js +1 -0
  198. package/dist/interface/assets/trash-can-YTXLzAmt.js +1 -0
  199. package/dist/interface/assets/trash-fill-ZI3YYgNp.js +1 -0
  200. package/dist/interface/assets/types-B_isDU64.js +1 -0
  201. package/dist/interface/assets/types-BxFyoO54.js +1 -0
  202. package/dist/interface/assets/types-kxdn9XBW.js +1 -0
  203. package/dist/interface/assets/ui-aYGNqaHi.js +1 -0
  204. package/dist/interface/assets/upload-Chr4Uunq.js +1 -0
  205. package/dist/interface/assets/useBiometricCredentials-B-zA6b-X.js +1 -0
  206. package/dist/interface/assets/useCameraOptions-0w0LNh72.js +1 -0
  207. package/dist/interface/assets/useCuiCameraDrawer-Dn97MLFe.js +1 -0
  208. package/dist/interface/assets/useCuiDialog-BbkaNkQN.js +2 -0
  209. package/dist/interface/assets/useElectron-mh8HQUAI.js +1 -0
  210. package/dist/interface/assets/useFileDownload-g3sM8lp6.js +1 -0
  211. package/dist/interface/assets/useLogsSocket-CZld674d.js +4 -0
  212. package/dist/interface/assets/useLogsSocket-pqdh7jNG.css +1 -0
  213. package/dist/interface/assets/useSharedComposables-riqEUgwX.js +1 -0
  214. package/dist/interface/assets/useStreamStatus-2lguNuWT.js +1 -0
  215. package/dist/interface/assets/users.schema-CUZOYClB.js +1 -0
  216. package/dist/interface/assets/vendor-DmhYd_sB.js +22 -0
  217. package/dist/interface/assets/vendor-ace-B9YSA4ub.js +1085 -0
  218. package/dist/interface/assets/vendor-cameraui-DggYb17u.js +1976 -0
  219. package/dist/interface/assets/vendor-capacitor-IA6kwsx8.js +2 -0
  220. package/dist/interface/assets/vendor-chart-Dnlz1Jgy.js +3 -0
  221. package/dist/interface/assets/vendor-core-B6F-imJj.js +1 -0
  222. package/dist/interface/assets/vendor-dnd-Dp0ottZI.js +2 -0
  223. package/dist/interface/assets/vendor-draggabilly-C2ae3o70.js +1 -0
  224. package/dist/interface/assets/vendor-gridstack-Dxjc1EeA.js +3 -0
  225. package/dist/interface/assets/vendor-gridstack-Rg2RhwAc.css +1 -0
  226. package/dist/interface/assets/vendor-leaflet-B5L2Aw8Y.js +1 -0
  227. package/dist/interface/assets/vendor-leaflet-vh-t_kPv.css +1 -0
  228. package/dist/interface/assets/vendor-markdown-D3nVi7gw.js +15 -0
  229. package/dist/interface/assets/vendor-markdown-DtOhvyRx.css +1 -0
  230. package/dist/interface/assets/vendor-primevue--pcuf6kA.js +4289 -0
  231. package/dist/interface/assets/vendor-vueflow-CBuKPASC.js +26 -0
  232. package/dist/interface/assets/vendor-xterm-BrP-ENHg.css +1 -0
  233. package/dist/interface/assets/vendor-xterm-D8Z_h2U0.js +145 -0
  234. package/dist/interface/assets/vendor-zod-CmGeQCqy.js +127 -0
  235. package/dist/interface/assets/view-grid-96p9T-KQ.js +1 -0
  236. package/dist/interface/assets/view-grid-SdzaC3O_.css +1 -0
  237. package/dist/interface/assets/web-3Sh2qjiP.js +1 -0
  238. package/dist/interface/assets/web-B0BK4Q2M.js +1 -0
  239. package/dist/interface/assets/web-BjKL51lK-DzG2kK8Q.js +1 -0
  240. package/dist/interface/assets/web-COttRPza.js +1 -0
  241. package/dist/interface/assets/web-Ck1J3gUt.js +1 -0
  242. package/dist/interface/assets/web-DPxPmEOR.js +1 -0
  243. package/dist/interface/assets/web-DRprnZwc.js +1 -0
  244. package/dist/interface/assets/web-DusfFKJE.js +1 -0
  245. package/dist/interface/assets/web-U3ajDFzM.js +1 -0
  246. package/dist/interface/assets/web-jcLz0P7f.js +1 -0
  247. package/dist/interface/assets/web-tQAiC0W2.js +1 -0
  248. package/dist/interface/assets/web-x9pvmNMf.js +1 -0
  249. package/dist/interface/assets/workbox-window.prod.es5-DkzC-kEO.js +1 -0
  250. package/dist/interface/assets/worker-base-ybazWkNy.js +1337 -0
  251. package/dist/interface/assets/worker-yaml-crtWQpDN.js +5824 -0
  252. package/dist/interface/assets/zoom-in-zoFmMkYM.js +1 -0
  253. package/dist/interface/index.html +96 -45
  254. package/dist/interface/manifest.webmanifest +1 -1
  255. package/dist/interface/og-share.png +0 -0
  256. package/dist/interface/sw.js +1 -1
  257. package/dist/interface/workbox-5f44db27.js +1 -0
  258. package/dist/server/package.json +73 -79
  259. package/dist/server/requirements.txt +9 -14
  260. package/dist/server/src/_camera_ui_tools/camera_ui_common/__init__.py +19 -11
  261. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/__init__.py +23 -0
  262. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/object_path.py +35 -22
  263. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/promise.py +41 -0
  264. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/reactive.py +17 -14
  265. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/signal_handler.py +12 -4
  266. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/subscribed.py +15 -2
  267. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/task.py +9 -3
  268. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/thread.py +10 -2
  269. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/utils.py +21 -13
  270. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/__init__.py +8 -0
  271. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/logger.py +237 -99
  272. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/__init__.py +77 -0
  273. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/channel.py +321 -0
  274. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/chunking.py +290 -0
  275. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/client.py +1694 -0
  276. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/codec.py +73 -0
  277. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/decorators.py +307 -0
  278. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/errors.py +76 -0
  279. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/executor.py +29 -0
  280. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/handler.py +523 -0
  281. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/service.py +524 -0
  282. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/svcm.py +15 -0
  283. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/types.py +427 -0
  284. package/dist/server/src/_camera_ui_tools/camera_ui_rpc/utils.py +332 -0
  285. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/__init__.py +515 -0
  286. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/__init__.py +173 -0
  287. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/config.py +256 -0
  288. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/detection.py +135 -0
  289. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/device.py +432 -0
  290. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/enums.py +111 -0
  291. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/events.py +146 -0
  292. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/frames.py +21 -0
  293. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/streaming.py +188 -0
  294. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/__init__.py +92 -0
  295. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/camera_config_internal.py +46 -0
  296. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/camera_enums.py +9 -0
  297. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/camera_wire.py +15 -0
  298. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/event_emitter.py +102 -0
  299. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/manager_rpc.py +27 -0
  300. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/sensor_rpc.py +89 -0
  301. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/sensor_triggers.py +4 -0
  302. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/shared_utils.py +73 -0
  303. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/streaming_internal.py +16 -0
  304. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/manager/__init__.py +348 -0
  305. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/observable/__init__.py +557 -0
  306. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/__init__.py +104 -0
  307. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/api.py +137 -0
  308. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/contract.py +164 -0
  309. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/helper.py +242 -0
  310. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/interfaces.py +427 -0
  311. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/notifier.py +142 -0
  312. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/oauth.py +150 -0
  313. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/__init__.py +203 -0
  314. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/audio.py +241 -0
  315. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/base.py +551 -0
  316. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/battery.py +167 -0
  317. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/classifier.py +196 -0
  318. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/clip.py +67 -0
  319. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/contact.py +88 -0
  320. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/detection.py +60 -0
  321. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/doorbell.py +122 -0
  322. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/face.py +184 -0
  323. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/garage.py +174 -0
  324. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/humidity.py +79 -0
  325. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/leak.py +88 -0
  326. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/license_plate.py +186 -0
  327. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/light.py +157 -0
  328. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/lock.py +149 -0
  329. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/motion.py +203 -0
  330. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/object.py +210 -0
  331. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/occupancy.py +88 -0
  332. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/ptz.py +256 -0
  333. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/security_system.py +157 -0
  334. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/siren.py +150 -0
  335. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/smoke.py +88 -0
  336. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/spec.py +56 -0
  337. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/switch.py +107 -0
  338. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/temperature.py +80 -0
  339. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/storage/__init__.py +695 -0
  340. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/types.py +54 -0
  341. package/dist/server/src/api/controllers/api.controller.d.ts +2 -2
  342. package/dist/server/src/api/controllers/api.controller.js +3 -3
  343. package/dist/server/src/api/controllers/api.controller.js.map +1 -1
  344. package/dist/server/src/api/controllers/auth.controller.d.ts +20 -5
  345. package/dist/server/src/api/controllers/auth.controller.js +418 -134
  346. package/dist/server/src/api/controllers/auth.controller.js.map +1 -1
  347. package/dist/server/src/api/controllers/automations.controller.d.ts +17 -0
  348. package/dist/server/src/api/controllers/automations.controller.js +146 -0
  349. package/dist/server/src/api/controllers/automations.controller.js.map +1 -0
  350. package/dist/server/src/api/controllers/backup.controller.js +0 -1
  351. package/dist/server/src/api/controllers/backup.controller.js.map +1 -1
  352. package/dist/server/src/api/controllers/cameras.controller.d.ts +14 -5
  353. package/dist/server/src/api/controllers/cameras.controller.js +490 -69
  354. package/dist/server/src/api/controllers/cameras.controller.js.map +1 -1
  355. package/dist/server/src/api/controllers/config.controller.d.ts +2 -2
  356. package/dist/server/src/api/controllers/config.controller.js +2 -2
  357. package/dist/server/src/api/controllers/config.controller.js.map +1 -1
  358. package/dist/server/src/api/controllers/download.controller.d.ts +7 -0
  359. package/dist/server/src/api/controllers/download.controller.js +12 -0
  360. package/dist/server/src/api/controllers/download.controller.js.map +1 -0
  361. package/dist/server/src/api/controllers/files.controller.js.map +1 -1
  362. package/dist/server/src/api/controllers/frameWorkers.controller.d.ts +1 -1
  363. package/dist/server/src/api/controllers/frameWorkers.controller.js +1 -1
  364. package/dist/server/src/api/controllers/frameWorkers.controller.js.map +1 -1
  365. package/dist/server/src/api/controllers/instances.controller.d.ts +15 -0
  366. package/dist/server/src/api/controllers/instances.controller.js +100 -0
  367. package/dist/server/src/api/controllers/instances.controller.js.map +1 -0
  368. package/dist/server/src/api/controllers/notifications.controller.d.ts +15 -0
  369. package/dist/server/src/api/controllers/notifications.controller.js +121 -0
  370. package/dist/server/src/api/controllers/notifications.controller.js.map +1 -0
  371. package/dist/server/src/api/controllers/oauthCallback.controller.d.ts +15 -0
  372. package/dist/server/src/api/controllers/oauthCallback.controller.js +53 -0
  373. package/dist/server/src/api/controllers/oauthCallback.controller.js.map +1 -0
  374. package/dist/server/src/api/controllers/plugins.controller.d.ts +5 -9
  375. package/dist/server/src/api/controllers/plugins.controller.js +129 -246
  376. package/dist/server/src/api/controllers/plugins.controller.js.map +1 -1
  377. package/dist/server/src/api/controllers/remote.controller.d.ts +27 -0
  378. package/dist/server/src/api/controllers/remote.controller.js +247 -0
  379. package/dist/server/src/api/controllers/remote.controller.js.map +1 -0
  380. package/dist/server/src/api/controllers/server.controller.d.ts +24 -0
  381. package/dist/server/src/api/controllers/server.controller.js +236 -0
  382. package/dist/server/src/api/controllers/server.controller.js.map +1 -0
  383. package/dist/server/src/api/controllers/shares.controller.d.ts +12 -0
  384. package/dist/server/src/api/controllers/shares.controller.js +121 -0
  385. package/dist/server/src/api/controllers/shares.controller.js.map +1 -0
  386. package/dist/server/src/api/controllers/tunnel.controller.d.ts +9 -0
  387. package/dist/server/src/api/controllers/tunnel.controller.js +39 -0
  388. package/dist/server/src/api/controllers/tunnel.controller.js.map +1 -0
  389. package/dist/server/src/api/controllers/users.controller.d.ts +2 -2
  390. package/dist/server/src/api/controllers/users.controller.js +11 -2
  391. package/dist/server/src/api/controllers/users.controller.js.map +1 -1
  392. package/dist/server/src/api/controllers/workers.controller.d.ts +14 -0
  393. package/dist/server/src/api/controllers/workers.controller.js +69 -0
  394. package/dist/server/src/api/controllers/workers.controller.js.map +1 -0
  395. package/dist/server/src/api/database/checks.js +2 -2
  396. package/dist/server/src/api/database/checks.js.map +1 -1
  397. package/dist/server/src/api/database/constants.d.ts +10 -1
  398. package/dist/server/src/api/database/constants.js +10 -1
  399. package/dist/server/src/api/database/constants.js.map +1 -1
  400. package/dist/server/src/api/database/index.d.ts +24 -12
  401. package/dist/server/src/api/database/index.js +182 -126
  402. package/dist/server/src/api/database/index.js.map +1 -1
  403. package/dist/server/src/api/database/migration.d.ts +4 -13
  404. package/dist/server/src/api/database/migration.js +20 -80
  405. package/dist/server/src/api/database/migration.js.map +1 -1
  406. package/dist/server/src/api/database/migrations/index.d.ts +2 -0
  407. package/dist/server/src/api/database/migrations/index.js +24 -0
  408. package/dist/server/src/api/database/migrations/index.js.map +1 -0
  409. package/dist/server/src/api/database/migrations/types.d.ts +13 -0
  410. package/dist/server/src/api/database/migrations/types.js.map +1 -0
  411. package/dist/server/src/api/database/selfcheck.js +3 -0
  412. package/dist/server/src/api/database/selfcheck.js.map +1 -1
  413. package/dist/server/src/api/database/types.d.ts +173 -28
  414. package/dist/server/src/api/index.d.ts +8 -2
  415. package/dist/server/src/api/index.js +122 -43
  416. package/dist/server/src/api/index.js.map +1 -1
  417. package/dist/server/src/api/middlewares/authPermission.middleware.d.ts +4 -4
  418. package/dist/server/src/api/middlewares/authPermission.middleware.js +8 -8
  419. package/dist/server/src/api/middlewares/authPermission.middleware.js.map +1 -1
  420. package/dist/server/src/api/middlewares/authValidation.middleware.d.ts +5 -2
  421. package/dist/server/src/api/middlewares/authValidation.middleware.js +75 -114
  422. package/dist/server/src/api/middlewares/authValidation.middleware.js.map +1 -1
  423. package/dist/server/src/api/middlewares/pagination.middleware.d.ts +1 -1
  424. package/dist/server/src/api/middlewares/pagination.middleware.js +2 -2
  425. package/dist/server/src/api/middlewares/pagination.middleware.js.map +1 -1
  426. package/dist/server/src/api/middlewares/socketAuth.middleware.d.ts +2 -2
  427. package/dist/server/src/api/middlewares/socketAuth.middleware.js +5 -4
  428. package/dist/server/src/api/middlewares/socketAuth.middleware.js.map +1 -1
  429. package/dist/server/src/api/plugins/header.plugin.js +1 -1
  430. package/dist/server/src/api/plugins/header.plugin.js.map +1 -1
  431. package/dist/server/src/api/plugins/logger.plugin.js +13 -10
  432. package/dist/server/src/api/plugins/logger.plugin.js.map +1 -1
  433. package/dist/server/src/api/plugins/proxy.plugin.js +76 -105
  434. package/dist/server/src/api/plugins/proxy.plugin.js.map +1 -1
  435. package/dist/server/src/api/plugins/system.plugin.js.map +1 -1
  436. package/dist/server/src/api/plugins/useragent.plugin.d.ts +2 -2
  437. package/dist/server/src/api/plugins/useragent.plugin.js +2 -2
  438. package/dist/server/src/api/plugins/useragent.plugin.js.map +1 -1
  439. package/dist/server/src/api/routes/api.routes.js +18 -2
  440. package/dist/server/src/api/routes/api.routes.js.map +1 -1
  441. package/dist/server/src/api/routes/auth.routes.js +131 -9
  442. package/dist/server/src/api/routes/auth.routes.js.map +1 -1
  443. package/dist/server/src/api/routes/automations.routes.d.ts +2 -0
  444. package/dist/server/src/api/routes/automations.routes.js +128 -0
  445. package/dist/server/src/api/routes/automations.routes.js.map +1 -0
  446. package/dist/server/src/api/routes/backup.routes.js +6 -0
  447. package/dist/server/src/api/routes/backup.routes.js.map +1 -1
  448. package/dist/server/src/api/routes/cameras.routes.js +346 -33
  449. package/dist/server/src/api/routes/cameras.routes.js.map +1 -1
  450. package/dist/server/src/api/routes/config.routes.js +26 -4
  451. package/dist/server/src/api/routes/config.routes.js.map +1 -1
  452. package/dist/server/src/api/routes/download.routes.d.ts +2 -0
  453. package/dist/server/src/api/routes/download.routes.js +16 -0
  454. package/dist/server/src/api/routes/download.routes.js.map +1 -0
  455. package/dist/server/src/api/routes/files.routes.js +7 -1
  456. package/dist/server/src/api/routes/files.routes.js.map +1 -1
  457. package/dist/server/src/api/routes/frameWorkers.routes.js +26 -4
  458. package/dist/server/src/api/routes/frameWorkers.routes.js.map +1 -1
  459. package/dist/server/src/api/routes/index.d.ts +1 -0
  460. package/dist/server/src/api/routes/index.js +23 -3
  461. package/dist/server/src/api/routes/index.js.map +1 -1
  462. package/dist/server/src/api/routes/instances.routes.d.ts +2 -0
  463. package/dist/server/src/api/routes/instances.routes.js +105 -0
  464. package/dist/server/src/api/routes/instances.routes.js.map +1 -0
  465. package/dist/server/src/api/routes/notifications.routes.d.ts +2 -0
  466. package/dist/server/src/api/routes/notifications.routes.js +102 -0
  467. package/dist/server/src/api/routes/notifications.routes.js.map +1 -0
  468. package/dist/server/src/api/routes/oauthCallback.routes.d.ts +2 -0
  469. package/dist/server/src/api/routes/oauthCallback.routes.js +17 -0
  470. package/dist/server/src/api/routes/oauthCallback.routes.js.map +1 -0
  471. package/dist/server/src/api/routes/plugins.routes.js +259 -95
  472. package/dist/server/src/api/routes/plugins.routes.js.map +1 -1
  473. package/dist/server/src/api/routes/remote.routes.d.ts +2 -0
  474. package/dist/server/src/api/routes/remote.routes.js +164 -0
  475. package/dist/server/src/api/routes/remote.routes.js.map +1 -0
  476. package/dist/server/src/api/routes/server.routes.d.ts +2 -0
  477. package/dist/server/src/api/routes/server.routes.js +130 -0
  478. package/dist/server/src/api/routes/server.routes.js.map +1 -0
  479. package/dist/server/src/api/routes/shares.routes.d.ts +2 -0
  480. package/dist/server/src/api/routes/shares.routes.js +71 -0
  481. package/dist/server/src/api/routes/shares.routes.js.map +1 -0
  482. package/dist/server/src/api/routes/tunnel.routes.d.ts +2 -0
  483. package/dist/server/src/api/routes/tunnel.routes.js +14 -0
  484. package/dist/server/src/api/routes/tunnel.routes.js.map +1 -0
  485. package/dist/server/src/api/routes/users.routes.js +92 -12
  486. package/dist/server/src/api/routes/users.routes.js.map +1 -1
  487. package/dist/server/src/api/routes/workers.routes.d.ts +2 -0
  488. package/dist/server/src/api/routes/workers.routes.js +71 -0
  489. package/dist/server/src/api/routes/workers.routes.js.map +1 -0
  490. package/dist/server/src/api/schemas/auth.schema.d.ts +35 -0
  491. package/dist/server/src/api/schemas/auth.schema.js +37 -0
  492. package/dist/server/src/api/schemas/auth.schema.js.map +1 -0
  493. package/dist/server/src/api/schemas/automations.schema.d.ts +151 -0
  494. package/dist/server/src/api/schemas/automations.schema.js +84 -0
  495. package/dist/server/src/api/schemas/automations.schema.js.map +1 -0
  496. package/dist/server/src/api/schemas/backup.schema.d.ts +15 -190
  497. package/dist/server/src/api/schemas/backup.schema.js +5 -23
  498. package/dist/server/src/api/schemas/backup.schema.js.map +1 -1
  499. package/dist/server/src/api/schemas/cameras.schema.d.ts +1062 -1647
  500. package/dist/server/src/api/schemas/cameras.schema.js +218 -49
  501. package/dist/server/src/api/schemas/cameras.schema.js.map +1 -1
  502. package/dist/server/src/api/schemas/common.schema.d.ts +7 -0
  503. package/dist/server/src/api/schemas/common.schema.js +7 -0
  504. package/dist/server/src/api/schemas/common.schema.js.map +1 -0
  505. package/dist/server/src/api/schemas/config.schema.d.ts +41 -79
  506. package/dist/server/src/api/schemas/config.schema.js +19 -1
  507. package/dist/server/src/api/schemas/config.schema.js.map +1 -1
  508. package/dist/server/src/api/schemas/download.schema.d.ts +5 -0
  509. package/dist/server/src/api/schemas/download.schema.js +5 -0
  510. package/dist/server/src/api/schemas/download.schema.js.map +1 -0
  511. package/dist/server/src/api/schemas/files.schema.d.ts +5 -0
  512. package/dist/server/src/api/schemas/files.schema.js +5 -0
  513. package/dist/server/src/api/schemas/files.schema.js.map +1 -0
  514. package/dist/server/src/api/schemas/frameWorkers.schema.d.ts +5 -0
  515. package/dist/server/src/api/schemas/frameWorkers.schema.js +5 -0
  516. package/dist/server/src/api/schemas/frameWorkers.schema.js.map +1 -0
  517. package/dist/server/src/api/schemas/go2rtc.schema.d.ts +90 -640
  518. package/dist/server/src/api/schemas/go2rtc.schema.js +1 -16
  519. package/dist/server/src/api/schemas/go2rtc.schema.js.map +1 -1
  520. package/dist/server/src/api/schemas/instances.schema.d.ts +23 -0
  521. package/dist/server/src/api/schemas/instances.schema.js +24 -0
  522. package/dist/server/src/api/schemas/instances.schema.js.map +1 -0
  523. package/dist/server/src/api/schemas/notifications.schema.d.ts +26 -0
  524. package/dist/server/src/api/schemas/notifications.schema.js +25 -0
  525. package/dist/server/src/api/schemas/notifications.schema.js.map +1 -0
  526. package/dist/server/src/api/schemas/oauthCallback.schema.d.ts +11 -0
  527. package/dist/server/src/api/schemas/oauthCallback.schema.js +10 -0
  528. package/dist/server/src/api/schemas/oauthCallback.schema.js.map +1 -0
  529. package/dist/server/src/api/schemas/plugins.schema.d.ts +62 -59
  530. package/dist/server/src/api/schemas/plugins.schema.js +54 -81
  531. package/dist/server/src/api/schemas/plugins.schema.js.map +1 -1
  532. package/dist/server/src/api/schemas/remote.schema.d.ts +44 -0
  533. package/dist/server/src/api/schemas/remote.schema.js +80 -0
  534. package/dist/server/src/api/schemas/remote.schema.js.map +1 -0
  535. package/dist/server/src/api/schemas/server.schema.d.ts +9 -0
  536. package/dist/server/src/api/schemas/server.schema.js +12 -0
  537. package/dist/server/src/api/schemas/server.schema.js.map +1 -0
  538. package/dist/server/src/api/schemas/shares.schema.d.ts +21 -0
  539. package/dist/server/src/api/schemas/shares.schema.js +22 -0
  540. package/dist/server/src/api/schemas/shares.schema.js.map +1 -0
  541. package/dist/server/src/api/schemas/storage.schema.d.ts +5 -15
  542. package/dist/server/src/api/schemas/users.schema.d.ts +294 -786
  543. package/dist/server/src/api/schemas/users.schema.js +76 -39
  544. package/dist/server/src/api/schemas/users.schema.js.map +1 -1
  545. package/dist/server/src/api/schemas/workers.schema.d.ts +14 -0
  546. package/dist/server/src/api/schemas/workers.schema.js +12 -0
  547. package/dist/server/src/api/schemas/workers.schema.js.map +1 -0
  548. package/dist/server/src/api/services/auth.service.d.ts +27 -17
  549. package/dist/server/src/api/services/auth.service.js +106 -134
  550. package/dist/server/src/api/services/auth.service.js.map +1 -1
  551. package/dist/server/src/api/services/automations.service.d.ts +24 -0
  552. package/dist/server/src/api/services/automations.service.js +157 -0
  553. package/dist/server/src/api/services/automations.service.js.map +1 -0
  554. package/dist/server/src/api/services/backup.service.js +0 -5
  555. package/dist/server/src/api/services/backup.service.js.map +1 -1
  556. package/dist/server/src/api/services/cameras.service.d.ts +28 -15
  557. package/dist/server/src/api/services/cameras.service.js +532 -305
  558. package/dist/server/src/api/services/cameras.service.js.map +1 -1
  559. package/dist/server/src/api/services/downloads.service.d.ts +9 -0
  560. package/dist/server/src/api/services/downloads.service.js +20 -0
  561. package/dist/server/src/api/services/downloads.service.js.map +1 -0
  562. package/dist/server/src/api/services/instances.service.d.ts +52 -0
  563. package/dist/server/src/api/services/instances.service.js +344 -0
  564. package/dist/server/src/api/services/instances.service.js.map +1 -0
  565. package/dist/server/src/api/services/notifications.service.d.ts +21 -0
  566. package/dist/server/src/api/services/notifications.service.js +48 -0
  567. package/dist/server/src/api/services/notifications.service.js.map +1 -0
  568. package/dist/server/src/api/services/plugins.service.js +31 -35
  569. package/dist/server/src/api/services/plugins.service.js.map +1 -1
  570. package/dist/server/src/api/services/remote.service.d.ts +35 -0
  571. package/dist/server/src/api/services/remote.service.js +207 -0
  572. package/dist/server/src/api/services/remote.service.js.map +1 -0
  573. package/dist/server/src/api/services/server.service.d.ts +15 -0
  574. package/dist/server/src/api/services/server.service.js +75 -0
  575. package/dist/server/src/api/services/server.service.js.map +1 -0
  576. package/dist/server/src/api/services/shares.service.d.ts +46 -0
  577. package/dist/server/src/api/services/shares.service.js +233 -0
  578. package/dist/server/src/api/services/shares.service.js.map +1 -0
  579. package/dist/server/src/api/services/twoFactor.service.d.ts +22 -0
  580. package/dist/server/src/api/services/twoFactor.service.js +81 -0
  581. package/dist/server/src/api/services/twoFactor.service.js.map +1 -0
  582. package/dist/server/src/api/services/users.service.d.ts +9 -5
  583. package/dist/server/src/api/services/users.service.js +157 -121
  584. package/dist/server/src/api/services/users.service.js.map +1 -1
  585. package/dist/server/src/api/services/workers.service.d.ts +5 -0
  586. package/dist/server/src/api/services/workers.service.js +19 -0
  587. package/dist/server/src/api/services/workers.service.js.map +1 -0
  588. package/dist/server/src/api/types/index.d.ts +350 -133
  589. package/dist/server/src/api/types/index.js +5 -4
  590. package/dist/server/src/api/types/index.js.map +1 -1
  591. package/dist/server/src/api/utils/cert.js +1 -1
  592. package/dist/server/src/api/utils/cert.js.map +1 -1
  593. package/dist/server/src/api/utils/encryption.d.ts +5 -0
  594. package/dist/server/src/api/utils/encryption.js +25 -0
  595. package/dist/server/src/api/utils/encryption.js.map +1 -0
  596. package/dist/server/src/api/utils/plugin.d.ts +4 -0
  597. package/dist/server/src/api/utils/plugin.js +8 -0
  598. package/dist/server/src/api/utils/plugin.js.map +1 -0
  599. package/dist/server/src/api/utils/regex.d.ts +3 -0
  600. package/dist/server/src/api/utils/regex.js +4 -0
  601. package/dist/server/src/api/utils/regex.js.map +1 -0
  602. package/dist/server/src/api/utils/upload.d.ts +3 -0
  603. package/dist/server/src/api/utils/upload.js +23 -0
  604. package/dist/server/src/api/utils/upload.js.map +1 -0
  605. package/dist/server/src/api/websocket/index.js +18 -16
  606. package/dist/server/src/api/websocket/index.js.map +1 -1
  607. package/dist/server/src/api/websocket/nsp/cameras.d.ts +21 -0
  608. package/dist/server/src/api/websocket/nsp/cameras.js +152 -0
  609. package/dist/server/src/api/websocket/nsp/cameras.js.map +1 -0
  610. package/dist/server/src/api/websocket/nsp/logs.d.ts +1 -1
  611. package/dist/server/src/api/websocket/nsp/logs.js +65 -52
  612. package/dist/server/src/api/websocket/nsp/logs.js.map +1 -1
  613. package/dist/server/src/api/websocket/nsp/main.d.ts +4 -1
  614. package/dist/server/src/api/websocket/nsp/main.js +29 -1
  615. package/dist/server/src/api/websocket/nsp/main.js.map +1 -1
  616. package/dist/server/src/api/websocket/nsp/metrics.js +4 -4
  617. package/dist/server/src/api/websocket/nsp/metrics.js.map +1 -1
  618. package/dist/server/src/api/websocket/nsp/notifications.d.ts +3 -3
  619. package/dist/server/src/api/websocket/nsp/notifications.js +10 -11
  620. package/dist/server/src/api/websocket/nsp/notifications.js.map +1 -1
  621. package/dist/server/src/api/websocket/nsp/server.d.ts +4 -4
  622. package/dist/server/src/api/websocket/nsp/server.js +48 -27
  623. package/dist/server/src/api/websocket/nsp/server.js.map +1 -1
  624. package/dist/server/src/api/websocket/nsp/status.d.ts +3 -3
  625. package/dist/server/src/api/websocket/nsp/status.js +3 -3
  626. package/dist/server/src/api/websocket/nsp/status.js.map +1 -1
  627. package/dist/server/src/api/websocket/nsp/workers.d.ts +17 -0
  628. package/dist/server/src/api/websocket/nsp/workers.js +46 -0
  629. package/dist/server/src/api/websocket/nsp/workers.js.map +1 -0
  630. package/dist/server/src/api/websocket/types.d.ts +2 -1
  631. package/dist/server/src/api.d.ts +11 -16
  632. package/dist/server/src/api.js +62 -48
  633. package/dist/server/src/api.js.map +1 -1
  634. package/dist/server/src/automations/actions/cameraControl.d.ts +2 -0
  635. package/dist/server/src/automations/actions/cameraControl.js +35 -0
  636. package/dist/server/src/automations/actions/cameraControl.js.map +1 -0
  637. package/dist/server/src/automations/actions/delay.d.ts +2 -0
  638. package/dist/server/src/automations/actions/delay.js +8 -0
  639. package/dist/server/src/automations/actions/delay.js.map +1 -0
  640. package/dist/server/src/automations/actions/http.d.ts +2 -0
  641. package/dist/server/src/automations/actions/http.js +44 -0
  642. package/dist/server/src/automations/actions/http.js.map +1 -0
  643. package/dist/server/src/automations/actions/index.d.ts +4 -0
  644. package/dist/server/src/automations/actions/index.js +20 -0
  645. package/dist/server/src/automations/actions/index.js.map +1 -0
  646. package/dist/server/src/automations/actions/notification.d.ts +2 -0
  647. package/dist/server/src/automations/actions/notification.js +76 -0
  648. package/dist/server/src/automations/actions/notification.js.map +1 -0
  649. package/dist/server/src/automations/actions/plugin.d.ts +3 -0
  650. package/dist/server/src/automations/actions/plugin.js +73 -0
  651. package/dist/server/src/automations/actions/plugin.js.map +1 -0
  652. package/dist/server/src/automations/actions/sensor.d.ts +2 -0
  653. package/dist/server/src/automations/actions/sensor.js +17 -0
  654. package/dist/server/src/automations/actions/sensor.js.map +1 -0
  655. package/dist/server/src/automations/actions/snapshot.d.ts +2 -0
  656. package/dist/server/src/automations/actions/snapshot.js +20 -0
  657. package/dist/server/src/automations/actions/snapshot.js.map +1 -0
  658. package/dist/server/src/automations/actions/types.d.ts +14 -0
  659. package/dist/server/src/automations/actions/types.js.map +1 -0
  660. package/dist/server/src/automations/actions/variable.d.ts +2 -0
  661. package/dist/server/src/automations/actions/variable.js +17 -0
  662. package/dist/server/src/automations/actions/variable.js.map +1 -0
  663. package/dist/server/src/automations/conditions/ifelse.d.ts +3 -0
  664. package/dist/server/src/automations/conditions/ifelse.js +39 -0
  665. package/dist/server/src/automations/conditions/ifelse.js.map +1 -0
  666. package/dist/server/src/automations/conditions/index.d.ts +4 -0
  667. package/dist/server/src/automations/conditions/index.js +20 -0
  668. package/dist/server/src/automations/conditions/index.js.map +1 -0
  669. package/dist/server/src/automations/conditions/sensorState.d.ts +3 -0
  670. package/dist/server/src/automations/conditions/sensorState.js +21 -0
  671. package/dist/server/src/automations/conditions/sensorState.js.map +1 -0
  672. package/dist/server/src/automations/conditions/switch.d.ts +3 -0
  673. package/dist/server/src/automations/conditions/switch.js +9 -0
  674. package/dist/server/src/automations/conditions/switch.js.map +1 -0
  675. package/dist/server/src/automations/conditions/time.d.ts +3 -0
  676. package/dist/server/src/automations/conditions/time.js +24 -0
  677. package/dist/server/src/automations/conditions/time.js.map +1 -0
  678. package/dist/server/src/automations/conditions/types.d.ts +7 -0
  679. package/dist/server/src/automations/conditions/types.js.map +1 -0
  680. package/dist/server/src/automations/context.d.ts +48 -0
  681. package/dist/server/src/automations/context.js +146 -0
  682. package/dist/server/src/automations/context.js.map +1 -0
  683. package/dist/server/src/automations/engine.d.ts +35 -0
  684. package/dist/server/src/automations/engine.js +321 -0
  685. package/dist/server/src/automations/engine.js.map +1 -0
  686. package/dist/server/src/automations/haversine.d.ts +1 -0
  687. package/dist/server/src/automations/haversine.js +9 -0
  688. package/dist/server/src/automations/haversine.js.map +1 -0
  689. package/dist/server/src/automations/parseValue.d.ts +1 -0
  690. package/dist/server/src/automations/parseValue.js +11 -0
  691. package/dist/server/src/automations/parseValue.js.map +1 -0
  692. package/dist/server/src/automations/pluginMethodRegistry.d.ts +37 -0
  693. package/dist/server/src/automations/pluginMethodRegistry.js +162 -0
  694. package/dist/server/src/automations/pluginMethodRegistry.js.map +1 -0
  695. package/dist/server/src/automations/runner.d.ts +23 -0
  696. package/dist/server/src/automations/runner.js +166 -0
  697. package/dist/server/src/automations/runner.js.map +1 -0
  698. package/dist/server/src/automations/triggers/detection.d.ts +3 -0
  699. package/dist/server/src/automations/triggers/detection.js +102 -0
  700. package/dist/server/src/automations/triggers/detection.js.map +1 -0
  701. package/dist/server/src/automations/triggers/geofence.d.ts +13 -0
  702. package/dist/server/src/automations/triggers/geofence.js +8 -0
  703. package/dist/server/src/automations/triggers/geofence.js.map +1 -0
  704. package/dist/server/src/automations/triggers/index.d.ts +9 -0
  705. package/dist/server/src/automations/triggers/index.js +7 -0
  706. package/dist/server/src/automations/triggers/index.js.map +1 -0
  707. package/dist/server/src/automations/triggers/schedule.d.ts +3 -0
  708. package/dist/server/src/automations/triggers/schedule.js +54 -0
  709. package/dist/server/src/automations/triggers/schedule.js.map +1 -0
  710. package/dist/server/src/automations/triggers/sensor.d.ts +3 -0
  711. package/dist/server/src/automations/triggers/sensor.js +44 -0
  712. package/dist/server/src/automations/triggers/sensor.js.map +1 -0
  713. package/dist/server/src/automations/triggers/system.d.ts +3 -0
  714. package/dist/server/src/automations/triggers/system.js +31 -0
  715. package/dist/server/src/automations/triggers/system.js.map +1 -0
  716. package/dist/server/src/automations/triggers/types.d.ts +12 -0
  717. package/dist/server/src/automations/triggers/types.js.map +1 -0
  718. package/dist/server/src/automations/triggers/webhook.d.ts +7 -0
  719. package/dist/server/src/automations/triggers/webhook.js +8 -0
  720. package/dist/server/src/automations/triggers/webhook.js.map +1 -0
  721. package/dist/server/src/automations/utilities/imageInput.d.ts +2 -0
  722. package/dist/server/src/automations/utilities/imageInput.js +139 -0
  723. package/dist/server/src/automations/utilities/imageInput.js.map +1 -0
  724. package/dist/server/src/automations/utilities/index.d.ts +2 -0
  725. package/dist/server/src/automations/utilities/index.js +7 -0
  726. package/dist/server/src/automations/utilities/index.js.map +1 -0
  727. package/dist/server/src/automations/utilities/output.d.ts +2 -0
  728. package/dist/server/src/automations/utilities/output.js +10 -0
  729. package/dist/server/src/automations/utilities/output.js.map +1 -0
  730. package/dist/server/src/camera/controller.d.ts +56 -45
  731. package/dist/server/src/camera/controller.js +468 -326
  732. package/dist/server/src/camera/controller.js.map +1 -1
  733. package/dist/server/src/camera/decoder/audio-source.d.ts +34 -0
  734. package/dist/server/src/camera/decoder/audio-source.js +170 -0
  735. package/dist/server/src/camera/decoder/audio-source.js.map +1 -0
  736. package/dist/server/src/camera/decoder/cascade-manager.d.ts +22 -0
  737. package/dist/server/src/camera/decoder/cascade-manager.js +82 -0
  738. package/dist/server/src/camera/decoder/cascade-manager.js.map +1 -0
  739. package/dist/server/src/camera/decoder/child.d.ts +28 -0
  740. package/dist/server/src/camera/decoder/child.js +187 -0
  741. package/dist/server/src/camera/decoder/child.js.map +1 -0
  742. package/dist/server/src/camera/decoder/detection-coordinator.d.ts +142 -0
  743. package/dist/server/src/camera/decoder/detection-coordinator.js +1844 -0
  744. package/dist/server/src/camera/decoder/detection-coordinator.js.map +1 -0
  745. package/dist/server/src/camera/decoder/detection-pipeline.d.ts +41 -0
  746. package/dist/server/src/camera/decoder/detection-pipeline.js +216 -0
  747. package/dist/server/src/camera/decoder/detection-pipeline.js.map +1 -0
  748. package/dist/server/src/camera/decoder/dwell-manager.d.ts +23 -0
  749. package/dist/server/src/camera/decoder/dwell-manager.js +82 -0
  750. package/dist/server/src/camera/decoder/dwell-manager.js.map +1 -0
  751. package/dist/server/src/camera/decoder/event-manager.d.ts +97 -0
  752. package/dist/server/src/camera/decoder/event-manager.js +674 -0
  753. package/dist/server/src/camera/decoder/event-manager.js.map +1 -0
  754. package/dist/server/src/camera/decoder/frame-scaler.d.ts +53 -0
  755. package/dist/server/src/camera/decoder/frame-scaler.js +136 -0
  756. package/dist/server/src/camera/decoder/frame-scaler.js.map +1 -0
  757. package/dist/server/src/camera/decoder/frame-source.d.ts +54 -0
  758. package/dist/server/src/camera/decoder/frame-source.js +341 -0
  759. package/dist/server/src/camera/decoder/frame-source.js.map +1 -0
  760. package/dist/server/src/camera/decoder/ptz-autotracker.d.ts +57 -0
  761. package/dist/server/src/camera/decoder/ptz-autotracker.js +369 -0
  762. package/dist/server/src/camera/decoder/ptz-autotracker.js.map +1 -0
  763. package/dist/server/src/camera/decoder/types.d.ts +7 -0
  764. package/dist/server/src/camera/decoder/types.js +6 -0
  765. package/dist/server/src/camera/decoder/types.js.map +1 -0
  766. package/dist/server/src/camera/decoder/worker.d.ts +48 -0
  767. package/dist/server/src/camera/decoder/worker.js +465 -0
  768. package/dist/server/src/camera/decoder/worker.js.map +1 -0
  769. package/dist/server/src/camera/index.d.ts +43 -59
  770. package/dist/server/src/camera/index.js +72 -438
  771. package/dist/server/src/camera/index.js.map +1 -1
  772. package/dist/server/src/camera/sensors/controller.d.ts +96 -0
  773. package/dist/server/src/camera/sensors/controller.js +517 -0
  774. package/dist/server/src/camera/sensors/controller.js.map +1 -0
  775. package/dist/server/src/camera/sensors/sensor.d.ts +34 -0
  776. package/dist/server/src/camera/sensors/sensor.js +176 -0
  777. package/dist/server/src/camera/sensors/sensor.js.map +1 -0
  778. package/dist/server/src/camera/sensors/types.d.ts +27 -0
  779. package/dist/server/src/camera/sensors/types.js +225 -0
  780. package/dist/server/src/camera/sensors/types.js.map +1 -0
  781. package/dist/server/src/camera/streaming/fmp4-session.d.ts +10 -12
  782. package/dist/server/src/camera/streaming/fmp4-session.js +162 -268
  783. package/dist/server/src/camera/streaming/fmp4-session.js.map +1 -1
  784. package/dist/server/src/camera/streaming/rtp-session.d.ts +19 -0
  785. package/dist/server/src/camera/streaming/rtp-session.js +363 -0
  786. package/dist/server/src/camera/streaming/rtp-session.js.map +1 -0
  787. package/dist/server/src/camera/utils/filter.d.ts +6 -0
  788. package/dist/server/src/camera/utils/filter.js +83 -0
  789. package/dist/server/src/camera/utils/filter.js.map +1 -0
  790. package/dist/server/src/camera/utils.d.ts +2 -7
  791. package/dist/server/src/camera/utils.js +53 -194
  792. package/dist/server/src/camera/utils.js.map +1 -1
  793. package/dist/server/src/go2rtc/api/index.d.ts +16 -0
  794. package/dist/server/src/go2rtc/api/index.js +33 -0
  795. package/dist/server/src/go2rtc/api/index.js.map +1 -0
  796. package/dist/server/src/go2rtc/api/instance.d.ts +7 -0
  797. package/dist/server/src/go2rtc/api/instance.js +49 -0
  798. package/dist/server/src/go2rtc/api/instance.js.map +1 -0
  799. package/dist/server/src/go2rtc/api/manager.d.ts +11 -0
  800. package/dist/server/src/go2rtc/api/manager.js +38 -0
  801. package/dist/server/src/go2rtc/api/manager.js.map +1 -0
  802. package/dist/server/src/go2rtc/api/routes/application.d.ts +9 -0
  803. package/dist/server/src/go2rtc/api/routes/application.js +40 -0
  804. package/dist/server/src/go2rtc/api/routes/application.js.map +1 -0
  805. package/dist/server/src/go2rtc/api/routes/config.d.ts +8 -0
  806. package/dist/server/src/go2rtc/api/routes/config.js +42 -0
  807. package/dist/server/src/go2rtc/api/routes/config.js.map +1 -0
  808. package/dist/server/src/go2rtc/api/routes/discover.d.ts +30 -0
  809. package/dist/server/src/go2rtc/api/routes/discover.js +158 -0
  810. package/dist/server/src/go2rtc/api/routes/discover.js.map +1 -0
  811. package/dist/server/src/go2rtc/api/routes/snapshot.d.ts +8 -0
  812. package/dist/server/src/go2rtc/api/routes/snapshot.js +34 -0
  813. package/dist/server/src/go2rtc/api/routes/snapshot.js.map +1 -0
  814. package/dist/server/src/go2rtc/api/routes/streams.d.ts +18 -0
  815. package/dist/server/src/go2rtc/api/routes/streams.js +161 -0
  816. package/dist/server/src/go2rtc/api/routes/streams.js.map +1 -0
  817. package/dist/server/src/go2rtc/index.d.ts +7 -2
  818. package/dist/server/src/go2rtc/index.js +52 -30
  819. package/dist/server/src/go2rtc/index.js.map +1 -1
  820. package/dist/server/src/go2rtc/types.d.ts +167 -1
  821. package/dist/server/src/go2rtc/types.js +3 -0
  822. package/dist/server/src/go2rtc/types.js.map +1 -1
  823. package/dist/server/src/internal-bus.d.ts +41 -0
  824. package/dist/server/src/internal-bus.js +19 -0
  825. package/dist/server/src/internal-bus.js.map +1 -0
  826. package/dist/server/src/main.d.ts +8 -2
  827. package/dist/server/src/main.js +110 -21
  828. package/dist/server/src/main.js.map +1 -1
  829. package/dist/server/src/manager/coreManager.d.ts +12 -9
  830. package/dist/server/src/manager/coreManager.js +45 -48
  831. package/dist/server/src/manager/coreManager.js.map +1 -1
  832. package/dist/server/src/manager/deviceManager.d.ts +10 -8
  833. package/dist/server/src/manager/deviceManager.js +31 -96
  834. package/dist/server/src/manager/deviceManager.js.map +1 -1
  835. package/dist/server/src/manager/discoveryManager.d.ts +73 -0
  836. package/dist/server/src/manager/discoveryManager.js +800 -0
  837. package/dist/server/src/manager/discoveryManager.js.map +1 -0
  838. package/dist/server/src/manager/downloadManager.d.ts +27 -0
  839. package/dist/server/src/manager/downloadManager.js +353 -0
  840. package/dist/server/src/manager/downloadManager.js.map +1 -0
  841. package/dist/server/src/manager/notificationManager.d.ts +37 -0
  842. package/dist/server/src/manager/notificationManager.js +334 -0
  843. package/dist/server/src/manager/notificationManager.js.map +1 -0
  844. package/dist/server/src/manager/terminalManager.d.ts +27 -0
  845. package/dist/server/src/manager/terminalManager.js +239 -0
  846. package/dist/server/src/manager/terminalManager.js.map +1 -0
  847. package/dist/server/src/manager/types.d.ts +39 -14
  848. package/dist/server/src/manager/types.js +12 -1
  849. package/dist/server/src/manager/types.js.map +1 -1
  850. package/dist/server/src/plugins/index.d.ts +9 -6
  851. package/dist/server/src/plugins/index.js +69 -52
  852. package/dist/server/src/plugins/index.js.map +1 -1
  853. package/dist/server/src/plugins/plugin.d.ts +16 -16
  854. package/dist/server/src/plugins/plugin.js +42 -36
  855. package/dist/server/src/plugins/plugin.js.map +1 -1
  856. package/dist/server/src/plugins/runtime/base.d.ts +5 -14
  857. package/dist/server/src/plugins/runtime/base.js +39 -111
  858. package/dist/server/src/plugins/runtime/base.js.map +1 -1
  859. package/dist/server/src/plugins/runtime/go/index.d.ts +7 -0
  860. package/dist/server/src/plugins/runtime/go/index.js +110 -0
  861. package/dist/server/src/plugins/runtime/go/index.js.map +1 -0
  862. package/dist/server/src/plugins/runtime/index.js +5 -1
  863. package/dist/server/src/plugins/runtime/index.js.map +1 -1
  864. package/dist/server/src/plugins/runtime/node/child.d.ts +7 -6
  865. package/dist/server/src/plugins/runtime/node/child.js +70 -38
  866. package/dist/server/src/plugins/runtime/node/child.js.map +1 -1
  867. package/dist/server/src/plugins/runtime/node/index.d.ts +1 -0
  868. package/dist/server/src/plugins/runtime/node/index.js +31 -5
  869. package/dist/server/src/plugins/runtime/node/index.js.map +1 -1
  870. package/dist/server/src/plugins/runtime/node/pluginApi.d.ts +9 -6
  871. package/dist/server/src/plugins/runtime/node/pluginApi.js +10 -4
  872. package/dist/server/src/plugins/runtime/node/pluginApi.js.map +1 -1
  873. package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.d.ts +27 -15
  874. package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.js +312 -173
  875. package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.js.map +1 -1
  876. package/dist/server/src/plugins/runtime/node/proxy/coreManager.d.ts +7 -10
  877. package/dist/server/src/plugins/runtime/node/proxy/coreManager.js +28 -43
  878. package/dist/server/src/plugins/runtime/node/proxy/coreManager.js.map +1 -1
  879. package/dist/server/src/plugins/runtime/node/proxy/deviceManager.d.ts +7 -11
  880. package/dist/server/src/plugins/runtime/node/proxy/deviceManager.js +40 -57
  881. package/dist/server/src/plugins/runtime/node/proxy/deviceManager.js.map +1 -1
  882. package/dist/server/src/plugins/runtime/node/proxy/downloadManager.d.ts +9 -0
  883. package/dist/server/src/plugins/runtime/node/proxy/downloadManager.js +22 -0
  884. package/dist/server/src/plugins/runtime/node/proxy/downloadManager.js.map +1 -0
  885. package/dist/server/src/plugins/runtime/node/proxy/notificationManager.d.ts +7 -0
  886. package/dist/server/src/plugins/runtime/node/proxy/notificationManager.js +20 -0
  887. package/dist/server/src/plugins/runtime/node/proxy/notificationManager.js.map +1 -0
  888. package/dist/server/src/plugins/runtime/node/proxy/sensor.d.ts +45 -0
  889. package/dist/server/src/plugins/runtime/node/proxy/sensor.js +149 -0
  890. package/dist/server/src/plugins/runtime/node/proxy/sensor.js.map +1 -0
  891. package/dist/server/src/plugins/runtime/node/storage.d.ts +6 -11
  892. package/dist/server/src/plugins/runtime/node/storage.js +69 -46
  893. package/dist/server/src/plugins/runtime/node/storage.js.map +1 -1
  894. package/dist/server/src/plugins/runtime/node/storageController.d.ts +10 -7
  895. package/dist/server/src/plugins/runtime/node/storageController.js +57 -17
  896. package/dist/server/src/plugins/runtime/node/storageController.js.map +1 -1
  897. package/dist/server/src/plugins/runtime/python/camera/utils.py +105 -0
  898. package/dist/server/src/plugins/runtime/python/child.py +108 -68
  899. package/dist/server/src/plugins/runtime/python/index.js.map +1 -1
  900. package/dist/server/src/plugins/runtime/python/namespaces.py +155 -60
  901. package/dist/server/src/plugins/runtime/python/plugin_api.py +72 -6
  902. package/dist/server/src/plugins/runtime/python/proxy/camera_device.py +592 -1522
  903. package/dist/server/src/plugins/runtime/python/proxy/core_manager.py +75 -76
  904. package/dist/server/src/plugins/runtime/python/proxy/device_manager.py +81 -93
  905. package/dist/server/src/plugins/runtime/python/proxy/download_manager.py +33 -0
  906. package/dist/server/src/plugins/runtime/python/proxy/notification_manager.py +31 -0
  907. package/dist/server/src/plugins/runtime/python/proxy/sensor.py +169 -0
  908. package/dist/server/src/plugins/runtime/python/rpc/typings.py +56 -0
  909. package/dist/server/src/plugins/runtime/python/schema.py +54 -19
  910. package/dist/server/src/plugins/runtime/python/storage.py +84 -66
  911. package/dist/server/src/plugins/runtime/python/storage_controller.py +132 -38
  912. package/dist/server/src/plugins/runtime/python/typings.py +78 -152
  913. package/dist/server/src/plugins/schema.d.ts +27 -26
  914. package/dist/server/src/plugins/schema.js +183 -103
  915. package/dist/server/src/plugins/schema.js.map +1 -1
  916. package/dist/server/src/plugins/types.d.ts +2 -14
  917. package/dist/server/src/plugins/types.js +0 -1
  918. package/dist/server/src/plugins/types.js.map +1 -1
  919. package/dist/server/src/plugins/worker.d.ts +7 -7
  920. package/dist/server/src/plugins/worker.js +37 -26
  921. package/dist/server/src/plugins/worker.js.map +1 -1
  922. package/dist/server/src/remote/api/credentialStore.d.ts +18 -0
  923. package/dist/server/src/remote/api/credentialStore.js +101 -0
  924. package/dist/server/src/remote/api/credentialStore.js.map +1 -0
  925. package/dist/server/src/remote/api/index.d.ts +9 -0
  926. package/dist/server/src/remote/api/index.js +16 -0
  927. package/dist/server/src/remote/api/index.js.map +1 -0
  928. package/dist/server/src/remote/api/instance.d.ts +9 -0
  929. package/dist/server/src/remote/api/instance.js +44 -0
  930. package/dist/server/src/remote/api/instance.js.map +1 -0
  931. package/dist/server/src/remote/api/routes/oauth.d.ts +23 -0
  932. package/dist/server/src/remote/api/routes/oauth.js +79 -0
  933. package/dist/server/src/remote/api/routes/oauth.js.map +1 -0
  934. package/dist/server/src/remote/api/routes/server.d.ts +20 -0
  935. package/dist/server/src/remote/api/routes/server.js +58 -0
  936. package/dist/server/src/remote/api/routes/server.js.map +1 -0
  937. package/dist/server/src/remote/index.d.ts +25 -0
  938. package/dist/server/src/remote/index.js +70 -0
  939. package/dist/server/src/remote/index.js.map +1 -0
  940. package/dist/server/src/remote/push.d.ts +15 -0
  941. package/dist/server/src/remote/push.js +85 -0
  942. package/dist/server/src/remote/push.js.map +1 -0
  943. package/dist/server/src/remote/services/cloudflare-managed.d.ts +42 -0
  944. package/dist/server/src/remote/services/cloudflare-managed.js +284 -0
  945. package/dist/server/src/remote/services/cloudflare-managed.js.map +1 -0
  946. package/dist/server/src/remote/services/cloudflare.d.ts +38 -0
  947. package/dist/server/src/remote/services/cloudflare.js +232 -0
  948. package/dist/server/src/remote/services/cloudflare.js.map +1 -0
  949. package/dist/server/src/remote/services/customDomain.d.ts +9 -0
  950. package/dist/server/src/remote/services/customDomain.js +40 -0
  951. package/dist/server/src/remote/services/customDomain.js.map +1 -0
  952. package/dist/server/src/remote/services/index.d.ts +43 -0
  953. package/dist/server/src/remote/services/index.js +285 -0
  954. package/dist/server/src/remote/services/index.js.map +1 -0
  955. package/dist/server/src/remote/services/upnp.js +2 -0
  956. package/dist/server/src/remote/services/upnp.js.map +1 -0
  957. package/dist/server/src/remote/tunnel/client.d.ts +38 -0
  958. package/dist/server/src/remote/tunnel/client.js +241 -0
  959. package/dist/server/src/remote/tunnel/client.js.map +1 -0
  960. package/dist/server/src/remote/tunnel/index.d.ts +15 -0
  961. package/dist/server/src/remote/tunnel/index.js +68 -0
  962. package/dist/server/src/remote/tunnel/index.js.map +1 -0
  963. package/dist/server/src/remote/types.d.ts +31 -0
  964. package/dist/server/src/remote/types.js +2 -0
  965. package/dist/server/src/remote/types.js.map +1 -0
  966. package/dist/server/src/rpc/index.d.ts +24 -25
  967. package/dist/server/src/rpc/index.js +93 -77
  968. package/dist/server/src/rpc/index.js.map +1 -1
  969. package/dist/server/src/rpc/interfaces/config.d.ts +74 -0
  970. package/dist/server/src/rpc/interfaces/config.js +2 -0
  971. package/dist/server/src/rpc/interfaces/config.js.map +1 -0
  972. package/dist/server/src/rpc/interfaces/core.d.ts +25 -0
  973. package/dist/server/src/rpc/interfaces/core.js +2 -0
  974. package/dist/server/src/rpc/interfaces/core.js.map +1 -0
  975. package/dist/server/src/rpc/interfaces/detection.d.ts +70 -0
  976. package/dist/server/src/rpc/interfaces/detection.js +2 -0
  977. package/dist/server/src/rpc/interfaces/detection.js.map +1 -0
  978. package/dist/server/src/rpc/interfaces/device.d.ts +62 -0
  979. package/dist/server/src/rpc/interfaces/device.js +2 -0
  980. package/dist/server/src/rpc/interfaces/device.js.map +1 -0
  981. package/dist/server/src/rpc/interfaces/discovery.d.ts +46 -0
  982. package/dist/server/src/rpc/interfaces/discovery.js +2 -0
  983. package/dist/server/src/rpc/interfaces/discovery.js.map +1 -0
  984. package/dist/server/src/rpc/interfaces/download.d.ts +22 -0
  985. package/dist/server/src/rpc/interfaces/download.js +2 -0
  986. package/dist/server/src/rpc/interfaces/download.js.map +1 -0
  987. package/dist/server/src/rpc/interfaces/frameworker.d.ts +12 -0
  988. package/dist/server/src/rpc/interfaces/frameworker.js +2 -0
  989. package/dist/server/src/rpc/interfaces/frameworker.js.map +1 -0
  990. package/dist/server/src/rpc/interfaces/notification.d.ts +6 -0
  991. package/dist/server/src/rpc/interfaces/notification.js +2 -0
  992. package/dist/server/src/rpc/interfaces/notification.js.map +1 -0
  993. package/dist/server/src/rpc/interfaces/sensor.d.ts +75 -0
  994. package/dist/server/src/rpc/interfaces/sensor.js +2 -0
  995. package/dist/server/src/rpc/interfaces/sensor.js.map +1 -0
  996. package/dist/server/src/rpc/interfaces/terminal.d.ts +34 -0
  997. package/dist/server/src/rpc/interfaces/terminal.js +2 -0
  998. package/dist/server/src/rpc/interfaces/terminal.js.map +1 -0
  999. package/dist/server/src/rpc/namespaces.d.ts +50 -2
  1000. package/dist/server/src/rpc/namespaces.js +70 -4
  1001. package/dist/server/src/rpc/namespaces.js.map +1 -1
  1002. package/dist/server/src/rpc/server.d.ts +22 -3
  1003. package/dist/server/src/rpc/server.js +110 -37
  1004. package/dist/server/src/rpc/server.js.map +1 -1
  1005. package/dist/server/src/rpc/utils.d.ts +2 -1
  1006. package/dist/server/src/rpc/utils.js +8 -0
  1007. package/dist/server/src/rpc/utils.js.map +1 -1
  1008. package/dist/server/src/services/config/constants.d.ts +7 -1
  1009. package/dist/server/src/services/config/constants.js +17 -2
  1010. package/dist/server/src/services/config/constants.js.map +1 -1
  1011. package/dist/server/src/services/config/defaults.js +3 -3
  1012. package/dist/server/src/services/config/defaults.js.map +1 -1
  1013. package/dist/server/src/services/config/index.d.ts +6 -43
  1014. package/dist/server/src/services/config/index.js +56 -108
  1015. package/dist/server/src/services/config/index.js.map +1 -1
  1016. package/dist/server/src/services/config/types.d.ts +14 -2
  1017. package/dist/server/src/services/config/types.js.map +1 -1
  1018. package/dist/server/src/services/logger/index.d.ts +13 -11
  1019. package/dist/server/src/services/logger/index.js +47 -50
  1020. package/dist/server/src/services/logger/index.js.map +1 -1
  1021. package/dist/server/src/services/logger/logManager.d.ts +35 -0
  1022. package/dist/server/src/services/logger/logManager.js +196 -0
  1023. package/dist/server/src/services/logger/logManager.js.map +1 -0
  1024. package/dist/server/src/services/logger/transports/fileTransport.d.ts +34 -0
  1025. package/dist/server/src/services/logger/transports/fileTransport.js +152 -0
  1026. package/dist/server/src/services/logger/transports/fileTransport.js.map +1 -0
  1027. package/dist/server/src/services/logger/transports/index.d.ts +1 -0
  1028. package/dist/server/src/services/logger/transports/index.js +2 -0
  1029. package/dist/server/src/services/logger/transports/index.js.map +1 -0
  1030. package/dist/server/src/types.d.ts +3 -0
  1031. package/dist/server/src/utils/camera.d.ts +4 -0
  1032. package/dist/server/src/utils/camera.js +79 -0
  1033. package/dist/server/src/utils/camera.js.map +1 -0
  1034. package/dist/server/src/utils/env.js +8 -0
  1035. package/dist/server/src/utils/env.js.map +1 -0
  1036. package/dist/server/src/utils/ipc.d.ts +1 -1
  1037. package/dist/server/src/utils/ipc.js +2 -2
  1038. package/dist/server/src/utils/ipc.js.map +1 -1
  1039. package/dist/server/src/utils/path.js +3 -3
  1040. package/dist/server/src/utils/path.js.map +1 -1
  1041. package/dist/server/src/utils/pythonInstaller.d.ts +2 -1
  1042. package/dist/server/src/utils/pythonInstaller.js +6 -6
  1043. package/dist/server/src/utils/pythonInstaller.js.map +1 -1
  1044. package/dist/server/src/workers/agent.d.ts +27 -0
  1045. package/dist/server/src/workers/agent.js +161 -0
  1046. package/dist/server/src/workers/agent.js.map +1 -0
  1047. package/dist/server/src/workers/capabilities/frame-decoding.d.ts +24 -0
  1048. package/dist/server/src/workers/capabilities/frame-decoding.js +180 -0
  1049. package/dist/server/src/workers/capabilities/frame-decoding.js.map +1 -0
  1050. package/dist/server/src/workers/capabilities/handler.d.ts +8 -0
  1051. package/dist/server/src/workers/capabilities/handler.js +2 -0
  1052. package/dist/server/src/workers/capabilities/handler.js.map +1 -0
  1053. package/dist/server/src/workers/manager.d.ts +31 -0
  1054. package/dist/server/src/workers/manager.js +260 -0
  1055. package/dist/server/src/workers/manager.js.map +1 -0
  1056. package/dist/server/src/workers/types.d.ts +59 -0
  1057. package/dist/server/src/workers/types.js +5 -0
  1058. package/dist/server/src/workers/types.js.map +1 -0
  1059. package/package.json +73 -79
  1060. package/dist/interface/assets/@xterm.DYP7pi_n.0.0.70.css +0 -32
  1061. package/dist/interface/assets/Adminpanel.BKek2EMH.0.0.70.css +0 -1
  1062. package/dist/interface/assets/Cameras.BDWZJqPN.0.0.70.css +0 -1
  1063. package/dist/interface/assets/Camview.Cvhuou6V.0.0.70.css +0 -1
  1064. package/dist/interface/assets/CuiConsole.DCYyxdVg.0.0.70.css +0 -1
  1065. package/dist/interface/assets/CuiPluginCard.yF8V0SZY.0.0.70.css +0 -1
  1066. package/dist/interface/assets/CuiTimeline.BkIwlYtw.0.0.70.css +0 -1
  1067. package/dist/interface/assets/Plugin.DJElsAn5.0.0.70.css +0 -1
  1068. package/dist/interface/assets/Plugins.BwPlcRrV.0.0.70.css +0 -1
  1069. package/dist/interface/assets/Settings.CkgfRkQr.0.0.70.css +0 -1
  1070. package/dist/interface/assets/SettingsAccount.CDZT7gN-.0.0.70.css +0 -1
  1071. package/dist/interface/assets/highlight.Ch2EwETz.0.0.70.css +0 -1
  1072. package/dist/interface/assets/main.BmO7mnW4.0.0.70.css +0 -1
  1073. package/dist/interface/assets/worker-base.jEXLGV2h.0.0.70.js +0 -1332
  1074. package/dist/interface/assets/worker-yaml.B3uUYINB.0.0.70.js +0 -5819
  1075. package/dist/interface/js/@babel.l0sNRNKZ.0.0.70.js +0 -1
  1076. package/dist/interface/js/@intlify.6ljJeWIl.0.0.70.js +0 -15
  1077. package/dist/interface/js/@kurkle.D8fDXNIl.0.0.70.js +0 -6
  1078. package/dist/interface/js/@primeuix.bRNqZjQz.0.0.70.js +0 -5889
  1079. package/dist/interface/js/@primevue.DH9ak_9x.0.0.70.js +0 -57
  1080. package/dist/interface/js/@react-dnd.CcwRs9xb.0.0.70.js +0 -1
  1081. package/dist/interface/js/@socket.io.Dkula2eQ.0.0.70.js +0 -1
  1082. package/dist/interface/js/@tanstack.Dk2rc1Gz.0.0.70.js +0 -1
  1083. package/dist/interface/js/@vee-validate.i4o6WINE.0.0.70.js +0 -5
  1084. package/dist/interface/js/@vue.BsSvBeCe.0.0.70.js +0 -17
  1085. package/dist/interface/js/@vueuse.T3qy5Jq4.0.0.70.js +0 -1
  1086. package/dist/interface/js/@xterm.CJZZM5vf.0.0.70.js +0 -66
  1087. package/dist/interface/js/Adminpanel.CBQfnvy1.0.0.70.js +0 -1
  1088. package/dist/interface/js/Camera.D39v2Qae.0.0.70.js +0 -1
  1089. package/dist/interface/js/Cameras.BOXzVzD9.0.0.70.js +0 -482
  1090. package/dist/interface/js/Cammesh.bs93Or8F.0.0.70.js +0 -1
  1091. package/dist/interface/js/Camview.R2Zpw-wS.0.0.70.js +0 -1
  1092. package/dist/interface/js/Config.D89tTvo2.0.0.70.js +0 -2
  1093. package/dist/interface/js/Console.DX4_ZVPM.0.0.70.js +0 -4
  1094. package/dist/interface/js/CuiConsole.B-YJZ4uY.0.0.70.js +0 -1
  1095. package/dist/interface/js/CuiPluginCard.CFaLdBEf.0.0.70.js +0 -4
  1096. package/dist/interface/js/CuiTimeline.DbPA3XCf.0.0.70.js +0 -1
  1097. package/dist/interface/js/FirstSteps.BjUQYXwF.0.0.70.js +0 -1
  1098. package/dist/interface/js/Plugin.Dl21oK_u.0.0.70.js +0 -1
  1099. package/dist/interface/js/Plugins.DphA9uPk.0.0.70.js +0 -1
  1100. package/dist/interface/js/Recordings.B2b7JutC.0.0.70.js +0 -1
  1101. package/dist/interface/js/Settings.D_hL6kBb.0.0.70.js +0 -1
  1102. package/dist/interface/js/SettingsAccount.2ETTD3p8.0.0.70.js +0 -1
  1103. package/dist/interface/js/SettingsAppearance.DkI9GlMu.0.0.70.js +0 -1
  1104. package/dist/interface/js/SettingsAppearance.vue_vue_type_script_setup_true_lang.D6sykhe2.0.0.70.js +0 -1
  1105. package/dist/interface/js/SettingsBackup.Ce3e31yn.0.0.70.js +0 -1
  1106. package/dist/interface/js/SettingsRecordings.C_hEpi6y.0.0.70.js +0 -1
  1107. package/dist/interface/js/SettingsRemote.BDp_l894.0.0.70.js +0 -1
  1108. package/dist/interface/js/SettingsSystem.CFjS9i7G.0.0.70.js +0 -1
  1109. package/dist/interface/js/SettingsUsers.BpTad4f8.0.0.70.js +0 -1
  1110. package/dist/interface/js/VersionsHandler.vue_vue_type_script_setup_true_lang.MC8r914h.0.0.70.js +0 -4
  1111. package/dist/interface/js/ace-builds.DPRnfcwI.0.0.70.js +0 -1091
  1112. package/dist/interface/js/ace.config.DReCZ4VN.0.0.70.js +0 -1
  1113. package/dist/interface/js/axios.lj9VQs0f.0.0.70.js +0 -6
  1114. package/dist/interface/js/backup.CqN-DI7C.0.0.70.js +0 -1
  1115. package/dist/interface/js/birpc.l0sNRNKZ.0.0.70.js +0 -1
  1116. package/dist/interface/js/chart.js.B5ohq2tj.0.0.70.js +0 -13
  1117. package/dist/interface/js/close-circle.CMnO5OKl.0.0.70.js +0 -1
  1118. package/dist/interface/js/compare-versions.DqEOhma6.0.0.70.js +0 -1
  1119. package/dist/interface/js/dijkstrajs.C00ieaqj.0.0.70.js +0 -1
  1120. package/dist/interface/js/dnd-core.DuFbUDJC.0.0.70.js +0 -1
  1121. package/dist/interface/js/draggabilly.Cuzjcd7v.0.0.70.js +0 -6
  1122. package/dist/interface/js/engine.io-client.CnosWdRP.0.0.70.js +0 -1
  1123. package/dist/interface/js/engine.io-parser.BiEtp6m2.0.0.70.js +0 -1
  1124. package/dist/interface/js/entities.C20TfXL6.0.0.70.js +0 -1
  1125. package/dist/interface/js/ev-emitter.X5f1qa-c.0.0.70.js +0 -1
  1126. package/dist/interface/js/fast-deep-equal.D0g7BF3f.0.0.70.js +0 -1
  1127. package/dist/interface/js/get-size.D1dS-IaP.0.0.70.js +0 -5
  1128. package/dist/interface/js/highlight.js.DTPofZhc.0.0.70.js +0 -3
  1129. package/dist/interface/js/hookable.l0sNRNKZ.0.0.70.js +0 -1
  1130. package/dist/interface/js/linkify-it.imhCvGRq.0.0.70.js +0 -1
  1131. package/dist/interface/js/main.D2NZuTnM.0.0.70.js +0 -31
  1132. package/dist/interface/js/markdown-it.VQvmcJVu.0.0.70.js +0 -15
  1133. package/dist/interface/js/mdurl.k9Sl0PQj.0.0.70.js +0 -2
  1134. package/dist/interface/js/nprogress.DuNJBXnf.0.0.70.js +0 -2
  1135. package/dist/interface/js/perfect-debounce.l0sNRNKZ.0.0.70.js +0 -1
  1136. package/dist/interface/js/pinia.BeBGFuqK.0.0.70.js +0 -5
  1137. package/dist/interface/js/primelocale.Bga3dOQu.0.0.70.js +0 -1
  1138. package/dist/interface/js/primevue.BVVo-ukB.0.0.70.js +0 -142
  1139. package/dist/interface/js/punycode.js.Dj65hjkv.0.0.70.js +0 -1
  1140. package/dist/interface/js/qrcode.D7KqKQTM.0.0.70.js +0 -8
  1141. package/dist/interface/js/react-dnd-html5-backend.1HQjlkwI.0.0.70.js +0 -2
  1142. package/dist/interface/js/react-dnd-touch-backend.4hAOsMRp.0.0.70.js +0 -1
  1143. package/dist/interface/js/redux.BFxtlG_c.0.0.70.js +0 -1
  1144. package/dist/interface/js/refresh-rounded.BzWz29y2.0.0.70.js +0 -1
  1145. package/dist/interface/js/rxjs.UbFxmZ7q.0.0.70.js +0 -3
  1146. package/dist/interface/js/socket.io-client.DC_wUGxw.0.0.70.js +0 -1
  1147. package/dist/interface/js/socket.io-parser.ChgZ8FD_.0.0.70.js +0 -1
  1148. package/dist/interface/js/system.Ccn9lMgI.0.0.70.js +0 -1
  1149. package/dist/interface/js/trash-fill.C8ZgD-Jz.0.0.70.js +0 -1
  1150. package/dist/interface/js/tslib.9k7AwCpt.0.0.70.js +0 -1
  1151. package/dist/interface/js/uc.micro.kMc2yuuw.0.0.70.js +0 -1
  1152. package/dist/interface/js/unidragger.DahEY3cm.0.0.70.js +0 -5
  1153. package/dist/interface/js/uuid.C6aID195.0.0.70.js +0 -1
  1154. package/dist/interface/js/vee-validate.DwwGVNzx.0.0.70.js +0 -5
  1155. package/dist/interface/js/vue-chartjs.KCIQuea5.0.0.70.js +0 -1
  1156. package/dist/interface/js/vue-i18n.BLwVbi61.0.0.70.js +0 -5
  1157. package/dist/interface/js/vue-inline-svg.B52C1cW8.0.0.70.js +0 -1
  1158. package/dist/interface/js/vue-router.BQuUBAAr.0.0.70.js +0 -5
  1159. package/dist/interface/js/vue-zoomable.Cq7IVJt5.0.0.70.js +0 -1
  1160. package/dist/interface/js/vue.l0sNRNKZ.0.0.70.js +0 -1
  1161. package/dist/interface/js/vue3-dnd.2Dj_EakH.0.0.70.js +0 -1
  1162. package/dist/interface/js/zod.2bfLsWMZ.0.0.70.js +0 -1
  1163. package/dist/interface/js/zoom-out.D4ga9c-w.0.0.70.js +0 -1
  1164. package/dist/interface/registerSW.js +0 -1
  1165. package/dist/interface/workbox-5ffe50d4.js +0 -1
  1166. package/dist/server/src/_camera_ui_tools/camera_ui_common/camera_utils/utils.py +0 -52
  1167. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/test.py +0 -116
  1168. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/__init__.py +0 -350
  1169. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/__init__.py +0 -0
  1170. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/base.py +0 -237
  1171. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/client.py +0 -256
  1172. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/connection.py +0 -784
  1173. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/errors.py +0 -745
  1174. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/messaging.py +0 -57
  1175. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/rpc.py +0 -227
  1176. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/rpc_generator.py +0 -584
  1177. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/constants.py +0 -96
  1178. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/typings.py +0 -218
  1179. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/__init__.py +0 -0
  1180. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/connection_state.py +0 -86
  1181. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/logger.py +0 -30
  1182. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/metrics.py +0 -152
  1183. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/packer.py +0 -20
  1184. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/routing.py +0 -75
  1185. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/rpc.py +0 -177
  1186. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/subscriptions.py +0 -24
  1187. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/tasks.py +0 -39
  1188. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/uid.py +0 -37
  1189. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/validate.py +0 -119
  1190. package/dist/server/src/_camera_ui_tools/camera_ui_types/__init__.py +0 -1369
  1191. package/dist/server/src/_camera_ui_tools/camera_ui_types/hybrid_observer.py +0 -338
  1192. package/dist/server/src/_camera_ui_tools/camera_ui_types/test.py +0 -196
  1193. package/dist/server/src/api/controllers/system.controller.d.ts +0 -24
  1194. package/dist/server/src/api/controllers/system.controller.js +0 -235
  1195. package/dist/server/src/api/controllers/system.controller.js.map +0 -1
  1196. package/dist/server/src/api/go2rtc/api/application.d.ts +0 -9
  1197. package/dist/server/src/api/go2rtc/api/application.js +0 -39
  1198. package/dist/server/src/api/go2rtc/api/application.js.map +0 -1
  1199. package/dist/server/src/api/go2rtc/api/config.d.ts +0 -8
  1200. package/dist/server/src/api/go2rtc/api/config.js +0 -44
  1201. package/dist/server/src/api/go2rtc/api/config.js.map +0 -1
  1202. package/dist/server/src/api/go2rtc/api/discover.d.ts +0 -30
  1203. package/dist/server/src/api/go2rtc/api/discover.js +0 -162
  1204. package/dist/server/src/api/go2rtc/api/discover.js.map +0 -1
  1205. package/dist/server/src/api/go2rtc/api/index.d.ts +0 -1
  1206. package/dist/server/src/api/go2rtc/api/index.js +0 -42
  1207. package/dist/server/src/api/go2rtc/api/index.js.map +0 -1
  1208. package/dist/server/src/api/go2rtc/api/snapshot.d.ts +0 -8
  1209. package/dist/server/src/api/go2rtc/api/snapshot.js +0 -34
  1210. package/dist/server/src/api/go2rtc/api/snapshot.js.map +0 -1
  1211. package/dist/server/src/api/go2rtc/api/streams.d.ts +0 -20
  1212. package/dist/server/src/api/go2rtc/api/streams.js +0 -190
  1213. package/dist/server/src/api/go2rtc/api/streams.js.map +0 -1
  1214. package/dist/server/src/api/go2rtc/index.d.ts +0 -16
  1215. package/dist/server/src/api/go2rtc/index.js +0 -33
  1216. package/dist/server/src/api/go2rtc/index.js.map +0 -1
  1217. package/dist/server/src/api/go2rtc/queue.d.ts +0 -10
  1218. package/dist/server/src/api/go2rtc/queue.js +0 -38
  1219. package/dist/server/src/api/go2rtc/queue.js.map +0 -1
  1220. package/dist/server/src/api/go2rtc/types.d.ts +0 -151
  1221. package/dist/server/src/api/go2rtc/types.js.map +0 -1
  1222. package/dist/server/src/api/routes/system.routes.d.ts +0 -2
  1223. package/dist/server/src/api/routes/system.routes.js +0 -86
  1224. package/dist/server/src/api/routes/system.routes.js.map +0 -1
  1225. package/dist/server/src/api/schemas/system.schema.d.ts +0 -185
  1226. package/dist/server/src/api/schemas/system.schema.js +0 -40
  1227. package/dist/server/src/api/schemas/system.schema.js.map +0 -1
  1228. package/dist/server/src/api/services/system.service.d.ts +0 -13
  1229. package/dist/server/src/api/services/system.service.js +0 -63
  1230. package/dist/server/src/api/services/system.service.js.map +0 -1
  1231. package/dist/server/src/camera/classes.d.ts +0 -2
  1232. package/dist/server/src/camera/classes.js +0 -24
  1233. package/dist/server/src/camera/classes.js.map +0 -1
  1234. package/dist/server/src/camera/device.d.ts +0 -34
  1235. package/dist/server/src/camera/device.js +0 -327
  1236. package/dist/server/src/camera/device.js.map +0 -1
  1237. package/dist/server/src/camera/frameWorker.d.ts +0 -46
  1238. package/dist/server/src/camera/frameWorker.js +0 -347
  1239. package/dist/server/src/camera/frameWorker.js.map +0 -1
  1240. package/dist/server/src/camera/interfaces.d.ts +0 -17
  1241. package/dist/server/src/camera/interfaces.js +0 -99
  1242. package/dist/server/src/camera/interfaces.js.map +0 -1
  1243. package/dist/server/src/camera/iou.d.ts +0 -2
  1244. package/dist/server/src/camera/iou.js +0 -122
  1245. package/dist/server/src/camera/iou.js.map +0 -1
  1246. package/dist/server/src/camera/polygon.d.ts +0 -4
  1247. package/dist/server/src/camera/polygon.js +0 -192
  1248. package/dist/server/src/camera/polygon.js.map +0 -1
  1249. package/dist/server/src/camera/python/__init__.py +0 -0
  1250. package/dist/server/src/camera/python/classes.py +0 -41
  1251. package/dist/server/src/camera/python/interfaces.py +0 -131
  1252. package/dist/server/src/camera/python/iou.py +0 -158
  1253. package/dist/server/src/camera/python/polygon.py +0 -230
  1254. package/dist/server/src/camera/python/typings.py +0 -50
  1255. package/dist/server/src/camera/python/video_frame.py +0 -143
  1256. package/dist/server/src/camera/streaming/peer-connection.d.ts +0 -26
  1257. package/dist/server/src/camera/streaming/peer-connection.js +0 -213
  1258. package/dist/server/src/camera/streaming/peer-connection.js.map +0 -1
  1259. package/dist/server/src/camera/streaming/rtsp-session.d.ts +0 -19
  1260. package/dist/server/src/camera/streaming/rtsp-session.js +0 -196
  1261. package/dist/server/src/camera/streaming/rtsp-session.js.map +0 -1
  1262. package/dist/server/src/camera/streaming/webrtc-connection.d.ts +0 -44
  1263. package/dist/server/src/camera/streaming/webrtc-connection.js +0 -177
  1264. package/dist/server/src/camera/streaming/webrtc-connection.js.map +0 -1
  1265. package/dist/server/src/camera/streaming/werift-session.d.ts +0 -19
  1266. package/dist/server/src/camera/streaming/werift-session.js +0 -246
  1267. package/dist/server/src/camera/streaming/werift-session.js.map +0 -1
  1268. package/dist/server/src/camera/types.d.ts +0 -17
  1269. package/dist/server/src/camera/types.js.map +0 -1
  1270. package/dist/server/src/camera/videoFrame.d.ts +0 -18
  1271. package/dist/server/src/camera/videoFrame.js +0 -88
  1272. package/dist/server/src/camera/videoFrame.js.map +0 -1
  1273. package/dist/server/src/cloud/index.d.ts +0 -12
  1274. package/dist/server/src/cloud/index.js +0 -49
  1275. package/dist/server/src/cloud/index.js.map +0 -1
  1276. package/dist/server/src/cloud/remote/cloudflare.d.ts +0 -7
  1277. package/dist/server/src/cloud/remote/cloudflare.js +0 -12
  1278. package/dist/server/src/cloud/remote/cloudflare.js.map +0 -1
  1279. package/dist/server/src/cloud/remote/upnp.d.ts +0 -7
  1280. package/dist/server/src/cloud/remote/upnp.js +0 -12
  1281. package/dist/server/src/cloud/remote/upnp.js.map +0 -1
  1282. package/dist/server/src/cloud/remote/utils.d.ts +0 -3
  1283. package/dist/server/src/cloud/remote/utils.js +0 -21
  1284. package/dist/server/src/cloud/remote/utils.js.map +0 -1
  1285. package/dist/server/src/cloud/types.d.ts +0 -15
  1286. package/dist/server/src/cloud/types.js +0 -11
  1287. package/dist/server/src/cloud/types.js.map +0 -1
  1288. package/dist/server/src/decoder/child.js +0 -748
  1289. package/dist/server/src/decoder/child.js.map +0 -1
  1290. package/dist/server/src/decoder/imageUtils.d.ts +0 -21
  1291. package/dist/server/src/decoder/imageUtils.js +0 -204
  1292. package/dist/server/src/decoder/imageUtils.js.map +0 -1
  1293. package/dist/server/src/decoder/manager.d.ts +0 -19
  1294. package/dist/server/src/decoder/manager.js +0 -208
  1295. package/dist/server/src/decoder/manager.js.map +0 -1
  1296. package/dist/server/src/decoder/python/__init__.py +0 -0
  1297. package/dist/server/src/decoder/python/child.py +0 -902
  1298. package/dist/server/src/decoder/python/image_utils.py +0 -196
  1299. package/dist/server/src/decoder/python/pool.py +0 -45
  1300. package/dist/server/src/decoder/python/typings.py +0 -57
  1301. package/dist/server/src/decoder/python/utils.py +0 -70
  1302. package/dist/server/src/decoder/types.d.ts +0 -23
  1303. package/dist/server/src/decoder/types.js.map +0 -1
  1304. package/dist/server/src/decoder/utils.d.ts +0 -13
  1305. package/dist/server/src/decoder/utils.js +0 -45
  1306. package/dist/server/src/decoder/utils.js.map +0 -1
  1307. package/dist/server/src/decoder/wasm/build/decoder.d.ts +0 -43
  1308. package/dist/server/src/decoder/wasm/build/decoder.js +0 -108
  1309. package/dist/server/src/decoder/wasm/build/decoder.wasm +0 -0
  1310. package/dist/server/src/decoder/worker.js +0 -79
  1311. package/dist/server/src/decoder/worker.js.map +0 -1
  1312. package/dist/server/src/plugins/runtime/node/plugin.d.ts +0 -24
  1313. package/dist/server/src/plugins/runtime/node/plugin.js +0 -128
  1314. package/dist/server/src/plugins/runtime/node/plugin.js.map +0 -1
  1315. package/dist/server/src/plugins/runtime/python/plugin.py +0 -155
  1316. package/dist/server/src/rpc/types.d.ts +0 -112
  1317. package/dist/server/src/rpc/types.js.map +0 -1
  1318. /package/dist/interface/assets/{SettingsBackup.CX0rT0QJ.0.0.70.css → SettingsBackup-CX0rT0QJ.css} +0 -0
  1319. /package/dist/interface/assets/{logo-512.DLKVOU2S.0.0.70.png → error-256-DLKVOU2S.png} +0 -0
  1320. /package/dist/interface/assets/{logo-256.BCQk9H1-.0.0.70.png → logo-256-BCQk9H1-.png} +0 -0
  1321. /package/dist/interface/assets/{logo.DmEiRk0z.0.0.70.png → logo-DmEiRk0z.png} +0 -0
  1322. /package/dist/interface/assets/{mode-yaml.CIYL8U3d.0.0.70.js → mode-yaml-CIYL8U3d.js} +0 -0
  1323. /package/dist/server/src/api/{go2rtc → database/migrations}/types.js +0 -0
  1324. /package/dist/server/src/{camera → automations/actions}/types.js +0 -0
  1325. /package/dist/server/src/{decoder → automations/conditions}/types.js +0 -0
  1326. /package/dist/server/src/{rpc → automations/triggers}/types.js +0 -0
  1327. /package/dist/server/src/{decoder/child.d.ts → remote/services/upnp.d.ts} +0 -0
  1328. /package/dist/server/src/{decoder/worker.d.ts → utils/env.d.ts} +0 -0
@@ -1,968 +1,397 @@
1
- import asyncio
2
- from collections.abc import AsyncGenerator
1
+ from __future__ import annotations
2
+
3
+ import contextlib
3
4
  from copy import deepcopy
4
- from datetime import datetime
5
- from typing import Any, Callable, Optional, Union, cast
5
+ from typing import TYPE_CHECKING, Any, Protocol, cast
6
6
 
7
- from cachetools import TTLCache
8
7
  from deepdiff.diff import DeepDiff
9
- from reactivex import operators as ops
10
- from reactivex.abc import DisposableBase
11
- from reactivex.subject.behaviorsubject import BehaviorSubject
12
- from typing_extensions import Literal, overload
13
-
14
- from _camera_ui_tools.camera_ui_common.camera_utils.utils import build_target_url
15
- from _camera_ui_tools.camera_ui_common.common_utils.subscribed import Subscribed
16
- from _camera_ui_tools.camera_ui_common.logger_service.logger import LoggerService as Logger
17
- from _camera_ui_tools.camera_ui_rpc_client import ClientInstance
18
- from _camera_ui_tools.camera_ui_rpc_client.typings import Message
19
- from _camera_ui_tools.camera_ui_rpc_client.utils.subscriptions import SubscriptionWrapper
20
- from _camera_ui_tools.camera_ui_types import (
21
- AudioSetEvent,
22
- AudioState,
23
- BatterySetEvent,
24
- BatteryState,
25
- BoundingBox,
8
+
9
+ from _camera_ui_tools.camera_ui_common import Subscribed, TaskSet
10
+ from _camera_ui_tools.camera_ui_rpc import CloseHandler, RPCClient
11
+ from _camera_ui_tools.camera_ui_sdk import (
12
+ API_EVENT,
13
+ BehaviorSubject,
26
14
  Camera,
27
- CameraCapabilitiesObservableObject,
28
15
  CameraDetectionSettings,
29
- CameraDevice,
30
- CameraDeviceCapability,
31
16
  CameraDeviceSource,
32
17
  CameraFrameWorkerSettings,
18
+ CameraImplementation,
33
19
  CameraInformation,
34
20
  CameraInput,
35
21
  CameraPluginInfo,
36
22
  CameraPropertyObservableObject,
37
23
  CameraPublicProperties,
24
+ CameraRole,
38
25
  CameraSource,
39
- CameraStateChangedObject,
40
26
  CameraType,
41
- DecoderFormat,
27
+ CameraUiSettings,
28
+ DetectionEventPayload,
29
+ DetectionLine,
42
30
  DetectionZone,
43
- DoorbellSetEvent,
44
- DoorbellState,
45
- FMP4ConnectionOptions,
46
- FrameData,
47
- FrameType,
48
- ImageOptions,
49
- LightSetEvent,
50
- LightState,
31
+ Disposable,
51
32
  LoggerService,
52
- MotionDetectionFrame,
53
- MotionSetEvent,
54
- MotionState,
55
- ObjectSetEvent,
56
- ObjectState,
33
+ Observable,
34
+ PluginContract,
57
35
  ProbeConfig,
58
36
  ProbeStream,
59
- PTZInterface,
60
- RTSPConnectionOptions,
37
+ PtzAutotrackSettings,
61
38
  RTSPUrlOptions,
62
- SirenSetEvent,
63
- SirenState,
64
- SnapshotInterface,
65
- StateNames,
66
- StateValue,
67
- StreamingInterface,
68
- WebRTCConnectionOptions,
69
- )
70
- from _camera_ui_tools.camera_ui_types import (
71
- PluginAPI as PluginAPIInterface,
39
+ Sensor,
40
+ SensorEventData,
41
+ SensorLike,
42
+ SensorType,
43
+ SnapshotSettings,
44
+ SnapshotUrlOptions,
45
+ StreamUrls,
46
+ Subject,
47
+ distinct_until_changed,
48
+ filter_op,
49
+ merge_map,
50
+ pairwise,
51
+ share,
72
52
  )
73
- from _camera_ui_tools.camera_ui_types import (
74
- VideoFrame as VideoFrameInterface,
75
- )
76
- from _camera_ui_tools.camera_ui_types.hybrid_observer import HybridObservable
77
- from camera.python.classes import transform_labels
78
- from camera.python.interfaces import CameraInterface
79
- from camera.python.iou import merge_detections
80
- from camera.python.polygon import are_detections_valid
81
- from camera.python.typings import (
82
- SetValue,
83
- )
84
- from camera.python.video_frame import VideoFrame
85
- from decoder.python.typings import FrameWorkerInterface
53
+ from _camera_ui_tools.camera_ui_sdk import CameraDevice as CameraDeviceInterface
54
+ from _camera_ui_tools.camera_ui_sdk.internal import SensorJSON
55
+ from plugins.runtime.python.camera.utils import build_snapshot_url, build_target_url
86
56
  from plugins.runtime.python.namespaces import (
87
- CameraFrameWorkerPluginNamespaces,
57
+ CameraNamespaces,
58
+ FrameWorkerDetectionNamespaces,
59
+ FrameWorkerNamespaces,
88
60
  NamespaceManager,
61
+ PluginCameraNamespaces,
62
+ SensorControllerNamespaces,
63
+ )
64
+ from plugins.runtime.python.proxy.sensor import (
65
+ DetectionCoordinatorRPC,
66
+ SensorControllerInterface,
67
+ SensorProxy,
89
68
  )
90
69
  from plugins.runtime.python.typings import (
91
- API_EVENT,
92
- CameraDeviceInterface,
93
- CameraInterfaces,
94
- PluginCapabilities,
70
+ CameraEventMessage,
95
71
  PluginInfo,
72
+ SensorAddedEvent,
73
+ SensorAssignmentChangedEvent,
74
+ SensorEventMessage,
75
+ SensorRemovedEvent,
76
+ StoredSensorData,
96
77
  )
97
78
 
79
+ if TYPE_CHECKING:
80
+ from plugins.runtime.python.plugin_api import PluginAPI
81
+ from plugins.runtime.python.storage_controller import StorageController
98
82
 
99
- class CameraSourceImp(CameraSource):
100
- def __init__(self, source: CameraInput, parent: Any):
101
- self.__parent: CameraDeviceProxy = parent
102
-
103
- self.id = source["_id"]
104
- self.name = source["name"]
105
- self.role = source["role"]
106
- self.useForSnapshot = source["useForSnapshot"]
107
- self.hotMode = source["hotMode"]
108
- self.preload = source["preload"]
109
- self.urls = source["urls"]
110
-
111
- async def snapshot(self, force_new: bool | None = None) -> bytes | None:
112
- return await self.__parent.snapshot(self.id, force_new)
113
-
114
- async def probe_stream(
115
- self, probe_config: Optional[ProbeConfig] = None, refresh: Optional[bool] = False
116
- ) -> Optional[ProbeStream]:
117
- return await self.__parent.probe_stream(self.id, probe_config, refresh)
118
83
 
84
+ DETECTION_SENSOR_TYPES: frozenset[SensorType] = frozenset(
85
+ {
86
+ SensorType.Motion,
87
+ SensorType.Audio,
88
+ SensorType.Object,
89
+ SensorType.Face,
90
+ SensorType.LicensePlate,
91
+ SensorType.Classifier,
92
+ }
93
+ )
119
94
 
120
- class CameraDeviceSourceImp(CameraSourceImp, CameraDeviceSource):
121
- def __init__(self, source: CameraInput, parent: Any):
122
- super().__init__(source, parent)
123
- self.__parent: CameraDeviceProxy = parent
124
95
 
125
- def generate_rtsp_url(self, options: Optional[RTSPUrlOptions]) -> str:
96
+ class CameraControllerInterface(Protocol):
97
+ async def connect(self) -> None: ...
98
+ async def disconnect(self) -> None: ...
99
+ async def snapshot(self, source_id: str, force_new: bool | None = None) -> bytes | None: ...
100
+ async def probeStream(
101
+ self, source_id: str, probe_config: ProbeConfig | None = None, refresh: bool | None = False
102
+ ) -> ProbeStream | None: ...
103
+ async def refreshStates(self) -> dict[str, Any]: ...
104
+ async def registerSensor(self, sensor: SensorJSON, plugin_id: str) -> bool: ...
105
+ async def unregisterSensor(self, sensor_id: str) -> None: ...
106
+ async def streamUrl(self, source_id: str) -> str | None: ...
107
+ async def getStreamStatus(self, source_id: str) -> str: ...
108
+
109
+
110
+ class CameraSourceImpl(CameraSource):
111
+ def __init__(self, source: CameraInput, parent: CameraDeviceProxy) -> None:
112
+ self._parent = parent
113
+ self._id: str = source["_id"]
114
+ self.name: str = source["name"]
115
+ self.role: CameraRole = source["role"]
116
+ self.useForSnapshot: bool = source["useForSnapshot"]
117
+ self.hotMode: bool = source["hotMode"]
118
+ self.preload: bool = source["preload"]
119
+ self.prebuffer: bool = source["prebuffer"]
120
+ self.urls: StreamUrls = source["urls"]
121
+ self.childSourceId: str | None = source.get("childSourceId")
122
+
123
+ async def snapshot(self, forceNew: bool | None = None) -> bytes | None:
124
+ return await self._parent._snapshot(self._id, forceNew) # pyright: ignore[reportPrivateUsage]
125
+
126
+ async def probeStream(
127
+ self, probeConfig: ProbeConfig | None = None, refresh: bool | None = False
128
+ ) -> ProbeStream | None:
129
+ return await self._parent._probe_stream(self._id, probeConfig, refresh) # pyright: ignore[reportPrivateUsage]
130
+
131
+ async def getStreamStatus(self) -> str:
132
+ return await self._parent._get_stream_status(self._id) # pyright: ignore[reportPrivateUsage]
133
+
134
+
135
+ class CameraDeviceSourceImpl(CameraSourceImpl, CameraDeviceSource):
136
+ def generateRTSPUrl(self, options: RTSPUrlOptions | None = None) -> str:
126
137
  return build_target_url(self.urls["rtsp"]["base"], options)
127
138
 
128
- def create_webrtc_session(self, options: Optional[WebRTCConnectionOptions]) -> None:
129
- # Todo: Implement
130
- pass
131
-
132
- def create_rtsp_session(self, options: Optional[RTSPConnectionOptions]) -> None:
133
- # Todo: Implement
134
- pass
139
+ def generateSnapshotUrl(self, options: SnapshotUrlOptions | None = None) -> str:
140
+ return build_snapshot_url(self._parent.name, self.name, self.urls["snapshot"]["jpeg"], options)
135
141
 
136
- def create_fmp4_session(self, options: Optional[FMP4ConnectionOptions]) -> None:
137
- # Todo: Implement
138
- pass
139
142
 
140
-
141
- class CameraDeviceProxy(CameraDevice, Subscribed):
143
+ class CameraDeviceProxy(Subscribed, CameraDeviceInterface):
142
144
  def __init__(
143
145
  self,
144
- proxy: ClientInstance,
145
- api: PluginAPIInterface,
146
+ proxy: RPCClient,
147
+ api: PluginAPI,
148
+ storage_controller: StorageController,
146
149
  camera: Camera,
147
150
  plugin: PluginInfo,
148
151
  logger: LoggerService,
149
- ):
150
- Subscribed.__init__(self)
151
-
152
- self.__camera_subject = BehaviorSubject(camera)
153
- self.__camera_state = BehaviorSubject[bool](False)
154
- self.__frame_worker_state = BehaviorSubject[bool](False)
155
- self.__light_state = BehaviorSubject[LightState](self.__get_light_state({"state": False}, True))
156
- self.__motion_state = BehaviorSubject[MotionState](
157
- self.__get_motion_state({"detections": [], "state": False}, True)
158
- )
159
- self.__audio_state = BehaviorSubject[AudioState](
160
- self.__get_audio_state({"state": False, "db": 0}, True)
161
- )
162
- self.__object_state = BehaviorSubject[ObjectState](self.__get_object_state({"detections": []}, True))
163
- self.__doorbell_state = BehaviorSubject[DoorbellState](
164
- self.__get_doorbell_state({"state": False}, True)
165
- )
166
- self.__siren_state = BehaviorSubject[SirenState](
167
- self.__get_siren_state({"state": False, "level": 0}, True)
168
- )
169
- self.__battery_state = BehaviorSubject[BatteryState](
170
- self.__get_battery_state({"level": 100, "charging": False, "lowBattery": False}, True)
171
- )
172
- self.__capabilities = BehaviorSubject[list[PluginCapabilities]]([])
173
-
174
- self.on_connected: HybridObservable[bool] = self.__create_state_observable(self.__camera_state)
175
- self.on_frameworker_connected: HybridObservable[bool] = self.__create_state_observable(
176
- self.__frame_worker_state
177
- )
178
- self.on_light_switched: HybridObservable[LightState] = self.__create_state_observable(
179
- self.__light_state
180
- )
181
- self.on_motion_detected: HybridObservable[MotionState] = self.__create_state_observable(
182
- self.__motion_state
183
- )
184
- self.on_audio_detected: HybridObservable[AudioState] = self.__create_state_observable(
185
- self.__audio_state
186
- )
187
- self.on_object_detected: HybridObservable[ObjectState] = self.__create_state_observable(
188
- self.__object_state
189
- )
190
- self.on_doorbell_pressed: HybridObservable[DoorbellState] = self.__create_state_observable(
191
- self.__doorbell_state
192
- )
193
- self.on_siren_detected: HybridObservable[SirenState] = self.__create_state_observable(
194
- self.__siren_state
195
- )
196
- self.on_battery_changed: HybridObservable[BatteryState] = self.__create_state_observable(
197
- self.__battery_state
198
- )
199
-
200
- if not camera.get("pluginInfo", None):
201
- self.__camera_state.on_next(True)
202
-
203
- self.logger = logger
152
+ ) -> None:
153
+ super().__init__()
204
154
 
205
- self.__api = api
206
- self.__proxy = proxy
207
- self.__plugin = plugin
208
- self.__snapshot_cache = TTLCache[str, bytes](maxsize=100, ttl=self.snapshot_ttl)
209
- self.__namespaces: CameraFrameWorkerPluginNamespaces = {
210
- **NamespaceManager.camera_namespaces(self.id),
211
- **NamespaceManager.frame_worker_namespaces(self.id),
212
- **NamespaceManager.plugin_camera_namespaces(self.__plugin["id"], self.id),
213
- }
155
+ self._camera_subject = BehaviorSubject(camera)
156
+ self._camera_state = BehaviorSubject[bool](False)
157
+ self._frame_worker_state = BehaviorSubject[bool](False)
158
+ self._initialized = BehaviorSubject[bool](False)
214
159
 
215
- self.__initialized = False
216
- self.__subscription: Optional[SubscriptionWrapper] = None
160
+ self._onConnected: Observable[bool] = self._create_state_observable(self._camera_state)
161
+ self._onFrameworkerConnected: Observable[bool] = self._create_state_observable(
162
+ self._frame_worker_state
163
+ )
217
164
 
218
- self.__camera_interfaces = CameraInterface(
219
- self.__proxy, self.__capabilities, self.id, self.plugin_info
165
+ self._logger = logger
166
+ self._api: PluginAPI = api
167
+ self._proxy = proxy
168
+ self._plugin = plugin
169
+ self._contract: PluginContract = plugin["contract"]
170
+ self._storage_controller: StorageController = storage_controller
171
+
172
+ self._sensor_added_subject: Subject[SensorEventData] = Subject()
173
+ self._sensor_removed_subject: Subject[SensorEventData] = Subject()
174
+ self._detection_event_subject: Subject[DetectionEventPayload] = Subject()
175
+
176
+ self._close_subscription: CloseHandler | None = None
177
+ self._close_sensor_subscription: CloseHandler | None = None
178
+ self._close_detection_subscription: CloseHandler | None = None
179
+
180
+ self._sensors: dict[str, SensorProxy] = {}
181
+ self._owned_sensors: dict[str, tuple[Sensor[Any, Any, Any], SensorType]] = {}
182
+ self._sensor_cleanup_functions: dict[str, CloseHandler] = {}
183
+
184
+ self._impl_cleanup_function: CloseHandler | None = None
185
+
186
+ self._tasks = TaskSet(name=f"CameraDevice:{camera['_id']}")
187
+
188
+ self._namespaces: tuple[
189
+ CameraNamespaces,
190
+ FrameWorkerNamespaces,
191
+ PluginCameraNamespaces,
192
+ SensorControllerNamespaces,
193
+ FrameWorkerDetectionNamespaces,
194
+ ] = (
195
+ NamespaceManager.camera_namespaces(self.id),
196
+ NamespaceManager.frame_worker_namespaces(self.id),
197
+ NamespaceManager.plugin_camera_namespaces(self._plugin["id"], self.id),
198
+ NamespaceManager.sensor_controller_namespaces(self.id),
199
+ NamespaceManager.frame_worker_detection_namespaces(self.id),
220
200
  )
221
201
 
222
- self.__api.once(API_EVENT.SHUTDOWN.value, self.cleanup)
202
+ self._api.once(API_EVENT.SHUTDOWN.value, self.cleanup)
223
203
 
224
- self.add_subscriptions(
225
- self.on_property_change("name").subscribe(self.__on_name_change),
226
- )
204
+ @property
205
+ def _cameraObject(self) -> Camera:
206
+ return deepcopy(self._camera_subject.value)
227
207
 
228
208
  @property
229
- def camera_object(self) -> Camera:
230
- return deepcopy(self.__camera_subject.value)
209
+ def logger(self) -> LoggerService:
210
+ return self._logger
231
211
 
232
212
  @property
233
213
  def id(self) -> str:
234
- return self.__camera_subject.value["_id"]
214
+ return self._camera_subject.value["_id"]
235
215
 
236
216
  @property
237
- def native_id(self) -> Optional[str]:
238
- return self.__camera_subject.value.get("nativeId")
217
+ def nativeId(self) -> str | None:
218
+ return self._camera_subject.value.get("nativeId")
239
219
 
240
220
  @property
241
- def plugin_info(self) -> Optional[CameraPluginInfo]:
242
- return self.__camera_subject.value.get("pluginInfo")
221
+ def pluginInfo(self) -> CameraPluginInfo | None:
222
+ plugin_info = self._camera_subject.value.get("pluginInfo")
223
+ if not plugin_info:
224
+ return None
225
+
226
+ return deepcopy(self._camera_subject.value.get("pluginInfo"))
243
227
 
244
228
  @property
245
229
  def connected(self) -> bool:
246
- return self.__camera_state.value or False
230
+ return self._camera_state.value or False
231
+
232
+ @property
233
+ def frameWorkerConnected(self) -> bool:
234
+ return self._frame_worker_state.value or False
235
+
236
+ @property
237
+ def onConnected(self) -> Observable[bool]:
238
+ return self._onConnected
247
239
 
248
240
  @property
249
- def frameworker_connected(self) -> bool:
250
- return self.__frame_worker_state.value or False
241
+ def onFrameWorkerConnected(self) -> Observable[bool]:
242
+ return self._onFrameworkerConnected
251
243
 
252
244
  @property
253
245
  def disabled(self) -> bool:
254
- return self.__camera_subject.value["disabled"]
246
+ return self._camera_subject.value["disabled"]
255
247
 
256
248
  @property
257
249
  def name(self) -> str:
258
- return self.__camera_subject.value["name"]
250
+ return self._camera_subject.value["name"]
259
251
 
260
252
  @property
261
- def type(self) -> CameraType:
262
- return self.__camera_subject.value["type"]
253
+ def room(self) -> str:
254
+ return self._camera_subject.value.get("room", "Default")
263
255
 
264
256
  @property
265
- def info(self) -> CameraInformation:
266
- return deepcopy(self.__camera_subject.value["info"])
257
+ def type(self) -> CameraType:
258
+ return self._camera_subject.value["type"]
267
259
 
268
260
  @property
269
- def is_cloud(self) -> bool:
270
- return self.__camera_subject.value["isCloud"]
261
+ def info(self) -> CameraInformation:
262
+ return deepcopy(self._camera_subject.value["info"])
271
263
 
272
264
  @property
273
- def has_light(self) -> bool:
274
- return self.has_capability(CameraDeviceCapability.Light)
265
+ def isCloud(self) -> bool:
266
+ return self._camera_subject.value["isCloud"]
275
267
 
276
268
  @property
277
- def has_siren(self) -> bool:
278
- return self.has_capability(CameraDeviceCapability.Siren)
269
+ def snapshotSettings(self) -> SnapshotSettings:
270
+ return deepcopy(self._camera_subject.value["snapshotSettings"])
279
271
 
280
272
  @property
281
- def has_doorbell(self) -> bool:
282
- return self.has_capability(CameraDeviceCapability.Doorbell)
273
+ def detectionZones(self) -> list[DetectionZone]:
274
+ return deepcopy(self._camera_subject.value["detectionZones"])
283
275
 
284
276
  @property
285
- def has_battery(self) -> bool:
286
- return self.has_capability(CameraDeviceCapability.Battery)
277
+ def detectionLines(self) -> list[DetectionLine]:
278
+ return deepcopy(self._camera_subject.value["detectionLines"])
287
279
 
288
280
  @property
289
- def has_audio_detector(self) -> bool:
290
- return self.has_capability(CameraDeviceCapability.AudioSensor)
281
+ def detectionSettings(self) -> CameraDetectionSettings:
282
+ return deepcopy(self._camera_subject.value["detectionSettings"])
291
283
 
292
284
  @property
293
- def has_motion_detector(self) -> bool:
294
- return self.has_capability(CameraDeviceCapability.MotionSensor) or self.has_capability(
295
- CameraDeviceCapability.MotionDetector
296
- )
285
+ def ptzAutotrack(self) -> PtzAutotrackSettings:
286
+ return deepcopy(self._camera_subject.value["ptzAutotrack"])
297
287
 
298
288
  @property
299
- def has_object_detector(self) -> bool:
300
- return self.has_capability(CameraDeviceCapability.ObjectSensor) or self.has_capability(
301
- CameraDeviceCapability.ObjectDetector
302
- )
289
+ def snooze(self) -> bool:
290
+ return bool(self._camera_subject.value["detectionSettings"].get("snooze", False))
303
291
 
304
292
  @property
305
- def has_ptz(self) -> bool:
306
- return self.has_capability(CameraDeviceCapability.PTZ)
293
+ def frameWorkerSettings(self) -> CameraFrameWorkerSettings:
294
+ return deepcopy(self._camera_subject.value["frameWorkerSettings"])
307
295
 
308
296
  @property
309
- def snapshot_ttl(self) -> int:
310
- return self.__camera_subject.value["snapshotTTL"]
297
+ def interfaceSettings(self) -> CameraUiSettings:
298
+ return deepcopy(self._camera_subject.value["interfaceSettings"])
311
299
 
312
300
  @property
313
- def detection_zones(self) -> list[DetectionZone]:
314
- return deepcopy(self.__camera_subject.value["detectionZones"])
301
+ def sources(self) -> list[CameraDeviceSource]:
302
+ sources = deepcopy(self._camera_subject.value["sources"])
303
+ return [CameraDeviceSourceImpl(source, self) for source in sources]
315
304
 
316
305
  @property
317
- def detection_settings(self) -> CameraDetectionSettings:
318
- return deepcopy(self.__camera_subject.value["detectionSettings"])
306
+ def streamSource(self) -> CameraDeviceSource:
307
+ return cast(
308
+ CameraDeviceSource,
309
+ self.highResolutionSource or self.midResolutionSource or self.lowResolutionSource,
310
+ )
319
311
 
320
312
  @property
321
- def frameworker_settings(self) -> CameraFrameWorkerSettings:
322
- return deepcopy(self.__camera_subject.value["frameWorkerSettings"])
313
+ def highResolutionSource(self) -> CameraDeviceSource | None:
314
+ return next((s for s in self.sources if s.role == "high-resolution"), None)
323
315
 
324
316
  @property
325
- def sources(self) -> list[CameraDeviceSource]:
326
- sources = deepcopy(self.__camera_subject.value["sources"])
327
- return [CameraDeviceSourceImp(source, self) for source in sources]
317
+ def midResolutionSource(self) -> CameraDeviceSource | None:
318
+ return next((s for s in self.sources if s.role == "mid-resolution"), None)
328
319
 
329
320
  @property
330
- def stream_source(self) -> CameraDeviceSource:
331
- source = self.high_resolution_source or self.mid_resolution_source or self.low_resolution_source
332
- return cast(CameraDeviceSource, source)
321
+ def lowResolutionSource(self) -> CameraDeviceSource | None:
322
+ return next((s for s in self.sources if s.role == "low-resolution"), None)
333
323
 
334
324
  @property
335
- def snapshot_source(self) -> Optional[CameraSource]:
336
- snapshot_source = next((source for source in self.sources if source.role == "snapshot"), None)
337
-
325
+ def snapshotSource(self) -> CameraDeviceSource | None:
326
+ snapshot_source = next((s for s in self.sources if s.role == "snapshot"), None)
338
327
  if not snapshot_source:
339
- snapshot_source = next((source for source in self.sources if source.useForSnapshot), None)
340
-
328
+ snapshot_source = next((s for s in self.sources if s.useForSnapshot), None)
341
329
  return snapshot_source
342
330
 
343
331
  @property
344
- def high_resolution_source(self) -> Optional[CameraDeviceSource]:
345
- return next((source for source in self.sources if source.role == "high-resolution"), None)
332
+ def _camera_controller_proxy(self) -> CameraControllerInterface:
333
+ return self._proxy.create_proxy(self._namespaces[0].camera_controller_rpc)
346
334
 
347
335
  @property
348
- def mid_resolution_source(self) -> Optional[CameraDeviceSource]:
349
- return next(
350
- (source for source in self.sources if "mid-resolution" in source.role == "mid-resolution"), None
351
- )
336
+ def _sensor_controller_proxy(self) -> SensorControllerInterface:
337
+ return self._proxy.create_proxy(self._namespaces[3].sensor_rpc)
352
338
 
353
339
  @property
354
- def low_resolution_source(self) -> Optional[CameraDeviceSource]:
355
- return next(
356
- (source for source in self.sources if "low-resolution" in source.role == "low-resolution"), None
357
- )
340
+ def _detection_coordinator_proxy(self) -> DetectionCoordinatorRPC:
341
+ return self._proxy.create_proxy(self._namespaces[4].detection_rpc)
358
342
 
359
- @property
360
- def interfaces(self) -> CameraInterfaces:
361
- return self.__camera_interfaces
343
+ def getSourceById(self, id: str) -> CameraDeviceSource | None:
344
+ return next((s for s in self.sources if s._id == id), None)
345
+
346
+ def _can_access_sensor(self, sensor: StoredSensorData) -> bool:
347
+ # Own sensors are always accessible
348
+ if sensor.get("pluginId") == self._plugin["id"]:
349
+ return True
350
+
351
+ # Foreign sensors require consumes declaration
352
+ return "consumes" in self._contract and sensor["type"] in self._contract["consumes"]
362
353
 
363
354
  async def init(self) -> None:
364
- if self.__initialized:
355
+ if self._initialized.value:
365
356
  return
366
357
 
367
- self.__initialized = True
358
+ self._initialized.next(True)
368
359
 
369
- self.__subscription = await self.__proxy.subscribe(
370
- self.__namespaces["cameraSubject"], self.__on_event_message
360
+ self._close_subscription = await self._proxy.subscribe(
361
+ self._namespaces[0].camera_subject, self._on_event_message
371
362
  )
372
363
 
373
- await self.__proxy.register_rpc_handler(
374
- self.__namespaces["cameraInterfacesRpc"], self.__camera_interfaces
364
+ self._close_sensor_subscription = await self._proxy.subscribe(
365
+ self._namespaces[3].sensor_subject, self._on_global_sensor_event
375
366
  )
376
- await self.__refresh_states()
377
-
378
- def extend(self, interfaces: PTZInterface | SnapshotInterface | StreamingInterface) -> None:
379
- self.__camera_interfaces.interfaces = interfaces
380
-
381
- async def connect(self) -> None:
382
- if self.plugin_info and self.plugin_info["id"] == self.__plugin["id"]:
383
- raise Exception("Camera plugin ID does not match the current plugin ID.")
384
-
385
- camera_controller_proxy = await self.__camera_controller_proxy()
386
- return await camera_controller_proxy.connect()
387
-
388
- async def disconnect(self) -> None:
389
- if self.plugin_info and self.plugin_info["id"] == self.__plugin["id"]:
390
- raise Exception("Camera plugin ID does not match the current plugin ID.")
391
-
392
- camera_controller_proxy = await self.__camera_controller_proxy()
393
- return await camera_controller_proxy.disconnect()
394
-
395
- @overload # type: ignore[override]
396
- async def get_frames(
397
- self, frame_type: Literal["video"], options: Optional[ImageOptions] = None
398
- ) -> AsyncGenerator[VideoFrameInterface, None]: ...
399
- @overload
400
- async def get_frames(
401
- self, frame_type: Literal["motion"], options: Optional[ImageOptions] = None
402
- ) -> AsyncGenerator[VideoFrameInterface, None]: ...
403
- async def get_frames( # type: ignore[misc]
404
- self, frame_type: FrameType, options: Optional[ImageOptions] = None
405
- ) -> AsyncGenerator[VideoFrameInterface, None]:
406
- subscription: Optional[SubscriptionWrapper] = None
407
- current_resolver: Optional[Callable[[Optional[MotionDetectionFrame]], None]] = None
408
- cap_subscription: Optional[DisposableBase] = None
409
- motion_subscription: Optional[DisposableBase] = None
410
- current_type = frame_type
411
-
412
- # For motion sensor only
413
- motion_detected: bool = False
414
- frameWorkerGenerator: Optional[AsyncGenerator[FrameData, None]] = None
415
- pendingFramePromise: Optional[asyncio.Task[Any]] = None
416
-
417
- def is_motion_detector() -> bool:
418
- return self.has_motion_detector and self.has_capability(CameraDeviceCapability.MotionDetector)
419
-
420
- def is_motion_sensor_only() -> bool:
421
- return (
422
- self.has_motion_detector
423
- and not self.has_capability(CameraDeviceCapability.MotionDetector)
424
- and self.has_capability(CameraDeviceCapability.MotionSensor)
425
- )
426
-
427
- async def stop_frameworker_generator() -> None:
428
- nonlocal frameWorkerGenerator, pendingFramePromise
429
- if frameWorkerGenerator is not None:
430
- try:
431
- await frameWorkerGenerator.aclose()
432
- except: # noqa: E722
433
- pass
434
- finally:
435
- frameWorkerGenerator = None
436
367
 
437
- if pendingFramePromise is not None and not pendingFramePromise.done():
438
- pendingFramePromise.cancel()
439
- pendingFramePromise = None
368
+ ns = NamespaceManager.detection_event_namespaces(self.id)
440
369
 
441
- try:
442
- frame_worker_proxy = await self.__frame_worker_proxy()
443
- queue: list[MotionDetectionFrame] = []
444
-
445
- # Subscribe to motion frames if needed for motion detector
446
- if current_type == "motion":
447
-
448
- def on_frame(message: Message[MotionDetectionFrame]) -> None:
449
- nonlocal current_resolver
450
- if current_resolver:
451
- current_resolver(message["data"])
452
- current_resolver = None
453
- else:
454
- queue.append(message["data"])
455
-
456
- subscription = await self.__proxy.subscribe(
457
- self.__namespaces["cameraMotionFrameSubject"], on_frame
458
- )
370
+ def _handle_detection_msg(msg: dict[str, Any]) -> None:
371
+ self._detection_event_subject.next({"type": msg["type"], "event": msg["data"]})
459
372
 
460
- # For motion sensor, subscribe to motion events
461
- if is_motion_sensor_only():
462
- # Initialize motion state from current value
463
- motion_detected = self.__motion_state.value.get("state", False)
464
-
465
- # Subscribe to motion state changes
466
- def on_motion_detected(state: MotionState) -> None:
467
- nonlocal motion_detected, current_resolver
468
- new_motion_state = state.get("state", False)
469
- if new_motion_state != motion_detected:
470
- motion_detected = new_motion_state
471
-
472
- # If motion just started and we're waiting, resolve to continue the loop
473
- if motion_detected and current_resolver:
474
- current_resolver(None)
475
- current_resolver = None
476
-
477
- motion_subscription = self.on_motion_detected.subscribe(on_motion_detected)
478
-
479
- # Subscribe to changes in capabilities
480
- if frame_type == "motion":
481
-
482
- async def on_capabilities_change(capabilities: CameraCapabilitiesObservableObject) -> None:
483
- nonlocal current_type, current_resolver, frameWorkerGenerator, pendingFramePromise
484
-
485
- new_capabilities: list[CameraDeviceCapability] = capabilities["new_capabilities"]
486
- old_capabilities: list[CameraDeviceCapability] = capabilities["old_capabilities"]
487
-
488
- had_motion_detector = CameraDeviceCapability.MotionDetector in old_capabilities
489
- has_motion_detector_now = CameraDeviceCapability.MotionDetector in new_capabilities
490
- has_new_motion_detector = is_motion_detector() or is_motion_sensor_only()
491
-
492
- # Case 1: Currently in motion mode, but no motion detector available anymore
493
- if current_type == "motion" and not has_new_motion_detector:
494
- self.logger.trace("Switching to stream mode due to missing motion detector")
495
-
496
- # Reset any motion sensor state
497
- await stop_frameworker_generator()
498
-
499
- # If we're waiting for motion, resolve to restart the loop
500
- if current_resolver:
501
- current_resolver(None)
502
- current_resolver = None
503
-
504
- # Case 2: Currently in stream mode, but motion detector available now
505
- elif current_type == "stream" and has_new_motion_detector:
506
- self.logger.trace("Switching to motion mode due to motion detector being available")
507
- current_type = frame_type
508
-
509
- # Case 3: Currently in motion sensor mode, but motion detector available now
510
- elif current_type == "motion" and not had_motion_detector and has_motion_detector_now:
511
- self.logger.trace("Switching from motion sensor to motion detector")
512
-
513
- # Reset any motion sensor state
514
- await stop_frameworker_generator()
515
-
516
- # If we're waiting for motion, resolve to restart the loop
517
- if current_resolver:
518
- current_resolver(None)
519
- current_resolver = None
520
-
521
- # Case 4: Currently using motion detector, but now switching back to motion sensor
522
- elif (
523
- current_type == "motion"
524
- and had_motion_detector
525
- and not has_motion_detector_now
526
- and is_motion_sensor_only()
527
- ):
528
- self.logger.trace("Switching from motion detector to motion sensor")
529
- # Reset frameWorkerGenerator so it will be re-initialized for motion sensor mode
530
- if frameWorkerGenerator is None and current_resolver:
531
- # If we're waiting for motion (which is likely since motion detector was removed),
532
- # resolve to restart the loop in built-in mode
533
- current_resolver(None)
534
- current_resolver = None
535
-
536
- cap_subscription = self.on_capabilities_change().asubscribe(on_capabilities_change)
537
-
538
- async def get_prebuffered_frame(timestamp: int) -> Optional[FrameData]:
539
- try:
540
- return await frame_worker_proxy.getPrebufferedFrame(timestamp, options)
541
- except: # noqa: E722
542
- return None
543
-
544
- async def process_motion_frame(motion_frame: MotionDetectionFrame) -> FrameData:
545
- frame_format = motion_frame["frame"]["info"]["format"]
546
- frame_width = motion_frame["frame"]["info"]["width"]
547
- frame_height = motion_frame["frame"]["info"]["height"]
548
-
549
- requested_format = (
550
- options.get("format", {}).get("to", frame_format) if options else frame_format
551
- )
552
- requested_width = (
553
- (
554
- options.get("resize", {}).get("width")
555
- or options.get("crop", {}).get("width")
556
- or frame_width
557
- )
558
- if options
559
- else frame_width
560
- )
561
- requested_height = (
562
- (
563
- options.get("resize", {}).get("height")
564
- or options.get("crop", {}).get("height")
565
- or frame_height
566
- )
567
- if options
568
- else frame_height
569
- )
570
-
571
- process_frame = (
572
- requested_format != frame_format
573
- or requested_width != frame_width
574
- or requested_height != frame_height
575
- )
576
-
577
- if process_frame and options:
578
- prebuffered_frame = await get_prebuffered_frame(motion_frame["frame"]["timestamp"])
579
- if prebuffered_frame:
580
- return prebuffered_frame
581
- else:
582
- format: Union[DecoderFormat, Literal["rgba", "gray"]] = (
583
- "rgb24" if frame_format == "rgb" else frame_format
584
- )
585
- frame_data = await frame_worker_proxy.processFrame(
586
- motion_frame["frame"]["data"], frame_width, frame_height, format, options
587
- )
588
- return {
589
- "data": frame_data["image"],
590
- "info": frame_data["info"],
591
- "metadata": {
592
- "format": motion_frame["frame"]["metadata"]["format"],
593
- "frameSize": motion_frame["frame"]["metadata"]["frameSize"],
594
- "height": frame_data["info"]["height"],
595
- "width": frame_data["info"]["width"],
596
- "origHeight": motion_frame["frame"]["info"]["height"],
597
- "origWidth": motion_frame["frame"]["info"]["width"],
598
- },
599
- "timestamp": motion_frame["frame"]["timestamp"],
600
- }
601
- else:
602
- return motion_frame["frame"]
603
-
604
- while self.__initialized:
605
- try:
606
- # Handle motion detector
607
- if current_type == "motion" and is_motion_detector():
608
- if queue:
609
- motion_frame = queue.pop(0)
610
- motion_frame["frame"] = await process_motion_frame(motion_frame)
611
- yield VideoFrame(
612
- motion_frame["frame"],
613
- self.__namespaces["frameWorkerChildRpc"],
614
- self.__proxy,
615
- motion_frame["state"],
616
- )
617
- else:
618
- future: asyncio.Future[Union[MotionDetectionFrame, None]] = asyncio.Future()
619
- current_resolver = future.set_result
620
- motion_frame_exists = await future
621
-
622
- if not motion_frame_exists:
623
- current_type = "stream"
624
- continue
625
-
626
- motion_frame = motion_frame_exists
627
- motion_frame["frame"] = await process_motion_frame(motion_frame)
628
- yield VideoFrame(
629
- motion_frame["frame"],
630
- self.__namespaces["frameWorkerChildRpc"],
631
- self.__proxy,
632
- motion_frame["state"],
633
- )
634
- # Handle motion sensor
635
- elif current_type == "motion" and is_motion_sensor_only():
636
- # Initialize frame generator immediately if needed
637
- if frameWorkerGenerator is None:
638
- self.logger.trace("Initializing frame worker generator for motion sensor")
639
- frameWorkerGenerator = frame_worker_proxy.generateFrames(options)
640
-
641
- # Execute first next() to establish the connection
642
- try:
643
- # Discard the first frame - we just want to establish the connection
644
- await frameWorkerGenerator.__anext__()
645
- except Exception as e:
646
- self.logger.warn(f"Failed to initialize frame worker generator: {str(e)}")
647
- frameWorkerGenerator = None
648
- current_type = "stream"
649
- continue
650
-
651
- # If no motion detected, wait for it
652
- if not motion_detected:
653
- future = asyncio.Future()
654
- current_resolver = future.set_result
655
- await future
656
- continue
657
-
658
- # Motion is detected - get the most current frame
659
- try:
660
- frame = await frameWorkerGenerator.__anext__()
661
- except StopAsyncIteration:
662
- # Generator ended, reset and switch to stream
663
- frameWorkerGenerator = None
664
- current_type = "stream"
665
- continue
666
-
667
- # Create a synthetic motion state for the frame
668
- motion_state: MotionSetEvent = {
669
- "state": True,
670
- "detections": self.__motion_state.value.get("detections", []),
671
- }
672
-
673
- # Yield the frame with motion state
674
- yield VideoFrame(
675
- frame, self.__namespaces["frameWorkerChildRpc"], self.__proxy, motion_state
676
- )
677
- else:
678
- # Handle regular streaming
679
- # Reset motion sensor resources if switching modes
680
- if frameWorkerGenerator is not None:
681
- frameWorkerGenerator = None
682
- pendingFramePromise = None
683
-
684
- # Regular stream mode
685
- async for frame in frame_worker_proxy.generateFrames(options):
686
- if (current_type == "motion" and is_motion_detector()) or (
687
- current_type == "motion" and is_motion_sensor_only()
688
- ):
689
- break # Break stream loop to switch back to motion mode
690
- yield VideoFrame(frame, self.__namespaces["frameWorkerChildRpc"], self.__proxy)
691
-
692
- except (StopAsyncIteration, GeneratorExit):
693
- self.logger.trace("Stopping frame generator")
694
- break
695
-
696
- except Exception as e:
697
- if not self.__initialized:
698
- return
699
-
700
- raise e
701
-
702
- finally:
703
- if subscription:
704
- await subscription.unsubscribe()
705
- if cap_subscription:
706
- cap_subscription.dispose()
707
- if motion_subscription:
708
- motion_subscription.dispose()
709
- if pendingFramePromise and not pendingFramePromise.done():
710
- pendingFramePromise.cancel()
711
-
712
- def add_capabilities(self, capabilities: list[CameraDeviceCapability]) -> None:
713
- new_capabilities: list[CameraDeviceCapability] = []
714
-
715
- for capability in capabilities:
716
- if not self.has_capability(capability):
717
- new_capabilities.append(capability)
718
-
719
- if new_capabilities:
720
- all_capabilities = deepcopy(self.__capabilities.value)
721
- plugin_related_capabilities = next(
722
- (cap for cap in all_capabilities if cap["pluginId"] == self.__plugin["id"]), None
723
- )
724
-
725
- if plugin_related_capabilities:
726
- plugin_related_capabilities["capabilities"].extend(new_capabilities)
727
- else:
728
- all_capabilities.append({"pluginId": self.__plugin["id"], "capabilities": new_capabilities})
729
-
730
- self.__capabilities.on_next(all_capabilities)
731
-
732
- async def updateCapabilities() -> None:
733
- try:
734
- camera_controller_proxy = await self.__camera_controller_proxy()
735
- await camera_controller_proxy.addPluginCapabilities(self.__plugin["id"], new_capabilities)
736
- except asyncio.CancelledError:
737
- # Ignore cancellation errors
738
- pass
739
- # except Exception as e:
740
- # self.logger.error("Failed to add capabilities:", e)
741
- except: # noqa: E722
742
- pass
743
-
744
- asyncio.create_task(updateCapabilities())
745
-
746
- def remove_capabilities(self, capabilities: list[CameraDeviceCapability]) -> None:
747
- all_capabilities = deepcopy(self.__capabilities.value)
748
- plugin_related_capabilities = next(
749
- (cap for cap in all_capabilities if cap["pluginId"] == self.__plugin["id"]), None
373
+ self._close_detection_subscription = await self._proxy.subscribe(
374
+ ns.detection_event_subject, _handle_detection_msg
750
375
  )
751
376
 
752
- if plugin_related_capabilities:
753
- plugin_related_capabilities["capabilities"] = (
754
- []
755
- if len(capabilities) == 0
756
- else [cap for cap in plugin_related_capabilities["capabilities"] if cap not in capabilities]
757
- )
758
-
759
- if not plugin_related_capabilities["capabilities"]:
760
- all_capabilities.remove(plugin_related_capabilities)
761
-
762
- self.__capabilities.on_next(all_capabilities)
377
+ await self._refresh_states()
378
+ await self._initialize_sensors()
763
379
 
764
- async def updateCapabilities() -> None:
765
- try:
766
- camera_controller_proxy = await self.__camera_controller_proxy()
767
- await camera_controller_proxy.removePluginCapabilities(self.__plugin["id"], capabilities)
768
- except Exception as e:
769
- if not self.__initialized:
770
- return
771
-
772
- self.logger.error("Failed to remove capabilities:", e)
773
-
774
- asyncio.create_task(updateCapabilities())
775
-
776
- def get_capabilities(self) -> list[CameraDeviceCapability]:
777
- capabilities: list[CameraDeviceCapability] = []
778
- for capability in self.__capabilities.value:
779
- if capability["capabilities"]:
780
- capabilities.extend(capability["capabilities"])
781
-
782
- return capabilities
783
-
784
- def has_capability(self, capability: CameraDeviceCapability) -> bool:
785
- capabilities = self.get_capabilities()
786
- return capability in capabilities
787
-
788
- @overload
789
- def get_value(self, state_name: Literal["light"]) -> LightState: ...
790
- @overload
791
- def get_value(self, state_name: Literal["motion"]) -> MotionState: ...
792
- @overload
793
- def get_value(self, state_name: Literal["audio"]) -> AudioState: ...
794
- @overload
795
- def get_value(self, state_name: Literal["object"]) -> ObjectState: ...
796
- @overload
797
- def get_value(self, state_name: Literal["doorbell"]) -> DoorbellState: ...
798
- @overload
799
- def get_value(self, state_name: Literal["siren"]) -> SirenState: ...
800
- @overload
801
- def get_value(self, state_name: Literal["battery"]) -> BatteryState: ...
802
- def get_value(
803
- self, state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"]
804
- ) -> Union[
805
- LightState,
806
- MotionState,
807
- AudioState,
808
- ObjectState,
809
- DoorbellState,
810
- SirenState,
811
- BatteryState,
812
- ]:
813
- if state_name == "light":
814
- return deepcopy(self.__light_state.value)
815
- elif state_name == "motion":
816
- return deepcopy(self.__motion_state.value)
817
- elif state_name == "audio":
818
- return deepcopy(self.__audio_state.value)
819
- elif state_name == "object":
820
- return deepcopy(self.__object_state.value)
821
- elif state_name == "doorbell":
822
- return deepcopy(self.__doorbell_state.value)
823
- elif state_name == "siren":
824
- return deepcopy(self.__siren_state.value)
825
- elif state_name == "battery":
826
- return deepcopy(self.__battery_state.value)
827
- else:
828
- raise Exception(f"Unknown state: {state_name}")
829
-
830
- @overload
831
- async def update_state(
832
- self,
833
- state_name: Literal["light"],
834
- event_data: LightSetEvent,
835
- ) -> None: ...
836
- @overload
837
- async def update_state(
838
- self,
839
- state_name: Literal["motion"],
840
- event_data: MotionSetEvent,
841
- frame: Optional[VideoFrameInterface] = None,
842
- ) -> None: ...
843
- @overload
844
- async def update_state(
845
- self,
846
- state_name: Literal["audio"],
847
- event_data: AudioSetEvent,
848
- ) -> None: ...
849
- @overload
850
- async def update_state(
851
- self,
852
- state_name: Literal["object"],
853
- event_data: ObjectSetEvent,
854
- ) -> None: ...
855
- @overload
856
- async def update_state(
857
- self,
858
- state_name: Literal["doorbell"],
859
- event_data: DoorbellSetEvent,
860
- ) -> None: ...
861
- @overload
862
- async def update_state(
863
- self,
864
- state_name: Literal["siren"],
865
- event_data: SirenSetEvent,
866
- ) -> None: ...
867
- @overload
868
- async def update_state(
869
- self,
870
- state_name: Literal["battery"],
871
- event_data: BatterySetEvent,
872
- ) -> None: ...
873
- async def update_state(
874
- self, state_name: Any, event_data: Any, frame: Optional[VideoFrameInterface] = None
875
- ) -> None:
876
- try:
877
- can_update = self.__can_update_state_internal(state_name)
878
- if not can_update:
879
- self.logger.warn(f"State '{state_name}' can only be updated by the corresponding plugin.")
880
- return
380
+ async def connect(self) -> None:
381
+ if not self.pluginInfo or self.pluginInfo["id"] != self._plugin["id"]:
382
+ return
881
383
 
882
- changed, event = cast(tuple[bool, Any], self.__check_state_internal(state_name, event_data))
384
+ await self._camera_controller_proxy.connect()
883
385
 
884
- if not changed:
885
- return
886
-
887
- self.__update_state_internal(state_name, event, True)
888
-
889
- if state_name == "motion" and frame and self.has_object_detector:
890
- motion_event = cast(MotionSetEvent, event)
891
- if motion_event["state"] and "detections" in motion_event and motion_event["detections"]:
892
- motion_frame: MotionDetectionFrame = {
893
- "frame": {
894
- "data": frame.data,
895
- "info": frame.info,
896
- "metadata": frame.metadata,
897
- "timestamp": int(datetime.now().timestamp() * 1000),
898
- },
899
- "state": motion_event,
900
- }
901
-
902
- await self.__proxy.publish(self.__namespaces["cameraMotionFrameSubject"], motion_frame)
903
-
904
- camera_controller_proxy = await self.__camera_controller_proxy()
905
- await camera_controller_proxy.updateState(state_name, event)
906
- except Exception as e:
907
- if not self.__initialized:
908
- return
386
+ async def disconnect(self) -> None:
387
+ if not self.pluginInfo or self.pluginInfo["id"] != self._plugin["id"]:
388
+ return
909
389
 
910
- raise e
911
-
912
- @overload
913
- def on_state_change(
914
- self, state_name: Literal["light"]
915
- ) -> HybridObservable[CameraStateChangedObject[LightState]]: ...
916
- @overload
917
- def on_state_change(
918
- self, state_name: Literal["motion"]
919
- ) -> HybridObservable[CameraStateChangedObject[MotionState]]: ...
920
- @overload
921
- def on_state_change(
922
- self, state_name: Literal["audio"]
923
- ) -> HybridObservable[CameraStateChangedObject[AudioState]]: ...
924
- @overload
925
- def on_state_change(
926
- self, state_name: Literal["doorbell"]
927
- ) -> HybridObservable[CameraStateChangedObject[DoorbellState]]: ...
928
- @overload
929
- def on_state_change(
930
- self, state_name: Literal["siren"]
931
- ) -> HybridObservable[CameraStateChangedObject[SirenState]]: ...
932
- @overload
933
- def on_state_change(
934
- self, state_name: Literal["battery"]
935
- ) -> HybridObservable[CameraStateChangedObject[BatteryState]]: ...
936
- @overload
937
- def on_state_change(
938
- self, state_name: Literal["object"]
939
- ) -> HybridObservable[CameraStateChangedObject[ObjectState]]: ...
940
- def on_state_change(self, state_name: Any) -> Any:
941
- state: Union[BehaviorSubject[StateValue], None] = getattr(self, f"{state_name}_state", None)
942
-
943
- if not state:
944
- raise Exception(f"{state_name}_state not found")
945
-
946
- def filter_fn(states: tuple[StateValue, StateValue]) -> bool:
947
- old_state = states[0]
948
- new_state = states[1]
949
- return self.__state_changed(old_state, new_state, state_name)
950
-
951
- def map_fn(states: tuple[StateValue, StateValue]) -> CameraStateChangedObject[StateValue]:
952
- return {"old_state": states[0], "new_state": states[1]}
953
-
954
- return HybridObservable(
955
- state.pipe(
956
- ops.pairwise(),
957
- ops.filter(filter_fn),
958
- ops.map(map_fn),
959
- ops.share(),
960
- )
961
- )
390
+ await self._camera_controller_proxy.disconnect()
962
391
 
963
- def on_property_change(
964
- self, property: Union[CameraPublicProperties, list[CameraPublicProperties]]
965
- ) -> HybridObservable[CameraPropertyObservableObject]:
392
+ def onPropertyChange(
393
+ self, property: CameraPublicProperties | list[CameraPublicProperties]
394
+ ) -> Observable[CameraPropertyObservableObject]:
966
395
  def map_fn(
967
396
  cameras: tuple[Camera, Camera],
968
397
  ) -> list[Any]:
@@ -989,758 +418,399 @@ class CameraDeviceProxy(CameraDevice, Subscribed):
989
418
  != {}
990
419
  )
991
420
 
992
- return HybridObservable(
993
- self.__camera_subject.pipe(
994
- ops.pairwise(),
995
- ops.flat_map(map_fn),
996
- ops.filter(filter_fn),
997
- ops.share(),
998
- )
421
+ return self._camera_subject.pipe(
422
+ pairwise(),
423
+ merge_map(lambda cameras, _idx: map_fn(cameras)),
424
+ filter_op(filter_fn),
425
+ share(),
999
426
  )
1000
427
 
1001
- def on_capabilities_change(self) -> HybridObservable[CameraCapabilitiesObservableObject]:
1002
- def filter_fn(
1003
- capabilities: tuple[list[PluginCapabilities], list[PluginCapabilities]],
1004
- ) -> bool:
1005
- return (
1006
- DeepDiff(
1007
- capabilities[0],
1008
- capabilities[1],
1009
- ignore_order=True,
1010
- use_enum_value=True,
1011
- )
1012
- != {}
1013
- )
428
+ def createStorage(self, schemas: list[Any]) -> Any:
429
+ return self._storage_controller.createCameraStorage(self.id, schemas)
1014
430
 
1015
- def map_fn(
1016
- capabilities: tuple[list[PluginCapabilities], list[PluginCapabilities]],
1017
- ) -> CameraCapabilitiesObservableObject:
1018
- old_capabilities: list[CameraDeviceCapability] = []
1019
- new_capabilities: list[CameraDeviceCapability] = []
1020
-
1021
- for capability in capabilities[0]:
1022
- if capability["capabilities"]:
1023
- old_capabilities.extend(capability["capabilities"])
1024
-
1025
- for capability in capabilities[1]:
1026
- if capability["capabilities"]:
1027
- new_capabilities.extend(capability["capabilities"])
1028
-
1029
- return {
1030
- "old_capabilities": old_capabilities,
1031
- "new_capabilities": new_capabilities,
1032
- }
1033
-
1034
- return HybridObservable(
1035
- self.__capabilities.pipe(
1036
- ops.pairwise(),
1037
- ops.filter(filter_fn),
1038
- ops.map(map_fn),
1039
- ops.share(),
1040
- )
431
+ def getSensors(self) -> list[SensorLike]:
432
+ owned_sensors = [entry[0] for entry in self._owned_sensors.values()]
433
+ proxy_sensors = list(self._sensors.values())
434
+ return [*owned_sensors, *proxy_sensors]
435
+
436
+ def getSensor(self, sensorId: str) -> SensorLike | None:
437
+ # Check if we own this sensor - return the real sensor
438
+ owned = self._owned_sensors.get(sensorId)
439
+ if owned:
440
+ return owned[0]
441
+ # Return proxy for foreign sensors
442
+ return self._sensors.get(sensorId)
443
+
444
+ def getSensorsByType(self, sensorType: SensorType) -> list[SensorLike]:
445
+ return [s for s in self.getSensors() if s.type == sensorType]
446
+
447
+ async def addSensor(self, sensor: Sensor[Any, Any, Any]) -> None:
448
+ plugin_id = self._plugin["id"]
449
+
450
+ sensor._setCameraId(self.id) # pyright: ignore[reportPrivateUsage]
451
+ sensor._setPluginId(plugin_id) # pyright: ignore[reportPrivateUsage]
452
+
453
+ sensor_type = sensor.type
454
+ sensor._init( # pyright: ignore[reportPrivateUsage]
455
+ lambda properties: self._on_sensor_state_write(sensor.id, sensor_type, properties)
1041
456
  )
1042
457
 
1043
- async def snapshot(self, source_id: str, force_new: Optional[bool] = None) -> Optional[bytes]:
1044
- self.__snapshot_cache.expire()
458
+ sensor._initCapabilities(lambda caps: self._on_sensor_capabilities_changed(sensor.id, caps)) # pyright: ignore[reportPrivateUsage]
1045
459
 
1046
- from_cache = self.__snapshot_cache.get(source_id) if source_id in self.__snapshot_cache else None
1047
- if from_cache and not force_new:
1048
- return from_cache
460
+ schemas = sensor.storage_schema
461
+ storage = self._storage_controller.createSensorStorage(
462
+ self.id,
463
+ sensor.type,
464
+ plugin_id,
465
+ sensor.name,
466
+ sensor.id,
467
+ schemas,
468
+ )
469
+ await storage.register_storage()
1049
470
 
1050
- camera_controller_proxy = await self.__camera_controller_proxy()
471
+ saved_display_name = storage.values.get("_displayName")
472
+ sensor.displayName = saved_display_name if saved_display_name else sensor.name
1051
473
 
1052
- snapshot = await camera_controller_proxy.snapshot(source_id, force_new)
1053
- if snapshot and len(snapshot) > 0:
1054
- self.__snapshot_cache[source_id] = snapshot
1055
- return snapshot
474
+ sensor._setStorage(storage) # pyright: ignore[reportPrivateUsage]
1056
475
 
1057
- return None
476
+ sensor_namespace = NamespaceManager.sensor_provider_namespaces(
477
+ plugin_id, self.id, sensor.id
478
+ ).sensor_rpc
1058
479
 
1059
- async def probe_stream(
1060
- self, source_id: str, probe_config: Optional[ProbeConfig] = None, refresh: Optional[bool] = False
1061
- ) -> Optional[ProbeStream]:
1062
- camera_controller_proxy = await self.__camera_controller_proxy()
1063
- return await camera_controller_proxy.probeStream(source_id, probe_config, refresh)
480
+ requires_frames = getattr(sensor, "_requires_frames", False)
481
+ model_spec = getattr(sensor, "modelSpec", None)
1064
482
 
1065
- async def cleanup(self) -> None:
1066
- self.__initialized = False
1067
- self.__remove_all_listeners()
1068
- self.unsubscribe()
1069
- self.__api.remove_listener(API_EVENT.SHUTDOWN.value, self.cleanup)
1070
- if self.__subscription:
1071
- await self.__subscription.unsubscribe()
1072
- self.__subscription = None
1073
- await self.__disconnect_rpc()
1074
-
1075
- @overload
1076
- def __check_state_internal(
1077
- self,
1078
- state_name: Literal["light"],
1079
- event_data: LightSetEvent,
1080
- skip_detections_check: Optional[bool] = None,
1081
- ) -> tuple[bool, LightState]: ...
1082
- @overload
1083
- def __check_state_internal(
1084
- self,
1085
- state_name: Literal["motion"],
1086
- event_data: MotionSetEvent,
1087
- skip_detections_check: Optional[bool] = None,
1088
- ) -> tuple[bool, MotionState]: ...
1089
- @overload
1090
- def __check_state_internal(
1091
- self,
1092
- state_name: Literal["audio"],
1093
- event_data: AudioSetEvent,
1094
- skip_detections_check: Optional[bool] = None,
1095
- ) -> tuple[bool, AudioState]: ...
1096
- @overload
1097
- def __check_state_internal(
1098
- self,
1099
- state_name: Literal["object"],
1100
- event_data: ObjectSetEvent,
1101
- skip_detections_check: Optional[bool] = None,
1102
- ) -> tuple[bool, ObjectState]: ...
1103
- @overload
1104
- def __check_state_internal(
1105
- self,
1106
- state_name: Literal["doorbell"],
1107
- event_data: DoorbellSetEvent,
1108
- skip_detections_check: Optional[bool] = None,
1109
- ) -> tuple[bool, DoorbellState]: ...
1110
- @overload
1111
- def __check_state_internal(
1112
- self,
1113
- state_name: Literal["siren"],
1114
- event_data: SirenSetEvent,
1115
- skip_detections_check: Optional[bool] = None,
1116
- ) -> tuple[bool, SirenState]: ...
1117
- @overload
1118
- def __check_state_internal(
1119
- self,
1120
- state_name: Literal["battery"],
1121
- event_data: BatterySetEvent,
1122
- skip_detections_check: Optional[bool] = None,
1123
- ) -> tuple[bool, BatteryState]: ...
1124
- def __check_state_internal(
1125
- self,
1126
- state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
1127
- event_data: Union[
1128
- LightSetEvent,
1129
- MotionSetEvent,
1130
- AudioSetEvent,
1131
- ObjectSetEvent,
1132
- DoorbellSetEvent,
1133
- SirenSetEvent,
1134
- BatterySetEvent,
1135
- ],
1136
- skip_detections_check: Optional[bool] = None,
1137
- ) -> tuple[
1138
- bool,
1139
- Union[
1140
- LightState,
1141
- MotionState,
1142
- AudioState,
1143
- ObjectState,
1144
- DoorbellState,
1145
- SirenState,
1146
- BatteryState,
1147
- ],
1148
- ]:
1149
- changed = False
1150
- target_state: Optional[StateValue] = None
1151
-
1152
- if state_name == "audio":
1153
- audio_event = cast(AudioSetEvent, event_data)
1154
- target_state = self.__get_audio_state(audio_event)
1155
- changed = self.__state_changed(self.get_value("audio"), target_state, "audio")
1156
-
1157
- elif state_name == "light":
1158
- light_event = cast(LightSetEvent, event_data)
1159
- target_state = self.__get_light_state(light_event)
1160
- changed = self.__state_changed(self.get_value("light"), target_state, "light")
1161
-
1162
- elif state_name == "motion":
1163
- motion_event = cast(MotionSetEvent, event_data)
1164
-
1165
- if not motion_event["state"]:
1166
- motion_event["detections"] = []
1167
-
1168
- if not skip_detections_check and "detections" in motion_event and motion_event["detections"]:
1169
- has_detections = len(motion_event["detections"]) > 0
1170
- motion_event["detections"] = transform_labels(motion_event["detections"])
1171
- motion_event["detections"] = merge_detections(motion_event["detections"])
1172
- motion_event["detections"] = are_detections_valid(
1173
- motion_event["detections"], self.detection_zones, self.detection_settings
1174
- )
1175
- if has_detections and len(motion_event["detections"]) == 0:
1176
- motion_event["state"] = False
1177
-
1178
- # fix bounding box type to to tuple, do we need?
1179
- if "detections" in motion_event and motion_event["detections"]:
1180
- for det in motion_event["detections"]:
1181
- det["boundingBox"] = cast(tuple[int, int, int, int], tuple(det["boundingBox"]))
1182
- det["confidence"] = float(det["confidence"])
1183
-
1184
- target_state = self.__get_motion_state(motion_event)
1185
- changed = self.__state_changed(self.get_value("motion"), target_state, "motion", True)
1186
-
1187
- elif state_name == "object":
1188
- object_event = cast(ObjectSetEvent, event_data)
1189
-
1190
- if not skip_detections_check:
1191
- object_event["detections"] = transform_labels(object_event["detections"])
1192
- object_event["detections"] = merge_detections(object_event["detections"])
1193
- object_event["detections"] = are_detections_valid(
1194
- object_event["detections"], self.detection_zones, self.detection_settings
1195
- )
483
+ cleanup = await self._proxy.register_handler(sensor_namespace, sensor, without_decorators=True)
484
+ self._sensor_cleanup_functions[sensor.id] = cleanup
1196
485
 
1197
- # fix bounding box type to to tuple
1198
- for det in object_event["detections"]:
1199
- det["boundingBox"] = cast(BoundingBox, tuple(det["boundingBox"]))
1200
- det["confidence"] = float(det["confidence"])
486
+ sensor_json = sensor.toJSON()
487
+ sensor_json["requiresFrames"] = requires_frames
488
+ if model_spec:
489
+ sensor_json["modelSpec"] = model_spec
1201
490
 
1202
- target_state = self.__get_object_state(object_event)
1203
- changed = self.__state_changed(self.get_value("object"), target_state, "object")
491
+ is_assigned = await self._camera_controller_proxy.registerSensor(sensor_json, plugin_id)
492
+ sensor._setAssigned(is_assigned) # pyright: ignore[reportPrivateUsage]
493
+ self._owned_sensors[sensor.id] = (sensor, sensor.type)
1204
494
 
1205
- elif state_name == "doorbell":
1206
- doorbell_event = cast(DoorbellSetEvent, event_data)
1207
- target_state = self.__get_doorbell_state(doorbell_event)
1208
- changed = self.__state_changed(self.get_value("doorbell"), target_state, "doorbell")
495
+ sensor_event_ns = NamespaceManager.sensor_event_namespaces(self.id, sensor.id)
1209
496
 
1210
- elif state_name == "siren":
1211
- siren_event = cast(SirenSetEvent, event_data)
1212
- target_state = self.__get_siren_state(siren_event)
1213
- changed = self.__state_changed(self.get_value("siren"), target_state, "siren")
497
+ async def handle_backend_event(event: dict[str, Any]) -> None:
498
+ if event.get("type") == "property:changed":
499
+ change_data = event.get("data", {})
500
+ prop = change_data.get("property")
501
+ value = change_data.get("value")
502
+ timestamp = change_data.get("timestamp")
503
+ if prop is not None:
504
+ sensor._onBackendPropertyChanged(prop, value, timestamp) # pyright: ignore[reportPrivateUsage]
1214
505
 
1215
- elif state_name == "battery":
1216
- battery_event = cast(BatterySetEvent, event_data)
1217
- target_state = self.__get_battery_state(battery_event)
1218
- changed = self.__state_changed(self.get_value("battery"), target_state, "battery")
506
+ unsubscribe_backend = await self._proxy.subscribe(
507
+ sensor_event_ns.sensor_subject, handle_backend_event
508
+ )
509
+
510
+ existing_cleanup = self._sensor_cleanup_functions.get(sensor.id)
511
+ if existing_cleanup:
512
+
513
+ async def combined_cleanup() -> None:
514
+ await unsubscribe_backend()
515
+ await existing_cleanup()
1219
516
 
517
+ self._sensor_cleanup_functions[sensor.id] = combined_cleanup
1220
518
  else:
1221
- raise Exception(f"Unknown state: {state_name}")
1222
-
1223
- return changed, target_state
1224
-
1225
- def __can_update_state_internal(self, state_name: StateNames) -> bool:
1226
- if state_name == "audio":
1227
- audio_sensor_capability = next(
1228
- (
1229
- cap
1230
- for cap in self.__capabilities.value
1231
- if CameraDeviceCapability.AudioSensor in cap["capabilities"]
1232
- ),
1233
- None,
1234
- )
1235
- return bool(
1236
- audio_sensor_capability and audio_sensor_capability["pluginId"] == self.__plugin["id"]
1237
- )
519
+ self._sensor_cleanup_functions[sensor.id] = unsubscribe_backend
1238
520
 
1239
- elif state_name == "motion":
1240
- motion_sensor_capability = next(
1241
- (
1242
- cap
1243
- for cap in self.__capabilities.value
1244
- if CameraDeviceCapability.MotionSensor in cap["capabilities"]
1245
- ),
1246
- None,
1247
- )
1248
- motion_detector_capability = next(
1249
- (
1250
- cap
1251
- for cap in self.__capabilities.value
1252
- if CameraDeviceCapability.MotionDetector in cap["capabilities"]
1253
- ),
1254
- None,
1255
- )
1256
- return bool(
1257
- (motion_sensor_capability and motion_sensor_capability["pluginId"] == self.__plugin["id"])
1258
- or (
1259
- motion_detector_capability
1260
- and motion_detector_capability["pluginId"] == self.__plugin["id"]
1261
- )
1262
- )
521
+ async def removeSensor(self, sensorId: str) -> None:
522
+ await self._camera_controller_proxy.unregisterSensor(sensorId)
1263
523
 
1264
- elif state_name == "object":
1265
- object_sensor_capability = next(
1266
- (
1267
- cap
1268
- for cap in self.__capabilities.value
1269
- if CameraDeviceCapability.ObjectSensor in cap["capabilities"]
1270
- ),
1271
- None,
1272
- )
1273
- object_detector_capability = next(
1274
- (
1275
- cap
1276
- for cap in self.__capabilities.value
1277
- if CameraDeviceCapability.ObjectDetector in cap["capabilities"]
1278
- ),
1279
- None,
1280
- )
1281
- return bool(
1282
- (object_sensor_capability and object_sensor_capability["pluginId"] == self.__plugin["id"])
1283
- or (
1284
- object_detector_capability
1285
- and object_detector_capability["pluginId"] == self.__plugin["id"]
1286
- )
1287
- )
524
+ cleanup = self._sensor_cleanup_functions.pop(sensorId, None)
525
+ if cleanup:
526
+ await cleanup()
1288
527
 
1289
- elif state_name == "light":
1290
- light_capability = next(
1291
- (
1292
- cap
1293
- for cap in self.__capabilities.value
1294
- if CameraDeviceCapability.Light in cap["capabilities"]
1295
- ),
1296
- None,
1297
- )
1298
- return bool(light_capability and light_capability["pluginId"] == self.__plugin["id"])
1299
-
1300
- elif state_name == "doorbell":
1301
- doorbell_capability = next(
1302
- (
1303
- cap
1304
- for cap in self.__capabilities.value
1305
- if CameraDeviceCapability.Doorbell in cap["capabilities"]
1306
- ),
1307
- None,
1308
- )
1309
- return bool(doorbell_capability and doorbell_capability["pluginId"] == self.__plugin["id"])
1310
-
1311
- elif state_name == "siren":
1312
- siren_capability = next(
1313
- (
1314
- cap
1315
- for cap in self.__capabilities.value
1316
- if CameraDeviceCapability.Siren in cap["capabilities"]
1317
- ),
1318
- None,
1319
- )
1320
- return bool(siren_capability and siren_capability["pluginId"] == self.__plugin["id"])
1321
-
1322
- elif state_name == "battery":
1323
- battery_capability = next(
1324
- (
1325
- cap
1326
- for cap in self.__capabilities.value
1327
- if CameraDeviceCapability.Battery in cap["capabilities"]
1328
- ),
1329
- None,
1330
- )
1331
- return bool(battery_capability and battery_capability["pluginId"] == self.__plugin["id"])
528
+ owned = self._owned_sensors.pop(sensorId, None)
529
+ if owned:
530
+ owned[0]._cleanup() # pyright: ignore[reportPrivateUsage]
1332
531
 
1333
- @overload
1334
- def __update_state_internal(
1335
- self,
1336
- state_name: Literal["light"],
1337
- event_data: LightSetEvent,
1338
- skip_check: Optional[bool] = None,
1339
- skip_detections_check: Optional[bool] = None,
1340
- ) -> None: ...
1341
- @overload
1342
- def __update_state_internal(
1343
- self,
1344
- state_name: Literal["motion"],
1345
- event_data: MotionSetEvent,
1346
- skip_check: Optional[bool] = None,
1347
- skip_detections_check: Optional[bool] = None,
1348
- ) -> None: ...
1349
- @overload
1350
- def __update_state_internal(
1351
- self,
1352
- state_name: Literal["audio"],
1353
- event_data: AudioSetEvent,
1354
- skip_check: Optional[bool] = None,
1355
- skip_detections_check: Optional[bool] = None,
1356
- ) -> None: ...
1357
- @overload
1358
- def __update_state_internal(
1359
- self,
1360
- state_name: Literal["object"],
1361
- event_data: ObjectSetEvent,
1362
- skip_check: Optional[bool] = None,
1363
- skip_detections_check: Optional[bool] = None,
1364
- ) -> None: ...
1365
- @overload
1366
- def __update_state_internal(
1367
- self,
1368
- state_name: Literal["doorbell"],
1369
- event_data: DoorbellSetEvent,
1370
- skip_check: Optional[bool] = None,
1371
- skip_detections_check: Optional[bool] = None,
1372
- ) -> None: ...
1373
- @overload
1374
- def __update_state_internal(
1375
- self,
1376
- state_name: Literal["siren"],
1377
- event_data: SirenSetEvent,
1378
- skip_check: Optional[bool] = None,
1379
- skip_detections_check: Optional[bool] = None,
1380
- ) -> None: ...
1381
- @overload
1382
- def __update_state_internal(
1383
- self,
1384
- state_name: Literal["battery"],
1385
- event_data: BatterySetEvent,
1386
- skip_check: Optional[bool] = None,
1387
- skip_detections_check: Optional[bool] = None,
1388
- ) -> None: ...
1389
- def __update_state_internal(
1390
- self,
1391
- state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
1392
- event_data: Union[
1393
- LightSetEvent,
1394
- MotionSetEvent,
1395
- AudioSetEvent,
1396
- ObjectSetEvent,
1397
- DoorbellSetEvent,
1398
- SirenSetEvent,
1399
- BatterySetEvent,
1400
- ],
1401
- skip_check: Optional[bool] = None,
1402
- skip_detections_check: Optional[bool] = None,
1403
- ) -> None:
1404
- if skip_check:
1405
- changed = True
1406
- event = event_data
1407
- else:
1408
- changed, event = cast(
1409
- tuple[
1410
- bool,
1411
- Union[
1412
- LightSetEvent,
1413
- MotionSetEvent,
1414
- AudioSetEvent,
1415
- ObjectSetEvent,
1416
- DoorbellSetEvent,
1417
- SirenSetEvent,
1418
- BatterySetEvent,
1419
- ],
1420
- ],
1421
- self.__check_state_internal(
1422
- cast(Any, state_name), cast(Any, event_data), skip_detections_check
1423
- ),
1424
- )
532
+ proxy = self._sensors.get(sensorId)
533
+ if proxy:
534
+ await proxy._unsubscribe_from_events() # pyright: ignore[reportPrivateUsage]
535
+ self._sensors.pop(sensorId, None)
1425
536
 
1426
- if not changed:
1427
- return
537
+ @property
538
+ def onSensorAdded(self) -> Observable[SensorEventData]:
539
+ return self._sensor_added_subject.as_observable()
1428
540
 
1429
- if state_name == "light":
1430
- self.__light_state.on_next(self.__get_light_state(cast(LightSetEvent, event)))
1431
- elif state_name == "motion":
1432
- self.__motion_state.on_next(self.__get_motion_state(cast(MotionSetEvent, event)))
1433
- elif state_name == "audio":
1434
- self.__audio_state.on_next(self.__get_audio_state(cast(AudioSetEvent, event)))
1435
- elif state_name == "object":
1436
- self.__object_state.on_next(self.__get_object_state(cast(ObjectSetEvent, event)))
1437
- elif state_name == "doorbell":
1438
- self.__doorbell_state.on_next(self.__get_doorbell_state(cast(DoorbellSetEvent, event)))
1439
- elif state_name == "siren":
1440
- self.__siren_state.on_next(self.__get_siren_state(cast(SirenSetEvent, event)))
1441
- elif state_name == "battery" and self.has_battery:
1442
- self.__battery_state.on_next(self.__get_battery_state(cast(BatterySetEvent, event)))
1443
-
1444
- def __create_state_observable(self, state_subject: BehaviorSubject[Any]) -> HybridObservable[Any]:
1445
- return HybridObservable(state_subject.pipe(ops.distinct_until_changed(), ops.share()))
1446
-
1447
- def __update_camera(self, camera: Camera) -> None:
1448
- if camera["snapshotTTL"] != self.snapshot_ttl:
1449
- self.__snapshot_cache = TTLCache[str, bytes](maxsize=100, ttl=self.snapshot_ttl)
1450
-
1451
- self.__camera_subject.on_next(camera)
1452
-
1453
- def __update_camera_state(self, state: bool) -> None:
1454
- self.__camera_state.on_next(state)
1455
-
1456
- def __update_frameworker_state(self, state: bool) -> None:
1457
- self.__frame_worker_state.on_next(state)
1458
-
1459
- def __update_capabilities(self, capabilities: list[PluginCapabilities]) -> None:
1460
- converted_capabilities: list[PluginCapabilities] = []
1461
-
1462
- for plugin_cap in capabilities:
1463
- converted_plugin_cap = plugin_cap.copy()
1464
- converted_plugin_cap["capabilities"] = [
1465
- CameraDeviceCapability(cap_str) for cap_str in plugin_cap["capabilities"]
1466
- ]
1467
- converted_capabilities.append(converted_plugin_cap)
1468
-
1469
- self.__capabilities.on_next(converted_capabilities)
1470
-
1471
- async def __refresh_states(self) -> None:
1472
- camera_controller_proxy = await self.__camera_controller_proxy()
1473
- response = await camera_controller_proxy.refreshStates()
1474
-
1475
- self.__update_camera(response["camera"])
1476
- self.__update_camera_state(response["cameraState"])
1477
- self.__update_frameworker_state(response["frameWorkerState"])
1478
- self.__update_capabilities(response["capabilities"])
1479
-
1480
- states = cast(dict[Any, Any], response["states"])
1481
- for key, value in states.items():
1482
- self.__update_state_internal(key, value, True)
1483
-
1484
- def __remove_all_listeners(self) -> None:
1485
- self.__light_state.on_completed()
1486
- self.__motion_state.on_completed()
1487
- self.__audio_state.on_completed()
1488
- self.__object_state.on_completed()
1489
- self.__doorbell_state.on_completed()
1490
- self.__siren_state.on_completed()
1491
- self.__battery_state.on_completed()
1492
- self.__camera_subject.on_completed()
1493
- self.__camera_state.on_completed()
1494
- self.__frame_worker_state.on_completed()
1495
- self.__capabilities.on_completed()
1496
- self.__snapshot_cache.clear()
1497
-
1498
- def __state_changed(
541
+ @property
542
+ def onSensorRemoved(self) -> Observable[SensorEventData]:
543
+ return self._sensor_removed_subject.as_observable()
544
+
545
+ def onSensorProperty(
1499
546
  self,
1500
- old_state: Optional[SetValue],
1501
- new_state: Optional[SetValue],
1502
- type_: Optional[StateNames],
1503
- test: Optional[bool] = False,
1504
- ) -> bool:
1505
- if not old_state or not new_state or not type_:
1506
- return False
1507
-
1508
- if (
1509
- (type_ == "audio" and not self.has_audio_detector)
1510
- or (type_ == "motion" and not self.has_motion_detector)
1511
- or (type_ == "object" and not self.has_object_detector)
1512
- or (type_ == "siren" and not self.has_siren)
1513
- or (type_ == "battery" and not self.has_battery)
1514
- or (type_ == "doorbell" and not self.has_doorbell)
1515
- or (type_ == "light" and not self.has_light)
1516
- ):
1517
- return False
1518
-
1519
- clean_old_state = self.__clean_state(old_state)
1520
- clean_new_state = self.__clean_state(new_state)
1521
-
1522
- return DeepDiff(clean_old_state, clean_new_state, ignore_order=True) != {}
1523
-
1524
- def __get_audio_state(
1525
- self, event: Union[AudioSetEvent, AudioState], ignore_last_event: bool = False
1526
- ) -> AudioState:
1527
- last_event: Optional[AudioState] = None
1528
-
1529
- if ignore_last_event is False:
1530
- last_event = self.get_value("audio")
1531
- if last_event and "lastEvent" in last_event:
1532
- del last_event["lastEvent"]
1533
-
1534
- if "timestamp" in event:
1535
- new_state: Any = event
1536
- else:
1537
- state = cast(AudioState, event).copy()
1538
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
547
+ sensor_type: SensorType,
548
+ property: str,
549
+ callback: Any,
550
+ ) -> Disposable:
551
+ property_sub: Disposable | None = None
552
+
553
+ def subscribe_to(sensor: SensorLike) -> None:
554
+ nonlocal property_sub
555
+ if property_sub is not None:
556
+ property_sub.dispose()
557
+ property_sub = sensor.onPropertyChanged.subscribe(
558
+ lambda e: callback(e["value"], e["timestamp"], sensor) if e["property"] == property else None
559
+ )
1539
560
 
1540
- new_state = {
1541
- **state,
1542
- "db": event.get("db", None) or last_event.get("db", None) if last_event else 0,
1543
- "lastEvent": last_event,
1544
- }
561
+ existing = self.getSensorsByType(sensor_type)
562
+ if existing:
563
+ subscribe_to(existing[0])
1545
564
 
1546
- return new_state
565
+ added_sub = self.onSensorAdded.subscribe(
566
+ lambda e: (
567
+ subscribe_to(self.getSensorsByType(sensor_type)[0])
568
+ if e["sensorType"] == sensor_type and self.getSensorsByType(sensor_type)
569
+ else None
570
+ )
571
+ )
1547
572
 
1548
- def __get_motion_state(
1549
- self, event: Union[MotionSetEvent, MotionState], ignore_last_event: bool = False
1550
- ) -> MotionState:
1551
- last_event: Optional[MotionState] = None
573
+ def on_removed(e: SensorEventData) -> None:
574
+ nonlocal property_sub
575
+ if e["sensorType"] == sensor_type and property_sub is not None:
576
+ property_sub.dispose()
577
+ property_sub = None
1552
578
 
1553
- if ignore_last_event is False:
1554
- last_event = self.get_value("motion")
1555
- if last_event and "lastEvent" in last_event:
1556
- del last_event["lastEvent"]
579
+ removed_sub = self.onSensorRemoved.subscribe(on_removed)
1557
580
 
1558
- if "timestamp" in event:
1559
- new_state: Any = event
1560
- else:
1561
- state = cast(MotionState, event).copy()
1562
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
581
+ def teardown() -> None:
582
+ nonlocal property_sub
583
+ if property_sub is not None:
584
+ property_sub.dispose()
585
+ added_sub.dispose()
586
+ removed_sub.dispose()
1563
587
 
1564
- new_state = {
1565
- **state,
1566
- "lastEvent": last_event,
1567
- }
588
+ return Disposable(teardown)
1568
589
 
1569
- return new_state
590
+ @property
591
+ def onDetectionEvent(self) -> Observable[DetectionEventPayload]:
592
+ return self._detection_event_subject.as_observable()
593
+
594
+ async def implement(self, impl: CameraImplementation) -> None:
595
+ plugin_id = self._plugin["id"]
596
+ namespace = NamespaceManager.plugin_camera_namespaces(plugin_id, self.id)
597
+ self._impl_cleanup_function = await self._proxy.register_handler(
598
+ namespace.camera_impl_rpc, impl, without_decorators=True
599
+ )
1570
600
 
1571
- def __get_object_state(
1572
- self, event: Union[ObjectSetEvent, ObjectState], ignore_last_event: bool = False
1573
- ) -> ObjectState:
1574
- last_event: Optional[ObjectState] = None
601
+ async def streamUrl(self, source_id: str) -> str | None:
602
+ return await self._camera_controller_proxy.streamUrl(source_id)
1575
603
 
1576
- if ignore_last_event is False:
1577
- last_event = self.get_value("object")
1578
- if last_event and "lastEvent" in last_event:
1579
- del last_event["lastEvent"]
604
+ async def _snapshot(self, source_id: str, force_new: bool | None = None) -> bytes | None:
605
+ return await self._camera_controller_proxy.snapshot(source_id, force_new)
1580
606
 
1581
- if "timestamp" in event:
1582
- new_state: Any = event
1583
- else:
1584
- state = cast(ObjectState, event).copy()
1585
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
607
+ async def _probe_stream(
608
+ self, source_id: str, probe_config: ProbeConfig | None = None, refresh: bool | None = False
609
+ ) -> ProbeStream | None:
610
+ return await self._camera_controller_proxy.probeStream(source_id, probe_config, refresh)
1586
611
 
1587
- new_state = {
1588
- **state,
1589
- "lastEvent": last_event,
1590
- }
612
+ async def _get_stream_status(self, source_id: str) -> str:
613
+ try:
614
+ return await self._camera_controller_proxy.getStreamStatus(source_id)
615
+ except Exception:
616
+ return "idle"
1591
617
 
1592
- return new_state
618
+ async def cleanup(self) -> None:
619
+ self._initialized.next(False)
1593
620
 
1594
- def __get_doorbell_state(
1595
- self, event: Union[DoorbellSetEvent, DoorbellState], ignore_last_event: bool = False
1596
- ) -> DoorbellState:
1597
- last_event: Optional[DoorbellState] = None
621
+ self.unsubscribe()
1598
622
 
1599
- if ignore_last_event is False:
1600
- last_event = self.get_value("doorbell")
1601
- if last_event and "lastEvent" in last_event:
1602
- del last_event["lastEvent"]
623
+ self._api.removeListener(API_EVENT.SHUTDOWN.value, self.cleanup)
1603
624
 
1604
- if "timestamp" in event:
1605
- new_state: Any = event
1606
- else:
1607
- state = cast(DoorbellState, event).copy()
1608
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
625
+ self._tasks.remove_all()
1609
626
 
1610
- new_state = {
1611
- **state,
1612
- "lastEvent": last_event,
1613
- }
627
+ if self._close_subscription:
628
+ await self._close_subscription()
629
+ self._close_subscription = None
1614
630
 
1615
- return new_state
631
+ if self._close_sensor_subscription:
632
+ await self._close_sensor_subscription()
633
+ self._close_sensor_subscription = None
1616
634
 
1617
- def __get_light_state(
1618
- self, event: Union[LightSetEvent, LightState], ignore_last_event: bool = False
1619
- ) -> LightState:
1620
- last_event: Optional[LightState] = None
635
+ if self._close_detection_subscription:
636
+ await self._close_detection_subscription()
637
+ self._close_detection_subscription = None
1621
638
 
1622
- if ignore_last_event is False:
1623
- last_event = self.get_value("light")
1624
- if last_event and "lastEvent" in last_event:
1625
- del last_event["lastEvent"]
639
+ if self._impl_cleanup_function:
640
+ with contextlib.suppress(Exception):
641
+ await self._impl_cleanup_function()
642
+ self._impl_cleanup_function = None
1626
643
 
1627
- if "timestamp" in event:
1628
- new_state: Any = event
1629
- else:
1630
- state = cast(LightState, event).copy()
1631
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
644
+ for cleanup in list(self._sensor_cleanup_functions.values()):
645
+ with contextlib.suppress(Exception):
646
+ await cleanup()
647
+ self._sensor_cleanup_functions.clear()
1632
648
 
1633
- new_state = {
1634
- **state,
1635
- "lastEvent": last_event,
1636
- }
649
+ for sensor_proxy in list(self._sensors.values()):
650
+ await sensor_proxy._unsubscribe_from_events() # pyright: ignore[reportPrivateUsage]
1637
651
 
1638
- return new_state
652
+ for owned_sensor, _ in list(self._owned_sensors.values()):
653
+ owned_sensor._cleanup() # pyright: ignore[reportPrivateUsage]
1639
654
 
1640
- def __get_siren_state(
1641
- self, event: Union[SirenSetEvent, SirenState], ignore_last_event: bool = False
1642
- ) -> SirenState:
1643
- last_event: Optional[SirenState] = None
655
+ self._sensors.clear()
656
+ self._owned_sensors.clear()
1644
657
 
1645
- if ignore_last_event is False:
1646
- last_event = self.get_value("siren")
1647
- if last_event and "lastEvent" in last_event:
1648
- del last_event["lastEvent"]
658
+ self._camera_subject.complete()
659
+ self._camera_state.complete()
660
+ self._frame_worker_state.complete()
661
+ self._initialized.complete()
662
+ self._sensor_added_subject.complete()
663
+ self._sensor_removed_subject.complete()
664
+ self._detection_event_subject.complete()
1649
665
 
1650
- if "timestamp" in event:
1651
- new_state: Any = event
1652
- else:
1653
- state = cast(SirenState, event).copy()
1654
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
666
+ async def _refresh_states(self) -> None:
667
+ response = await self._camera_controller_proxy.refreshStates()
1655
668
 
1656
- new_state = {
1657
- **state,
1658
- "level": event.get("level", None) or last_event.get("level", None) if last_event else 0,
1659
- "lastEvent": last_event,
1660
- }
669
+ self._camera_subject.next(response["camera"])
670
+ self._camera_state.next(response["cameraState"])
671
+ self._frame_worker_state.next(response["frameWorkerState"])
1661
672
 
1662
- return new_state
673
+ async def _initialize_sensors(self) -> None:
674
+ try:
675
+ sensors = await self._sensor_controller_proxy.getSensors(self._plugin["id"])
676
+ newly_added: list[SensorProxy] = []
677
+
678
+ for sensor_data in sensors:
679
+ if sensor_data["id"] in self._sensors:
680
+ continue
681
+
682
+ if sensor_data["id"] in self._owned_sensors:
683
+ continue
684
+
685
+ plugin_id = sensor_data.get("pluginId", self._plugin["id"])
686
+ owner_ns = NamespaceManager.sensor_provider_namespaces(
687
+ plugin_id, self.id, sensor_data["id"]
688
+ ).sensor_rpc
689
+ proxy = SensorProxy(sensor_data, self._proxy, owner_ns, self.id)
690
+ self._sensors[sensor_data["id"]] = proxy
691
+ newly_added.append(proxy)
692
+
693
+ current_ids = {s["id"] for s in sensors}
694
+ for sensor_id in list(self._sensors.keys()):
695
+ if sensor_id not in current_ids:
696
+ sensor = self._sensors.get(sensor_id)
697
+ if sensor:
698
+ await sensor._unsubscribe_from_events() # pyright: ignore[reportPrivateUsage]
699
+ self._sensors.pop(sensor_id, None)
700
+
701
+ if newly_added:
702
+ await self._get_sensor_states(newly_added)
703
+ # Subscribe each sensor to its own per-sensor namespace
704
+ for sensor in newly_added:
705
+ await sensor._subscribe_to_events() # pyright: ignore[reportPrivateUsage]
706
+
707
+ except Exception:
708
+ # SensorController not available yet
709
+ pass
710
+
711
+ async def _get_sensor_states(self, sensors: list[SensorProxy]) -> None:
712
+ try:
713
+ states = await self._sensor_controller_proxy.getSensorStates()
714
+ for sensor in sensors:
715
+ state = states.get(sensor.id)
716
+ if state:
717
+ sensor._apply_refreshed_state(state) # pyright: ignore[reportPrivateUsage]
718
+ except Exception:
719
+ pass
720
+
721
+ async def _on_event_message(self, event: CameraEventMessage) -> None:
722
+ if not self._initialized.value:
723
+ return
1663
724
 
1664
- def __get_battery_state(
1665
- self, event: Union[BatterySetEvent, BatteryState], ignore_last_event: bool = False
1666
- ) -> BatteryState:
1667
- last_event: Optional[BatteryState] = None
725
+ event_type = event.get("type")
726
+ data = event.get("data")
1668
727
 
1669
- if ignore_last_event is False:
1670
- last_event = self.get_value("battery")
1671
- if last_event and "lastEvent" in last_event:
1672
- del last_event["lastEvent"]
728
+ if event_type == "removed":
729
+ await self.cleanup()
730
+ elif event_type == "updated" and data is not None:
731
+ self._camera_subject.next(cast(Camera, data))
732
+ elif event_type == "cameraState" and data is not None:
733
+ self._camera_state.next(cast(bool, data))
734
+ elif event_type == "frameWorkerState" and data is not None:
735
+ self._frame_worker_state.next(cast(bool, data))
1673
736
 
1674
- if "timestamp" in event:
1675
- new_state: Any = event
1676
- else:
1677
- state = cast(BatteryState, event).copy()
1678
- state["timestamp"] = int(datetime.now().timestamp() * 1000)
737
+ async def _on_global_sensor_event(self, event: SensorEventMessage) -> None:
738
+ if not self._initialized.value:
739
+ return
1679
740
 
1680
- new_state = {
1681
- "level": event["level"],
1682
- "charging": event.get("charging", None) or last_event.get("charging", None)
1683
- if last_event
1684
- else False,
1685
- "lowBattery": event.get("lowBattery", None) or last_event.get("lowBattery", None)
1686
- if last_event
1687
- else False,
1688
- "timestamp": int(datetime.now().timestamp() * 1000),
1689
- "lastEvent": last_event,
1690
- }
741
+ event_type = event.get("type")
742
+
743
+ if event_type == "sensor:added":
744
+ added_data = cast(SensorAddedEvent, event.get("data"))
745
+ sensor_data = added_data["sensor"]
746
+ # Only add if not already in cache and not our own sensor
747
+ if sensor_data["id"] not in self._sensors and sensor_data["id"] not in self._owned_sensors:
748
+ # Check if plugin can access this sensor based on contract.consumes
749
+ if not self._can_access_sensor(sensor_data):
750
+ return # Skip - sensor type not in contract.consumes
751
+ plugin_id = sensor_data.get("pluginId", self._plugin["id"])
752
+ owner_ns = NamespaceManager.sensor_provider_namespaces(
753
+ plugin_id, self.id, sensor_data["id"]
754
+ ).sensor_rpc
755
+ proxy = SensorProxy(sensor_data, self._proxy, owner_ns, self.id)
756
+ await proxy._subscribe_to_events() # pyright: ignore[reportPrivateUsage]
757
+ self._sensors[sensor_data["id"]] = proxy
758
+
759
+ self._sensor_added_subject.next(
760
+ {"sensorId": sensor_data["id"], "sensorType": sensor_data["type"]}
761
+ )
1691
762
 
1692
- return new_state
763
+ elif event_type == "sensor:removed":
764
+ removed_data = cast(SensorRemovedEvent, event.get("data"))
765
+ sensor = self._sensors.get(removed_data["sensorId"])
766
+ if sensor:
767
+ await sensor._unsubscribe_from_events() # pyright: ignore[reportPrivateUsage]
768
+ self._sensors.pop(removed_data["sensorId"], None)
1693
769
 
1694
- def __clean_state(self, state: Union[StateValue, SetValue]) -> SetValue:
1695
- state_copy: Any = deepcopy(state)
770
+ self._sensor_removed_subject.next(
771
+ {"sensorId": removed_data["sensorId"], "sensorType": removed_data["sensorType"]}
772
+ )
1696
773
 
1697
- if "timestamp" in state_copy:
1698
- del state_copy["timestamp"]
774
+ elif event_type == "sensor:assignment:changed":
775
+ assign_data = cast(SensorAssignmentChangedEvent, event.get("data"))
776
+ sensor_type = assign_data["sensorType"]
777
+ is_assigned = assign_data["assigned"]
1699
778
 
1700
- if "lastEvent" in state_copy:
1701
- del state_copy["lastEvent"]
779
+ if assign_data["pluginId"] == self._plugin["id"]:
780
+ for _, (owned_sensor, s_type) in self._owned_sensors.items():
781
+ if s_type == sensor_type:
782
+ owned_sensor._setAssigned(is_assigned) # pyright: ignore[reportPrivateUsage]
1702
783
 
1703
- return state_copy
784
+ def _on_sensor_state_write(
785
+ self, sensor_id: str, sensor_type: SensorType, properties: dict[str, Any]
786
+ ) -> None:
787
+ if sensor_type in DETECTION_SENSOR_TYPES:
788
+ if not (self._frame_worker_state.value or False):
789
+ return
1704
790
 
1705
- def __on_name_change(self, val: Any) -> None:
1706
- cast(Logger, self.logger).suffix = self.name
791
+ async def notify_coordinator() -> None:
792
+ try:
793
+ await self._detection_coordinator_proxy.reportSensorWrite(
794
+ sensor_id, sensor_type, properties
795
+ )
796
+ except Exception as e:
797
+ self._logger.warn(f"Failed to forward sensor write to coordinator for {sensor_id}: {e}")
1707
798
 
1708
- async def __on_event_message(self, event: Message[Any]) -> None:
1709
- if not self.__initialized:
799
+ self._tasks.add(notify_coordinator())
1710
800
  return
1711
801
 
1712
- message = event["data"]
1713
-
1714
- if "type" in message:
1715
- type = message["type"]
1716
- if type == "removed":
1717
- await self.cleanup()
1718
- elif type == "updated":
1719
- self.__update_camera(message["data"])
1720
- elif type == "cameraState":
1721
- self.__update_camera_state(message["data"])
1722
- elif type == "frameWorkerState":
1723
- self.__update_frameworker_state(message["data"])
1724
- elif type == "capabilities":
1725
- self.__update_capabilities(message["data"])
1726
- else:
1727
- state_name = message["stateName"]
1728
- new_data = message["data"]["newEvent"]
802
+ async def notify_controller() -> None:
803
+ with contextlib.suppress(Exception):
804
+ await self._sensor_controller_proxy.updatePropertyValues(sensor_id, properties)
1729
805
 
1730
- self.__update_state_internal(state_name, new_data, True)
806
+ self._tasks.add(notify_controller())
1731
807
 
1732
- async def __frame_worker_proxy(self) -> FrameWorkerInterface:
1733
- return await self.__proxy.create_rpc_proxy(
1734
- FrameWorkerInterface, self.__namespaces["frameWorkerChildRpc"]
1735
- )
808
+ def _on_sensor_capabilities_changed(self, sensor_id: str, capabilities: list[str]) -> None:
809
+ async def notify() -> None:
810
+ with contextlib.suppress(Exception):
811
+ await self._sensor_controller_proxy.updateCapabilities(sensor_id, capabilities)
1736
812
 
1737
- async def __camera_controller_proxy(self) -> CameraDeviceInterface:
1738
- return await self.__proxy.create_rpc_proxy(
1739
- CameraDeviceInterface, self.__namespaces["cameraControllerRpc"]
1740
- )
813
+ self._tasks.add(notify())
1741
814
 
1742
- async def __disconnect_rpc(self) -> None:
1743
- await self.__proxy.unregister_rpc_handler(self.__namespaces["cameraInterfacesRpc"])
1744
- await self.__proxy.disconnect_rpc_connection(self.__namespaces["cameraControllerRpc"])
1745
- await self.__proxy.disconnect_rpc_connection(self.__namespaces["frameWorkerChildRpc"])
1746
- await self.__camera_interfaces.disconnect()
815
+ def _create_state_observable(self, state_subject: BehaviorSubject[Any]) -> Observable[Any]:
816
+ return state_subject.pipe(distinct_until_changed(), share())