@camera.ui/server 0.0.49 → 0.0.50-internal.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 (873) hide show
  1. package/.prettierignore +12 -0
  2. package/.prettierrc.json +12 -0
  3. package/artillery.yaml +29 -0
  4. package/bin/cameraui-server.ts +11 -0
  5. package/dist/interface/assets/@xterm.DYP7pi_n.0.0.50-internal.0.css +32 -0
  6. package/dist/interface/assets/Adminpanel.BKek2EMH.0.0.50-internal.0.css +1 -0
  7. package/dist/interface/assets/Cameras.BDWZJqPN.0.0.50-internal.0.css +1 -0
  8. package/dist/interface/assets/Camview.BFUFMoNX.0.0.50-internal.0.css +1 -0
  9. package/dist/interface/assets/CuiConsole.DCYyxdVg.0.0.50-internal.0.css +1 -0
  10. package/dist/interface/assets/CuiPluginCard.yF8V0SZY.0.0.50-internal.0.css +1 -0
  11. package/dist/interface/assets/CuiTimeline.BkIwlYtw.0.0.50-internal.0.css +1 -0
  12. package/dist/interface/assets/Plugin.DJElsAn5.0.0.50-internal.0.css +1 -0
  13. package/dist/interface/assets/Plugins.0h77qnmN.0.0.50-internal.0.css +1 -0
  14. package/dist/interface/assets/Settings.CkgfRkQr.0.0.50-internal.0.css +1 -0
  15. package/dist/interface/assets/SettingsAccount.DeFul3eQ.0.0.50-internal.0.css +1 -0
  16. package/dist/interface/assets/main.Cip9LkS3.0.0.50-internal.0.css +1 -0
  17. package/dist/interface/assets/worker-base.jEXLGV2h.0.0.50-internal.0.js +1332 -0
  18. package/dist/interface/assets/worker-json.DgwNIOck.0.0.50-internal.0.js +1626 -0
  19. package/dist/interface/assets/worker-yaml.B3uUYINB.0.0.50-internal.0.js +5819 -0
  20. package/dist/interface/fonts/InterVariable.woff2 +0 -0
  21. package/dist/interface/index.html +48 -38
  22. package/dist/interface/js/@intlify.BkGPX90O.0.0.50-internal.0.js +15 -0
  23. package/dist/interface/js/@kurkle.D8fDXNIl.0.0.50-internal.0.js +6 -0
  24. package/dist/interface/js/@primeuix.BFAY2Bk9.0.0.50-internal.0.js +5722 -0
  25. package/dist/interface/js/@primevue.OhxoO3MD.0.0.50-internal.0.js +57 -0
  26. package/dist/interface/js/@tanstack.D1IL6eOv.0.0.50-internal.0.js +1 -0
  27. package/dist/interface/{@vee-validate.DHkwupr6.0.0.49.js → js/@vee-validate.BGPyWWTh.0.0.50-internal.0.js} +2 -2
  28. package/dist/interface/js/@vue.B5vqhCp2.0.0.50-internal.0.js +17 -0
  29. package/dist/interface/js/@vueuse.BsKtqdiG.0.0.50-internal.0.js +1 -0
  30. package/dist/interface/{@xterm.D6R4zI7m.0.0.49.js → js/@xterm.CAa7rpjv.0.0.50-internal.0.js} +8 -8
  31. package/dist/interface/js/Adminpanel.D93Kvbwp.0.0.50-internal.0.js +1 -0
  32. package/dist/interface/js/Camera.DF2l3OMA.0.0.50-internal.0.js +1 -0
  33. package/dist/interface/js/Cameras.YzvZccdv.0.0.50-internal.0.js +482 -0
  34. package/dist/interface/js/Cammesh.D-6dAROQ.0.0.50-internal.0.js +1 -0
  35. package/dist/interface/js/Camview.CB7_HnoQ.0.0.50-internal.0.js +1 -0
  36. package/dist/interface/js/Config.BwflsWTm.0.0.50-internal.0.js +2 -0
  37. package/dist/interface/js/Console.DZM8pN8Q.0.0.50-internal.0.js +4 -0
  38. package/dist/interface/js/CuiConsole.BXXU7Gth.0.0.50-internal.0.js +1 -0
  39. package/dist/interface/js/CuiPluginCard.YFOrpbVD.0.0.50-internal.0.js +4 -0
  40. package/dist/interface/js/CuiTimeline.VV5KSJd5.0.0.50-internal.0.js +1 -0
  41. package/dist/interface/js/FirstSteps.b-nvymgb.0.0.50-internal.0.js +1 -0
  42. package/dist/interface/js/Plugin.BOMpVEwM.0.0.50-internal.0.js +1 -0
  43. package/dist/interface/js/Plugins.DdPwaUDA.0.0.50-internal.0.js +1 -0
  44. package/dist/interface/js/Recordings.DhxjIW7e.0.0.50-internal.0.js +1 -0
  45. package/dist/interface/js/Settings.D24ttaPu.0.0.50-internal.0.js +1 -0
  46. package/dist/interface/js/SettingsAccount.ms3aqz4E.0.0.50-internal.0.js +1 -0
  47. package/dist/interface/js/SettingsAppearance.DsTjKXk1.0.0.50-internal.0.js +1 -0
  48. package/dist/interface/js/SettingsAppearance.vue_vue_type_script_setup_true_lang.CBQ6lL3T.0.0.50-internal.0.js +1 -0
  49. package/dist/interface/js/SettingsBackup.BPEc4Rjg.0.0.50-internal.0.js +1 -0
  50. package/dist/interface/js/SettingsRecordings.DgW7M0jj.0.0.50-internal.0.js +1 -0
  51. package/dist/interface/js/SettingsRemote.BL5nXbUT.0.0.50-internal.0.js +1 -0
  52. package/dist/interface/js/SettingsSystem.D7T0AIpm.0.0.50-internal.0.js +1 -0
  53. package/dist/interface/js/SettingsUsers.1u0vCOVG.0.0.50-internal.0.js +1 -0
  54. package/dist/interface/js/VersionsHandler.vue_vue_type_script_setup_true_lang.xDishkkS.0.0.50-internal.0.js +4 -0
  55. package/dist/interface/js/ace-builds.D1nmvCwb.0.0.50-internal.0.js +1090 -0
  56. package/dist/interface/js/ace.config.G96T2z54.0.0.50-internal.0.js +1 -0
  57. package/dist/interface/js/axios.DHr9lByg.0.0.50-internal.0.js +6 -0
  58. package/dist/interface/js/backup.B_Gzxtp_.0.0.50-internal.0.js +1 -0
  59. package/dist/interface/js/chart.js.CP_nMnnf.0.0.50-internal.0.js +13 -0
  60. package/dist/interface/js/close-circle.DYLuVIOg.0.0.50-internal.0.js +1 -0
  61. package/dist/interface/js/dnd-core.T9OeW7mu.0.0.50-internal.0.js +1 -0
  62. package/dist/interface/{draggabilly.C0hZWkL0.0.0.49.js → js/draggabilly.D3zGcBb3.0.0.50-internal.0.js} +1 -1
  63. package/dist/interface/js/engine.io-client.kITRnq-g.0.0.50-internal.0.js +1 -0
  64. package/dist/interface/js/fast-deep-equal.Bpc9mIsj.0.0.50-internal.0.js +1 -0
  65. package/dist/interface/js/highlight.js.BlSXU-Wb.0.0.50-internal.0.js +3 -0
  66. package/dist/interface/js/linkify-it.C3N1lWsJ.0.0.50-internal.0.js +1 -0
  67. package/dist/interface/js/main.D0YR3Jat.0.0.50-internal.0.js +31 -0
  68. package/dist/interface/{markdown-it.64FJJcTG.0.0.49.js → js/markdown-it.Dj0dt5s2.0.0.50-internal.0.js} +1 -1
  69. package/dist/interface/{nprogress.DkWvUoHh.0.0.49.js → js/nprogress.BwQWDcGj.0.0.50-internal.0.js} +1 -1
  70. package/dist/interface/js/perfect-debounce.l0sNRNKZ.0.0.50-internal.0.js +1 -0
  71. package/dist/interface/js/pinia.DRh7plEC.0.0.50-internal.0.js +5 -0
  72. package/dist/interface/js/primelocale.Bga3dOQu.0.0.50-internal.0.js +1 -0
  73. package/dist/interface/js/primevue.Cl58krXf.0.0.50-internal.0.js +142 -0
  74. package/dist/interface/{qrcode.BixA_YE2.0.0.49.js → js/qrcode.C1sDj6P8.0.0.50-internal.0.js} +1 -1
  75. package/dist/interface/js/react-dnd-touch-backend.BA4WhUJo.0.0.50-internal.0.js +1 -0
  76. package/dist/interface/js/refresh-rounded.D_SmhhUf.0.0.50-internal.0.js +1 -0
  77. package/dist/interface/js/rxjs.C-fTBwEO.0.0.50-internal.0.js +3 -0
  78. package/dist/interface/js/socket.io-client.DKrRxgjP.0.0.50-internal.0.js +1 -0
  79. package/dist/interface/js/socket.io-parser.EXj3YDH2.0.0.50-internal.0.js +1 -0
  80. package/dist/interface/js/system.CY8rGd-Q.0.0.50-internal.0.js +1 -0
  81. package/dist/interface/js/trash-fill.CMnCN3Oy.0.0.50-internal.0.js +1 -0
  82. package/dist/interface/{unidragger.C8ueS-PW.0.0.49.js → js/unidragger.D0w6Tqtt.0.0.50-internal.0.js} +1 -1
  83. package/dist/interface/js/uuid.C6aID195.0.0.50-internal.0.js +1 -0
  84. package/dist/interface/js/vee-validate.BeiObIH8.0.0.50-internal.0.js +5 -0
  85. package/dist/interface/js/vue-chartjs.DtdZdiYw.0.0.50-internal.0.js +1 -0
  86. package/dist/interface/js/vue-i18n.BW2bx_6z.0.0.50-internal.0.js +5 -0
  87. package/dist/interface/js/vue-inline-svg.BJkQGmKz.0.0.50-internal.0.js +1 -0
  88. package/dist/interface/js/vue-router.B2mOXHaC.0.0.50-internal.0.js +5 -0
  89. package/dist/interface/js/vue-zoomable.BKDyCJE7.0.0.50-internal.0.js +1 -0
  90. package/dist/interface/js/vue.l0sNRNKZ.0.0.50-internal.0.js +1 -0
  91. package/dist/interface/js/vue3-dnd.DRK24CBp.0.0.50-internal.0.js +1 -0
  92. package/dist/interface/js/zod.SKKegNRO.0.0.50-internal.0.js +1 -0
  93. package/dist/interface/js/zoom-out.DxvzgVEo.0.0.50-internal.0.js +1 -0
  94. package/dist/interface/manifest.webmanifest +1 -1
  95. package/dist/interface/pwa/favicon-32.ico +0 -0
  96. package/dist/interface/pwa/favicon-48.ico +0 -0
  97. package/dist/interface/sw.js +1 -1
  98. package/dist/server/package.json +57 -45
  99. package/dist/server/requirements.txt +12 -11
  100. package/dist/server/src/__init__.py +0 -0
  101. package/dist/server/src/_camera_ui_tools/__init__.py +0 -0
  102. package/dist/server/src/_camera_ui_tools/camera_ui_common/__init__.py +28 -0
  103. package/dist/server/src/_camera_ui_tools/camera_ui_common/camera_utils/utils.py +52 -0
  104. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/__init__.py +0 -0
  105. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/object_path.py +198 -0
  106. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/reactive.py +42 -0
  107. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/signal_handler.py +92 -0
  108. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/subscribed.py +21 -0
  109. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/task.py +39 -0
  110. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/thread.py +10 -0
  111. package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/utils.py +91 -0
  112. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/__init__.py +0 -0
  113. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/ansicolor.py +62 -0
  114. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/logger.py +178 -0
  115. package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/test.py +116 -0
  116. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/__init__.py +350 -0
  117. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/__init__.py +0 -0
  118. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/base.py +237 -0
  119. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/client.py +256 -0
  120. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/connection.py +784 -0
  121. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/errors.py +745 -0
  122. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/messaging.py +57 -0
  123. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/rpc.py +227 -0
  124. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/rpc_generator.py +584 -0
  125. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/constants.py +96 -0
  126. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/typings.py +218 -0
  127. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/__init__.py +0 -0
  128. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/connection_state.py +86 -0
  129. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/logger.py +30 -0
  130. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/metrics.py +152 -0
  131. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/packer.py +20 -0
  132. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/routing.py +75 -0
  133. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/rpc.py +177 -0
  134. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/subscriptions.py +24 -0
  135. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/tasks.py +39 -0
  136. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/uid.py +37 -0
  137. package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/validate.py +119 -0
  138. package/dist/server/src/_camera_ui_tools/camera_ui_types/__init__.py +1360 -0
  139. package/dist/server/src/_camera_ui_tools/camera_ui_types/hybrid_observer.py +338 -0
  140. package/dist/server/src/_camera_ui_tools/camera_ui_types/test.py +196 -0
  141. package/dist/server/src/api/controllers/auth.controller.d.ts +2 -2
  142. package/dist/server/src/api/controllers/auth.controller.js +49 -43
  143. package/dist/server/src/api/controllers/auth.controller.js.map +1 -1
  144. package/dist/server/src/api/controllers/backup.controller.js +1 -2
  145. package/dist/server/src/api/controllers/backup.controller.js.map +1 -1
  146. package/dist/server/src/api/controllers/cameras.controller.d.ts +13 -11
  147. package/dist/server/src/api/controllers/cameras.controller.js +314 -105
  148. package/dist/server/src/api/controllers/cameras.controller.js.map +1 -1
  149. package/dist/server/src/api/controllers/plugins.controller.d.ts +8 -8
  150. package/dist/server/src/api/controllers/plugins.controller.js +208 -244
  151. package/dist/server/src/api/controllers/plugins.controller.js.map +1 -1
  152. package/dist/server/src/api/controllers/system.controller.d.ts +1 -0
  153. package/dist/server/src/api/controllers/system.controller.js +22 -8
  154. package/dist/server/src/api/controllers/system.controller.js.map +1 -1
  155. package/dist/server/src/api/controllers/users.controller.d.ts +2 -2
  156. package/dist/server/src/api/controllers/users.controller.js +13 -25
  157. package/dist/server/src/api/controllers/users.controller.js.map +1 -1
  158. package/dist/server/src/api/database/checks.js +2 -2
  159. package/dist/server/src/api/database/checks.js.map +1 -1
  160. package/dist/server/src/api/database/index.d.ts +4 -7
  161. package/dist/server/src/api/database/index.js +59 -86
  162. package/dist/server/src/api/database/index.js.map +1 -1
  163. package/dist/server/src/api/database/migration.js +5 -141
  164. package/dist/server/src/api/database/migration.js.map +1 -1
  165. package/dist/server/src/api/database/selfcheck.js +5 -5
  166. package/dist/server/src/api/database/selfcheck.js.map +1 -1
  167. package/dist/server/src/api/database/types.d.ts +17 -25
  168. package/dist/server/src/api/go2rtc/api/discover.d.ts +30 -0
  169. package/dist/server/src/api/go2rtc/api/discover.js +162 -0
  170. package/dist/server/src/api/go2rtc/api/discover.js.map +1 -0
  171. package/dist/server/src/api/go2rtc/api/index.d.ts +1 -1
  172. package/dist/server/src/api/go2rtc/api/index.js +15 -4
  173. package/dist/server/src/api/go2rtc/api/index.js.map +1 -1
  174. package/dist/server/src/api/go2rtc/api/streams.d.ts +3 -1
  175. package/dist/server/src/api/go2rtc/api/streams.js +66 -9
  176. package/dist/server/src/api/go2rtc/api/streams.js.map +1 -1
  177. package/dist/server/src/api/go2rtc/index.d.ts +2 -0
  178. package/dist/server/src/api/go2rtc/index.js +3 -0
  179. package/dist/server/src/api/go2rtc/index.js.map +1 -1
  180. package/dist/server/src/api/go2rtc/queue.js +3 -3
  181. package/dist/server/src/api/go2rtc/queue.js.map +1 -1
  182. package/dist/server/src/api/go2rtc/types.d.ts +66 -11
  183. package/dist/server/src/api/index.d.ts +4 -0
  184. package/dist/server/src/api/index.js +45 -9
  185. package/dist/server/src/api/index.js.map +1 -1
  186. package/dist/server/src/api/middlewares/authPermission.middleware.d.ts +1 -0
  187. package/dist/server/src/api/middlewares/authPermission.middleware.js +11 -2
  188. package/dist/server/src/api/middlewares/authPermission.middleware.js.map +1 -1
  189. package/dist/server/src/api/middlewares/authValidation.middleware.js +20 -12
  190. package/dist/server/src/api/middlewares/authValidation.middleware.js.map +1 -1
  191. package/dist/server/src/api/middlewares/pagination.middleware.js +45 -53
  192. package/dist/server/src/api/middlewares/pagination.middleware.js.map +1 -1
  193. package/dist/server/src/api/plugins/proxy.plugin.d.ts +14 -0
  194. package/dist/server/src/api/plugins/proxy.plugin.js +200 -0
  195. package/dist/server/src/api/plugins/proxy.plugin.js.map +1 -0
  196. package/dist/server/src/api/routes/cameras.routes.js +56 -30
  197. package/dist/server/src/api/routes/cameras.routes.js.map +1 -1
  198. package/dist/server/src/api/routes/plugins.routes.js +65 -63
  199. package/dist/server/src/api/routes/plugins.routes.js.map +1 -1
  200. package/dist/server/src/api/routes/system.routes.js +7 -1
  201. package/dist/server/src/api/routes/system.routes.js.map +1 -1
  202. package/dist/server/src/api/routes/users.routes.js +8 -8
  203. package/dist/server/src/api/routes/users.routes.js.map +1 -1
  204. package/dist/server/src/api/schemas/backup.schema.d.ts +3 -3
  205. package/dist/server/src/api/schemas/backup.schema.js +1 -1
  206. package/dist/server/src/api/schemas/backup.schema.js.map +1 -1
  207. package/dist/server/src/api/schemas/cameras.schema.d.ts +1413 -529
  208. package/dist/server/src/api/schemas/cameras.schema.js +228 -182
  209. package/dist/server/src/api/schemas/cameras.schema.js.map +1 -1
  210. package/dist/server/src/api/schemas/config.schema.d.ts +29 -41
  211. package/dist/server/src/api/schemas/config.schema.js +10 -21
  212. package/dist/server/src/api/schemas/config.schema.js.map +1 -1
  213. package/dist/server/src/api/schemas/go2rtc.schema.d.ts +194 -162
  214. package/dist/server/src/api/schemas/go2rtc.schema.js +33 -58
  215. package/dist/server/src/api/schemas/go2rtc.schema.js.map +1 -1
  216. package/dist/server/src/api/schemas/plugins.schema.d.ts +17 -17
  217. package/dist/server/src/api/schemas/plugins.schema.js +1 -1
  218. package/dist/server/src/api/schemas/plugins.schema.js.map +1 -1
  219. package/dist/server/src/api/schemas/storage.schema.d.ts +22 -0
  220. package/dist/server/src/api/schemas/storage.schema.js +5 -0
  221. package/dist/server/src/api/schemas/storage.schema.js.map +1 -0
  222. package/dist/server/src/api/schemas/system.schema.d.ts +171 -3
  223. package/dist/server/src/api/schemas/system.schema.js +30 -3
  224. package/dist/server/src/api/schemas/system.schema.js.map +1 -1
  225. package/dist/server/src/api/schemas/users.schema.d.ts +98 -254
  226. package/dist/server/src/api/schemas/users.schema.js +6 -6
  227. package/dist/server/src/api/schemas/users.schema.js.map +1 -1
  228. package/dist/server/src/api/services/auth.service.d.ts +5 -5
  229. package/dist/server/src/api/services/auth.service.js +26 -35
  230. package/dist/server/src/api/services/auth.service.js.map +1 -1
  231. package/dist/server/src/api/services/cameras.service.d.ts +11 -16
  232. package/dist/server/src/api/services/cameras.service.js +143 -310
  233. package/dist/server/src/api/services/cameras.service.js.map +1 -1
  234. package/dist/server/src/api/services/plugins.service.d.ts +3 -1
  235. package/dist/server/src/api/services/plugins.service.js +48 -50
  236. package/dist/server/src/api/services/plugins.service.js.map +1 -1
  237. package/dist/server/src/api/services/users.service.d.ts +1 -0
  238. package/dist/server/src/api/services/users.service.js +20 -14
  239. package/dist/server/src/api/services/users.service.js.map +1 -1
  240. package/dist/server/src/api/types/index.d.ts +57 -46
  241. package/dist/server/src/api/types/index.js +0 -4
  242. package/dist/server/src/api/types/index.js.map +1 -1
  243. package/dist/server/src/api/utils/cert.d.ts +5 -1
  244. package/dist/server/src/api/utils/cert.js +24 -26
  245. package/dist/server/src/api/utils/cert.js.map +1 -1
  246. package/dist/server/src/api/utils/constants.d.ts +4 -2
  247. package/dist/server/src/api/utils/constants.js +4 -2
  248. package/dist/server/src/api/utils/constants.js.map +1 -1
  249. package/dist/server/src/api/utils/fetch.d.ts +1 -1
  250. package/dist/server/src/api/utils/fetch.js +2 -2
  251. package/dist/server/src/api/utils/fetch.js.map +1 -1
  252. package/dist/server/src/api/websocket/index.d.ts +1 -0
  253. package/dist/server/src/api/websocket/index.js +14 -9
  254. package/dist/server/src/api/websocket/index.js.map +1 -1
  255. package/dist/server/src/api/websocket/nsp/logs.d.ts +10 -2
  256. package/dist/server/src/api/websocket/nsp/logs.js +75 -27
  257. package/dist/server/src/api/websocket/nsp/logs.js.map +1 -1
  258. package/dist/server/src/api/websocket/nsp/metrics.d.ts +20 -12
  259. package/dist/server/src/api/websocket/nsp/metrics.js +188 -117
  260. package/dist/server/src/api/websocket/nsp/metrics.js.map +1 -1
  261. package/dist/server/src/api/websocket/nsp/plugins.d.ts +1 -1
  262. package/dist/server/src/api/websocket/nsp/plugins.js +3 -5
  263. package/dist/server/src/api/websocket/nsp/plugins.js.map +1 -1
  264. package/dist/server/src/api/websocket/nsp/server.js +6 -0
  265. package/dist/server/src/api/websocket/nsp/server.js.map +1 -1
  266. package/dist/server/src/api/websocket/types.d.ts +4 -2
  267. package/dist/server/src/api.d.ts +3 -4
  268. package/dist/server/src/api.js +13 -13
  269. package/dist/server/src/api.js.map +1 -1
  270. package/dist/server/src/camera/classes.d.ts +2 -0
  271. package/dist/server/src/camera/classes.js +24 -0
  272. package/dist/server/src/camera/classes.js.map +1 -0
  273. package/dist/server/src/camera/controller.d.ts +30 -18
  274. package/dist/server/src/camera/controller.js +236 -202
  275. package/dist/server/src/camera/controller.js.map +1 -1
  276. package/dist/server/src/camera/device.d.ts +34 -0
  277. package/dist/server/src/camera/device.js +327 -0
  278. package/dist/server/src/camera/device.js.map +1 -0
  279. package/dist/server/src/camera/frameWorker.d.ts +32 -31
  280. package/dist/server/src/camera/frameWorker.js +257 -247
  281. package/dist/server/src/camera/frameWorker.js.map +1 -1
  282. package/dist/server/src/camera/index.d.ts +92 -0
  283. package/dist/server/src/camera/index.js +531 -0
  284. package/dist/server/src/camera/index.js.map +1 -0
  285. package/dist/server/src/camera/interfaces.d.ts +17 -0
  286. package/dist/server/src/camera/interfaces.js +99 -0
  287. package/dist/server/src/camera/interfaces.js.map +1 -0
  288. package/dist/server/src/camera/iou.d.ts +2 -0
  289. package/dist/server/src/camera/iou.js +123 -0
  290. package/dist/server/src/camera/iou.js.map +1 -0
  291. package/dist/server/src/camera/polygon.d.ts +4 -0
  292. package/dist/server/src/camera/polygon.js +192 -0
  293. package/dist/server/src/camera/polygon.js.map +1 -0
  294. package/dist/server/src/camera/python/__init__.py +0 -0
  295. package/dist/server/src/camera/python/classes.py +41 -0
  296. package/dist/server/src/camera/python/interfaces.py +130 -0
  297. package/dist/server/src/camera/python/iou.py +158 -0
  298. package/dist/server/src/camera/python/polygon.py +230 -0
  299. package/dist/server/src/camera/python/typings.py +50 -0
  300. package/dist/server/src/camera/python/video_frame.py +143 -0
  301. package/dist/server/src/camera/session.d.ts +37 -0
  302. package/dist/server/src/camera/session.js +160 -0
  303. package/dist/server/src/camera/session.js.map +1 -0
  304. package/dist/server/src/camera/streaming/fmp4-session.d.ts +17 -0
  305. package/dist/server/src/camera/streaming/fmp4-session.js +308 -0
  306. package/dist/server/src/camera/streaming/fmp4-session.js.map +1 -0
  307. package/dist/server/src/camera/streaming/peer-connection.d.ts +26 -0
  308. package/dist/server/src/camera/streaming/peer-connection.js +213 -0
  309. package/dist/server/src/camera/streaming/peer-connection.js.map +1 -0
  310. package/dist/server/src/camera/streaming/rtsp-session.d.ts +19 -0
  311. package/dist/server/src/camera/streaming/rtsp-session.js +253 -0
  312. package/dist/server/src/camera/streaming/rtsp-session.js.map +1 -0
  313. package/dist/server/src/camera/streaming/webrtc-connection.d.ts +44 -0
  314. package/dist/server/src/camera/streaming/webrtc-connection.js +177 -0
  315. package/dist/server/src/camera/streaming/webrtc-connection.js.map +1 -0
  316. package/dist/server/src/camera/streaming/werift-session.d.ts +19 -0
  317. package/dist/server/src/camera/streaming/werift-session.js +246 -0
  318. package/dist/server/src/camera/streaming/werift-session.js.map +1 -0
  319. package/dist/server/src/camera/types.d.ts +16 -10
  320. package/dist/server/src/camera/utils.d.ts +9 -0
  321. package/dist/server/src/camera/utils.js +416 -0
  322. package/dist/server/src/camera/utils.js.map +1 -0
  323. package/dist/server/src/camera/videoFrame.d.ts +18 -0
  324. package/dist/server/src/camera/videoFrame.js +88 -0
  325. package/dist/server/src/camera/videoFrame.js.map +1 -0
  326. package/dist/server/src/cloud/index.d.ts +12 -0
  327. package/dist/server/src/cloud/index.js +49 -0
  328. package/dist/server/src/cloud/index.js.map +1 -0
  329. package/dist/server/src/cloud/remote/cloudflare.d.ts +7 -0
  330. package/dist/server/src/cloud/remote/cloudflare.js +12 -0
  331. package/dist/server/src/cloud/remote/cloudflare.js.map +1 -0
  332. package/dist/server/src/cloud/remote/upnp.d.ts +7 -0
  333. package/dist/server/src/cloud/remote/upnp.js +12 -0
  334. package/dist/server/src/cloud/remote/upnp.js.map +1 -0
  335. package/dist/server/src/cloud/remote/utils.d.ts +3 -0
  336. package/dist/server/src/cloud/remote/utils.js +20 -0
  337. package/dist/server/src/cloud/remote/utils.js.map +1 -0
  338. package/dist/server/src/cloud/types.d.ts +15 -0
  339. package/dist/server/src/cloud/types.js +11 -0
  340. package/dist/server/src/cloud/types.js.map +1 -0
  341. package/dist/server/src/decoder/child.d.ts +1 -0
  342. package/dist/server/src/decoder/child.js +749 -0
  343. package/dist/server/src/decoder/child.js.map +1 -0
  344. package/dist/server/src/decoder/imageUtils.d.ts +22 -0
  345. package/dist/server/src/decoder/imageUtils.js +196 -0
  346. package/dist/server/src/decoder/imageUtils.js.map +1 -0
  347. package/dist/server/src/decoder/manager.d.ts +19 -0
  348. package/dist/server/src/decoder/manager.js +208 -0
  349. package/dist/server/src/decoder/manager.js.map +1 -0
  350. package/dist/server/src/decoder/python/__init__.py +0 -0
  351. package/dist/server/src/decoder/python/child.py +903 -0
  352. package/dist/server/src/decoder/python/image_utils.py +196 -0
  353. package/dist/server/src/decoder/python/pool.py +45 -0
  354. package/dist/server/src/decoder/python/typings.py +57 -0
  355. package/dist/server/src/decoder/python/utils.py +70 -0
  356. package/dist/server/src/decoder/types.d.ts +23 -0
  357. package/dist/server/src/decoder/types.js.map +1 -0
  358. package/dist/server/src/decoder/utils.d.ts +13 -0
  359. package/dist/server/src/decoder/utils.js +45 -0
  360. package/dist/server/src/decoder/utils.js.map +1 -0
  361. package/dist/server/src/decoder/wasm/build/decoder.d.ts +43 -0
  362. package/dist/server/src/decoder/wasm/build/decoder.js +108 -0
  363. package/dist/server/src/decoder/wasm/build/decoder.wasm +0 -0
  364. package/dist/server/src/decoder/worker.d.ts +1 -0
  365. package/dist/server/src/decoder/worker.js +79 -0
  366. package/dist/server/src/decoder/worker.js.map +1 -0
  367. package/dist/server/src/go2rtc/index.d.ts +1 -0
  368. package/dist/server/src/go2rtc/index.js +27 -9
  369. package/dist/server/src/go2rtc/index.js.map +1 -1
  370. package/dist/server/src/go2rtc/types.d.ts +5 -4
  371. package/dist/server/src/go2rtc/types.js +6 -2
  372. package/dist/server/src/go2rtc/types.js.map +1 -1
  373. package/dist/server/src/main.js +19 -5
  374. package/dist/server/src/main.js.map +1 -1
  375. package/dist/server/src/manager/coreManager.d.ts +16 -0
  376. package/dist/server/src/manager/coreManager.js +95 -0
  377. package/dist/server/src/manager/coreManager.js.map +1 -0
  378. package/dist/server/src/manager/deviceManager.d.ts +12 -0
  379. package/dist/server/src/manager/deviceManager.js +130 -0
  380. package/dist/server/src/manager/deviceManager.js.map +1 -0
  381. package/dist/server/src/manager/types.d.ts +15 -0
  382. package/dist/server/src/manager/types.js +2 -0
  383. package/dist/server/src/manager/types.js.map +1 -0
  384. package/dist/server/src/plugins/index.d.ts +3 -1
  385. package/dist/server/src/plugins/index.js +42 -21
  386. package/dist/server/src/plugins/index.js.map +1 -1
  387. package/dist/server/src/plugins/plugin.d.ts +3 -3
  388. package/dist/server/src/plugins/plugin.js +13 -20
  389. package/dist/server/src/plugins/plugin.js.map +1 -1
  390. package/dist/server/src/plugins/runtime/base.d.ts +54 -0
  391. package/dist/server/src/plugins/runtime/base.js +223 -0
  392. package/dist/server/src/plugins/runtime/base.js.map +1 -0
  393. package/dist/server/src/plugins/runtime/index.d.ts +5 -0
  394. package/dist/server/src/plugins/runtime/index.js +13 -0
  395. package/dist/server/src/plugins/runtime/index.js.map +1 -0
  396. package/dist/server/src/plugins/runtime/node/child.d.ts +22 -0
  397. package/dist/server/src/plugins/runtime/node/child.js +152 -0
  398. package/dist/server/src/plugins/runtime/node/child.js.map +1 -0
  399. package/dist/server/src/plugins/runtime/node/index.d.ts +7 -0
  400. package/dist/server/src/plugins/runtime/node/index.js +54 -0
  401. package/dist/server/src/plugins/runtime/node/index.js.map +1 -0
  402. package/dist/server/src/plugins/runtime/node/plugin.d.ts +24 -0
  403. package/dist/server/src/plugins/runtime/node/plugin.js +128 -0
  404. package/dist/server/src/plugins/runtime/node/plugin.js.map +1 -0
  405. package/dist/server/src/plugins/runtime/node/pluginApi.d.ts +16 -0
  406. package/dist/server/src/plugins/runtime/node/pluginApi.js +18 -0
  407. package/dist/server/src/plugins/runtime/node/pluginApi.js.map +1 -0
  408. package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.d.ts +25 -0
  409. package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.js +230 -0
  410. package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.js.map +1 -0
  411. package/dist/server/src/plugins/runtime/node/proxy/coreManager.d.ts +16 -0
  412. package/dist/server/src/plugins/runtime/node/proxy/coreManager.js +98 -0
  413. package/dist/server/src/plugins/runtime/node/proxy/coreManager.js.map +1 -0
  414. package/dist/server/src/plugins/runtime/node/proxy/deviceManager.d.ts +19 -0
  415. package/dist/server/src/plugins/runtime/node/proxy/deviceManager.js +144 -0
  416. package/dist/server/src/plugins/runtime/node/proxy/deviceManager.js.map +1 -0
  417. package/dist/server/src/plugins/runtime/node/storage.d.ts +34 -0
  418. package/dist/server/src/plugins/runtime/node/storage.js +313 -0
  419. package/dist/server/src/plugins/runtime/node/storage.js.map +1 -0
  420. package/dist/server/src/plugins/runtime/node/storageController.d.ts +18 -0
  421. package/dist/server/src/plugins/runtime/node/storageController.js +67 -0
  422. package/dist/server/src/plugins/runtime/node/storageController.js.map +1 -0
  423. package/dist/server/src/plugins/runtime/python/__init__.py +0 -0
  424. package/dist/server/src/plugins/runtime/python/child.py +248 -0
  425. package/dist/server/src/plugins/runtime/python/index.d.ts +9 -0
  426. package/dist/server/src/plugins/runtime/python/index.js +57 -0
  427. package/dist/server/src/plugins/runtime/python/index.js.map +1 -0
  428. package/dist/server/src/plugins/runtime/python/namespaces.py +101 -0
  429. package/dist/server/src/plugins/runtime/python/plugin.py +155 -0
  430. package/dist/server/src/plugins/runtime/python/plugin_api.py +29 -0
  431. package/dist/server/src/plugins/runtime/python/proxy/camera_device.py +1732 -0
  432. package/dist/server/src/plugins/runtime/python/proxy/core_manager.py +126 -0
  433. package/dist/server/src/plugins/runtime/python/proxy/device_manager.py +197 -0
  434. package/dist/server/src/plugins/runtime/python/schema.py +99 -0
  435. package/dist/server/src/plugins/runtime/python/storage.py +353 -0
  436. package/dist/server/src/plugins/runtime/python/storage_controller.py +102 -0
  437. package/dist/server/src/plugins/runtime/python/typings.py +195 -0
  438. package/dist/server/src/plugins/schema.d.ts +27 -34
  439. package/dist/server/src/plugins/schema.js +358 -369
  440. package/dist/server/src/plugins/schema.js.map +1 -1
  441. package/dist/server/src/plugins/types.d.ts +43 -1
  442. package/dist/server/src/plugins/types.js +16 -0
  443. package/dist/server/src/plugins/types.js.map +1 -1
  444. package/dist/server/src/plugins/worker.d.ts +12 -31
  445. package/dist/server/src/plugins/worker.js +89 -343
  446. package/dist/server/src/plugins/worker.js.map +1 -1
  447. package/dist/server/src/rpc/index.d.ts +32 -0
  448. package/dist/server/src/rpc/index.js +103 -0
  449. package/dist/server/src/rpc/index.js.map +1 -0
  450. package/dist/server/src/rpc/namespaces.d.ts +35 -0
  451. package/dist/server/src/rpc/namespaces.js +42 -0
  452. package/dist/server/src/rpc/namespaces.js.map +1 -0
  453. package/dist/server/src/{nats → rpc}/server.d.ts +6 -2
  454. package/dist/server/src/{nats → rpc}/server.js +76 -55
  455. package/dist/server/src/rpc/server.js.map +1 -0
  456. package/dist/server/src/rpc/types.d.ts +111 -0
  457. package/dist/server/src/rpc/types.js +2 -0
  458. package/dist/server/src/{nats → rpc}/types.js.map +1 -1
  459. package/dist/server/src/{nats → rpc}/utils.d.ts +1 -1
  460. package/dist/server/src/rpc/utils.js.map +1 -0
  461. package/dist/server/src/services/config/constants.js +12 -48
  462. package/dist/server/src/services/config/constants.js.map +1 -1
  463. package/dist/server/src/services/config/defaults.d.ts +12 -0
  464. package/dist/server/src/services/config/defaults.js +55 -0
  465. package/dist/server/src/services/config/defaults.js.map +1 -0
  466. package/dist/server/src/services/config/index.d.ts +57 -9
  467. package/dist/server/src/services/config/index.js +277 -130
  468. package/dist/server/src/services/config/index.js.map +1 -1
  469. package/dist/server/src/services/config/types.d.ts +10 -4
  470. package/dist/server/src/types.d.ts +3 -0
  471. package/dist/server/src/utils/path.d.ts +5 -0
  472. package/dist/server/src/utils/path.js +12 -0
  473. package/dist/server/src/utils/path.js.map +1 -0
  474. package/dist/server/src/utils/pythonInstaller.d.ts +46 -0
  475. package/dist/server/src/utils/pythonInstaller.js +463 -0
  476. package/dist/server/src/utils/pythonInstaller.js.map +1 -0
  477. package/eslint.config.js +103 -0
  478. package/localdeps.txt +10 -0
  479. package/mypy.ini +30 -0
  480. package/package.json +57 -45
  481. package/requirements.txt +15 -0
  482. package/ruff.toml +90 -0
  483. package/src/__init__.py +0 -0
  484. package/src/_camera_ui_tools/__init__.py +0 -0
  485. package/src/_camera_ui_tools/__pycache__/__init__.cpython-311.pyc +0 -0
  486. package/src/api/controllers/api.controller.ts +19 -0
  487. package/src/api/controllers/auth.controller.ts +294 -0
  488. package/src/api/controllers/backup.controller.ts +72 -0
  489. package/src/api/controllers/cameras.controller.ts +1029 -0
  490. package/src/api/controllers/config.controller.ts +102 -0
  491. package/src/api/controllers/files.controller.ts +35 -0
  492. package/src/api/controllers/frameWorkers.controller.ts +109 -0
  493. package/src/api/controllers/plugins.controller.ts +1206 -0
  494. package/src/api/controllers/system.controller.ts +273 -0
  495. package/src/api/controllers/users.controller.ts +648 -0
  496. package/src/api/database/checks.ts +268 -0
  497. package/src/api/database/constants.ts +8 -0
  498. package/src/api/database/index.ts +262 -0
  499. package/src/api/database/migration.ts +62 -0
  500. package/src/api/database/selfcheck.ts +492 -0
  501. package/src/api/database/types.ts +104 -0
  502. package/src/api/go2rtc/api/application.ts +48 -0
  503. package/src/api/go2rtc/api/config.ts +61 -0
  504. package/src/api/go2rtc/api/discover.ts +197 -0
  505. package/src/api/go2rtc/api/index.ts +49 -0
  506. package/src/api/go2rtc/api/snapshot.ts +44 -0
  507. package/src/api/go2rtc/api/streams.ts +168 -0
  508. package/src/api/go2rtc/index.ts +43 -0
  509. package/src/api/go2rtc/queue.ts +50 -0
  510. package/src/api/go2rtc/types.ts +174 -0
  511. package/src/api/index.ts +286 -0
  512. package/src/api/middlewares/authPermission.middleware.ts +46 -0
  513. package/src/api/middlewares/authValidation.middleware.ts +160 -0
  514. package/src/api/middlewares/pagination.middleware.ts +67 -0
  515. package/src/api/middlewares/socketAuth.middleware.ts +136 -0
  516. package/src/api/plugins/header.plugin.ts +15 -0
  517. package/src/api/plugins/logger.plugin.ts +44 -0
  518. package/src/api/plugins/proxy.plugin.ts +255 -0
  519. package/src/api/plugins/socket.plugin.ts +28 -0
  520. package/src/api/plugins/system.plugin.ts +48 -0
  521. package/src/api/plugins/useragent.plugin.ts +19 -0
  522. package/src/api/routes/api.routes.ts +10 -0
  523. package/src/api/routes/auth.routes.ts +56 -0
  524. package/src/api/routes/backup.routes.ts +28 -0
  525. package/src/api/routes/cameras.routes.ts +281 -0
  526. package/src/api/routes/config.routes.ts +66 -0
  527. package/src/api/routes/files.routes.ts +15 -0
  528. package/src/api/routes/frameWorkers.routes.ts +39 -0
  529. package/src/api/routes/index.ts +37 -0
  530. package/src/api/routes/plugins.routes.ts +420 -0
  531. package/src/api/routes/system.routes.ts +101 -0
  532. package/src/api/routes/users.routes.ts +167 -0
  533. package/src/api/schemas/backup.schema.ts +112 -0
  534. package/src/api/schemas/cameras.schema.ts +479 -0
  535. package/src/api/schemas/config.schema.ts +38 -0
  536. package/src/api/schemas/go2rtc.schema.ts +189 -0
  537. package/src/api/schemas/plugins.schema.ts +126 -0
  538. package/src/api/schemas/storage.schema.ts +11 -0
  539. package/src/api/schemas/system.schema.ts +45 -0
  540. package/src/api/schemas/users.schema.ts +185 -0
  541. package/src/api/services/auth.service.ts +210 -0
  542. package/src/api/services/backup.service.ts +144 -0
  543. package/src/api/services/cameras.service.ts +671 -0
  544. package/src/api/services/plugins.service.ts +470 -0
  545. package/src/api/services/system.service.ts +85 -0
  546. package/src/api/services/users.service.ts +276 -0
  547. package/src/api/types/index.ts +675 -0
  548. package/src/api/utils/cert.ts +254 -0
  549. package/src/api/utils/constants.ts +17 -0
  550. package/src/api/utils/fetch.ts +21 -0
  551. package/src/api/utils/moveFiles.ts +45 -0
  552. package/src/api/utils/parse.ts +17 -0
  553. package/src/api/websocket/index.ts +110 -0
  554. package/src/api/websocket/nsp/logs.ts +240 -0
  555. package/src/api/websocket/nsp/main.ts +27 -0
  556. package/src/api/websocket/nsp/metrics.ts +301 -0
  557. package/src/api/websocket/nsp/notifications.ts +43 -0
  558. package/src/api/websocket/nsp/plugins.ts +37 -0
  559. package/src/api/websocket/nsp/server.ts +220 -0
  560. package/src/api/websocket/nsp/status.ts +77 -0
  561. package/src/api/websocket/types.ts +55 -0
  562. package/src/api.ts +163 -0
  563. package/src/camera/classes.ts +32 -0
  564. package/src/camera/controller.ts +579 -0
  565. package/src/camera/device.ts +422 -0
  566. package/src/camera/frameWorker.ts +403 -0
  567. package/src/camera/index.ts +679 -0
  568. package/src/camera/interfaces.ts +95 -0
  569. package/src/camera/iou.ts +153 -0
  570. package/src/camera/polygon.ts +226 -0
  571. package/src/camera/python/__init__.py +0 -0
  572. package/src/camera/python/__pycache__/__init__.cpython-311.pyc +0 -0
  573. package/src/camera/python/__pycache__/classes.cpython-311.pyc +0 -0
  574. package/src/camera/python/__pycache__/delegate_controller.cpython-311.pyc +0 -0
  575. package/src/camera/python/__pycache__/interfaces.cpython-311.pyc +0 -0
  576. package/src/camera/python/__pycache__/iou.cpython-310.pyc +0 -0
  577. package/src/camera/python/__pycache__/iou.cpython-311.pyc +0 -0
  578. package/src/camera/python/__pycache__/iou2.cpython-310.pyc +0 -0
  579. package/src/camera/python/__pycache__/polygon.cpython-311.pyc +0 -0
  580. package/src/camera/python/__pycache__/typings.cpython-311.pyc +0 -0
  581. package/src/camera/python/__pycache__/video_frame.cpython-311.pyc +0 -0
  582. package/src/camera/python/classes.py +41 -0
  583. package/src/camera/python/interfaces.py +130 -0
  584. package/src/camera/python/iou.py +158 -0
  585. package/src/camera/python/polygon.py +230 -0
  586. package/src/camera/python/test/__pycache__/polygon.cpython-310.pyc +0 -0
  587. package/src/camera/python/test/iou_test.py +799 -0
  588. package/src/camera/python/test/polygon.py +238 -0
  589. package/src/camera/python/test/polygon_test.py +256 -0
  590. package/src/camera/python/test/polygon_test2.py +484 -0
  591. package/src/camera/python/typings.py +50 -0
  592. package/src/camera/python/video_frame.py +143 -0
  593. package/src/camera/session.ts +192 -0
  594. package/src/camera/streaming/fmp4-session.ts +390 -0
  595. package/src/camera/streaming/peer-connection.ts +273 -0
  596. package/src/camera/streaming/rtsp-session.ts +331 -0
  597. package/src/camera/streaming/webrtc-connection.ts +260 -0
  598. package/src/camera/streaming/werift-session.ts +317 -0
  599. package/src/camera/test/iou_test.ts +761 -0
  600. package/src/camera/test/polygon.test.ts +611 -0
  601. package/src/camera/test/polygon_test.ts +210 -0
  602. package/src/camera/types.ts +48 -0
  603. package/src/camera/utils.ts +489 -0
  604. package/src/camera/videoFrame.ts +123 -0
  605. package/src/cloud/index.ts +61 -0
  606. package/src/cloud/remote/cloudflare.ts +18 -0
  607. package/src/cloud/remote/upnp.ts +18 -0
  608. package/src/cloud/remote/utils.ts +24 -0
  609. package/src/cloud/types.ts +16 -0
  610. package/src/decoder/child.ts +883 -0
  611. package/src/decoder/imageUtils.ts +275 -0
  612. package/src/decoder/manager.ts +251 -0
  613. package/src/decoder/python/__init__.py +0 -0
  614. package/src/decoder/python/__pycache__/__init__.cpython-311.pyc +0 -0
  615. package/src/decoder/python/__pycache__/image_utils.cpython-311.pyc +0 -0
  616. package/src/decoder/python/__pycache__/typings.cpython-311.pyc +0 -0
  617. package/src/decoder/python/__pycache__/utils.cpython-311.pyc +0 -0
  618. package/src/decoder/python/child.py +903 -0
  619. package/src/decoder/python/image_utils.py +196 -0
  620. package/src/decoder/python/pool.py +45 -0
  621. package/src/decoder/python/test/group.py +62 -0
  622. package/src/decoder/python/test/motion.mp4 +0 -0
  623. package/src/decoder/python/test/motion2.mp4 +0 -0
  624. package/src/decoder/python/test/opencl.cl +70 -0
  625. package/src/decoder/python/test/opencl2.cl +130 -0
  626. package/src/decoder/python/test/test.py +427 -0
  627. package/src/decoder/python/test/test1.jpg +0 -0
  628. package/src/decoder/python/test/test1_resized.jpg +0 -0
  629. package/src/decoder/python/test/test2.jpg +0 -0
  630. package/src/decoder/python/test/test2.py +451 -0
  631. package/src/decoder/python/test/test2_resized.jpg +0 -0
  632. package/src/decoder/python/test/test3.jpg +0 -0
  633. package/src/decoder/python/test/utils.py +50 -0
  634. package/src/decoder/python/typings.py +57 -0
  635. package/src/decoder/python/utils.py +70 -0
  636. package/src/decoder/test/child.ts +117 -0
  637. package/src/decoder/test/ffmpeg.ts +371 -0
  638. package/src/decoder/test/test.ts +182 -0
  639. package/src/decoder/types.ts +27 -0
  640. package/src/decoder/utils.ts +64 -0
  641. package/src/decoder/wasm/asconfig.json +28 -0
  642. package/src/decoder/wasm/assembly/console.ts +1 -0
  643. package/src/decoder/wasm/assembly/index.ts +890 -0
  644. package/src/decoder/wasm/build/decoder.d.ts +43 -0
  645. package/src/decoder/wasm/build/decoder.js +108 -0
  646. package/src/decoder/wasm/build/decoder.wasm +0 -0
  647. package/src/decoder/wasm/tsconfig.json +5 -0
  648. package/src/decoder/worker.ts +113 -0
  649. package/src/go2rtc/index.ts +324 -0
  650. package/src/go2rtc/types.ts +88 -0
  651. package/src/main.ts +267 -0
  652. package/src/manager/coreManager.ts +78 -0
  653. package/src/manager/deviceManager.ts +132 -0
  654. package/src/manager/types.ts +17 -0
  655. package/src/plugins/index.ts +443 -0
  656. package/src/plugins/plugin.ts +177 -0
  657. package/src/plugins/runtime/base.ts +282 -0
  658. package/src/plugins/runtime/index.ts +15 -0
  659. package/src/plugins/runtime/node/child.ts +193 -0
  660. package/src/plugins/runtime/node/index.ts +67 -0
  661. package/src/plugins/runtime/node/plugin.ts +122 -0
  662. package/src/plugins/runtime/node/pluginApi.ts +27 -0
  663. package/src/plugins/runtime/node/proxy/cameraDevice.ts +299 -0
  664. package/src/plugins/runtime/node/proxy/coreManager.ts +128 -0
  665. package/src/plugins/runtime/node/proxy/deviceManager.ts +187 -0
  666. package/src/plugins/runtime/node/storage.ts +312 -0
  667. package/src/plugins/runtime/node/storageController.ts +91 -0
  668. package/src/plugins/runtime/python/__init__.py +0 -0
  669. package/src/plugins/runtime/python/__pycache__/__init__.cpython-311.pyc +0 -0
  670. package/src/plugins/runtime/python/__pycache__/camera_storage.cpython-311.pyc +0 -0
  671. package/src/plugins/runtime/python/__pycache__/config_service.cpython-311.pyc +0 -0
  672. package/src/plugins/runtime/python/__pycache__/constants.cpython-311.pyc +0 -0
  673. package/src/plugins/runtime/python/__pycache__/ipc.cpython-311.pyc +0 -0
  674. package/src/plugins/runtime/python/__pycache__/logger.cpython-311.pyc +0 -0
  675. package/src/plugins/runtime/python/__pycache__/message_queue.cpython-311.pyc +0 -0
  676. package/src/plugins/runtime/python/__pycache__/namespaces.cpython-311.pyc +0 -0
  677. package/src/plugins/runtime/python/__pycache__/plugin.cpython-311.pyc +0 -0
  678. package/src/plugins/runtime/python/__pycache__/plugin_api.cpython-311.pyc +0 -0
  679. package/src/plugins/runtime/python/__pycache__/plugin_logger.cpython-311.pyc +0 -0
  680. package/src/plugins/runtime/python/__pycache__/proxy_utils.cpython-311.pyc +0 -0
  681. package/src/plugins/runtime/python/__pycache__/schema.cpython-311.pyc +0 -0
  682. package/src/plugins/runtime/python/__pycache__/storage.cpython-311.pyc +0 -0
  683. package/src/plugins/runtime/python/__pycache__/storage_controller.cpython-311.pyc +0 -0
  684. package/src/plugins/runtime/python/__pycache__/typings.cpython-311.pyc +0 -0
  685. package/src/plugins/runtime/python/child.py +248 -0
  686. package/src/plugins/runtime/python/index.ts +73 -0
  687. package/src/plugins/runtime/python/namespaces.py +101 -0
  688. package/src/plugins/runtime/python/plugin.py +155 -0
  689. package/src/plugins/runtime/python/plugin_api.py +29 -0
  690. package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-310.pyc +0 -0
  691. package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-311.pyc +0 -0
  692. package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-38.pyc +0 -0
  693. package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-39.pyc +0 -0
  694. package/src/plugins/runtime/python/proxy/__pycache__/constants.cpython-311.pyc +0 -0
  695. package/src/plugins/runtime/python/proxy/__pycache__/constants.cpython-39.pyc +0 -0
  696. package/src/plugins/runtime/python/proxy/__pycache__/core_manager.cpython-311.pyc +0 -0
  697. package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-310.pyc +0 -0
  698. package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-311.pyc +0 -0
  699. package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-38.pyc +0 -0
  700. package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-39.pyc +0 -0
  701. package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-310.pyc +0 -0
  702. package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-311.pyc +0 -0
  703. package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-38.pyc +0 -0
  704. package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-39.pyc +0 -0
  705. package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-310.pyc +0 -0
  706. package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-311.pyc +0 -0
  707. package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-38.pyc +0 -0
  708. package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-39.pyc +0 -0
  709. package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-310.pyc +0 -0
  710. package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-311.pyc +0 -0
  711. package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-38.pyc +0 -0
  712. package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-39.pyc +0 -0
  713. package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-310.pyc +0 -0
  714. package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-311.pyc +0 -0
  715. package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-38.pyc +0 -0
  716. package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-39.pyc +0 -0
  717. package/src/plugins/runtime/python/proxy/camera_device.py +1732 -0
  718. package/src/plugins/runtime/python/proxy/core_manager.py +126 -0
  719. package/src/plugins/runtime/python/proxy/device_manager.py +197 -0
  720. package/src/plugins/runtime/python/schema.py +99 -0
  721. package/src/plugins/runtime/python/storage.py +353 -0
  722. package/src/plugins/runtime/python/storage_controller.py +102 -0
  723. package/src/plugins/runtime/python/typings.py +195 -0
  724. package/src/plugins/schema.ts +472 -0
  725. package/src/plugins/types.ts +60 -0
  726. package/src/plugins/worker.ts +250 -0
  727. package/src/rpc/index.ts +149 -0
  728. package/src/rpc/namespaces.ts +79 -0
  729. package/src/rpc/server.ts +422 -0
  730. package/src/rpc/types.ts +119 -0
  731. package/src/rpc/utils.ts +16 -0
  732. package/src/services/config/constants.ts +47 -0
  733. package/src/services/config/defaults.ts +57 -0
  734. package/src/services/config/index.ts +744 -0
  735. package/src/services/config/types.ts +211 -0
  736. package/src/services/logger/index.ts +96 -0
  737. package/src/types.ts +47 -0
  738. package/src/utils/path.ts +16 -0
  739. package/src/utils/pythonInstaller.ts +597 -0
  740. package/tsconfig.json +37 -0
  741. package/types/fastify.d.ts +14 -0
  742. package/updates.config.js +3 -0
  743. package/dist/interface/@intlify.Do1-T-x0.0.0.49.js +0 -15
  744. package/dist/interface/@mdi.CbjpODVZ.0.0.49.js +0 -1
  745. package/dist/interface/@tanstack.CgZ4BVuY.0.0.49.js +0 -1
  746. package/dist/interface/@vue.DeX8WChi.0.0.49.js +0 -17
  747. package/dist/interface/@vueform.WCJNykTK.0.0.49.js +0 -1
  748. package/dist/interface/@vueuse.fmA4o7MO.0.0.49.js +0 -1
  749. package/dist/interface/Account.D_hgF7as.0.0.49.js +0 -1
  750. package/dist/interface/Adminpanel.Cr2ysRnk.0.0.49.js +0 -2
  751. package/dist/interface/Appearance.DJPnnakw.0.0.49.js +0 -1
  752. package/dist/interface/Backup.DWrnTw65.0.0.49.js +0 -1
  753. package/dist/interface/Camera.Cm8bv5Jw.0.0.49.js +0 -1
  754. package/dist/interface/Cameras.BdMnnB_B.0.0.49.js +0 -1
  755. package/dist/interface/Camview.CvyTACeS.0.0.49.js +0 -1
  756. package/dist/interface/Config.R58trs6R.0.0.49.js +0 -1
  757. package/dist/interface/Console.ByS6OcfG.0.0.49.js +0 -4
  758. package/dist/interface/FirstSteps.BSZVBND8.0.0.49.js +0 -1
  759. package/dist/interface/NewCamera.CpKY8-_z.0.0.49.js +0 -469
  760. package/dist/interface/Plugin.ucDXXC6d.0.0.49.js +0 -1
  761. package/dist/interface/Plugins.Bl6Yy3fd.0.0.49.js +0 -1
  762. package/dist/interface/Recordings.Bm-_HDqk.0.0.49.js +0 -1
  763. package/dist/interface/Recordings.CVFqRJTQ.0.0.49.js +0 -1
  764. package/dist/interface/Settings.ClbXnv3j.0.0.49.js +0 -1
  765. package/dist/interface/System.BE0hX95Q.0.0.49.js +0 -4
  766. package/dist/interface/User.Ih1R_8u4.0.0.49.js +0 -1
  767. package/dist/interface/VConfigEditor.vue_vue_type_script_setup_true_lang.CAHg6HiL.0.0.49.js +0 -2
  768. package/dist/interface/VConsole.B9yVZ89i.0.0.49.js +0 -1
  769. package/dist/interface/VPlayer.DWJVzwuw.0.0.49.js +0 -4
  770. package/dist/interface/VPluginCard.pJNHjHpP.0.0.49.js +0 -4
  771. package/dist/interface/ace-builds.S1varnlI.0.0.49.js +0 -970
  772. package/dist/interface/apexcharts.BQn4Fbzn.0.0.49.js +0 -838
  773. package/dist/interface/assets/@vueform.0.0.49.CroAHJs8.css +0 -1
  774. package/dist/interface/assets/@xterm.0.0.49.CFbL2ovg.css +0 -32
  775. package/dist/interface/assets/Account.0.0.49.Bnw6Lbtd.css +0 -1
  776. package/dist/interface/assets/Adminpanel.0.0.49.a3t1v3MB.css +0 -1
  777. package/dist/interface/assets/Camera.0.0.49.Br9s6-lM.css +0 -1
  778. package/dist/interface/assets/Cameras.0.0.49.Buf1Dgce.css +0 -1
  779. package/dist/interface/assets/Camview.0.0.49.B7Cja2ry.css +0 -1
  780. package/dist/interface/assets/Config.0.0.49.DNGo2krN.css +0 -1
  781. package/dist/interface/assets/Console.0.0.49.Bh8l9QnM.css +0 -1
  782. package/dist/interface/assets/FirstSteps.0.0.49.Mu8VPl13.css +0 -1
  783. package/dist/interface/assets/NewCamera.0.0.49.DtjxW0Pf.css +0 -1
  784. package/dist/interface/assets/Plugin.0.0.49.YIpAU1_n.css +0 -1
  785. package/dist/interface/assets/Plugins.0.0.49.DXSoO9M1.css +0 -1
  786. package/dist/interface/assets/Settings.0.0.49.CVmui2kE.css +0 -1
  787. package/dist/interface/assets/User.0.0.49.BiGtIFqt.css +0 -1
  788. package/dist/interface/assets/VConsole.0.0.49.BCqKHpmJ.css +0 -1
  789. package/dist/interface/assets/VPlayer.0.0.49.C4lm2rVR.css +0 -1
  790. package/dist/interface/assets/VPluginCard.0.0.49.C8Lj6X-J.css +0 -1
  791. package/dist/interface/assets/main.0.0.49.OJngntGT.css +0 -1
  792. package/dist/interface/assets/vue3-toastify.0.0.49.DHXAGmwn.css +0 -1
  793. package/dist/interface/assets/vuetify.0.0.49.Dua9WSqa.css +0 -5
  794. package/dist/interface/axios.DIsA03vz.0.0.49.js +0 -6
  795. package/dist/interface/backup.DO02r0Uq.0.0.49.js +0 -1
  796. package/dist/interface/dnd-core.De50QAoi.0.0.49.js +0 -1
  797. package/dist/interface/engine.io-client.BkCVneko.0.0.49.js +0 -1
  798. package/dist/interface/fast-deep-equal.Cba0yG7P.0.0.49.js +0 -1
  799. package/dist/interface/fonts/Inter/Inter-Regular.ttf +0 -0
  800. package/dist/interface/highlight.js.B_E0LW5C.0.0.49.js +0 -2
  801. package/dist/interface/hookable.B8xFkYCm.0.0.49.js +0 -1
  802. package/dist/interface/linkify-it.B6s2BWlj.0.0.49.js +0 -1
  803. package/dist/interface/main.BBe3SGhH.0.0.49.js +0 -4
  804. package/dist/interface/perfect-debounce.Cp2ysxOb.0.0.49.js +0 -1
  805. package/dist/interface/pinia.ggULzsrQ.0.0.49.js +0 -5
  806. package/dist/interface/plugins.D11FBqVV.0.0.49.js +0 -1
  807. package/dist/interface/react-dnd-touch-backend.Bu6wFEmw.0.0.49.js +0 -1
  808. package/dist/interface/rxjs.BoFuGUYG.0.0.49.js +0 -3
  809. package/dist/interface/socket.io-client.DkEQDv7C.0.0.49.js +0 -1
  810. package/dist/interface/socket.io-parser.DIURoCw8.0.0.49.js +0 -1
  811. package/dist/interface/system.D_LabhBl.0.0.49.js +0 -1
  812. package/dist/interface/types.Cz9TaZAP.0.0.49.js +0 -1
  813. package/dist/interface/utils.mAKpSMLY.0.0.49.js +0 -1
  814. package/dist/interface/uuid.Ch9TGLTe.0.0.49.js +0 -1
  815. package/dist/interface/vee-validate.8pUAwQ7T.0.0.49.js +0 -5
  816. package/dist/interface/vue-i18n.CBqdKRmG.0.0.49.js +0 -5
  817. package/dist/interface/vue-inline-svg.ZWpe_tFT.0.0.49.js +0 -1
  818. package/dist/interface/vue-router.DvFvaoP2.0.0.49.js +0 -5
  819. package/dist/interface/vue3-apexcharts.BHSDC9pf.0.0.49.js +0 -1
  820. package/dist/interface/vue3-dnd.DbCy3Qbj.0.0.49.js +0 -1
  821. package/dist/interface/vue3-toastify.JJyrPHKk.0.0.49.js +0 -1
  822. package/dist/interface/vuetify.kkqUjVJA.0.0.49.js +0 -5
  823. package/dist/interface/zod.bkdEMpUp.0.0.49.js +0 -1
  824. package/dist/server/src/api/utils/cameraSource.d.ts +0 -6
  825. package/dist/server/src/api/utils/cameraSource.js +0 -51
  826. package/dist/server/src/api/utils/cameraSource.js.map +0 -1
  827. package/dist/server/src/api/websocket/go2rtc.d.ts +0 -21
  828. package/dist/server/src/api/websocket/go2rtc.js +0 -88
  829. package/dist/server/src/api/websocket/go2rtc.js.map +0 -1
  830. package/dist/server/src/api/websocket/nsp/proxy.d.ts +0 -27
  831. package/dist/server/src/api/websocket/nsp/proxy.js +0 -127
  832. package/dist/server/src/api/websocket/nsp/proxy.js.map +0 -1
  833. package/dist/server/src/nats/index.d.ts +0 -40
  834. package/dist/server/src/nats/index.js +0 -164
  835. package/dist/server/src/nats/index.js.map +0 -1
  836. package/dist/server/src/nats/proxy/cameraDevice.d.ts +0 -22
  837. package/dist/server/src/nats/proxy/cameraDevice.js +0 -249
  838. package/dist/server/src/nats/proxy/cameraDevice.js.map +0 -1
  839. package/dist/server/src/nats/proxy/coreManager.d.ts +0 -14
  840. package/dist/server/src/nats/proxy/coreManager.js +0 -68
  841. package/dist/server/src/nats/proxy/coreManager.js.map +0 -1
  842. package/dist/server/src/nats/proxy/deviceManager.d.ts +0 -14
  843. package/dist/server/src/nats/proxy/deviceManager.js +0 -101
  844. package/dist/server/src/nats/proxy/deviceManager.js.map +0 -1
  845. package/dist/server/src/nats/server.js.map +0 -1
  846. package/dist/server/src/nats/types.d.ts +0 -18
  847. package/dist/server/src/nats/utils.js.map +0 -1
  848. /package/dist/interface/assets/{Backup.0.0.49.CX0rT0QJ.css → SettingsBackup.CX0rT0QJ.0.0.50-internal.0.css} +0 -0
  849. /package/dist/interface/assets/{highlight.0.0.49.Ch2EwETz.css → highlight.Ch2EwETz.0.0.50-internal.0.css} +0 -0
  850. /package/dist/interface/assets/{logo-256.0.0.49.BCQk9H1-.png → logo-256.BCQk9H1-.0.0.50-internal.0.png} +0 -0
  851. /package/dist/interface/assets/{logo-512.0.0.49.DLKVOU2S.png → logo-512.DLKVOU2S.0.0.50-internal.0.png} +0 -0
  852. /package/dist/interface/assets/{logo.0.0.49.DmEiRk0z.png → logo.DmEiRk0z.0.0.50-internal.0.png} +0 -0
  853. /package/dist/interface/assets/{mode-json.0.0.49.Br7xisR1.js → mode-json.Br7xisR1.0.0.50-internal.0.js} +0 -0
  854. /package/dist/interface/assets/{mode-yaml.0.0.49.CIYL8U3d.js → mode-yaml.CIYL8U3d.0.0.50-internal.0.js} +0 -0
  855. /package/dist/interface/{@babel.l0sNRNKZ.0.0.49.js → js/@babel.l0sNRNKZ.0.0.50-internal.0.js} +0 -0
  856. /package/dist/interface/{@react-dnd.CcwRs9xb.0.0.49.js → js/@react-dnd.CcwRs9xb.0.0.50-internal.0.js} +0 -0
  857. /package/dist/interface/{@socket.io.Dkula2eQ.0.0.49.js → js/@socket.io.Dkula2eQ.0.0.50-internal.0.js} +0 -0
  858. /package/dist/interface/{birpc.l0sNRNKZ.0.0.49.js → js/birpc.l0sNRNKZ.0.0.50-internal.0.js} +0 -0
  859. /package/dist/interface/{compare-versions.DqEOhma6.0.0.49.js → js/compare-versions.DqEOhma6.0.0.50-internal.0.js} +0 -0
  860. /package/dist/interface/{dijkstrajs.C00ieaqj.0.0.49.js → js/dijkstrajs.C00ieaqj.0.0.50-internal.0.js} +0 -0
  861. /package/dist/interface/{engine.io-parser.BiEtp6m2.0.0.49.js → js/engine.io-parser.BiEtp6m2.0.0.50-internal.0.js} +0 -0
  862. /package/dist/interface/{entities.C20TfXL6.0.0.49.js → js/entities.C20TfXL6.0.0.50-internal.0.js} +0 -0
  863. /package/dist/interface/{ev-emitter.X5f1qa-c.0.0.49.js → js/ev-emitter.X5f1qa-c.0.0.50-internal.0.js} +0 -0
  864. /package/dist/interface/{get-size.D1dS-IaP.0.0.49.js → js/get-size.D1dS-IaP.0.0.50-internal.0.js} +0 -0
  865. /package/dist/interface/{vue.l0sNRNKZ.0.0.49.js → js/hookable.l0sNRNKZ.0.0.50-internal.0.js} +0 -0
  866. /package/dist/interface/{mdurl.k9Sl0PQj.0.0.49.js → js/mdurl.k9Sl0PQj.0.0.50-internal.0.js} +0 -0
  867. /package/dist/interface/{punycode.js.Dj65hjkv.0.0.49.js → js/punycode.js.Dj65hjkv.0.0.50-internal.0.js} +0 -0
  868. /package/dist/interface/{react-dnd-html5-backend.1HQjlkwI.0.0.49.js → js/react-dnd-html5-backend.1HQjlkwI.0.0.50-internal.0.js} +0 -0
  869. /package/dist/interface/{redux.BFxtlG_c.0.0.49.js → js/redux.BFxtlG_c.0.0.50-internal.0.js} +0 -0
  870. /package/dist/interface/{tslib.9k7AwCpt.0.0.49.js → js/tslib.9k7AwCpt.0.0.50-internal.0.js} +0 -0
  871. /package/dist/interface/{uc.micro.kMc2yuuw.0.0.49.js → js/uc.micro.kMc2yuuw.0.0.50-internal.0.js} +0 -0
  872. /package/dist/server/src/{nats → decoder}/types.js +0 -0
  873. /package/dist/server/src/{nats → rpc}/utils.js +0 -0
