@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.
- package/.prettierignore +12 -0
- package/.prettierrc.json +12 -0
- package/artillery.yaml +29 -0
- package/bin/cameraui-server.ts +11 -0
- package/dist/interface/assets/@xterm.DYP7pi_n.0.0.50-internal.0.css +32 -0
- package/dist/interface/assets/Adminpanel.BKek2EMH.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/Cameras.BDWZJqPN.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/Camview.BFUFMoNX.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/CuiConsole.DCYyxdVg.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/CuiPluginCard.yF8V0SZY.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/CuiTimeline.BkIwlYtw.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/Plugin.DJElsAn5.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/Plugins.0h77qnmN.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/Settings.CkgfRkQr.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/SettingsAccount.DeFul3eQ.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/main.Cip9LkS3.0.0.50-internal.0.css +1 -0
- package/dist/interface/assets/worker-base.jEXLGV2h.0.0.50-internal.0.js +1332 -0
- package/dist/interface/assets/worker-json.DgwNIOck.0.0.50-internal.0.js +1626 -0
- package/dist/interface/assets/worker-yaml.B3uUYINB.0.0.50-internal.0.js +5819 -0
- package/dist/interface/fonts/InterVariable.woff2 +0 -0
- package/dist/interface/index.html +48 -38
- package/dist/interface/js/@intlify.BkGPX90O.0.0.50-internal.0.js +15 -0
- package/dist/interface/js/@kurkle.D8fDXNIl.0.0.50-internal.0.js +6 -0
- package/dist/interface/js/@primeuix.BFAY2Bk9.0.0.50-internal.0.js +5722 -0
- package/dist/interface/js/@primevue.OhxoO3MD.0.0.50-internal.0.js +57 -0
- package/dist/interface/js/@tanstack.D1IL6eOv.0.0.50-internal.0.js +1 -0
- package/dist/interface/{@vee-validate.DHkwupr6.0.0.49.js → js/@vee-validate.BGPyWWTh.0.0.50-internal.0.js} +2 -2
- package/dist/interface/js/@vue.B5vqhCp2.0.0.50-internal.0.js +17 -0
- package/dist/interface/js/@vueuse.BsKtqdiG.0.0.50-internal.0.js +1 -0
- package/dist/interface/{@xterm.D6R4zI7m.0.0.49.js → js/@xterm.CAa7rpjv.0.0.50-internal.0.js} +8 -8
- package/dist/interface/js/Adminpanel.D93Kvbwp.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Camera.DF2l3OMA.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Cameras.YzvZccdv.0.0.50-internal.0.js +482 -0
- package/dist/interface/js/Cammesh.D-6dAROQ.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Camview.CB7_HnoQ.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Config.BwflsWTm.0.0.50-internal.0.js +2 -0
- package/dist/interface/js/Console.DZM8pN8Q.0.0.50-internal.0.js +4 -0
- package/dist/interface/js/CuiConsole.BXXU7Gth.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/CuiPluginCard.YFOrpbVD.0.0.50-internal.0.js +4 -0
- package/dist/interface/js/CuiTimeline.VV5KSJd5.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/FirstSteps.b-nvymgb.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Plugin.BOMpVEwM.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Plugins.DdPwaUDA.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Recordings.DhxjIW7e.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/Settings.D24ttaPu.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsAccount.ms3aqz4E.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsAppearance.DsTjKXk1.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsAppearance.vue_vue_type_script_setup_true_lang.CBQ6lL3T.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsBackup.BPEc4Rjg.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsRecordings.DgW7M0jj.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsRemote.BL5nXbUT.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsSystem.D7T0AIpm.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/SettingsUsers.1u0vCOVG.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/VersionsHandler.vue_vue_type_script_setup_true_lang.xDishkkS.0.0.50-internal.0.js +4 -0
- package/dist/interface/js/ace-builds.D1nmvCwb.0.0.50-internal.0.js +1090 -0
- package/dist/interface/js/ace.config.G96T2z54.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/axios.DHr9lByg.0.0.50-internal.0.js +6 -0
- package/dist/interface/js/backup.B_Gzxtp_.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/chart.js.CP_nMnnf.0.0.50-internal.0.js +13 -0
- package/dist/interface/js/close-circle.DYLuVIOg.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/dnd-core.T9OeW7mu.0.0.50-internal.0.js +1 -0
- package/dist/interface/{draggabilly.C0hZWkL0.0.0.49.js → js/draggabilly.D3zGcBb3.0.0.50-internal.0.js} +1 -1
- package/dist/interface/js/engine.io-client.kITRnq-g.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/fast-deep-equal.Bpc9mIsj.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/highlight.js.BlSXU-Wb.0.0.50-internal.0.js +3 -0
- package/dist/interface/js/linkify-it.C3N1lWsJ.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/main.D0YR3Jat.0.0.50-internal.0.js +31 -0
- package/dist/interface/{markdown-it.64FJJcTG.0.0.49.js → js/markdown-it.Dj0dt5s2.0.0.50-internal.0.js} +1 -1
- package/dist/interface/{nprogress.DkWvUoHh.0.0.49.js → js/nprogress.BwQWDcGj.0.0.50-internal.0.js} +1 -1
- package/dist/interface/js/perfect-debounce.l0sNRNKZ.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/pinia.DRh7plEC.0.0.50-internal.0.js +5 -0
- package/dist/interface/js/primelocale.Bga3dOQu.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/primevue.Cl58krXf.0.0.50-internal.0.js +142 -0
- package/dist/interface/{qrcode.BixA_YE2.0.0.49.js → js/qrcode.C1sDj6P8.0.0.50-internal.0.js} +1 -1
- package/dist/interface/js/react-dnd-touch-backend.BA4WhUJo.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/refresh-rounded.D_SmhhUf.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/rxjs.C-fTBwEO.0.0.50-internal.0.js +3 -0
- package/dist/interface/js/socket.io-client.DKrRxgjP.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/socket.io-parser.EXj3YDH2.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/system.CY8rGd-Q.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/trash-fill.CMnCN3Oy.0.0.50-internal.0.js +1 -0
- package/dist/interface/{unidragger.C8ueS-PW.0.0.49.js → js/unidragger.D0w6Tqtt.0.0.50-internal.0.js} +1 -1
- package/dist/interface/js/uuid.C6aID195.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/vee-validate.BeiObIH8.0.0.50-internal.0.js +5 -0
- package/dist/interface/js/vue-chartjs.DtdZdiYw.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/vue-i18n.BW2bx_6z.0.0.50-internal.0.js +5 -0
- package/dist/interface/js/vue-inline-svg.BJkQGmKz.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/vue-router.B2mOXHaC.0.0.50-internal.0.js +5 -0
- package/dist/interface/js/vue-zoomable.BKDyCJE7.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/vue.l0sNRNKZ.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/vue3-dnd.DRK24CBp.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/zod.SKKegNRO.0.0.50-internal.0.js +1 -0
- package/dist/interface/js/zoom-out.DxvzgVEo.0.0.50-internal.0.js +1 -0
- package/dist/interface/manifest.webmanifest +1 -1
- package/dist/interface/pwa/favicon-32.ico +0 -0
- package/dist/interface/pwa/favicon-48.ico +0 -0
- package/dist/interface/sw.js +1 -1
- package/dist/server/package.json +57 -45
- package/dist/server/requirements.txt +12 -11
- package/dist/server/src/__init__.py +0 -0
- package/dist/server/src/_camera_ui_tools/__init__.py +0 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/__init__.py +28 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/camera_utils/utils.py +52 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/__init__.py +0 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/object_path.py +198 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/reactive.py +42 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/signal_handler.py +92 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/subscribed.py +21 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/task.py +39 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/thread.py +10 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/common_utils/utils.py +91 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/__init__.py +0 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/ansicolor.py +62 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/logger.py +178 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_common/logger_service/test.py +116 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/__init__.py +350 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/__init__.py +0 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/base.py +237 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/client.py +256 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/connection.py +784 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/errors.py +745 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/messaging.py +57 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/rpc.py +227 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/base/rpc_generator.py +584 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/constants.py +96 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/typings.py +218 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/__init__.py +0 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/connection_state.py +86 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/logger.py +30 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/metrics.py +152 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/packer.py +20 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/routing.py +75 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/rpc.py +177 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/subscriptions.py +24 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/tasks.py +39 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/uid.py +37 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_rpc_client/utils/validate.py +119 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_types/__init__.py +1360 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_types/hybrid_observer.py +338 -0
- package/dist/server/src/_camera_ui_tools/camera_ui_types/test.py +196 -0
- package/dist/server/src/api/controllers/auth.controller.d.ts +2 -2
- package/dist/server/src/api/controllers/auth.controller.js +49 -43
- package/dist/server/src/api/controllers/auth.controller.js.map +1 -1
- package/dist/server/src/api/controllers/backup.controller.js +1 -2
- package/dist/server/src/api/controllers/backup.controller.js.map +1 -1
- package/dist/server/src/api/controllers/cameras.controller.d.ts +13 -11
- package/dist/server/src/api/controllers/cameras.controller.js +314 -105
- package/dist/server/src/api/controllers/cameras.controller.js.map +1 -1
- package/dist/server/src/api/controllers/plugins.controller.d.ts +8 -8
- package/dist/server/src/api/controllers/plugins.controller.js +208 -244
- package/dist/server/src/api/controllers/plugins.controller.js.map +1 -1
- package/dist/server/src/api/controllers/system.controller.d.ts +1 -0
- package/dist/server/src/api/controllers/system.controller.js +22 -8
- package/dist/server/src/api/controllers/system.controller.js.map +1 -1
- package/dist/server/src/api/controllers/users.controller.d.ts +2 -2
- package/dist/server/src/api/controllers/users.controller.js +13 -25
- package/dist/server/src/api/controllers/users.controller.js.map +1 -1
- package/dist/server/src/api/database/checks.js +2 -2
- package/dist/server/src/api/database/checks.js.map +1 -1
- package/dist/server/src/api/database/index.d.ts +4 -7
- package/dist/server/src/api/database/index.js +59 -86
- package/dist/server/src/api/database/index.js.map +1 -1
- package/dist/server/src/api/database/migration.js +5 -141
- package/dist/server/src/api/database/migration.js.map +1 -1
- package/dist/server/src/api/database/selfcheck.js +5 -5
- package/dist/server/src/api/database/selfcheck.js.map +1 -1
- package/dist/server/src/api/database/types.d.ts +17 -25
- package/dist/server/src/api/go2rtc/api/discover.d.ts +30 -0
- package/dist/server/src/api/go2rtc/api/discover.js +162 -0
- package/dist/server/src/api/go2rtc/api/discover.js.map +1 -0
- package/dist/server/src/api/go2rtc/api/index.d.ts +1 -1
- package/dist/server/src/api/go2rtc/api/index.js +15 -4
- package/dist/server/src/api/go2rtc/api/index.js.map +1 -1
- package/dist/server/src/api/go2rtc/api/streams.d.ts +3 -1
- package/dist/server/src/api/go2rtc/api/streams.js +66 -9
- package/dist/server/src/api/go2rtc/api/streams.js.map +1 -1
- package/dist/server/src/api/go2rtc/index.d.ts +2 -0
- package/dist/server/src/api/go2rtc/index.js +3 -0
- package/dist/server/src/api/go2rtc/index.js.map +1 -1
- package/dist/server/src/api/go2rtc/queue.js +3 -3
- package/dist/server/src/api/go2rtc/queue.js.map +1 -1
- package/dist/server/src/api/go2rtc/types.d.ts +66 -11
- package/dist/server/src/api/index.d.ts +4 -0
- package/dist/server/src/api/index.js +45 -9
- package/dist/server/src/api/index.js.map +1 -1
- package/dist/server/src/api/middlewares/authPermission.middleware.d.ts +1 -0
- package/dist/server/src/api/middlewares/authPermission.middleware.js +11 -2
- package/dist/server/src/api/middlewares/authPermission.middleware.js.map +1 -1
- package/dist/server/src/api/middlewares/authValidation.middleware.js +20 -12
- package/dist/server/src/api/middlewares/authValidation.middleware.js.map +1 -1
- package/dist/server/src/api/middlewares/pagination.middleware.js +45 -53
- package/dist/server/src/api/middlewares/pagination.middleware.js.map +1 -1
- package/dist/server/src/api/plugins/proxy.plugin.d.ts +14 -0
- package/dist/server/src/api/plugins/proxy.plugin.js +200 -0
- package/dist/server/src/api/plugins/proxy.plugin.js.map +1 -0
- package/dist/server/src/api/routes/cameras.routes.js +56 -30
- package/dist/server/src/api/routes/cameras.routes.js.map +1 -1
- package/dist/server/src/api/routes/plugins.routes.js +65 -63
- package/dist/server/src/api/routes/plugins.routes.js.map +1 -1
- package/dist/server/src/api/routes/system.routes.js +7 -1
- package/dist/server/src/api/routes/system.routes.js.map +1 -1
- package/dist/server/src/api/routes/users.routes.js +8 -8
- package/dist/server/src/api/routes/users.routes.js.map +1 -1
- package/dist/server/src/api/schemas/backup.schema.d.ts +3 -3
- package/dist/server/src/api/schemas/backup.schema.js +1 -1
- package/dist/server/src/api/schemas/backup.schema.js.map +1 -1
- package/dist/server/src/api/schemas/cameras.schema.d.ts +1413 -529
- package/dist/server/src/api/schemas/cameras.schema.js +228 -182
- package/dist/server/src/api/schemas/cameras.schema.js.map +1 -1
- package/dist/server/src/api/schemas/config.schema.d.ts +29 -41
- package/dist/server/src/api/schemas/config.schema.js +10 -21
- package/dist/server/src/api/schemas/config.schema.js.map +1 -1
- package/dist/server/src/api/schemas/go2rtc.schema.d.ts +194 -162
- package/dist/server/src/api/schemas/go2rtc.schema.js +33 -58
- package/dist/server/src/api/schemas/go2rtc.schema.js.map +1 -1
- package/dist/server/src/api/schemas/plugins.schema.d.ts +17 -17
- package/dist/server/src/api/schemas/plugins.schema.js +1 -1
- package/dist/server/src/api/schemas/plugins.schema.js.map +1 -1
- package/dist/server/src/api/schemas/storage.schema.d.ts +22 -0
- package/dist/server/src/api/schemas/storage.schema.js +5 -0
- package/dist/server/src/api/schemas/storage.schema.js.map +1 -0
- package/dist/server/src/api/schemas/system.schema.d.ts +171 -3
- package/dist/server/src/api/schemas/system.schema.js +30 -3
- package/dist/server/src/api/schemas/system.schema.js.map +1 -1
- package/dist/server/src/api/schemas/users.schema.d.ts +98 -254
- package/dist/server/src/api/schemas/users.schema.js +6 -6
- package/dist/server/src/api/schemas/users.schema.js.map +1 -1
- package/dist/server/src/api/services/auth.service.d.ts +5 -5
- package/dist/server/src/api/services/auth.service.js +26 -35
- package/dist/server/src/api/services/auth.service.js.map +1 -1
- package/dist/server/src/api/services/cameras.service.d.ts +11 -16
- package/dist/server/src/api/services/cameras.service.js +143 -310
- package/dist/server/src/api/services/cameras.service.js.map +1 -1
- package/dist/server/src/api/services/plugins.service.d.ts +3 -1
- package/dist/server/src/api/services/plugins.service.js +48 -50
- package/dist/server/src/api/services/plugins.service.js.map +1 -1
- package/dist/server/src/api/services/users.service.d.ts +1 -0
- package/dist/server/src/api/services/users.service.js +20 -14
- package/dist/server/src/api/services/users.service.js.map +1 -1
- package/dist/server/src/api/types/index.d.ts +57 -46
- package/dist/server/src/api/types/index.js +0 -4
- package/dist/server/src/api/types/index.js.map +1 -1
- package/dist/server/src/api/utils/cert.d.ts +5 -1
- package/dist/server/src/api/utils/cert.js +24 -26
- package/dist/server/src/api/utils/cert.js.map +1 -1
- package/dist/server/src/api/utils/constants.d.ts +4 -2
- package/dist/server/src/api/utils/constants.js +4 -2
- package/dist/server/src/api/utils/constants.js.map +1 -1
- package/dist/server/src/api/utils/fetch.d.ts +1 -1
- package/dist/server/src/api/utils/fetch.js +2 -2
- package/dist/server/src/api/utils/fetch.js.map +1 -1
- package/dist/server/src/api/websocket/index.d.ts +1 -0
- package/dist/server/src/api/websocket/index.js +14 -9
- package/dist/server/src/api/websocket/index.js.map +1 -1
- package/dist/server/src/api/websocket/nsp/logs.d.ts +10 -2
- package/dist/server/src/api/websocket/nsp/logs.js +75 -27
- package/dist/server/src/api/websocket/nsp/logs.js.map +1 -1
- package/dist/server/src/api/websocket/nsp/metrics.d.ts +20 -12
- package/dist/server/src/api/websocket/nsp/metrics.js +188 -117
- package/dist/server/src/api/websocket/nsp/metrics.js.map +1 -1
- package/dist/server/src/api/websocket/nsp/plugins.d.ts +1 -1
- package/dist/server/src/api/websocket/nsp/plugins.js +3 -5
- package/dist/server/src/api/websocket/nsp/plugins.js.map +1 -1
- package/dist/server/src/api/websocket/nsp/server.js +6 -0
- package/dist/server/src/api/websocket/nsp/server.js.map +1 -1
- package/dist/server/src/api/websocket/types.d.ts +4 -2
- package/dist/server/src/api.d.ts +3 -4
- package/dist/server/src/api.js +13 -13
- package/dist/server/src/api.js.map +1 -1
- package/dist/server/src/camera/classes.d.ts +2 -0
- package/dist/server/src/camera/classes.js +24 -0
- package/dist/server/src/camera/classes.js.map +1 -0
- package/dist/server/src/camera/controller.d.ts +30 -18
- package/dist/server/src/camera/controller.js +236 -202
- package/dist/server/src/camera/controller.js.map +1 -1
- package/dist/server/src/camera/device.d.ts +34 -0
- package/dist/server/src/camera/device.js +327 -0
- package/dist/server/src/camera/device.js.map +1 -0
- package/dist/server/src/camera/frameWorker.d.ts +32 -31
- package/dist/server/src/camera/frameWorker.js +257 -247
- package/dist/server/src/camera/frameWorker.js.map +1 -1
- package/dist/server/src/camera/index.d.ts +92 -0
- package/dist/server/src/camera/index.js +531 -0
- package/dist/server/src/camera/index.js.map +1 -0
- package/dist/server/src/camera/interfaces.d.ts +17 -0
- package/dist/server/src/camera/interfaces.js +99 -0
- package/dist/server/src/camera/interfaces.js.map +1 -0
- package/dist/server/src/camera/iou.d.ts +2 -0
- package/dist/server/src/camera/iou.js +123 -0
- package/dist/server/src/camera/iou.js.map +1 -0
- package/dist/server/src/camera/polygon.d.ts +4 -0
- package/dist/server/src/camera/polygon.js +192 -0
- package/dist/server/src/camera/polygon.js.map +1 -0
- package/dist/server/src/camera/python/__init__.py +0 -0
- package/dist/server/src/camera/python/classes.py +41 -0
- package/dist/server/src/camera/python/interfaces.py +130 -0
- package/dist/server/src/camera/python/iou.py +158 -0
- package/dist/server/src/camera/python/polygon.py +230 -0
- package/dist/server/src/camera/python/typings.py +50 -0
- package/dist/server/src/camera/python/video_frame.py +143 -0
- package/dist/server/src/camera/session.d.ts +37 -0
- package/dist/server/src/camera/session.js +160 -0
- package/dist/server/src/camera/session.js.map +1 -0
- package/dist/server/src/camera/streaming/fmp4-session.d.ts +17 -0
- package/dist/server/src/camera/streaming/fmp4-session.js +308 -0
- package/dist/server/src/camera/streaming/fmp4-session.js.map +1 -0
- package/dist/server/src/camera/streaming/peer-connection.d.ts +26 -0
- package/dist/server/src/camera/streaming/peer-connection.js +213 -0
- package/dist/server/src/camera/streaming/peer-connection.js.map +1 -0
- package/dist/server/src/camera/streaming/rtsp-session.d.ts +19 -0
- package/dist/server/src/camera/streaming/rtsp-session.js +253 -0
- package/dist/server/src/camera/streaming/rtsp-session.js.map +1 -0
- package/dist/server/src/camera/streaming/webrtc-connection.d.ts +44 -0
- package/dist/server/src/camera/streaming/webrtc-connection.js +177 -0
- package/dist/server/src/camera/streaming/webrtc-connection.js.map +1 -0
- package/dist/server/src/camera/streaming/werift-session.d.ts +19 -0
- package/dist/server/src/camera/streaming/werift-session.js +246 -0
- package/dist/server/src/camera/streaming/werift-session.js.map +1 -0
- package/dist/server/src/camera/types.d.ts +16 -10
- package/dist/server/src/camera/utils.d.ts +9 -0
- package/dist/server/src/camera/utils.js +416 -0
- package/dist/server/src/camera/utils.js.map +1 -0
- package/dist/server/src/camera/videoFrame.d.ts +18 -0
- package/dist/server/src/camera/videoFrame.js +88 -0
- package/dist/server/src/camera/videoFrame.js.map +1 -0
- package/dist/server/src/cloud/index.d.ts +12 -0
- package/dist/server/src/cloud/index.js +49 -0
- package/dist/server/src/cloud/index.js.map +1 -0
- package/dist/server/src/cloud/remote/cloudflare.d.ts +7 -0
- package/dist/server/src/cloud/remote/cloudflare.js +12 -0
- package/dist/server/src/cloud/remote/cloudflare.js.map +1 -0
- package/dist/server/src/cloud/remote/upnp.d.ts +7 -0
- package/dist/server/src/cloud/remote/upnp.js +12 -0
- package/dist/server/src/cloud/remote/upnp.js.map +1 -0
- package/dist/server/src/cloud/remote/utils.d.ts +3 -0
- package/dist/server/src/cloud/remote/utils.js +20 -0
- package/dist/server/src/cloud/remote/utils.js.map +1 -0
- package/dist/server/src/cloud/types.d.ts +15 -0
- package/dist/server/src/cloud/types.js +11 -0
- package/dist/server/src/cloud/types.js.map +1 -0
- package/dist/server/src/decoder/child.d.ts +1 -0
- package/dist/server/src/decoder/child.js +749 -0
- package/dist/server/src/decoder/child.js.map +1 -0
- package/dist/server/src/decoder/imageUtils.d.ts +22 -0
- package/dist/server/src/decoder/imageUtils.js +196 -0
- package/dist/server/src/decoder/imageUtils.js.map +1 -0
- package/dist/server/src/decoder/manager.d.ts +19 -0
- package/dist/server/src/decoder/manager.js +208 -0
- package/dist/server/src/decoder/manager.js.map +1 -0
- package/dist/server/src/decoder/python/__init__.py +0 -0
- package/dist/server/src/decoder/python/child.py +903 -0
- package/dist/server/src/decoder/python/image_utils.py +196 -0
- package/dist/server/src/decoder/python/pool.py +45 -0
- package/dist/server/src/decoder/python/typings.py +57 -0
- package/dist/server/src/decoder/python/utils.py +70 -0
- package/dist/server/src/decoder/types.d.ts +23 -0
- package/dist/server/src/decoder/types.js.map +1 -0
- package/dist/server/src/decoder/utils.d.ts +13 -0
- package/dist/server/src/decoder/utils.js +45 -0
- package/dist/server/src/decoder/utils.js.map +1 -0
- package/dist/server/src/decoder/wasm/build/decoder.d.ts +43 -0
- package/dist/server/src/decoder/wasm/build/decoder.js +108 -0
- package/dist/server/src/decoder/wasm/build/decoder.wasm +0 -0
- package/dist/server/src/decoder/worker.d.ts +1 -0
- package/dist/server/src/decoder/worker.js +79 -0
- package/dist/server/src/decoder/worker.js.map +1 -0
- package/dist/server/src/go2rtc/index.d.ts +1 -0
- package/dist/server/src/go2rtc/index.js +27 -9
- package/dist/server/src/go2rtc/index.js.map +1 -1
- package/dist/server/src/go2rtc/types.d.ts +5 -4
- package/dist/server/src/go2rtc/types.js +6 -2
- package/dist/server/src/go2rtc/types.js.map +1 -1
- package/dist/server/src/main.js +19 -5
- package/dist/server/src/main.js.map +1 -1
- package/dist/server/src/manager/coreManager.d.ts +16 -0
- package/dist/server/src/manager/coreManager.js +95 -0
- package/dist/server/src/manager/coreManager.js.map +1 -0
- package/dist/server/src/manager/deviceManager.d.ts +12 -0
- package/dist/server/src/manager/deviceManager.js +130 -0
- package/dist/server/src/manager/deviceManager.js.map +1 -0
- package/dist/server/src/manager/types.d.ts +15 -0
- package/dist/server/src/manager/types.js +2 -0
- package/dist/server/src/manager/types.js.map +1 -0
- package/dist/server/src/plugins/index.d.ts +3 -1
- package/dist/server/src/plugins/index.js +42 -21
- package/dist/server/src/plugins/index.js.map +1 -1
- package/dist/server/src/plugins/plugin.d.ts +3 -3
- package/dist/server/src/plugins/plugin.js +13 -20
- package/dist/server/src/plugins/plugin.js.map +1 -1
- package/dist/server/src/plugins/runtime/base.d.ts +54 -0
- package/dist/server/src/plugins/runtime/base.js +223 -0
- package/dist/server/src/plugins/runtime/base.js.map +1 -0
- package/dist/server/src/plugins/runtime/index.d.ts +5 -0
- package/dist/server/src/plugins/runtime/index.js +13 -0
- package/dist/server/src/plugins/runtime/index.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/child.d.ts +22 -0
- package/dist/server/src/plugins/runtime/node/child.js +152 -0
- package/dist/server/src/plugins/runtime/node/child.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/index.d.ts +7 -0
- package/dist/server/src/plugins/runtime/node/index.js +54 -0
- package/dist/server/src/plugins/runtime/node/index.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/plugin.d.ts +24 -0
- package/dist/server/src/plugins/runtime/node/plugin.js +128 -0
- package/dist/server/src/plugins/runtime/node/plugin.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/pluginApi.d.ts +16 -0
- package/dist/server/src/plugins/runtime/node/pluginApi.js +18 -0
- package/dist/server/src/plugins/runtime/node/pluginApi.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.d.ts +25 -0
- package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.js +230 -0
- package/dist/server/src/plugins/runtime/node/proxy/cameraDevice.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/proxy/coreManager.d.ts +16 -0
- package/dist/server/src/plugins/runtime/node/proxy/coreManager.js +98 -0
- package/dist/server/src/plugins/runtime/node/proxy/coreManager.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/proxy/deviceManager.d.ts +19 -0
- package/dist/server/src/plugins/runtime/node/proxy/deviceManager.js +144 -0
- package/dist/server/src/plugins/runtime/node/proxy/deviceManager.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/storage.d.ts +34 -0
- package/dist/server/src/plugins/runtime/node/storage.js +313 -0
- package/dist/server/src/plugins/runtime/node/storage.js.map +1 -0
- package/dist/server/src/plugins/runtime/node/storageController.d.ts +18 -0
- package/dist/server/src/plugins/runtime/node/storageController.js +67 -0
- package/dist/server/src/plugins/runtime/node/storageController.js.map +1 -0
- package/dist/server/src/plugins/runtime/python/__init__.py +0 -0
- package/dist/server/src/plugins/runtime/python/child.py +248 -0
- package/dist/server/src/plugins/runtime/python/index.d.ts +9 -0
- package/dist/server/src/plugins/runtime/python/index.js +57 -0
- package/dist/server/src/plugins/runtime/python/index.js.map +1 -0
- package/dist/server/src/plugins/runtime/python/namespaces.py +101 -0
- package/dist/server/src/plugins/runtime/python/plugin.py +155 -0
- package/dist/server/src/plugins/runtime/python/plugin_api.py +29 -0
- package/dist/server/src/plugins/runtime/python/proxy/camera_device.py +1732 -0
- package/dist/server/src/plugins/runtime/python/proxy/core_manager.py +126 -0
- package/dist/server/src/plugins/runtime/python/proxy/device_manager.py +197 -0
- package/dist/server/src/plugins/runtime/python/schema.py +99 -0
- package/dist/server/src/plugins/runtime/python/storage.py +353 -0
- package/dist/server/src/plugins/runtime/python/storage_controller.py +102 -0
- package/dist/server/src/plugins/runtime/python/typings.py +195 -0
- package/dist/server/src/plugins/schema.d.ts +27 -34
- package/dist/server/src/plugins/schema.js +358 -369
- package/dist/server/src/plugins/schema.js.map +1 -1
- package/dist/server/src/plugins/types.d.ts +43 -1
- package/dist/server/src/plugins/types.js +16 -0
- package/dist/server/src/plugins/types.js.map +1 -1
- package/dist/server/src/plugins/worker.d.ts +12 -31
- package/dist/server/src/plugins/worker.js +89 -343
- package/dist/server/src/plugins/worker.js.map +1 -1
- package/dist/server/src/rpc/index.d.ts +32 -0
- package/dist/server/src/rpc/index.js +103 -0
- package/dist/server/src/rpc/index.js.map +1 -0
- package/dist/server/src/rpc/namespaces.d.ts +35 -0
- package/dist/server/src/rpc/namespaces.js +42 -0
- package/dist/server/src/rpc/namespaces.js.map +1 -0
- package/dist/server/src/{nats → rpc}/server.d.ts +6 -2
- package/dist/server/src/{nats → rpc}/server.js +76 -55
- package/dist/server/src/rpc/server.js.map +1 -0
- package/dist/server/src/rpc/types.d.ts +111 -0
- package/dist/server/src/rpc/types.js +2 -0
- package/dist/server/src/{nats → rpc}/types.js.map +1 -1
- package/dist/server/src/{nats → rpc}/utils.d.ts +1 -1
- package/dist/server/src/rpc/utils.js.map +1 -0
- package/dist/server/src/services/config/constants.js +12 -48
- package/dist/server/src/services/config/constants.js.map +1 -1
- package/dist/server/src/services/config/defaults.d.ts +12 -0
- package/dist/server/src/services/config/defaults.js +55 -0
- package/dist/server/src/services/config/defaults.js.map +1 -0
- package/dist/server/src/services/config/index.d.ts +57 -9
- package/dist/server/src/services/config/index.js +277 -130
- package/dist/server/src/services/config/index.js.map +1 -1
- package/dist/server/src/services/config/types.d.ts +10 -4
- package/dist/server/src/types.d.ts +3 -0
- package/dist/server/src/utils/path.d.ts +5 -0
- package/dist/server/src/utils/path.js +12 -0
- package/dist/server/src/utils/path.js.map +1 -0
- package/dist/server/src/utils/pythonInstaller.d.ts +46 -0
- package/dist/server/src/utils/pythonInstaller.js +463 -0
- package/dist/server/src/utils/pythonInstaller.js.map +1 -0
- package/eslint.config.js +103 -0
- package/localdeps.txt +10 -0
- package/mypy.ini +30 -0
- package/package.json +57 -45
- package/requirements.txt +15 -0
- package/ruff.toml +90 -0
- package/src/__init__.py +0 -0
- package/src/_camera_ui_tools/__init__.py +0 -0
- package/src/_camera_ui_tools/__pycache__/__init__.cpython-311.pyc +0 -0
- package/src/api/controllers/api.controller.ts +19 -0
- package/src/api/controllers/auth.controller.ts +294 -0
- package/src/api/controllers/backup.controller.ts +72 -0
- package/src/api/controllers/cameras.controller.ts +1029 -0
- package/src/api/controllers/config.controller.ts +102 -0
- package/src/api/controllers/files.controller.ts +35 -0
- package/src/api/controllers/frameWorkers.controller.ts +109 -0
- package/src/api/controllers/plugins.controller.ts +1206 -0
- package/src/api/controllers/system.controller.ts +273 -0
- package/src/api/controllers/users.controller.ts +648 -0
- package/src/api/database/checks.ts +268 -0
- package/src/api/database/constants.ts +8 -0
- package/src/api/database/index.ts +262 -0
- package/src/api/database/migration.ts +62 -0
- package/src/api/database/selfcheck.ts +492 -0
- package/src/api/database/types.ts +104 -0
- package/src/api/go2rtc/api/application.ts +48 -0
- package/src/api/go2rtc/api/config.ts +61 -0
- package/src/api/go2rtc/api/discover.ts +197 -0
- package/src/api/go2rtc/api/index.ts +49 -0
- package/src/api/go2rtc/api/snapshot.ts +44 -0
- package/src/api/go2rtc/api/streams.ts +168 -0
- package/src/api/go2rtc/index.ts +43 -0
- package/src/api/go2rtc/queue.ts +50 -0
- package/src/api/go2rtc/types.ts +174 -0
- package/src/api/index.ts +286 -0
- package/src/api/middlewares/authPermission.middleware.ts +46 -0
- package/src/api/middlewares/authValidation.middleware.ts +160 -0
- package/src/api/middlewares/pagination.middleware.ts +67 -0
- package/src/api/middlewares/socketAuth.middleware.ts +136 -0
- package/src/api/plugins/header.plugin.ts +15 -0
- package/src/api/plugins/logger.plugin.ts +44 -0
- package/src/api/plugins/proxy.plugin.ts +255 -0
- package/src/api/plugins/socket.plugin.ts +28 -0
- package/src/api/plugins/system.plugin.ts +48 -0
- package/src/api/plugins/useragent.plugin.ts +19 -0
- package/src/api/routes/api.routes.ts +10 -0
- package/src/api/routes/auth.routes.ts +56 -0
- package/src/api/routes/backup.routes.ts +28 -0
- package/src/api/routes/cameras.routes.ts +281 -0
- package/src/api/routes/config.routes.ts +66 -0
- package/src/api/routes/files.routes.ts +15 -0
- package/src/api/routes/frameWorkers.routes.ts +39 -0
- package/src/api/routes/index.ts +37 -0
- package/src/api/routes/plugins.routes.ts +420 -0
- package/src/api/routes/system.routes.ts +101 -0
- package/src/api/routes/users.routes.ts +167 -0
- package/src/api/schemas/backup.schema.ts +112 -0
- package/src/api/schemas/cameras.schema.ts +479 -0
- package/src/api/schemas/config.schema.ts +38 -0
- package/src/api/schemas/go2rtc.schema.ts +189 -0
- package/src/api/schemas/plugins.schema.ts +126 -0
- package/src/api/schemas/storage.schema.ts +11 -0
- package/src/api/schemas/system.schema.ts +45 -0
- package/src/api/schemas/users.schema.ts +185 -0
- package/src/api/services/auth.service.ts +210 -0
- package/src/api/services/backup.service.ts +144 -0
- package/src/api/services/cameras.service.ts +671 -0
- package/src/api/services/plugins.service.ts +470 -0
- package/src/api/services/system.service.ts +85 -0
- package/src/api/services/users.service.ts +276 -0
- package/src/api/types/index.ts +675 -0
- package/src/api/utils/cert.ts +254 -0
- package/src/api/utils/constants.ts +17 -0
- package/src/api/utils/fetch.ts +21 -0
- package/src/api/utils/moveFiles.ts +45 -0
- package/src/api/utils/parse.ts +17 -0
- package/src/api/websocket/index.ts +110 -0
- package/src/api/websocket/nsp/logs.ts +240 -0
- package/src/api/websocket/nsp/main.ts +27 -0
- package/src/api/websocket/nsp/metrics.ts +301 -0
- package/src/api/websocket/nsp/notifications.ts +43 -0
- package/src/api/websocket/nsp/plugins.ts +37 -0
- package/src/api/websocket/nsp/server.ts +220 -0
- package/src/api/websocket/nsp/status.ts +77 -0
- package/src/api/websocket/types.ts +55 -0
- package/src/api.ts +163 -0
- package/src/camera/classes.ts +32 -0
- package/src/camera/controller.ts +579 -0
- package/src/camera/device.ts +422 -0
- package/src/camera/frameWorker.ts +403 -0
- package/src/camera/index.ts +679 -0
- package/src/camera/interfaces.ts +95 -0
- package/src/camera/iou.ts +153 -0
- package/src/camera/polygon.ts +226 -0
- package/src/camera/python/__init__.py +0 -0
- package/src/camera/python/__pycache__/__init__.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/classes.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/delegate_controller.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/interfaces.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/iou.cpython-310.pyc +0 -0
- package/src/camera/python/__pycache__/iou.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/iou2.cpython-310.pyc +0 -0
- package/src/camera/python/__pycache__/polygon.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/typings.cpython-311.pyc +0 -0
- package/src/camera/python/__pycache__/video_frame.cpython-311.pyc +0 -0
- package/src/camera/python/classes.py +41 -0
- package/src/camera/python/interfaces.py +130 -0
- package/src/camera/python/iou.py +158 -0
- package/src/camera/python/polygon.py +230 -0
- package/src/camera/python/test/__pycache__/polygon.cpython-310.pyc +0 -0
- package/src/camera/python/test/iou_test.py +799 -0
- package/src/camera/python/test/polygon.py +238 -0
- package/src/camera/python/test/polygon_test.py +256 -0
- package/src/camera/python/test/polygon_test2.py +484 -0
- package/src/camera/python/typings.py +50 -0
- package/src/camera/python/video_frame.py +143 -0
- package/src/camera/session.ts +192 -0
- package/src/camera/streaming/fmp4-session.ts +390 -0
- package/src/camera/streaming/peer-connection.ts +273 -0
- package/src/camera/streaming/rtsp-session.ts +331 -0
- package/src/camera/streaming/webrtc-connection.ts +260 -0
- package/src/camera/streaming/werift-session.ts +317 -0
- package/src/camera/test/iou_test.ts +761 -0
- package/src/camera/test/polygon.test.ts +611 -0
- package/src/camera/test/polygon_test.ts +210 -0
- package/src/camera/types.ts +48 -0
- package/src/camera/utils.ts +489 -0
- package/src/camera/videoFrame.ts +123 -0
- package/src/cloud/index.ts +61 -0
- package/src/cloud/remote/cloudflare.ts +18 -0
- package/src/cloud/remote/upnp.ts +18 -0
- package/src/cloud/remote/utils.ts +24 -0
- package/src/cloud/types.ts +16 -0
- package/src/decoder/child.ts +883 -0
- package/src/decoder/imageUtils.ts +275 -0
- package/src/decoder/manager.ts +251 -0
- package/src/decoder/python/__init__.py +0 -0
- package/src/decoder/python/__pycache__/__init__.cpython-311.pyc +0 -0
- package/src/decoder/python/__pycache__/image_utils.cpython-311.pyc +0 -0
- package/src/decoder/python/__pycache__/typings.cpython-311.pyc +0 -0
- package/src/decoder/python/__pycache__/utils.cpython-311.pyc +0 -0
- package/src/decoder/python/child.py +903 -0
- package/src/decoder/python/image_utils.py +196 -0
- package/src/decoder/python/pool.py +45 -0
- package/src/decoder/python/test/group.py +62 -0
- package/src/decoder/python/test/motion.mp4 +0 -0
- package/src/decoder/python/test/motion2.mp4 +0 -0
- package/src/decoder/python/test/opencl.cl +70 -0
- package/src/decoder/python/test/opencl2.cl +130 -0
- package/src/decoder/python/test/test.py +427 -0
- package/src/decoder/python/test/test1.jpg +0 -0
- package/src/decoder/python/test/test1_resized.jpg +0 -0
- package/src/decoder/python/test/test2.jpg +0 -0
- package/src/decoder/python/test/test2.py +451 -0
- package/src/decoder/python/test/test2_resized.jpg +0 -0
- package/src/decoder/python/test/test3.jpg +0 -0
- package/src/decoder/python/test/utils.py +50 -0
- package/src/decoder/python/typings.py +57 -0
- package/src/decoder/python/utils.py +70 -0
- package/src/decoder/test/child.ts +117 -0
- package/src/decoder/test/ffmpeg.ts +371 -0
- package/src/decoder/test/test.ts +182 -0
- package/src/decoder/types.ts +27 -0
- package/src/decoder/utils.ts +64 -0
- package/src/decoder/wasm/asconfig.json +28 -0
- package/src/decoder/wasm/assembly/console.ts +1 -0
- package/src/decoder/wasm/assembly/index.ts +890 -0
- package/src/decoder/wasm/build/decoder.d.ts +43 -0
- package/src/decoder/wasm/build/decoder.js +108 -0
- package/src/decoder/wasm/build/decoder.wasm +0 -0
- package/src/decoder/wasm/tsconfig.json +5 -0
- package/src/decoder/worker.ts +113 -0
- package/src/go2rtc/index.ts +324 -0
- package/src/go2rtc/types.ts +88 -0
- package/src/main.ts +267 -0
- package/src/manager/coreManager.ts +78 -0
- package/src/manager/deviceManager.ts +132 -0
- package/src/manager/types.ts +17 -0
- package/src/plugins/index.ts +443 -0
- package/src/plugins/plugin.ts +177 -0
- package/src/plugins/runtime/base.ts +282 -0
- package/src/plugins/runtime/index.ts +15 -0
- package/src/plugins/runtime/node/child.ts +193 -0
- package/src/plugins/runtime/node/index.ts +67 -0
- package/src/plugins/runtime/node/plugin.ts +122 -0
- package/src/plugins/runtime/node/pluginApi.ts +27 -0
- package/src/plugins/runtime/node/proxy/cameraDevice.ts +299 -0
- package/src/plugins/runtime/node/proxy/coreManager.ts +128 -0
- package/src/plugins/runtime/node/proxy/deviceManager.ts +187 -0
- package/src/plugins/runtime/node/storage.ts +312 -0
- package/src/plugins/runtime/node/storageController.ts +91 -0
- package/src/plugins/runtime/python/__init__.py +0 -0
- package/src/plugins/runtime/python/__pycache__/__init__.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/camera_storage.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/config_service.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/constants.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/ipc.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/logger.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/message_queue.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/namespaces.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/plugin.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/plugin_api.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/plugin_logger.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/proxy_utils.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/schema.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/storage.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/storage_controller.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/__pycache__/typings.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/child.py +248 -0
- package/src/plugins/runtime/python/index.ts +73 -0
- package/src/plugins/runtime/python/namespaces.py +101 -0
- package/src/plugins/runtime/python/plugin.py +155 -0
- package/src/plugins/runtime/python/plugin_api.py +29 -0
- package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-310.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-38.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/camera_device.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/constants.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/constants.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/core_manager.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-310.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-38.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/device_manager.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-310.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-38.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/generate_keys.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-310.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-38.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/message_queue.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-310.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-38.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/plugins_manager.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-310.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-311.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-38.pyc +0 -0
- package/src/plugins/runtime/python/proxy/__pycache__/system_manager.cpython-39.pyc +0 -0
- package/src/plugins/runtime/python/proxy/camera_device.py +1732 -0
- package/src/plugins/runtime/python/proxy/core_manager.py +126 -0
- package/src/plugins/runtime/python/proxy/device_manager.py +197 -0
- package/src/plugins/runtime/python/schema.py +99 -0
- package/src/plugins/runtime/python/storage.py +353 -0
- package/src/plugins/runtime/python/storage_controller.py +102 -0
- package/src/plugins/runtime/python/typings.py +195 -0
- package/src/plugins/schema.ts +472 -0
- package/src/plugins/types.ts +60 -0
- package/src/plugins/worker.ts +250 -0
- package/src/rpc/index.ts +149 -0
- package/src/rpc/namespaces.ts +79 -0
- package/src/rpc/server.ts +422 -0
- package/src/rpc/types.ts +119 -0
- package/src/rpc/utils.ts +16 -0
- package/src/services/config/constants.ts +47 -0
- package/src/services/config/defaults.ts +57 -0
- package/src/services/config/index.ts +744 -0
- package/src/services/config/types.ts +211 -0
- package/src/services/logger/index.ts +96 -0
- package/src/types.ts +47 -0
- package/src/utils/path.ts +16 -0
- package/src/utils/pythonInstaller.ts +597 -0
- package/tsconfig.json +37 -0
- package/types/fastify.d.ts +14 -0
- package/updates.config.js +3 -0
- package/dist/interface/@intlify.Do1-T-x0.0.0.49.js +0 -15
- package/dist/interface/@mdi.CbjpODVZ.0.0.49.js +0 -1
- package/dist/interface/@tanstack.CgZ4BVuY.0.0.49.js +0 -1
- package/dist/interface/@vue.DeX8WChi.0.0.49.js +0 -17
- package/dist/interface/@vueform.WCJNykTK.0.0.49.js +0 -1
- package/dist/interface/@vueuse.fmA4o7MO.0.0.49.js +0 -1
- package/dist/interface/Account.D_hgF7as.0.0.49.js +0 -1
- package/dist/interface/Adminpanel.Cr2ysRnk.0.0.49.js +0 -2
- package/dist/interface/Appearance.DJPnnakw.0.0.49.js +0 -1
- package/dist/interface/Backup.DWrnTw65.0.0.49.js +0 -1
- package/dist/interface/Camera.Cm8bv5Jw.0.0.49.js +0 -1
- package/dist/interface/Cameras.BdMnnB_B.0.0.49.js +0 -1
- package/dist/interface/Camview.CvyTACeS.0.0.49.js +0 -1
- package/dist/interface/Config.R58trs6R.0.0.49.js +0 -1
- package/dist/interface/Console.ByS6OcfG.0.0.49.js +0 -4
- package/dist/interface/FirstSteps.BSZVBND8.0.0.49.js +0 -1
- package/dist/interface/NewCamera.CpKY8-_z.0.0.49.js +0 -469
- package/dist/interface/Plugin.ucDXXC6d.0.0.49.js +0 -1
- package/dist/interface/Plugins.Bl6Yy3fd.0.0.49.js +0 -1
- package/dist/interface/Recordings.Bm-_HDqk.0.0.49.js +0 -1
- package/dist/interface/Recordings.CVFqRJTQ.0.0.49.js +0 -1
- package/dist/interface/Settings.ClbXnv3j.0.0.49.js +0 -1
- package/dist/interface/System.BE0hX95Q.0.0.49.js +0 -4
- package/dist/interface/User.Ih1R_8u4.0.0.49.js +0 -1
- package/dist/interface/VConfigEditor.vue_vue_type_script_setup_true_lang.CAHg6HiL.0.0.49.js +0 -2
- package/dist/interface/VConsole.B9yVZ89i.0.0.49.js +0 -1
- package/dist/interface/VPlayer.DWJVzwuw.0.0.49.js +0 -4
- package/dist/interface/VPluginCard.pJNHjHpP.0.0.49.js +0 -4
- package/dist/interface/ace-builds.S1varnlI.0.0.49.js +0 -970
- package/dist/interface/apexcharts.BQn4Fbzn.0.0.49.js +0 -838
- package/dist/interface/assets/@vueform.0.0.49.CroAHJs8.css +0 -1
- package/dist/interface/assets/@xterm.0.0.49.CFbL2ovg.css +0 -32
- package/dist/interface/assets/Account.0.0.49.Bnw6Lbtd.css +0 -1
- package/dist/interface/assets/Adminpanel.0.0.49.a3t1v3MB.css +0 -1
- package/dist/interface/assets/Camera.0.0.49.Br9s6-lM.css +0 -1
- package/dist/interface/assets/Cameras.0.0.49.Buf1Dgce.css +0 -1
- package/dist/interface/assets/Camview.0.0.49.B7Cja2ry.css +0 -1
- package/dist/interface/assets/Config.0.0.49.DNGo2krN.css +0 -1
- package/dist/interface/assets/Console.0.0.49.Bh8l9QnM.css +0 -1
- package/dist/interface/assets/FirstSteps.0.0.49.Mu8VPl13.css +0 -1
- package/dist/interface/assets/NewCamera.0.0.49.DtjxW0Pf.css +0 -1
- package/dist/interface/assets/Plugin.0.0.49.YIpAU1_n.css +0 -1
- package/dist/interface/assets/Plugins.0.0.49.DXSoO9M1.css +0 -1
- package/dist/interface/assets/Settings.0.0.49.CVmui2kE.css +0 -1
- package/dist/interface/assets/User.0.0.49.BiGtIFqt.css +0 -1
- package/dist/interface/assets/VConsole.0.0.49.BCqKHpmJ.css +0 -1
- package/dist/interface/assets/VPlayer.0.0.49.C4lm2rVR.css +0 -1
- package/dist/interface/assets/VPluginCard.0.0.49.C8Lj6X-J.css +0 -1
- package/dist/interface/assets/main.0.0.49.OJngntGT.css +0 -1
- package/dist/interface/assets/vue3-toastify.0.0.49.DHXAGmwn.css +0 -1
- package/dist/interface/assets/vuetify.0.0.49.Dua9WSqa.css +0 -5
- package/dist/interface/axios.DIsA03vz.0.0.49.js +0 -6
- package/dist/interface/backup.DO02r0Uq.0.0.49.js +0 -1
- package/dist/interface/dnd-core.De50QAoi.0.0.49.js +0 -1
- package/dist/interface/engine.io-client.BkCVneko.0.0.49.js +0 -1
- package/dist/interface/fast-deep-equal.Cba0yG7P.0.0.49.js +0 -1
- package/dist/interface/fonts/Inter/Inter-Regular.ttf +0 -0
- package/dist/interface/highlight.js.B_E0LW5C.0.0.49.js +0 -2
- package/dist/interface/hookable.B8xFkYCm.0.0.49.js +0 -1
- package/dist/interface/linkify-it.B6s2BWlj.0.0.49.js +0 -1
- package/dist/interface/main.BBe3SGhH.0.0.49.js +0 -4
- package/dist/interface/perfect-debounce.Cp2ysxOb.0.0.49.js +0 -1
- package/dist/interface/pinia.ggULzsrQ.0.0.49.js +0 -5
- package/dist/interface/plugins.D11FBqVV.0.0.49.js +0 -1
- package/dist/interface/react-dnd-touch-backend.Bu6wFEmw.0.0.49.js +0 -1
- package/dist/interface/rxjs.BoFuGUYG.0.0.49.js +0 -3
- package/dist/interface/socket.io-client.DkEQDv7C.0.0.49.js +0 -1
- package/dist/interface/socket.io-parser.DIURoCw8.0.0.49.js +0 -1
- package/dist/interface/system.D_LabhBl.0.0.49.js +0 -1
- package/dist/interface/types.Cz9TaZAP.0.0.49.js +0 -1
- package/dist/interface/utils.mAKpSMLY.0.0.49.js +0 -1
- package/dist/interface/uuid.Ch9TGLTe.0.0.49.js +0 -1
- package/dist/interface/vee-validate.8pUAwQ7T.0.0.49.js +0 -5
- package/dist/interface/vue-i18n.CBqdKRmG.0.0.49.js +0 -5
- package/dist/interface/vue-inline-svg.ZWpe_tFT.0.0.49.js +0 -1
- package/dist/interface/vue-router.DvFvaoP2.0.0.49.js +0 -5
- package/dist/interface/vue3-apexcharts.BHSDC9pf.0.0.49.js +0 -1
- package/dist/interface/vue3-dnd.DbCy3Qbj.0.0.49.js +0 -1
- package/dist/interface/vue3-toastify.JJyrPHKk.0.0.49.js +0 -1
- package/dist/interface/vuetify.kkqUjVJA.0.0.49.js +0 -5
- package/dist/interface/zod.bkdEMpUp.0.0.49.js +0 -1
- package/dist/server/src/api/utils/cameraSource.d.ts +0 -6
- package/dist/server/src/api/utils/cameraSource.js +0 -51
- package/dist/server/src/api/utils/cameraSource.js.map +0 -1
- package/dist/server/src/api/websocket/go2rtc.d.ts +0 -21
- package/dist/server/src/api/websocket/go2rtc.js +0 -88
- package/dist/server/src/api/websocket/go2rtc.js.map +0 -1
- package/dist/server/src/api/websocket/nsp/proxy.d.ts +0 -27
- package/dist/server/src/api/websocket/nsp/proxy.js +0 -127
- package/dist/server/src/api/websocket/nsp/proxy.js.map +0 -1
- package/dist/server/src/nats/index.d.ts +0 -40
- package/dist/server/src/nats/index.js +0 -164
- package/dist/server/src/nats/index.js.map +0 -1
- package/dist/server/src/nats/proxy/cameraDevice.d.ts +0 -22
- package/dist/server/src/nats/proxy/cameraDevice.js +0 -249
- package/dist/server/src/nats/proxy/cameraDevice.js.map +0 -1
- package/dist/server/src/nats/proxy/coreManager.d.ts +0 -14
- package/dist/server/src/nats/proxy/coreManager.js +0 -68
- package/dist/server/src/nats/proxy/coreManager.js.map +0 -1
- package/dist/server/src/nats/proxy/deviceManager.d.ts +0 -14
- package/dist/server/src/nats/proxy/deviceManager.js +0 -101
- package/dist/server/src/nats/proxy/deviceManager.js.map +0 -1
- package/dist/server/src/nats/server.js.map +0 -1
- package/dist/server/src/nats/types.d.ts +0 -18
- package/dist/server/src/nats/utils.js.map +0 -1
- /package/dist/interface/assets/{Backup.0.0.49.CX0rT0QJ.css → SettingsBackup.CX0rT0QJ.0.0.50-internal.0.css} +0 -0
- /package/dist/interface/assets/{highlight.0.0.49.Ch2EwETz.css → highlight.Ch2EwETz.0.0.50-internal.0.css} +0 -0
- /package/dist/interface/assets/{logo-256.0.0.49.BCQk9H1-.png → logo-256.BCQk9H1-.0.0.50-internal.0.png} +0 -0
- /package/dist/interface/assets/{logo-512.0.0.49.DLKVOU2S.png → logo-512.DLKVOU2S.0.0.50-internal.0.png} +0 -0
- /package/dist/interface/assets/{logo.0.0.49.DmEiRk0z.png → logo.DmEiRk0z.0.0.50-internal.0.png} +0 -0
- /package/dist/interface/assets/{mode-json.0.0.49.Br7xisR1.js → mode-json.Br7xisR1.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/assets/{mode-yaml.0.0.49.CIYL8U3d.js → mode-yaml.CIYL8U3d.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{@babel.l0sNRNKZ.0.0.49.js → js/@babel.l0sNRNKZ.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{@react-dnd.CcwRs9xb.0.0.49.js → js/@react-dnd.CcwRs9xb.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{@socket.io.Dkula2eQ.0.0.49.js → js/@socket.io.Dkula2eQ.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{birpc.l0sNRNKZ.0.0.49.js → js/birpc.l0sNRNKZ.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{compare-versions.DqEOhma6.0.0.49.js → js/compare-versions.DqEOhma6.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{dijkstrajs.C00ieaqj.0.0.49.js → js/dijkstrajs.C00ieaqj.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{engine.io-parser.BiEtp6m2.0.0.49.js → js/engine.io-parser.BiEtp6m2.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{entities.C20TfXL6.0.0.49.js → js/entities.C20TfXL6.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{ev-emitter.X5f1qa-c.0.0.49.js → js/ev-emitter.X5f1qa-c.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{get-size.D1dS-IaP.0.0.49.js → js/get-size.D1dS-IaP.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{vue.l0sNRNKZ.0.0.49.js → js/hookable.l0sNRNKZ.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{mdurl.k9Sl0PQj.0.0.49.js → js/mdurl.k9Sl0PQj.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{punycode.js.Dj65hjkv.0.0.49.js → js/punycode.js.Dj65hjkv.0.0.50-internal.0.js} +0 -0
- /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
- /package/dist/interface/{redux.BFxtlG_c.0.0.49.js → js/redux.BFxtlG_c.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{tslib.9k7AwCpt.0.0.49.js → js/tslib.9k7AwCpt.0.0.50-internal.0.js} +0 -0
- /package/dist/interface/{uc.micro.kMc2yuuw.0.0.49.js → js/uc.micro.kMc2yuuw.0.0.50-internal.0.js} +0 -0
- /package/dist/server/src/{nats → decoder}/types.js +0 -0
- /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()
|