@@ -0,0 +1,1732 @@
1
+ import asyncio
2
+ from collections.abc import AsyncGenerator
3
+ from copy import deepcopy
4
+ from datetime import datetime
5
+ from typing import Any, Callable, Optional, Union, cast
6
+
7
+ from cachetools import TTLCache
8
+ 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,
26
+ Camera,
27
+ CameraCapabilitiesObservableObject,
28
+ CameraDetectionSettings,
29
+ CameraDevice,
30
+ CameraDeviceCapability,
31
+ CameraDeviceSource,
32
+ CameraFrameWorkerSettings,
33
+ CameraInformation,
34
+ CameraInput,
35
+ CameraPropertyObservableObject,
36
+ CameraPublicProperties,
37
+ CameraSource,
38
+ CameraStateChangedObject,
39
+ CameraType,
40
+ DecoderFormat,
41
+ DetectionZone,
42
+ DoorbellSetEvent,
43
+ DoorbellState,
44
+ FMP4ConnectionOptions,
45
+ FrameData,
46
+ FrameType,
47
+ ImageOptions,
48
+ LightSetEvent,
49
+ LightState,
50
+ LoggerService,
51
+ MotionDetectionFrame,
52
+ MotionSetEvent,
53
+ MotionState,
54
+ ObjectSetEvent,
55
+ ObjectState,
56
+ ProbeConfig,
57
+ ProbeStream,
58
+ PTZInterface,
59
+ RTSPConnectionOptions,
60
+ RTSPUrlOptions,
61
+ SirenSetEvent,
62
+ SirenState,
63
+ SnapshotInterface,
64
+ StateNames,
65
+ StateValue,
66
+ StreamingInterface,
67
+ WebRTCConnectionOptions,
68
+ )
69
+ from _camera_ui_tools.camera_ui_types import (
70
+ PluginAPI as PluginAPIInterface,
71
+ )
72
+ from _camera_ui_tools.camera_ui_types import (
73
+ VideoFrame as VideoFrameInterface,
74
+ )
75
+ from _camera_ui_tools.camera_ui_types.hybrid_observer import HybridObservable
76
+ from camera.python.classes import transform_labels
77
+ from camera.python.interfaces import CameraInterface
78
+ from camera.python.iou import merge_detections
79
+ from camera.python.polygon import are_detections_valid
80
+ from camera.python.typings import (
81
+ SetValue,
82
+ )
83
+ from camera.python.video_frame import VideoFrame
84
+ from decoder.python.typings import FrameWorkerInterface
85
+ from plugins.runtime.python.namespaces import (
86
+ CameraFrameWorkerPluginNamespaces,
87
+ NamespaceManager,
88
+ )
89
+ from plugins.runtime.python.typings import (
90
+ API_EVENT,
91
+ CameraDeviceInterface,
92
+ CameraInterfaces,
93
+ PluginCapabilities,
94
+ PluginInfo,
95
+ )
96
+
97
+
98
+ class CameraSourceImp(CameraSource):
99
+ def __init__(self, source: CameraInput, parent: Any):
100
+ self.__parent: CameraDeviceProxy = parent
101
+
102
+ self.id = source["_id"]
103
+ self.name = source["name"]
104
+ self.role = source["role"]
105
+ self.useForSnapshot = source["useForSnapshot"]
106
+ self.hotMode = source["hotMode"]
107
+ self.urls = source["urls"]
108
+
109
+ async def snapshot(self, force_new: bool | None = None) -> bytes | None:
110
+ return await self.__parent.snapshot(self.id, force_new)
111
+
112
+ async def probe_stream(
113
+ self, probe_config: Optional[ProbeConfig] = None, refresh: Optional[bool] = False
114
+ ) -> Optional[ProbeStream]:
115
+ return await self.__parent.probe_stream(self.id, probe_config, refresh)
116
+
117
+
118
+ class CameraDeviceSourceImp(CameraSourceImp, CameraDeviceSource):
119
+ def __init__(self, source: CameraInput, parent: Any):
120
+ super().__init__(source, parent)
121
+ self.__parent: CameraDeviceProxy = parent
122
+
123
+ def generate_rtsp_url(self, options: Optional[RTSPUrlOptions]) -> str:
124
+ return build_target_url(self.urls["rtsp"]["base"], options)
125
+
126
+ def create_webrtc_session(self, options: Optional[WebRTCConnectionOptions]) -> None:
127
+ # Todo: Implement
128
+ pass
129
+
130
+ def create_rtsp_session(self, options: Optional[RTSPConnectionOptions]) -> None:
131
+ # Todo: Implement
132
+ pass
133
+
134
+ def create_fmp4_session(self, options: Optional[FMP4ConnectionOptions]) -> None:
135
+ # Todo: Implement
136
+ pass
137
+
138
+
139
+ class CameraDeviceProxy(CameraDevice, Subscribed):
140
+ def __init__(
141
+ self,
142
+ proxy: ClientInstance,
143
+ api: PluginAPIInterface,
144
+ camera: Camera,
145
+ plugin: PluginInfo,
146
+ logger: LoggerService,
147
+ ):
148
+ Subscribed.__init__(self)
149
+
150
+ self.__camera_subject = BehaviorSubject(camera)
151
+ self.__camera_state = BehaviorSubject[bool](False)
152
+ self.__frame_worker_state = BehaviorSubject[bool](False)
153
+ self.__light_state = BehaviorSubject[LightState](self.__get_light_state({"state": False}, True))
154
+ self.__motion_state = BehaviorSubject[MotionState](
155
+ self.__get_motion_state({"detections": [], "state": False}, True)
156
+ )
157
+ self.__audio_state = BehaviorSubject[AudioState](
158
+ self.__get_audio_state({"state": False, "db": 0}, True)
159
+ )
160
+ self.__object_state = BehaviorSubject[ObjectState](self.__get_object_state({"detections": []}, True))
161
+ self.__doorbell_state = BehaviorSubject[DoorbellState](
162
+ self.__get_doorbell_state({"state": False}, True)
163
+ )
164
+ self.__siren_state = BehaviorSubject[SirenState](
165
+ self.__get_siren_state({"state": False, "level": 0}, True)
166
+ )
167
+ self.__battery_state = BehaviorSubject[BatteryState](
168
+ self.__get_battery_state({"level": 100, "charging": False, "lowBattery": False}, True)
169
+ )
170
+ self.__capabilities = BehaviorSubject[list[PluginCapabilities]]([])
171
+
172
+ self.on_connected: HybridObservable[bool] = self.__create_state_observable(self.__camera_state)
173
+ self.on_frameworker_connected: HybridObservable[bool] = self.__create_state_observable(
174
+ self.__frame_worker_state
175
+ )
176
+ self.on_light_switched: HybridObservable[LightState] = self.__create_state_observable(
177
+ self.__light_state
178
+ )
179
+ self.on_motion_detected: HybridObservable[MotionState] = self.__create_state_observable(
180
+ self.__motion_state
181
+ )
182
+ self.on_audio_detected: HybridObservable[AudioState] = self.__create_state_observable(
183
+ self.__audio_state
184
+ )
185
+ self.on_object_detected: HybridObservable[ObjectState] = self.__create_state_observable(
186
+ self.__object_state
187
+ )
188
+ self.on_doorbell_pressed: HybridObservable[DoorbellState] = self.__create_state_observable(
189
+ self.__doorbell_state
190
+ )
191
+ self.on_siren_detected: HybridObservable[SirenState] = self.__create_state_observable(
192
+ self.__siren_state
193
+ )
194
+ self.on_battery_changed: HybridObservable[BatteryState] = self.__create_state_observable(
195
+ self.__battery_state
196
+ )
197
+
198
+ if camera["pluginId"] == "native":
199
+ self.__camera_state.on_next(True)
200
+
201
+ self.logger = logger
202
+
203
+ self.__api = api
204
+ self.__proxy = proxy
205
+ self.__plugin = plugin
206
+ self.__snapshot_cache = TTLCache[str, bytes](maxsize=100, ttl=self.snapshot_ttl)
207
+ self.__namespaces: CameraFrameWorkerPluginNamespaces = {
208
+ **NamespaceManager.camera_namespaces(self.id),
209
+ **NamespaceManager.frame_worker_namespaces(self.id),
210
+ **NamespaceManager.plugin_camera_namespaces(self.__plugin["id"], self.id),
211
+ }
212
+
213
+ self.__initialized = False
214
+ self.__subscription: Optional[SubscriptionWrapper] = None
215
+
216
+ self.__camera_interfaces = CameraInterface(self.__proxy, self.__capabilities, self.id, self.plugin_id)
217
+
218
+ self.__api.once(API_EVENT.SHUTDOWN.value, self.cleanup)
219
+
220
+ self.add_subscriptions(
221
+ self.on_property_change("name").subscribe(self.__on_name_change),
222
+ )
223
+
224
+ @property
225
+ def camera_object(self) -> Camera:
226
+ return deepcopy(self.__camera_subject.value)
227
+
228
+ @property
229
+ def id(self) -> str:
230
+ return self.__camera_subject.value["_id"]
231
+
232
+ @property
233
+ def native_id(self) -> Optional[str]:
234
+ return self.__camera_subject.value.get("nativeId")
235
+
236
+ @property
237
+ def plugin_id(self) -> str:
238
+ return self.__camera_subject.value["pluginId"]
239
+
240
+ @property
241
+ def connected(self) -> bool:
242
+ return self.__camera_state.value or False
243
+
244
+ @property
245
+ def frameworker_connected(self) -> bool:
246
+ return self.__frame_worker_state.value or False
247
+
248
+ @property
249
+ def disabled(self) -> bool:
250
+ return self.__camera_subject.value["disabled"]
251
+
252
+ @property
253
+ def name(self) -> str:
254
+ return self.__camera_subject.value["name"]
255
+
256
+ @property
257
+ def type(self) -> CameraType:
258
+ return self.__camera_subject.value["type"]
259
+
260
+ @property
261
+ def info(self) -> CameraInformation:
262
+ return deepcopy(self.__camera_subject.value["info"])
263
+
264
+ @property
265
+ def is_cloud(self) -> bool:
266
+ return self.__camera_subject.value["isCloud"]
267
+
268
+ @property
269
+ def has_light(self) -> bool:
270
+ return self.has_capability(CameraDeviceCapability.Light)
271
+
272
+ @property
273
+ def has_siren(self) -> bool:
274
+ return self.has_capability(CameraDeviceCapability.Siren)
275
+
276
+ @property
277
+ def has_doorbell(self) -> bool:
278
+ return self.has_capability(CameraDeviceCapability.Doorbell)
279
+
280
+ @property
281
+ def has_battery(self) -> bool:
282
+ return self.has_capability(CameraDeviceCapability.Battery)
283
+
284
+ @property
285
+ def has_audio_detector(self) -> bool:
286
+ return self.has_capability(CameraDeviceCapability.AudioSensor)
287
+
288
+ @property
289
+ def has_motion_detector(self) -> bool:
290
+ return self.has_capability(CameraDeviceCapability.MotionSensor) or self.has_capability(
291
+ CameraDeviceCapability.MotionDetector
292
+ )
293
+
294
+ @property
295
+ def has_object_detector(self) -> bool:
296
+ return self.has_capability(CameraDeviceCapability.ObjectSensor) or self.has_capability(
297
+ CameraDeviceCapability.ObjectDetector
298
+ )
299
+
300
+ @property
301
+ def has_ptz(self) -> bool:
302
+ return self.has_capability(CameraDeviceCapability.PTZ)
303
+
304
+ @property
305
+ def snapshot_ttl(self) -> int:
306
+ return self.__camera_subject.value["snapshotTTL"]
307
+
308
+ @property
309
+ def detection_zones(self) -> list[DetectionZone]:
310
+ return deepcopy(self.__camera_subject.value["detectionZones"])
311
+
312
+ @property
313
+ def detection_settings(self) -> CameraDetectionSettings:
314
+ return deepcopy(self.__camera_subject.value["detectionSettings"])
315
+
316
+ @property
317
+ def frameworker_settings(self) -> CameraFrameWorkerSettings:
318
+ return deepcopy(self.__camera_subject.value["frameWorkerSettings"])
319
+
320
+ @property
321
+ def sources(self) -> list[CameraDeviceSource]:
322
+ sources = deepcopy(self.__camera_subject.value["sources"])
323
+ return [CameraDeviceSourceImp(source, self) for source in sources]
324
+
325
+ @property
326
+ def stream_source(self) -> CameraDeviceSource:
327
+ source = self.high_resolution_source or self.mid_resolution_source or self.low_resolution_source
328
+ return cast(CameraDeviceSource, source)
329
+
330
+ @property
331
+ def snapshot_source(self) -> Optional[CameraSource]:
332
+ snapshot_source = next((source for source in self.sources if source.role == "snapshot"), None)
333
+
334
+ if not snapshot_source:
335
+ snapshot_source = next((source for source in self.sources if source.useForSnapshot), None)
336
+
337
+ return snapshot_source
338
+
339
+ @property
340
+ def high_resolution_source(self) -> Optional[CameraDeviceSource]:
341
+ return next((source for source in self.sources if source.role == "high-resolution"), None)
342
+
343
+ @property
344
+ def mid_resolution_source(self) -> Optional[CameraDeviceSource]:
345
+ return next(
346
+ (source for source in self.sources if "mid-resolution" in source.role == "mid-resolution"), None
347
+ )
348
+
349
+ @property
350
+ def low_resolution_source(self) -> Optional[CameraDeviceSource]:
351
+ return next(
352
+ (source for source in self.sources if "low-resolution" in source.role == "low-resolution"), None
353
+ )
354
+
355
+ @property
356
+ def interfaces(self) -> CameraInterfaces:
357
+ return self.__camera_interfaces
358
+
359
+ async def init(self) -> None:
360
+ if self.__initialized:
361
+ return
362
+
363
+ self.__initialized = True
364
+
365
+ self.__subscription = await self.__proxy.subscribe(
366
+ self.__namespaces["cameraSubject"], self.__on_event_message
367
+ )
368
+
369
+ await self.__proxy.register_rpc_handler(
370
+ self.__namespaces["cameraInterfacesRpc"], self.__camera_interfaces
371
+ )
372
+ await self.__refresh_states()
373
+
374
+ def extend(self, interfaces: PTZInterface | SnapshotInterface | StreamingInterface) -> None:
375
+ self.__camera_interfaces.interfaces = interfaces
376
+
377
+ async def connect(self) -> None:
378
+ camera_controller_proxy = await self.__camera_controller_proxy()
379
+ return await camera_controller_proxy.connect()
380
+
381
+ async def disconnect(self) -> None:
382
+ camera_controller_proxy = await self.__camera_controller_proxy()
383
+ return await camera_controller_proxy.disconnect()
384
+
385
+ @overload # type: ignore[override]
386
+ async def get_frames(
387
+ self, frame_type: Literal["video"], options: Optional[ImageOptions] = None
388
+ ) -> AsyncGenerator[VideoFrameInterface, None]: ...
389
+ @overload
390
+ async def get_frames(
391
+ self, frame_type: Literal["motion"], options: Optional[ImageOptions] = None
392
+ ) -> AsyncGenerator[VideoFrameInterface, None]: ...
393
+ async def get_frames( # type: ignore[misc]
394
+ self, frame_type: FrameType, options: Optional[ImageOptions] = None
395
+ ) -> AsyncGenerator[VideoFrameInterface, None]:
396
+ subscription: Optional[SubscriptionWrapper] = None
397
+ current_resolver: Optional[Callable[[Optional[MotionDetectionFrame]], None]] = None
398
+ cap_subscription: Optional[DisposableBase] = None
399
+ motion_subscription: Optional[DisposableBase] = None
400
+ current_type = frame_type
401
+
402
+ # For motion sensor only
403
+ motion_detected: bool = False
404
+ frameWorkerGenerator: Optional[AsyncGenerator[FrameData, None]] = None
405
+ pendingFramePromise: Optional[asyncio.Task[Any]] = None
406
+
407
+ def is_motion_detector() -> bool:
408
+ return self.has_motion_detector and self.has_capability(CameraDeviceCapability.MotionDetector)
409
+
410
+ def is_motion_sensor_only() -> bool:
411
+ return (
412
+ self.has_motion_detector
413
+ and not self.has_capability(CameraDeviceCapability.MotionDetector)
414
+ and self.has_capability(CameraDeviceCapability.MotionSensor)
415
+ )
416
+
417
+ async def stop_frameworker_generator() -> None:
418
+ nonlocal frameWorkerGenerator, pendingFramePromise
419
+ if frameWorkerGenerator is not None:
420
+ try:
421
+ await frameWorkerGenerator.aclose()
422
+ except: # noqa: E722
423
+ pass
424
+ finally:
425
+ frameWorkerGenerator = None
426
+
427
+ if pendingFramePromise is not None and not pendingFramePromise.done():
428
+ pendingFramePromise.cancel()
429
+ pendingFramePromise = None
430
+
431
+ try:
432
+ frame_worker_proxy = await self.__frame_worker_proxy()
433
+ queue: list[MotionDetectionFrame] = []
434
+
435
+ # Subscribe to motion frames if needed for motion detector
436
+ if current_type == "motion":
437
+
438
+ def on_frame(message: Message[MotionDetectionFrame]) -> None:
439
+ nonlocal current_resolver
440
+ if current_resolver:
441
+ current_resolver(message["data"])
442
+ current_resolver = None
443
+ else:
444
+ queue.append(message["data"])
445
+
446
+ subscription = await self.__proxy.subscribe(
447
+ self.__namespaces["cameraMotionFrameSubject"], on_frame
448
+ )
449
+
450
+ # For motion sensor, subscribe to motion events
451
+ if is_motion_sensor_only():
452
+ # Initialize motion state from current value
453
+ motion_detected = self.__motion_state.value.get("state", False)
454
+
455
+ # Subscribe to motion state changes
456
+ def on_motion_detected(state: MotionState) -> None:
457
+ nonlocal motion_detected, current_resolver
458
+ new_motion_state = state.get("state", False)
459
+ if new_motion_state != motion_detected:
460
+ motion_detected = new_motion_state
461
+
462
+ # If motion just started and we're waiting, resolve to continue the loop
463
+ if motion_detected and current_resolver:
464
+ current_resolver(None)
465
+ current_resolver = None
466
+
467
+ motion_subscription = self.on_motion_detected.subscribe(on_motion_detected)
468
+
469
+ # Subscribe to changes in capabilities
470
+ if frame_type == "motion":
471
+
472
+ async def on_capabilities_change(capabilities: CameraCapabilitiesObservableObject) -> None:
473
+ nonlocal current_type, current_resolver, frameWorkerGenerator, pendingFramePromise
474
+
475
+ new_capabilities: list[CameraDeviceCapability] = capabilities["new_capabilities"]
476
+ old_capabilities: list[CameraDeviceCapability] = capabilities["old_capabilities"]
477
+
478
+ had_motion_detector = CameraDeviceCapability.MotionDetector in old_capabilities
479
+ has_motion_detector_now = CameraDeviceCapability.MotionDetector in new_capabilities
480
+ has_new_motion_detector = is_motion_detector() or is_motion_sensor_only()
481
+
482
+ # Case 1: Currently in motion mode, but no motion detector available anymore
483
+ if current_type == "motion" and not has_new_motion_detector:
484
+ self.logger.trace("Switching to stream mode due to missing motion detector")
485
+
486
+ # Reset any motion sensor state
487
+ await stop_frameworker_generator()
488
+
489
+ # If we're waiting for motion, resolve to restart the loop
490
+ if current_resolver:
491
+ current_resolver(None)
492
+ current_resolver = None
493
+
494
+ # Case 2: Currently in stream mode, but motion detector available now
495
+ elif current_type == "stream" and has_new_motion_detector:
496
+ self.logger.trace("Switching to motion mode due to motion detector being available")
497
+ current_type = frame_type
498
+
499
+ # Case 3: Currently in motion sensor mode, but motion detector available now
500
+ elif current_type == "motion" and not had_motion_detector and has_motion_detector_now:
501
+ self.logger.trace("Switching from motion sensor to motion detector")
502
+
503
+ # Reset any motion sensor state
504
+ await stop_frameworker_generator()
505
+
506
+ # If we're waiting for motion, resolve to restart the loop
507
+ if current_resolver:
508
+ current_resolver(None)
509
+ current_resolver = None
510
+
511
+ # Case 4: Currently using motion detector, but now switching back to motion sensor
512
+ elif (
513
+ current_type == "motion"
514
+ and had_motion_detector
515
+ and not has_motion_detector_now
516
+ and is_motion_sensor_only()
517
+ ):
518
+ self.logger.trace("Switching from motion detector to motion sensor")
519
+ # Reset frameWorkerGenerator so it will be re-initialized for motion sensor mode
520
+ if frameWorkerGenerator is None and current_resolver:
521
+ # If we're waiting for motion (which is likely since motion detector was removed),
522
+ # resolve to restart the loop in built-in mode
523
+ current_resolver(None)
524
+ current_resolver = None
525
+
526
+ cap_subscription = self.on_capabilities_change().asubscribe(on_capabilities_change)
527
+
528
+ async def get_prebuffered_frame(timestamp: int) -> Optional[FrameData]:
529
+ try:
530
+ return await frame_worker_proxy.getPrebufferedFrame(timestamp, options)
531
+ except: # noqa: E722
532
+ return None
533
+
534
+ async def process_motion_frame(motion_frame: MotionDetectionFrame) -> FrameData:
535
+ frame_format = motion_frame["frame"]["info"]["format"]
536
+ frame_width = motion_frame["frame"]["info"]["width"]
537
+ frame_height = motion_frame["frame"]["info"]["height"]
538
+
539
+ requested_format = (
540
+ options.get("format", {}).get("to", frame_format) if options else frame_format
541
+ )
542
+ requested_width = (
543
+ (
544
+ options.get("resize", {}).get("width")
545
+ or options.get("crop", {}).get("width")
546
+ or frame_width
547
+ )
548
+ if options
549
+ else frame_width
550
+ )
551
+ requested_height = (
552
+ (
553
+ options.get("resize", {}).get("height")
554
+ or options.get("crop", {}).get("height")
555
+ or frame_height
556
+ )
557
+ if options
558
+ else frame_height
559
+ )
560
+
561
+ process_frame = (
562
+ requested_format != frame_format
563
+ or requested_width != frame_width
564
+ or requested_height != frame_height
565
+ )
566
+
567
+ if process_frame and options:
568
+ prebuffered_frame = await get_prebuffered_frame(motion_frame["frame"]["timestamp"])
569
+ if prebuffered_frame:
570
+ return prebuffered_frame
571
+ else:
572
+ format: Union[DecoderFormat, Literal["rgba", "gray"]] = (
573
+ "rgb24" if frame_format == "rgb" else frame_format
574
+ )
575
+ frame_data = await frame_worker_proxy.processFrame(
576
+ motion_frame["frame"]["data"], frame_width, frame_height, format, options
577
+ )
578
+ return {
579
+ "data": frame_data["image"],
580
+ "info": frame_data["info"],
581
+ "metadata": {
582
+ "format": motion_frame["frame"]["metadata"]["format"],
583
+ "frameSize": motion_frame["frame"]["metadata"]["frameSize"],
584
+ "height": frame_data["info"]["height"],
585
+ "width": frame_data["info"]["width"],
586
+ "origHeight": motion_frame["frame"]["info"]["height"],
587
+ "origWidth": motion_frame["frame"]["info"]["width"],
588
+ },
589
+ "timestamp": motion_frame["frame"]["timestamp"],
590
+ }
591
+ else:
592
+ return motion_frame["frame"]
593
+
594
+ while self.__initialized:
595
+ try:
596
+ # Handle motion detector
597
+ if current_type == "motion" and is_motion_detector():
598
+ if queue:
599
+ motion_frame = queue.pop(0)
600
+ motion_frame["frame"] = await process_motion_frame(motion_frame)
601
+ yield VideoFrame(
602
+ motion_frame["frame"],
603
+ self.__namespaces["frameWorkerChildRpc"],
604
+ self.__proxy,
605
+ motion_frame["state"],
606
+ )
607
+ else:
608
+ future: asyncio.Future[Union[MotionDetectionFrame, None]] = asyncio.Future()
609
+ current_resolver = future.set_result
610
+ motion_frame_exists = await future
611
+
612
+ if not motion_frame_exists:
613
+ current_type = "stream"
614
+ continue
615
+
616
+ motion_frame = motion_frame_exists
617
+ motion_frame["frame"] = await process_motion_frame(motion_frame)
618
+ yield VideoFrame(
619
+ motion_frame["frame"],
620
+ self.__namespaces["frameWorkerChildRpc"],
621
+ self.__proxy,
622
+ motion_frame["state"],
623
+ )
624
+ # Handle motion sensor
625
+ elif current_type == "motion" and is_motion_sensor_only():
626
+ # Initialize frame generator immediately if needed
627
+ if frameWorkerGenerator is None:
628
+ self.logger.trace("Initializing frame worker generator for motion sensor")
629
+ frameWorkerGenerator = frame_worker_proxy.generateFrames(options)
630
+
631
+ # Execute first next() to establish the connection
632
+ try:
633
+ # Discard the first frame - we just want to establish the connection
634
+ await frameWorkerGenerator.__anext__()
635
+ except Exception as e:
636
+ self.logger.warn(f"Failed to initialize frame worker generator: {str(e)}")
637
+ frameWorkerGenerator = None
638
+ current_type = "stream"
639
+ continue
640
+
641
+ # If no motion detected, wait for it
642
+ if not motion_detected:
643
+ future = asyncio.Future()
644
+ current_resolver = future.set_result
645
+ await future
646
+ continue
647
+
648
+ # Motion is detected - get the most current frame
649
+ try:
650
+ frame = await frameWorkerGenerator.__anext__()
651
+ except StopAsyncIteration:
652
+ # Generator ended, reset and switch to stream
653
+ frameWorkerGenerator = None
654
+ current_type = "stream"
655
+ continue
656
+
657
+ # Create a synthetic motion state for the frame
658
+ motion_state: MotionSetEvent = {
659
+ "state": True,
660
+ "detections": self.__motion_state.value.get("detections", []),
661
+ }
662
+
663
+ # Yield the frame with motion state
664
+ yield VideoFrame(
665
+ frame, self.__namespaces["frameWorkerChildRpc"], self.__proxy, motion_state
666
+ )
667
+ else:
668
+ # Handle regular streaming
669
+ # Reset motion sensor resources if switching modes
670
+ if frameWorkerGenerator is not None:
671
+ frameWorkerGenerator = None
672
+ pendingFramePromise = None
673
+
674
+ # Regular stream mode
675
+ async for frame in frame_worker_proxy.generateFrames(options):
676
+ if (current_type == "motion" and is_motion_detector()) or (
677
+ current_type == "motion" and is_motion_sensor_only()
678
+ ):
679
+ break # Break stream loop to switch back to motion mode
680
+ yield VideoFrame(frame, self.__namespaces["frameWorkerChildRpc"], self.__proxy)
681
+
682
+ except (StopAsyncIteration, GeneratorExit):
683
+ self.logger.trace("Stopping frame generator")
684
+ break
685
+
686
+ except Exception as e:
687
+ if not self.__initialized:
688
+ return
689
+
690
+ raise e
691
+
692
+ finally:
693
+ if subscription:
694
+ await subscription.unsubscribe()
695
+ if cap_subscription:
696
+ cap_subscription.dispose()
697
+ if motion_subscription:
698
+ motion_subscription.dispose()
699
+ if pendingFramePromise and not pendingFramePromise.done():
700
+ pendingFramePromise.cancel()
701
+
702
+ def add_capabilities(self, capabilities: list[CameraDeviceCapability]) -> None:
703
+ new_capabilities: list[CameraDeviceCapability] = []
704
+
705
+ for capability in capabilities:
706
+ if not self.has_capability(capability):
707
+ new_capabilities.append(capability)
708
+
709
+ if new_capabilities:
710
+ all_capabilities = deepcopy(self.__capabilities.value)
711
+ plugin_related_capabilities = next(
712
+ (cap for cap in all_capabilities if cap["pluginId"] == self.__plugin["id"]), None
713
+ )
714
+
715
+ if plugin_related_capabilities:
716
+ plugin_related_capabilities["capabilities"].extend(new_capabilities)
717
+ else:
718
+ all_capabilities.append({"pluginId": self.__plugin["id"], "capabilities": new_capabilities})
719
+
720
+ self.__capabilities.on_next(all_capabilities)
721
+
722
+ async def updateCapabilities() -> None:
723
+ try:
724
+ camera_controller_proxy = await self.__camera_controller_proxy()
725
+ await camera_controller_proxy.addPluginCapabilities(self.__plugin["id"], new_capabilities)
726
+ except asyncio.CancelledError:
727
+ # Ignore cancellation errors
728
+ pass
729
+ # except Exception as e:
730
+ # self.logger.error("Failed to add capabilities:", e)
731
+ except: # noqa: E722
732
+ pass
733
+
734
+ asyncio.create_task(updateCapabilities())
735
+
736
+ def remove_capabilities(self, capabilities: list[CameraDeviceCapability]) -> None:
737
+ all_capabilities = deepcopy(self.__capabilities.value)
738
+ plugin_related_capabilities = next(
739
+ (cap for cap in all_capabilities if cap["pluginId"] == self.__plugin["id"]), None
740
+ )
741
+
742
+ if plugin_related_capabilities:
743
+ plugin_related_capabilities["capabilities"] = (
744
+ []
745
+ if len(capabilities) == 0
746
+ else [cap for cap in plugin_related_capabilities["capabilities"] if cap not in capabilities]
747
+ )
748
+
749
+ if not plugin_related_capabilities["capabilities"]:
750
+ all_capabilities.remove(plugin_related_capabilities)
751
+
752
+ self.__capabilities.on_next(all_capabilities)
753
+
754
+ async def updateCapabilities() -> None:
755
+ try:
756
+ camera_controller_proxy = await self.__camera_controller_proxy()
757
+ await camera_controller_proxy.removePluginCapabilities(self.__plugin["id"], capabilities)
758
+ except Exception as e:
759
+ if not self.__initialized:
760
+ return
761
+
762
+ self.logger.error("Failed to remove capabilities:", e)
763
+
764
+ asyncio.create_task(updateCapabilities())
765
+
766
+ def get_capabilities(self) -> list[CameraDeviceCapability]:
767
+ capabilities: list[CameraDeviceCapability] = []
768
+ for capability in self.__capabilities.value:
769
+ if capability["capabilities"]:
770
+ capabilities.extend(capability["capabilities"])
771
+
772
+ return capabilities
773
+
774
+ def has_capability(self, capability: CameraDeviceCapability) -> bool:
775
+ capabilities = self.get_capabilities()
776
+ return capability in capabilities
777
+
778
+ @overload
779
+ def get_value(self, state_name: Literal["light"]) -> LightState: ...
780
+ @overload
781
+ def get_value(self, state_name: Literal["motion"]) -> MotionState: ...
782
+ @overload
783
+ def get_value(self, state_name: Literal["audio"]) -> AudioState: ...
784
+ @overload
785
+ def get_value(self, state_name: Literal["object"]) -> ObjectState: ...
786
+ @overload
787
+ def get_value(self, state_name: Literal["doorbell"]) -> DoorbellState: ...
788
+ @overload
789
+ def get_value(self, state_name: Literal["siren"]) -> SirenState: ...
790
+ @overload
791
+ def get_value(self, state_name: Literal["battery"]) -> BatteryState: ...
792
+ def get_value(
793
+ self, state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"]
794
+ ) -> Union[
795
+ LightState,
796
+ MotionState,
797
+ AudioState,
798
+ ObjectState,
799
+ DoorbellState,
800
+ SirenState,
801
+ BatteryState,
802
+ ]:
803
+ if state_name == "light":
804
+ return deepcopy(self.__light_state.value)
805
+ elif state_name == "motion":
806
+ return deepcopy(self.__motion_state.value)
807
+ elif state_name == "audio":
808
+ return deepcopy(self.__audio_state.value)
809
+ elif state_name == "object":
810
+ return deepcopy(self.__object_state.value)
811
+ elif state_name == "doorbell":
812
+ return deepcopy(self.__doorbell_state.value)
813
+ elif state_name == "siren":
814
+ return deepcopy(self.__siren_state.value)
815
+ elif state_name == "battery":
816
+ return deepcopy(self.__battery_state.value)
817
+ else:
818
+ raise Exception(f"Unknown state: {state_name}")
819
+
820
+ @overload
821
+ async def update_state(
822
+ self,
823
+ state_name: Literal["light"],
824
+ event_data: LightSetEvent,
825
+ ) -> None: ...
826
+ @overload
827
+ async def update_state(
828
+ self,
829
+ state_name: Literal["motion"],
830
+ event_data: MotionSetEvent,
831
+ frame: Optional[VideoFrameInterface] = None,
832
+ ) -> None: ...
833
+ @overload
834
+ async def update_state(
835
+ self,
836
+ state_name: Literal["audio"],
837
+ event_data: AudioSetEvent,
838
+ ) -> None: ...
839
+ @overload
840
+ async def update_state(
841
+ self,
842
+ state_name: Literal["object"],
843
+ event_data: ObjectSetEvent,
844
+ ) -> None: ...
845
+ @overload
846
+ async def update_state(
847
+ self,
848
+ state_name: Literal["doorbell"],
849
+ event_data: DoorbellSetEvent,
850
+ ) -> None: ...
851
+ @overload
852
+ async def update_state(
853
+ self,
854
+ state_name: Literal["siren"],
855
+ event_data: SirenSetEvent,
856
+ ) -> None: ...
857
+ @overload
858
+ async def update_state(
859
+ self,
860
+ state_name: Literal["battery"],
861
+ event_data: BatterySetEvent,
862
+ ) -> None: ...
863
+ async def update_state(
864
+ self, state_name: Any, event_data: Any, frame: Optional[VideoFrameInterface] = None
865
+ ) -> None:
866
+ try:
867
+ can_update = self.__can_update_state_internal(state_name)
868
+ if not can_update:
869
+ self.logger.warn(f"State '{state_name}' can only be updated by the corresponding plugin.")
870
+ return
871
+
872
+ changed, event = cast(tuple[bool, Any], self.__check_state_internal(state_name, event_data))
873
+
874
+ if not changed:
875
+ return
876
+
877
+ self.__update_state_internal(state_name, event, True)
878
+
879
+ if state_name == "motion" and frame and self.has_object_detector:
880
+ motion_event = cast(MotionSetEvent, event)
881
+ if motion_event["state"] and "detections" in motion_event and motion_event["detections"]:
882
+ motion_frame: MotionDetectionFrame = {
883
+ "frame": {
884
+ "data": frame.data,
885
+ "info": frame.info,
886
+ "metadata": frame.metadata,
887
+ "timestamp": int(datetime.now().timestamp() * 1000),
888
+ },
889
+ "state": motion_event,
890
+ }
891
+
892
+ await self.__proxy.publish(self.__namespaces["cameraMotionFrameSubject"], motion_frame)
893
+
894
+ camera_controller_proxy = await self.__camera_controller_proxy()
895
+ await camera_controller_proxy.updateState(state_name, event)
896
+ except Exception as e:
897
+ if not self.__initialized:
898
+ return
899
+
900
+ raise e
901
+
902
+ @overload
903
+ def on_state_change(
904
+ self, state_name: Literal["light"]
905
+ ) -> HybridObservable[CameraStateChangedObject[LightState]]: ...
906
+ @overload
907
+ def on_state_change(
908
+ self, state_name: Literal["motion"]
909
+ ) -> HybridObservable[CameraStateChangedObject[MotionState]]: ...
910
+ @overload
911
+ def on_state_change(
912
+ self, state_name: Literal["audio"]
913
+ ) -> HybridObservable[CameraStateChangedObject[AudioState]]: ...
914
+ @overload
915
+ def on_state_change(
916
+ self, state_name: Literal["doorbell"]
917
+ ) -> HybridObservable[CameraStateChangedObject[DoorbellState]]: ...
918
+ @overload
919
+ def on_state_change(
920
+ self, state_name: Literal["siren"]
921
+ ) -> HybridObservable[CameraStateChangedObject[SirenState]]: ...
922
+ @overload
923
+ def on_state_change(
924
+ self, state_name: Literal["battery"]
925
+ ) -> HybridObservable[CameraStateChangedObject[BatteryState]]: ...
926
+ @overload
927
+ def on_state_change(
928
+ self, state_name: Literal["object"]
929
+ ) -> HybridObservable[CameraStateChangedObject[ObjectState]]: ...
930
+ def on_state_change(self, state_name: Any) -> Any:
931
+ state: Union[BehaviorSubject[StateValue], None] = getattr(self, f"{state_name}_state", None)
932
+
933
+ if not state:
934
+ raise Exception(f"{state_name}_state not found")
935
+
936
+ def filter_fn(states: tuple[StateValue, StateValue]) -> bool:
937
+ old_state = states[0]
938
+ new_state = states[1]
939
+ return self.__state_changed(old_state, new_state, state_name)
940
+
941
+ def map_fn(states: tuple[StateValue, StateValue]) -> CameraStateChangedObject[StateValue]:
942
+ return {"old_state": states[0], "new_state": states[1]}
943
+
944
+ return HybridObservable(
945
+ state.pipe(
946
+ ops.pairwise(),
947
+ ops.filter(filter_fn),
948
+ ops.map(map_fn),
949
+ ops.share(),
950
+ )
951
+ )
952
+
953
+ def on_property_change(
954
+ self, property: Union[CameraPublicProperties, list[CameraPublicProperties]]
955
+ ) -> HybridObservable[CameraPropertyObservableObject]:
956
+ def map_fn(
957
+ cameras: tuple[Camera, Camera],
958
+ ) -> list[Any]:
959
+ properties: list[Any] = property if isinstance(property, list) else [property]
960
+
961
+ return [
962
+ {
963
+ "property": prop,
964
+ "old_state": cameras[0].get(prop),
965
+ "new_state": cameras[1].get(prop),
966
+ }
967
+ for prop in properties
968
+ ]
969
+
970
+ def filter_fn(
971
+ camera: CameraPropertyObservableObject,
972
+ ) -> bool:
973
+ return (
974
+ DeepDiff(
975
+ camera["old_state"],
976
+ camera["new_state"],
977
+ ignore_order=True,
978
+ )
979
+ != {}
980
+ )
981
+
982
+ return HybridObservable(
983
+ self.__camera_subject.pipe(
984
+ ops.pairwise(),
985
+ ops.flat_map(map_fn),
986
+ ops.filter(filter_fn),
987
+ ops.share(),
988
+ )
989
+ )
990
+
991
+ def on_capabilities_change(self) -> HybridObservable[CameraCapabilitiesObservableObject]:
992
+ def filter_fn(
993
+ capabilities: tuple[list[PluginCapabilities], list[PluginCapabilities]],
994
+ ) -> bool:
995
+ return (
996
+ DeepDiff(
997
+ capabilities[0],
998
+ capabilities[1],
999
+ ignore_order=True,
1000
+ use_enum_value=True,
1001
+ )
1002
+ != {}
1003
+ )
1004
+
1005
+ def map_fn(
1006
+ capabilities: tuple[list[PluginCapabilities], list[PluginCapabilities]],
1007
+ ) -> CameraCapabilitiesObservableObject:
1008
+ old_capabilities: list[CameraDeviceCapability] = []
1009
+ new_capabilities: list[CameraDeviceCapability] = []
1010
+
1011
+ for capability in capabilities[0]:
1012
+ if capability["capabilities"]:
1013
+ old_capabilities.extend(capability["capabilities"])
1014
+
1015
+ for capability in capabilities[1]:
1016
+ if capability["capabilities"]:
1017
+ new_capabilities.extend(capability["capabilities"])
1018
+
1019
+ return {
1020
+ "old_capabilities": old_capabilities,
1021
+ "new_capabilities": new_capabilities,
1022
+ }
1023
+
1024
+ return HybridObservable(
1025
+ self.__capabilities.pipe(
1026
+ ops.pairwise(),
1027
+ ops.filter(filter_fn),
1028
+ ops.map(map_fn),
1029
+ ops.share(),
1030
+ )
1031
+ )
1032
+
1033
+ async def snapshot(self, source_id: str, force_new: Optional[bool] = None) -> Optional[bytes]:
1034
+ from_cache = self.__snapshot_cache.get(source_id) if source_id in self.__snapshot_cache else None
1035
+ if from_cache and not force_new:
1036
+ return from_cache
1037
+ camera_controller_proxy = await self.__camera_controller_proxy()
1038
+ snapshot = await camera_controller_proxy.snapshot(source_id, force_new)
1039
+ if snapshot and len(snapshot) > 0:
1040
+ self.__snapshot_cache[source_id] = snapshot
1041
+ return snapshot
1042
+
1043
+ return None
1044
+
1045
+ async def probe_stream(
1046
+ self, source_id: str, probe_config: Optional[ProbeConfig] = None, refresh: Optional[bool] = False
1047
+ ) -> Optional[ProbeStream]:
1048
+ camera_controller_proxy = await self.__camera_controller_proxy()
1049
+ return await camera_controller_proxy.probeStream(source_id, probe_config, refresh)
1050
+
1051
+ async def cleanup(self) -> None:
1052
+ self.__initialized = False
1053
+ self.__remove_all_listeners()
1054
+ self.unsubscribe()
1055
+ self.__api.remove_listener(API_EVENT.SHUTDOWN.value, self.cleanup)
1056
+ if self.__subscription:
1057
+ await self.__subscription.unsubscribe()
1058
+ self.__subscription = None
1059
+ await self.__disconnect_rpc()
1060
+
1061
+ @overload
1062
+ def __check_state_internal(
1063
+ self,
1064
+ state_name: Literal["light"],
1065
+ event_data: LightSetEvent,
1066
+ skip_detections_check: Optional[bool] = None,
1067
+ ) -> tuple[bool, LightState]: ...
1068
+ @overload
1069
+ def __check_state_internal(
1070
+ self,
1071
+ state_name: Literal["motion"],
1072
+ event_data: MotionSetEvent,
1073
+ skip_detections_check: Optional[bool] = None,
1074
+ ) -> tuple[bool, MotionState]: ...
1075
+ @overload
1076
+ def __check_state_internal(
1077
+ self,
1078
+ state_name: Literal["audio"],
1079
+ event_data: AudioSetEvent,
1080
+ skip_detections_check: Optional[bool] = None,
1081
+ ) -> tuple[bool, AudioState]: ...
1082
+ @overload
1083
+ def __check_state_internal(
1084
+ self,
1085
+ state_name: Literal["object"],
1086
+ event_data: ObjectSetEvent,
1087
+ skip_detections_check: Optional[bool] = None,
1088
+ ) -> tuple[bool, ObjectState]: ...
1089
+ @overload
1090
+ def __check_state_internal(
1091
+ self,
1092
+ state_name: Literal["doorbell"],
1093
+ event_data: DoorbellSetEvent,
1094
+ skip_detections_check: Optional[bool] = None,
1095
+ ) -> tuple[bool, DoorbellState]: ...
1096
+ @overload
1097
+ def __check_state_internal(
1098
+ self,
1099
+ state_name: Literal["siren"],
1100
+ event_data: SirenSetEvent,
1101
+ skip_detections_check: Optional[bool] = None,
1102
+ ) -> tuple[bool, SirenState]: ...
1103
+ @overload
1104
+ def __check_state_internal(
1105
+ self,
1106
+ state_name: Literal["battery"],
1107
+ event_data: BatterySetEvent,
1108
+ skip_detections_check: Optional[bool] = None,
1109
+ ) -> tuple[bool, BatteryState]: ...
1110
+ def __check_state_internal(
1111
+ self,
1112
+ state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
1113
+ event_data: Union[
1114
+ LightSetEvent,
1115
+ MotionSetEvent,
1116
+ AudioSetEvent,
1117
+ ObjectSetEvent,
1118
+ DoorbellSetEvent,
1119
+ SirenSetEvent,
1120
+ BatterySetEvent,
1121
+ ],
1122
+ skip_detections_check: Optional[bool] = None,
1123
+ ) -> tuple[
1124
+ bool,
1125
+ Union[
1126
+ LightState,
1127
+ MotionState,
1128
+ AudioState,
1129
+ ObjectState,
1130
+ DoorbellState,
1131
+ SirenState,
1132
+ BatteryState,
1133
+ ],
1134
+ ]:
1135
+ changed = False
1136
+ target_state: Optional[StateValue] = None
1137
+
1138
+ if state_name == "audio":
1139
+ audio_event = cast(AudioSetEvent, event_data)
1140
+ target_state = self.__get_audio_state(audio_event)
1141
+ changed = self.__state_changed(self.get_value("audio"), target_state, "audio")
1142
+
1143
+ elif state_name == "light":
1144
+ light_event = cast(LightSetEvent, event_data)
1145
+ target_state = self.__get_light_state(light_event)
1146
+ changed = self.__state_changed(self.get_value("light"), target_state, "light")
1147
+
1148
+ elif state_name == "motion":
1149
+ motion_event = cast(MotionSetEvent, event_data)
1150
+
1151
+ if not motion_event["state"]:
1152
+ motion_event["detections"] = []
1153
+
1154
+ if not skip_detections_check and "detections" in motion_event and motion_event["detections"]:
1155
+ has_detections = len(motion_event["detections"]) > 0
1156
+ motion_event["detections"] = transform_labels(motion_event["detections"])
1157
+ motion_event["detections"] = merge_detections(motion_event["detections"])
1158
+ motion_event["detections"] = are_detections_valid(
1159
+ motion_event["detections"], self.detection_zones, self.detection_settings
1160
+ )
1161
+ if has_detections and len(motion_event["detections"]) == 0:
1162
+ motion_event["state"] = False
1163
+
1164
+ # fix bounding box type to to tuple, do we need?
1165
+ if "detections" in motion_event and motion_event["detections"]:
1166
+ for det in motion_event["detections"]:
1167
+ det["boundingBox"] = cast(tuple[int, int, int, int], tuple(det["boundingBox"]))
1168
+ det["confidence"] = float(det["confidence"])
1169
+
1170
+ target_state = self.__get_motion_state(motion_event)
1171
+ changed = self.__state_changed(self.get_value("motion"), target_state, "motion", True)
1172
+
1173
+ elif state_name == "object":
1174
+ object_event = cast(ObjectSetEvent, event_data)
1175
+
1176
+ if not skip_detections_check:
1177
+ object_event["detections"] = transform_labels(object_event["detections"])
1178
+ object_event["detections"] = merge_detections(object_event["detections"])
1179
+ object_event["detections"] = are_detections_valid(
1180
+ object_event["detections"], self.detection_zones, self.detection_settings
1181
+ )
1182
+
1183
+ # fix bounding box type to to tuple
1184
+ for det in object_event["detections"]:
1185
+ det["boundingBox"] = cast(BoundingBox, tuple(det["boundingBox"]))
1186
+ det["confidence"] = float(det["confidence"])
1187
+
1188
+ target_state = self.__get_object_state(object_event)
1189
+ changed = self.__state_changed(self.get_value("object"), target_state, "object")
1190
+
1191
+ elif state_name == "doorbell":
1192
+ doorbell_event = cast(DoorbellSetEvent, event_data)
1193
+ target_state = self.__get_doorbell_state(doorbell_event)
1194
+ changed = self.__state_changed(self.get_value("doorbell"), target_state, "doorbell")
1195
+
1196
+ elif state_name == "siren":
1197
+ siren_event = cast(SirenSetEvent, event_data)
1198
+ target_state = self.__get_siren_state(siren_event)
1199
+ changed = self.__state_changed(self.get_value("siren"), target_state, "siren")
1200
+
1201
+ elif state_name == "battery":
1202
+ battery_event = cast(BatterySetEvent, event_data)
1203
+ target_state = self.__get_battery_state(battery_event)
1204
+ changed = self.__state_changed(self.get_value("battery"), target_state, "battery")
1205
+
1206
+ else:
1207
+ raise Exception(f"Unknown state: {state_name}")
1208
+
1209
+ return changed, target_state
1210
+
1211
+ def __can_update_state_internal(self, state_name: StateNames) -> bool:
1212
+ if state_name == "audio":
1213
+ audio_sensor_capability = next(
1214
+ (
1215
+ cap
1216
+ for cap in self.__capabilities.value
1217
+ if CameraDeviceCapability.AudioSensor in cap["capabilities"]
1218
+ ),
1219
+ None,
1220
+ )
1221
+ return bool(
1222
+ audio_sensor_capability and audio_sensor_capability["pluginId"] == self.__plugin["id"]
1223
+ )
1224
+
1225
+ elif state_name == "motion":
1226
+ motion_sensor_capability = next(
1227
+ (
1228
+ cap
1229
+ for cap in self.__capabilities.value
1230
+ if CameraDeviceCapability.MotionSensor in cap["capabilities"]
1231
+ ),
1232
+ None,
1233
+ )
1234
+ motion_detector_capability = next(
1235
+ (
1236
+ cap
1237
+ for cap in self.__capabilities.value
1238
+ if CameraDeviceCapability.MotionDetector in cap["capabilities"]
1239
+ ),
1240
+ None,
1241
+ )
1242
+ return bool(
1243
+ (motion_sensor_capability and motion_sensor_capability["pluginId"] == self.__plugin["id"])
1244
+ or (
1245
+ motion_detector_capability
1246
+ and motion_detector_capability["pluginId"] == self.__plugin["id"]
1247
+ )
1248
+ )
1249
+
1250
+ elif state_name == "object":
1251
+ object_sensor_capability = next(
1252
+ (
1253
+ cap
1254
+ for cap in self.__capabilities.value
1255
+ if CameraDeviceCapability.ObjectSensor in cap["capabilities"]
1256
+ ),
1257
+ None,
1258
+ )
1259
+ object_detector_capability = next(
1260
+ (
1261
+ cap
1262
+ for cap in self.__capabilities.value
1263
+ if CameraDeviceCapability.ObjectDetector in cap["capabilities"]
1264
+ ),
1265
+ None,
1266
+ )
1267
+ return bool(
1268
+ (object_sensor_capability and object_sensor_capability["pluginId"] == self.__plugin["id"])
1269
+ or (
1270
+ object_detector_capability
1271
+ and object_detector_capability["pluginId"] == self.__plugin["id"]
1272
+ )
1273
+ )
1274
+
1275
+ elif state_name == "light":
1276
+ light_capability = next(
1277
+ (
1278
+ cap
1279
+ for cap in self.__capabilities.value
1280
+ if CameraDeviceCapability.Light in cap["capabilities"]
1281
+ ),
1282
+ None,
1283
+ )
1284
+ return bool(light_capability and light_capability["pluginId"] == self.__plugin["id"])
1285
+
1286
+ elif state_name == "doorbell":
1287
+ doorbell_capability = next(
1288
+ (
1289
+ cap
1290
+ for cap in self.__capabilities.value
1291
+ if CameraDeviceCapability.Doorbell in cap["capabilities"]
1292
+ ),
1293
+ None,
1294
+ )
1295
+ return bool(doorbell_capability and doorbell_capability["pluginId"] == self.__plugin["id"])
1296
+
1297
+ elif state_name == "siren":
1298
+ siren_capability = next(
1299
+ (
1300
+ cap
1301
+ for cap in self.__capabilities.value
1302
+ if CameraDeviceCapability.Siren in cap["capabilities"]
1303
+ ),
1304
+ None,
1305
+ )
1306
+ return bool(siren_capability and siren_capability["pluginId"] == self.__plugin["id"])
1307
+
1308
+ elif state_name == "battery":
1309
+ battery_capability = next(
1310
+ (
1311
+ cap
1312
+ for cap in self.__capabilities.value
1313
+ if CameraDeviceCapability.Battery in cap["capabilities"]
1314
+ ),
1315
+ None,
1316
+ )
1317
+ return bool(battery_capability and battery_capability["pluginId"] == self.__plugin["id"])
1318
+
1319
+ @overload
1320
+ def __update_state_internal(
1321
+ self,
1322
+ state_name: Literal["light"],
1323
+ event_data: LightSetEvent,
1324
+ skip_check: Optional[bool] = None,
1325
+ skip_detections_check: Optional[bool] = None,
1326
+ ) -> None: ...
1327
+ @overload
1328
+ def __update_state_internal(
1329
+ self,
1330
+ state_name: Literal["motion"],
1331
+ event_data: MotionSetEvent,
1332
+ skip_check: Optional[bool] = None,
1333
+ skip_detections_check: Optional[bool] = None,
1334
+ ) -> None: ...
1335
+ @overload
1336
+ def __update_state_internal(
1337
+ self,
1338
+ state_name: Literal["audio"],
1339
+ event_data: AudioSetEvent,
1340
+ skip_check: Optional[bool] = None,
1341
+ skip_detections_check: Optional[bool] = None,
1342
+ ) -> None: ...
1343
+ @overload
1344
+ def __update_state_internal(
1345
+ self,
1346
+ state_name: Literal["object"],
1347
+ event_data: ObjectSetEvent,
1348
+ skip_check: Optional[bool] = None,
1349
+ skip_detections_check: Optional[bool] = None,
1350
+ ) -> None: ...
1351
+ @overload
1352
+ def __update_state_internal(
1353
+ self,
1354
+ state_name: Literal["doorbell"],
1355
+ event_data: DoorbellSetEvent,
1356
+ skip_check: Optional[bool] = None,
1357
+ skip_detections_check: Optional[bool] = None,
1358
+ ) -> None: ...
1359
+ @overload
1360
+ def __update_state_internal(
1361
+ self,
1362
+ state_name: Literal["siren"],
1363
+ event_data: SirenSetEvent,
1364
+ skip_check: Optional[bool] = None,
1365
+ skip_detections_check: Optional[bool] = None,
1366
+ ) -> None: ...
1367
+ @overload
1368
+ def __update_state_internal(
1369
+ self,
1370
+ state_name: Literal["battery"],
1371
+ event_data: BatterySetEvent,
1372
+ skip_check: Optional[bool] = None,
1373
+ skip_detections_check: Optional[bool] = None,
1374
+ ) -> None: ...
1375
+ def __update_state_internal(
1376
+ self,
1377
+ state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
1378
+ event_data: Union[
1379
+ LightSetEvent,
1380
+ MotionSetEvent,
1381
+ AudioSetEvent,
1382
+ ObjectSetEvent,
1383
+ DoorbellSetEvent,
1384
+ SirenSetEvent,
1385
+ BatterySetEvent,
1386
+ ],
1387
+ skip_check: Optional[bool] = None,
1388
+ skip_detections_check: Optional[bool] = None,
1389
+ ) -> None:
1390
+ if skip_check:
1391
+ changed = True
1392
+ event = event_data
1393
+ else:
1394
+ changed, event = cast(
1395
+ tuple[
1396
+ bool,
1397
+ Union[
1398
+ LightSetEvent,
1399
+ MotionSetEvent,
1400
+ AudioSetEvent,
1401
+ ObjectSetEvent,
1402
+ DoorbellSetEvent,
1403
+ SirenSetEvent,
1404
+ BatterySetEvent,
1405
+ ],
1406
+ ],
1407
+ self.__check_state_internal(
1408
+ cast(Any, state_name), cast(Any, event_data), skip_detections_check
1409
+ ),
1410
+ )
1411
+
1412
+ if not changed:
1413
+ return
1414
+
1415
+ if state_name == "light":
1416
+ self.__light_state.on_next(self.__get_light_state(cast(LightSetEvent, event)))
1417
+ elif state_name == "motion":
1418
+ self.__motion_state.on_next(self.__get_motion_state(cast(MotionSetEvent, event)))
1419
+ elif state_name == "audio":
1420
+ self.__audio_state.on_next(self.__get_audio_state(cast(AudioSetEvent, event)))
1421
+ elif state_name == "object":
1422
+ self.__object_state.on_next(self.__get_object_state(cast(ObjectSetEvent, event)))
1423
+ elif state_name == "doorbell":
1424
+ self.__doorbell_state.on_next(self.__get_doorbell_state(cast(DoorbellSetEvent, event)))
1425
+ elif state_name == "siren":
1426
+ self.__siren_state.on_next(self.__get_siren_state(cast(SirenSetEvent, event)))
1427
+ elif state_name == "battery" and self.has_battery:
1428
+ self.__battery_state.on_next(self.__get_battery_state(cast(BatterySetEvent, event)))
1429
+
1430
+ def __create_state_observable(self, state_subject: BehaviorSubject[Any]) -> HybridObservable[Any]:
1431
+ return HybridObservable(state_subject.pipe(ops.distinct_until_changed(), ops.share()))
1432
+
1433
+ def __update_camera(self, camera: Camera) -> None:
1434
+ if camera["snapshotTTL"] != self.snapshot_ttl:
1435
+ self.__snapshot_cache.clear()
1436
+
1437
+ self.__camera_subject.on_next(camera)
1438
+
1439
+ def __update_camera_state(self, state: bool) -> None:
1440
+ self.__camera_state.on_next(state)
1441
+
1442
+ def __update_frameworker_state(self, state: bool) -> None:
1443
+ self.__frame_worker_state.on_next(state)
1444
+
1445
+ def __update_capabilities(self, capabilities: list[PluginCapabilities]) -> None:
1446
+ converted_capabilities: list[PluginCapabilities] = []
1447
+
1448
+ for plugin_cap in capabilities:
1449
+ converted_plugin_cap = plugin_cap.copy()
1450
+ converted_plugin_cap["capabilities"] = [
1451
+ CameraDeviceCapability(cap_str) for cap_str in plugin_cap["capabilities"]
1452
+ ]
1453
+ converted_capabilities.append(converted_plugin_cap)
1454
+
1455
+ self.__capabilities.on_next(converted_capabilities)
1456
+
1457
+ async def __refresh_states(self) -> None:
1458
+ camera_controller_proxy = await self.__camera_controller_proxy()
1459
+ response = await camera_controller_proxy.refreshStates()
1460
+
1461
+ self.__update_camera(response["camera"])
1462
+ self.__update_camera_state(response["cameraState"])
1463
+ self.__update_frameworker_state(response["frameWorkerState"])
1464
+ self.__update_capabilities(response["capabilities"])
1465
+
1466
+ states = cast(dict[Any, Any], response["states"])
1467
+ for key, value in states.items():
1468
+ self.__update_state_internal(key, value, True)
1469
+
1470
+ def __remove_all_listeners(self) -> None:
1471
+ self.__light_state.on_completed()
1472
+ self.__motion_state.on_completed()
1473
+ self.__audio_state.on_completed()
1474
+ self.__object_state.on_completed()
1475
+ self.__doorbell_state.on_completed()
1476
+ self.__siren_state.on_completed()
1477
+ self.__battery_state.on_completed()
1478
+ self.__camera_subject.on_completed()
1479
+ self.__camera_state.on_completed()
1480
+ self.__frame_worker_state.on_completed()
1481
+ self.__capabilities.on_completed()
1482
+ self.__snapshot_cache.clear()
1483
+
1484
+ def __state_changed(
1485
+ self,
1486
+ old_state: Optional[SetValue],
1487
+ new_state: Optional[SetValue],
1488
+ type_: Optional[StateNames],
1489
+ test: Optional[bool] = False,
1490
+ ) -> bool:
1491
+ if not old_state or not new_state or not type_:
1492
+ return False
1493
+
1494
+ if (
1495
+ (type_ == "audio" and not self.has_audio_detector)
1496
+ or (type_ == "motion" and not self.has_motion_detector)
1497
+ or (type_ == "object" and not self.has_object_detector)
1498
+ or (type_ == "siren" and not self.has_siren)
1499
+ or (type_ == "battery" and not self.has_battery)
1500
+ or (type_ == "doorbell" and not self.has_doorbell)
1501
+ or (type_ == "light" and not self.has_light)
1502
+ ):
1503
+ return False
1504
+
1505
+ clean_old_state = self.__clean_state(old_state)
1506
+ clean_new_state = self.__clean_state(new_state)
1507
+
1508
+ return DeepDiff(clean_old_state, clean_new_state, ignore_order=True) != {}
1509
+
1510
+ def __get_audio_state(
1511
+ self, event: Union[AudioSetEvent, AudioState], ignore_last_event: bool = False
1512
+ ) -> AudioState:
1513
+ last_event: Optional[AudioState] = None
1514
+
1515
+ if ignore_last_event is False:
1516
+ last_event = self.get_value("audio")
1517
+ if last_event and "lastEvent" in last_event:
1518
+ del last_event["lastEvent"]
1519
+
1520
+ if "timestamp" in event:
1521
+ new_state: Any = event
1522
+ else:
1523
+ state = cast(AudioState, event).copy()
1524
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1525
+
1526
+ new_state = {
1527
+ **state,
1528
+ "db": event.get("db", None) or last_event.get("db", None) if last_event else 0,
1529
+ "lastEvent": last_event,
1530
+ }
1531
+
1532
+ return new_state
1533
+
1534
+ def __get_motion_state(
1535
+ self, event: Union[MotionSetEvent, MotionState], ignore_last_event: bool = False
1536
+ ) -> MotionState:
1537
+ last_event: Optional[MotionState] = None
1538
+
1539
+ if ignore_last_event is False:
1540
+ last_event = self.get_value("motion")
1541
+ if last_event and "lastEvent" in last_event:
1542
+ del last_event["lastEvent"]
1543
+
1544
+ if "timestamp" in event:
1545
+ new_state: Any = event
1546
+ else:
1547
+ state = cast(MotionState, event).copy()
1548
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1549
+
1550
+ new_state = {
1551
+ **state,
1552
+ "lastEvent": last_event,
1553
+ }
1554
+
1555
+ return new_state
1556
+
1557
+ def __get_object_state(
1558
+ self, event: Union[ObjectSetEvent, ObjectState], ignore_last_event: bool = False
1559
+ ) -> ObjectState:
1560
+ last_event: Optional[ObjectState] = None
1561
+
1562
+ if ignore_last_event is False:
1563
+ last_event = self.get_value("object")
1564
+ if last_event and "lastEvent" in last_event:
1565
+ del last_event["lastEvent"]
1566
+
1567
+ if "timestamp" in event:
1568
+ new_state: Any = event
1569
+ else:
1570
+ state = cast(ObjectState, event).copy()
1571
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1572
+
1573
+ new_state = {
1574
+ **state,
1575
+ "lastEvent": last_event,
1576
+ }
1577
+
1578
+ return new_state
1579
+
1580
+ def __get_doorbell_state(
1581
+ self, event: Union[DoorbellSetEvent, DoorbellState], ignore_last_event: bool = False
1582
+ ) -> DoorbellState:
1583
+ last_event: Optional[DoorbellState] = None
1584
+
1585
+ if ignore_last_event is False:
1586
+ last_event = self.get_value("doorbell")
1587
+ if last_event and "lastEvent" in last_event:
1588
+ del last_event["lastEvent"]
1589
+
1590
+ if "timestamp" in event:
1591
+ new_state: Any = event
1592
+ else:
1593
+ state = cast(DoorbellState, event).copy()
1594
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1595
+
1596
+ new_state = {
1597
+ **state,
1598
+ "lastEvent": last_event,
1599
+ }
1600
+
1601
+ return new_state
1602
+
1603
+ def __get_light_state(
1604
+ self, event: Union[LightSetEvent, LightState], ignore_last_event: bool = False
1605
+ ) -> LightState:
1606
+ last_event: Optional[LightState] = None
1607
+
1608
+ if ignore_last_event is False:
1609
+ last_event = self.get_value("light")
1610
+ if last_event and "lastEvent" in last_event:
1611
+ del last_event["lastEvent"]
1612
+
1613
+ if "timestamp" in event:
1614
+ new_state: Any = event
1615
+ else:
1616
+ state = cast(LightState, event).copy()
1617
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1618
+
1619
+ new_state = {
1620
+ **state,
1621
+ "lastEvent": last_event,
1622
+ }
1623
+
1624
+ return new_state
1625
+
1626
+ def __get_siren_state(
1627
+ self, event: Union[SirenSetEvent, SirenState], ignore_last_event: bool = False
1628
+ ) -> SirenState:
1629
+ last_event: Optional[SirenState] = None
1630
+
1631
+ if ignore_last_event is False:
1632
+ last_event = self.get_value("siren")
1633
+ if last_event and "lastEvent" in last_event:
1634
+ del last_event["lastEvent"]
1635
+
1636
+ if "timestamp" in event:
1637
+ new_state: Any = event
1638
+ else:
1639
+ state = cast(SirenState, event).copy()
1640
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1641
+
1642
+ new_state = {
1643
+ **state,
1644
+ "level": event.get("level", None) or last_event.get("level", None) if last_event else 0,
1645
+ "lastEvent": last_event,
1646
+ }
1647
+
1648
+ return new_state
1649
+
1650
+ def __get_battery_state(
1651
+ self, event: Union[BatterySetEvent, BatteryState], ignore_last_event: bool = False
1652
+ ) -> BatteryState:
1653
+ last_event: Optional[BatteryState] = None
1654
+
1655
+ if ignore_last_event is False:
1656
+ last_event = self.get_value("battery")
1657
+ if last_event and "lastEvent" in last_event:
1658
+ del last_event["lastEvent"]
1659
+
1660
+ if "timestamp" in event:
1661
+ new_state: Any = event
1662
+ else:
1663
+ state = cast(BatteryState, event).copy()
1664
+ state["timestamp"] = int(datetime.now().timestamp() * 1000)
1665
+
1666
+ new_state = {
1667
+ "level": event["level"],
1668
+ "charging": event.get("charging", None) or last_event.get("charging", None)
1669
+ if last_event
1670
+ else False,
1671
+ "lowBattery": event.get("lowBattery", None) or last_event.get("lowBattery", None)
1672
+ if last_event
1673
+ else False,
1674
+ "timestamp": int(datetime.now().timestamp() * 1000),
1675
+ "lastEvent": last_event,
1676
+ }
1677
+
1678
+ return new_state
1679
+
1680
+ def __clean_state(self, state: Union[StateValue, SetValue]) -> SetValue:
1681
+ state_copy: Any = deepcopy(state)
1682
+
1683
+ if "timestamp" in state_copy:
1684
+ del state_copy["timestamp"]
1685
+
1686
+ if "lastEvent" in state_copy:
1687
+ del state_copy["lastEvent"]
1688
+
1689
+ return state_copy
1690
+
1691
+ def __on_name_change(self, val: Any) -> None:
1692
+ cast(Logger, self.logger).suffix = self.name
1693
+
1694
+ async def __on_event_message(self, event: Message[Any]) -> None:
1695
+ if not self.__initialized:
1696
+ return
1697
+
1698
+ message = event["data"]
1699
+
1700
+ if "type" in message:
1701
+ type = message["type"]
1702
+ if type == "removed":
1703
+ await self.cleanup()
1704
+ elif type == "updated":
1705
+ self.__update_camera(message["data"])
1706
+ elif type == "cameraState":
1707
+ self.__update_camera_state(message["data"])
1708
+ elif type == "frameWorkerState":
1709
+ self.__update_frameworker_state(message["data"])
1710
+ elif type == "capabilities":
1711
+ self.__update_capabilities(message["data"])
1712
+ else:
1713
+ state_name = message["stateName"]
1714
+ new_data = message["data"]["newEvent"]
1715
+
1716
+ self.__update_state_internal(state_name, new_data, True)
1717
+
1718
+ async def __frame_worker_proxy(self) -> FrameWorkerInterface:
1719
+ return await self.__proxy.create_rpc_proxy(
1720
+ FrameWorkerInterface, self.__namespaces["frameWorkerChildRpc"]
1721
+ )
1722
+
1723
+ async def __camera_controller_proxy(self) -> CameraDeviceInterface:
1724
+ return await self.__proxy.create_rpc_proxy(
1725
+ CameraDeviceInterface, self.__namespaces["cameraControllerRpc"]
1726
+ )
1727
+
1728
+ async def __disconnect_rpc(self) -> None:
1729
+ await self.__proxy.unregister_rpc_handler(self.__namespaces["cameraInterfacesRpc"])
1730
+ await self.__proxy.disconnect_rpc_connection(self.__namespaces["cameraControllerRpc"])
1731
+ await self.__proxy.disconnect_rpc_connection(self.__namespaces["frameWorkerChildRpc"])
1732
+ await self.__camera_interfaces.disconnect()