camera.ui3 0.0.30-alpha.0 → 0.0.30-alpha.3
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/dist/interface/@camera.ui.DuwfK59t.0.0.30-alpha.3.js +3 -0
- package/dist/interface/@tanstack.DBBaUHTS.0.0.30-alpha.3.js +1 -0
- package/dist/interface/{@vee-validate.0Cv0x9aN.0.0.30-alpha.0.js → @vee-validate.BRR3_tWq.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/@vue.BeJw0wEm.0.0.30-alpha.3.js +17 -0
- package/dist/interface/{@vueform.Du_niMHk.0.0.30-alpha.0.js → @vueform.Dcx-RQUw.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{@vueuse.Dv9U068T.0.0.30-alpha.0.js → @vueuse.Sz46sDez.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/Account.hmetZWTc.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Adminpanel.DxC80W0K.0.0.30-alpha.3.js +2 -0
- package/dist/interface/Appearance.BHZdWQlZ.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Backup.petPSq60.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Camera.DS7gbgwV.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Cameras.eqceAkdR.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Camview.DumV6nmv.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Config.DQ5vyHcx.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Console.CWp-LL5w.0.0.30-alpha.3.js +4 -0
- package/dist/interface/FirstSteps.DR2B1Gmx.0.0.30-alpha.3.js +1 -0
- package/dist/interface/{NewCamera.Kn9biZIb.0.0.30-alpha.0.js → NewCamera.CpENkWIP.0.0.30-alpha.3.js} +2 -2
- package/dist/interface/Plugin.KK2gWYUL.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Plugins.Dy1rL-Pc.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Recordings.Bny11D38.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Recordings.IdGxswmI.0.0.30-alpha.3.js +1 -0
- package/dist/interface/Settings.D6l7BlOF.0.0.30-alpha.3.js +1 -0
- package/dist/interface/System.FIkCpF0A.0.0.30-alpha.3.js +4 -0
- package/dist/interface/User.By9sAd8k.0.0.30-alpha.3.js +1 -0
- package/dist/interface/VConfigEditor.vue_vue_type_script_setup_true_lang.C7ZcC7dX.0.0.30-alpha.3.js +2 -0
- package/dist/interface/{VConsole.BT0UxZb1.0.0.30-alpha.0.js → VConsole.BG4nEIk8.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/VPlayer.CZqXCM-i.0.0.30-alpha.3.js +1 -0
- package/dist/interface/{VPluginCard.Bz3GmzAE.0.0.30-alpha.0.js → VPluginCard.B_M3puzM.0.0.30-alpha.3.js} +2 -2
- package/dist/interface/{ace-builds.SRW0xGs1.0.0.30-alpha.0.js → ace-builds.D4S-MJ6b.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{apexcharts.BV8prH5x.0.0.30-alpha.0.js → apexcharts.u0duws01.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{dnd-core.BdsXoke-.0.0.30-alpha.0.js → dnd-core.C4232Xyz.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{draggabilly.D9j4BYFu.0.0.30-alpha.0.js → draggabilly.Xgwn1bT3.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{engine.io-client.di4Pt8W8.0.0.30-alpha.0.js → engine.io-client.CUastNh3.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{ev-emitter.Dxl4QoSg.0.0.30-alpha.0.js → ev-emitter.BYRnnQXb.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{fast-deep-equal.BUna8KlC.0.0.30-alpha.0.js → fast-deep-equal.CqwdqDxW.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{highlight.js.CMosnU3p.0.0.30-alpha.0.js → highlight.js.sNLmnsuC.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/index.html +34 -33
- package/dist/interface/{linkify-it.B9RFwlcp.0.0.30-alpha.0.js → linkify-it.8PrPWg7W.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/main.gxLiydtV.0.0.30-alpha.3.js +2 -0
- package/dist/interface/{markdown-it.DAiultxC.0.0.30-alpha.0.js → markdown-it.Q4_2MGLy.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{nprogress.C2KbBHcZ.0.0.30-alpha.0.js → nprogress.DQYtKLt9.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{pinia.DRjp4GU7.0.0.30-alpha.0.js → pinia.DcgsdRJU.0.0.30-alpha.3.js} +2 -2
- package/dist/interface/{plugins.Ur_7V4x8.0.0.30-alpha.0.js → plugins.DZjXmoDp.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{qrcode.DrYVb5am.0.0.30-alpha.0.js → qrcode.XqSuoGPb.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{react-dnd-touch-backend.ByHGbrKq.0.0.30-alpha.0.js → react-dnd-touch-backend.VzlzWkdX.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{rxjs.Dl5P76vZ.0.0.30-alpha.0.js → rxjs.CXnJywSk.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{socket.io-client.Cf7ABgrO.0.0.30-alpha.0.js → socket.io-client.DiiooL5k.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{socket.io-parser.DHnwqfTj.0.0.30-alpha.0.js → socket.io-parser.Dsh2ZviN.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/sw.js +1 -1
- package/dist/interface/{system.CRn9Cy3C.0.0.30-alpha.0.js → system.Bh4wNIkr.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{ui.C-XbEPHk.0.0.30-alpha.0.js → ui.B0YwbqBU.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{unidragger.zHlf1Df_.0.0.30-alpha.0.js → unidragger.DDL70rPA.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/utils.mAKpSMLY.0.0.30-alpha.3.js +1 -0
- package/dist/interface/{v-calendar.CapJoEkJ.0.0.30-alpha.0.js → v-calendar.C8Yj7x1Q.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{vee-validate.DcgOEpak.0.0.30-alpha.0.js → vee-validate.BbcoErf-.0.0.30-alpha.3.js} +2 -2
- package/dist/interface/{vue-i18n.D2pqkMP3.0.0.30-alpha.0.js → vue-i18n.B7m8y9GA.0.0.30-alpha.3.js} +2 -2
- package/dist/interface/{vue-inline-svg.DorOTPIf.0.0.30-alpha.0.js → vue-inline-svg.DC2U7Qim.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{vue-router.BVs4qaVs.0.0.30-alpha.0.js → vue-router.B3QeItm5.0.0.30-alpha.3.js} +2 -2
- package/dist/interface/{vue3-apexcharts.CBV9x5vk.0.0.30-alpha.0.js → vue3-apexcharts.DVzl7xGy.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{vue3-dnd.CXMddGIZ.0.0.30-alpha.0.js → vue3-dnd.76cFMD9V.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{vue3-toastify.DE7YmDSX.0.0.30-alpha.0.js → vue3-toastify.B-AJ7WuP.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/{vuetify.CYxxHEVN.0.0.30-alpha.0.js → vuetify.CYln2r6g.0.0.30-alpha.3.js} +1 -1
- package/dist/interface/zod.DnW1_kUe.0.0.30-alpha.3.js +1 -0
- package/dist/server/bin/cameraui.js +10 -7
- package/dist/server/bin/cameraui.js.map +1 -1
- package/dist/server/bin/fork.js +2 -2
- package/dist/server/bin/fork.js.map +1 -1
- package/dist/server/bin/installer/darwin.js +1 -1
- package/dist/server/bin/installer/darwin.js.map +1 -1
- package/dist/server/bin/installer/linux.js +1 -1
- package/dist/server/bin/installer/linux.js.map +1 -1
- package/dist/server/package.json +11 -15
- package/dist/server/src/api/controllers/backup.controller.js.map +1 -1
- package/dist/server/src/api/controllers/cameras.controller.js +1 -1
- package/dist/server/src/api/controllers/cameras.controller.js.map +1 -1
- package/dist/server/src/api/controllers/frameWorkers.controller.js +1 -1
- package/dist/server/src/api/controllers/frameWorkers.controller.js.map +1 -1
- package/dist/server/src/api/controllers/plugins.controller.js +1 -2
- package/dist/server/src/api/controllers/plugins.controller.js.map +1 -1
- package/dist/server/src/api/controllers/system.controller.js +1 -3
- package/dist/server/src/api/controllers/system.controller.js.map +1 -1
- package/dist/server/src/api/controllers/users.controller.js +2 -2
- package/dist/server/src/api/controllers/users.controller.js.map +1 -1
- package/dist/server/src/api/database/constants.d.ts +8 -0
- package/dist/server/src/api/database/constants.js +9 -0
- package/dist/server/src/api/database/constants.js.map +1 -0
- package/dist/server/src/api/database/index.d.ts +0 -8
- package/dist/server/src/api/database/index.js +14 -21
- package/dist/server/src/api/database/index.js.map +1 -1
- package/dist/server/src/api/database/migration.js +5 -4
- package/dist/server/src/api/database/migration.js.map +1 -1
- package/dist/server/src/api/database/types.d.ts +6 -6
- package/dist/server/src/api/go2rtc/api/application.js +1 -1
- package/dist/server/src/api/go2rtc/api/application.js.map +1 -1
- package/dist/server/src/api/index.js.map +1 -1
- package/dist/server/src/api/plugins/logger.plugin.js.map +1 -1
- package/dist/server/src/api/schemas/cameras.schema.d.ts +71 -71
- package/dist/server/src/api/schemas/config.schema.d.ts +6 -6
- package/dist/server/src/api/schemas/go2rtc.schema.d.ts +98 -98
- package/dist/server/src/api/schemas/users.schema.d.ts +116 -116
- package/dist/server/src/api/services/auth.service.js +1 -1
- package/dist/server/src/api/services/auth.service.js.map +1 -1
- package/dist/server/src/api/services/backup.service.js.map +1 -1
- package/dist/server/src/api/services/cameras.service.js +1 -1
- package/dist/server/src/api/services/cameras.service.js.map +1 -1
- package/dist/server/src/api/services/system.service.js +1 -1
- package/dist/server/src/api/services/system.service.js.map +1 -1
- package/dist/server/src/api/services/users.service.js +1 -1
- package/dist/server/src/api/services/users.service.js.map +1 -1
- package/dist/server/src/api/types/index.d.ts +2 -2
- package/dist/server/src/api/types/index.js.map +1 -1
- package/dist/server/src/api/utils/cert.js.map +1 -1
- package/dist/server/src/api/websocket/index.js.map +1 -1
- package/dist/server/src/api/websocket/nsp/notifications.js.map +1 -1
- package/dist/server/src/api/websocket/nsp/server.js +1 -1
- package/dist/server/src/api/websocket/nsp/server.js.map +1 -1
- package/dist/server/src/api.d.ts +1 -7
- package/dist/server/src/api.js.map +1 -1
- package/dist/server/src/camera/controller.d.ts +4 -6
- package/dist/server/src/camera/controller.js +5 -8
- package/dist/server/src/camera/controller.js.map +1 -1
- package/dist/server/src/camera/types.d.ts +140 -13
- package/dist/server/src/camera/types.js.map +1 -1
- package/dist/server/src/decoder/index.js.map +1 -1
- package/dist/server/src/decoder/types.d.ts +1 -18
- package/dist/server/src/decoder/worker.d.ts +3 -2
- package/dist/server/src/decoder/worker.js +10 -22
- package/dist/server/src/decoder/worker.js.map +1 -1
- package/dist/server/src/go2rtc/index.js +2 -3
- package/dist/server/src/go2rtc/index.js.map +1 -1
- package/dist/server/src/main.js +3 -3
- package/dist/server/src/main.js.map +1 -1
- package/dist/server/src/nats/index.d.ts +3 -4
- package/dist/server/src/nats/index.js +1 -3
- package/dist/server/src/nats/index.js.map +1 -1
- package/dist/server/src/nats/proxy/cameraDevice.d.ts +2 -2
- package/dist/server/src/nats/proxy/coreManager.d.ts +4 -2
- package/dist/server/src/nats/proxy/coreManager.js +7 -0
- package/dist/server/src/nats/proxy/coreManager.js.map +1 -1
- package/dist/server/src/nats/proxy/deviceManager.d.ts +5 -5
- package/dist/server/src/nats/proxy/deviceManager.js +4 -2
- package/dist/server/src/nats/proxy/deviceManager.js.map +1 -1
- package/dist/server/src/nats/server.js +2 -3
- package/dist/server/src/nats/server.js.map +1 -1
- package/dist/server/src/nats/types.d.ts +19 -32
- package/dist/server/src/nats/utils.d.ts +1 -1
- package/dist/server/src/nats/websocket.js.map +1 -1
- package/dist/server/src/plugins/index.js +11 -9
- package/dist/server/src/plugins/index.js.map +1 -1
- package/dist/server/src/plugins/interfaces/base.d.ts +1 -1
- package/dist/server/src/plugins/plugin.d.ts +1 -1
- package/dist/server/src/plugins/plugin.js +4 -4
- package/dist/server/src/plugins/plugin.js.map +1 -1
- package/dist/server/src/plugins/types.d.ts +36 -3
- package/dist/server/src/plugins/types.js.map +1 -1
- package/dist/server/src/plugins/worker.js +7 -16
- package/dist/server/src/plugins/worker.js.map +1 -1
- package/dist/server/src/services/config/constants.js +2 -2
- package/dist/server/src/services/config/constants.js.map +1 -1
- package/dist/server/src/services/config/index.d.ts +2 -0
- package/dist/server/src/services/config/index.js +10 -2
- package/dist/server/src/services/config/index.js.map +1 -1
- package/dist/server/src/services/logger/index.d.ts +4 -16
- package/dist/server/src/services/logger/index.js +4 -83
- package/dist/server/src/services/logger/index.js.map +1 -1
- package/dist/server/src/services/logger/types.d.ts +8 -0
- package/dist/server/src/services/logger/types.js +2 -0
- package/dist/server/src/services/logger/types.js.map +1 -0
- package/localdeps.txt +4 -0
- package/package.json +11 -15
- package/dist/interface/@tanstack.DYQ7Jj8U.0.0.30-alpha.0.js +0 -1
- package/dist/interface/@vue.CvjRlaU6.0.0.30-alpha.0.js +0 -17
- package/dist/interface/Account.Dm2FouAU.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Adminpanel.B2Aiobnt.0.0.30-alpha.0.js +0 -2
- package/dist/interface/Appearance.EfH0tMdM.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Backup.D8SRclhB.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Camera.D-cOf4sS.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Cameras.oolxbmXU.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Camview.BHw8Pe3v.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Config.DmPTI5iz.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Console.Dq4khHFF.0.0.30-alpha.0.js +0 -4
- package/dist/interface/FirstSteps.Bo467abx.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Plugin.BLTVcTt1.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Plugins.Cp8mK__o.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Recordings.B_JIFk_G.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Recordings.gMbvwmk_.0.0.30-alpha.0.js +0 -1
- package/dist/interface/Settings.EhHJjGrl.0.0.30-alpha.0.js +0 -1
- package/dist/interface/System.VodoK0U6.0.0.30-alpha.0.js +0 -4
- package/dist/interface/User.DpcN7DEC.0.0.30-alpha.0.js +0 -1
- package/dist/interface/VConfigEditor.vue_vue_type_script_setup_true_lang.Br68bfQJ.0.0.30-alpha.0.js +0 -2
- package/dist/interface/VPlayer.DYua3Eh_.0.0.30-alpha.0.js +0 -1
- package/dist/interface/main.19pRAqPU.0.0.30-alpha.0.js +0 -4
- package/dist/interface/utils.BvINh1mj.0.0.30-alpha.0.js +0 -1
- package/dist/interface/zod.BaF2dDCd.0.0.30-alpha.0.js +0 -1
- package/dist/server/src/camera/device.d.ts +0 -29
- package/dist/server/src/camera/device.js +0 -20
- package/dist/server/src/camera/device.js.map +0 -1
- package/dist/server/src/camera/index.d.ts +0 -90
- package/dist/server/src/camera/index.js +0 -581
- package/dist/server/src/camera/index.js.map +0 -1
- package/dist/server/src/camera/interfaces/camera.d.ts +0 -10
- package/dist/server/src/camera/interfaces/camera.js +0 -23
- package/dist/server/src/camera/interfaces/camera.js.map +0 -1
- package/dist/server/src/camera/interfaces/prebuffer.d.ts +0 -11
- package/dist/server/src/camera/interfaces/prebuffer.js +0 -31
- package/dist/server/src/camera/interfaces/prebuffer.js.map +0 -1
- package/dist/server/src/camera/interfaces/ptz.d.ts +0 -13
- package/dist/server/src/camera/interfaces/ptz.js +0 -47
- package/dist/server/src/camera/interfaces/ptz.js.map +0 -1
- package/dist/server/src/camera/iou.d.ts +0 -2
- package/dist/server/src/camera/iou.js +0 -53
- package/dist/server/src/camera/iou.js.map +0 -1
- package/dist/server/src/camera/polygon.d.ts +0 -6
- package/dist/server/src/camera/polygon.js +0 -151
- package/dist/server/src/camera/polygon.js.map +0 -1
- package/dist/server/src/camera/streaming/peer-connection.d.ts +0 -55
- package/dist/server/src/camera/streaming/peer-connection.js +0 -203
- package/dist/server/src/camera/streaming/peer-connection.js.map +0 -1
- package/dist/server/src/camera/streaming/webrtc-connection.d.ts +0 -35
- package/dist/server/src/camera/streaming/webrtc-connection.js +0 -170
- package/dist/server/src/camera/streaming/webrtc-connection.js.map +0 -1
- package/dist/server/src/camera/streaming/werift-session.d.ts +0 -41
- package/dist/server/src/camera/streaming/werift-session.js +0 -179
- package/dist/server/src/camera/streaming/werift-session.js.map +0 -1
- package/dist/server/src/camera/videoFrame.d.ts +0 -24
- package/dist/server/src/camera/videoFrame.js +0 -104
- package/dist/server/src/camera/videoFrame.js.map +0 -1
- package/dist/server/src/index.d.ts +0 -18
- package/dist/server/src/index.js +0 -5
- package/dist/server/src/index.js.map +0 -1
- package/dist/server/src/nats/connection.d.ts +0 -17
- package/dist/server/src/nats/connection.js +0 -66
- package/dist/server/src/nats/connection.js.map +0 -1
- package/dist/server/src/nats/constants.d.ts +0 -1
- package/dist/server/src/nats/constants.js +0 -2
- package/dist/server/src/nats/constants.js.map +0 -1
- package/dist/server/src/nats/error.d.ts +0 -9
- package/dist/server/src/nats/error.js +0 -11
- package/dist/server/src/nats/error.js.map +0 -1
- package/dist/server/src/nats/messageQueue.d.ts +0 -20
- package/dist/server/src/nats/messageQueue.js +0 -132
- package/dist/server/src/nats/messageQueue.js.map +0 -1
- package/dist/server/src/nats/subscription.d.ts +0 -12
- package/dist/server/src/nats/subscription.js +0 -21
- package/dist/server/src/nats/subscription.js.map +0 -1
- package/dist/server/src/polyglot/node/decoder/child.d.ts +0 -1
- package/dist/server/src/polyglot/node/decoder/child.js +0 -644
- package/dist/server/src/polyglot/node/decoder/child.js.map +0 -1
- package/dist/server/src/polyglot/node/decoder/imageUtils.d.ts +0 -24
- package/dist/server/src/polyglot/node/decoder/imageUtils.js +0 -205
- package/dist/server/src/polyglot/node/decoder/imageUtils.js.map +0 -1
- package/dist/server/src/polyglot/node/decoder/wasm/build/decoder.d.ts +0 -144
- package/dist/server/src/polyglot/node/decoder/wasm/build/decoder.js +0 -65
- package/dist/server/src/polyglot/node/decoder/wasm/build/decoder.wasm +0 -0
- package/dist/server/src/polyglot/node/decoder/wasm/test/imageUtils.py +0 -106
- package/dist/server/src/polyglot/node/plugins/cameraStorage.d.ts +0 -107
- package/dist/server/src/polyglot/node/plugins/cameraStorage.js +0 -292
- package/dist/server/src/polyglot/node/plugins/cameraStorage.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/child.d.ts +0 -28
- package/dist/server/src/polyglot/node/plugins/child.js +0 -222
- package/dist/server/src/polyglot/node/plugins/child.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/configService.d.ts +0 -104
- package/dist/server/src/polyglot/node/plugins/configService.js +0 -213
- package/dist/server/src/polyglot/node/plugins/configService.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/pluginApi.d.ts +0 -35
- package/dist/server/src/polyglot/node/plugins/pluginApi.js +0 -23
- package/dist/server/src/polyglot/node/plugins/pluginApi.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/pluginLogger.d.ts +0 -18
- package/dist/server/src/polyglot/node/plugins/pluginLogger.js +0 -89
- package/dist/server/src/polyglot/node/plugins/pluginLogger.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/proxy/cameraDevice.d.ts +0 -69
- package/dist/server/src/polyglot/node/plugins/proxy/cameraDevice.js +0 -423
- package/dist/server/src/polyglot/node/plugins/proxy/cameraDevice.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/proxy/coreManager.d.ts +0 -40
- package/dist/server/src/polyglot/node/plugins/proxy/coreManager.js +0 -105
- package/dist/server/src/polyglot/node/plugins/proxy/coreManager.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/proxy/deviceManager.d.ts +0 -47
- package/dist/server/src/polyglot/node/plugins/proxy/deviceManager.js +0 -164
- package/dist/server/src/polyglot/node/plugins/proxy/deviceManager.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/schema.d.ts +0 -293
- package/dist/server/src/polyglot/node/plugins/schema.js +0 -740
- package/dist/server/src/polyglot/node/plugins/schema.js.map +0 -1
- package/dist/server/src/polyglot/node/plugins/storageController.d.ts +0 -30
- package/dist/server/src/polyglot/node/plugins/storageController.js +0 -40
- package/dist/server/src/polyglot/node/plugins/storageController.js.map +0 -1
- package/dist/server/src/polyglot/python/camera/interfaces/camera.py +0 -20
- package/dist/server/src/polyglot/python/camera/interfaces/prebuffer.py +0 -28
- package/dist/server/src/polyglot/python/camera/interfaces/ptz.py +0 -38
- package/dist/server/src/polyglot/python/camera/iou.py +0 -80
- package/dist/server/src/polyglot/python/camera/polygon.py +0 -173
- package/dist/server/src/polyglot/python/camera/video_frame.py +0 -188
- package/dist/server/src/polyglot/python/camera_ui_types/__init__.py +0 -1200
- package/dist/server/src/polyglot/python/decoder/child.py +0 -882
- package/dist/server/src/polyglot/python/decoder/image_utils.py +0 -149
- package/dist/server/src/polyglot/python/decoder/typings.py +0 -99
- package/dist/server/src/polyglot/python/plugins/camera_storage.py +0 -391
- package/dist/server/src/polyglot/python/plugins/child.py +0 -394
- package/dist/server/src/polyglot/python/plugins/config_service.py +0 -187
- package/dist/server/src/polyglot/python/plugins/constants.py +0 -1
- package/dist/server/src/polyglot/python/plugins/message_queue.py +0 -182
- package/dist/server/src/polyglot/python/plugins/plugin_api.py +0 -34
- package/dist/server/src/polyglot/python/plugins/plugin_logger.py +0 -111
- package/dist/server/src/polyglot/python/plugins/proxy/camera_device.py +0 -1599
- package/dist/server/src/polyglot/python/plugins/proxy/core_manager.py +0 -145
- package/dist/server/src/polyglot/python/plugins/proxy/device_manager.py +0 -226
- package/dist/server/src/polyglot/python/plugins/schema.py +0 -181
- package/dist/server/src/polyglot/python/plugins/storage_controller.py +0 -58
- package/dist/server/src/polyglot/python/plugins/typings.py +0 -253
- package/dist/server/src/polyglot/python/utilities/connection.py +0 -86
- package/dist/server/src/polyglot/python/utilities/json_lmdb.py +0 -19
- package/dist/server/src/polyglot/python/utilities/object_path.py +0 -195
- package/dist/server/src/polyglot/python/utilities/packer.py +0 -11
- package/dist/server/src/polyglot/python/utilities/subscriptions.py +0 -22
- package/dist/server/src/polyglot/python/utilities/task.py +0 -35
- package/dist/server/src/polyglot/python/utilities/thread.py +0 -10
- package/dist/server/src/polyglot/python/utilities/utils.py +0 -73
- package/dist/server/src/utils/ffmpeg.d.ts +0 -2
- package/dist/server/src/utils/ffmpeg.js +0 -61
- package/dist/server/src/utils/ffmpeg.js.map +0 -1
- package/dist/server/src/utils/network.d.ts +0 -12
- package/dist/server/src/utils/network.js +0 -92
- package/dist/server/src/utils/network.js.map +0 -1
- package/dist/server/src/utils/npm.d.ts +0 -4
- package/dist/server/src/utils/npm.js +0 -128
- package/dist/server/src/utils/npm.js.map +0 -1
- package/dist/server/src/utils/packer.d.ts +0 -2
- package/dist/server/src/utils/packer.js +0 -17
- package/dist/server/src/utils/packer.js.map +0 -1
- package/dist/server/src/utils/pythonInstaller.d.ts +0 -48
- package/dist/server/src/utils/pythonInstaller.js +0 -494
- package/dist/server/src/utils/pythonInstaller.js.map +0 -1
- package/dist/server/src/utils/reader.d.ts +0 -5
- package/dist/server/src/utils/reader.js +0 -41
- package/dist/server/src/utils/reader.js.map +0 -1
- package/dist/server/src/utils/subscribed.d.ts +0 -9
- package/dist/server/src/utils/subscribed.js +0 -17
- package/dist/server/src/utils/subscribed.js.map +0 -1
- package/dist/server/src/utils/utils.d.ts +0 -10
- package/dist/server/src/utils/utils.js +0 -165
- package/dist/server/src/utils/utils.js.map +0 -1
- /package/dist/interface/{@babel.l0sNRNKZ.0.0.30-alpha.0.js → @babel.l0sNRNKZ.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{@intlify.YW_pt133.0.0.30-alpha.0.js → @intlify.YW_pt133.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{@mdi.DnMbZhUH.0.0.30-alpha.0.js → @mdi.DnMbZhUH.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{@popperjs.BQBsAJpH.0.0.30-alpha.0.js → @popperjs.BQBsAJpH.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{@react-dnd.CcwRs9xb.0.0.30-alpha.0.js → @react-dnd.CcwRs9xb.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{@socket.io.Dkula2eQ.0.0.30-alpha.0.js → @socket.io.Dkula2eQ.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{@xterm.CnserxUX.0.0.30-alpha.0.js → @xterm.-WsTvn6n.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/assets/{@vueform.0.0.30-alpha.0.h7tNX9p6.css → @vueform.0.0.30-alpha.3.h7tNX9p6.css} +0 -0
- /package/dist/interface/assets/{@xterm.0.0.30-alpha.0.CGrrDQr5.css → @xterm.0.0.30-alpha.3.CGrrDQr5.css} +0 -0
- /package/dist/interface/assets/{Account.0.0.30-alpha.0.Ce3OmKrC.css → Account.0.0.30-alpha.3.Ce3OmKrC.css} +0 -0
- /package/dist/interface/assets/{Adminpanel.0.0.30-alpha.0.CXsTAXPL.css → Adminpanel.0.0.30-alpha.3.CXsTAXPL.css} +0 -0
- /package/dist/interface/assets/{Backup.0.0.30-alpha.0.BIwaSlv3.css → Backup.0.0.30-alpha.3.BIwaSlv3.css} +0 -0
- /package/dist/interface/assets/{Camera.0.0.30-alpha.0.BDtUJ-lA.css → Camera.0.0.30-alpha.3.BDtUJ-lA.css} +0 -0
- /package/dist/interface/assets/{Cameras.0.0.30-alpha.0.Djx0F2MM.css → Cameras.0.0.30-alpha.3.Djx0F2MM.css} +0 -0
- /package/dist/interface/assets/{Camview.0.0.30-alpha.0.Ce_V-Nxj.css → Camview.0.0.30-alpha.3.Ce_V-Nxj.css} +0 -0
- /package/dist/interface/assets/{Config.0.0.30-alpha.0.k4QpWumg.css → Config.0.0.30-alpha.3.k4QpWumg.css} +0 -0
- /package/dist/interface/assets/{Console.0.0.30-alpha.0.DWrfRWs9.css → Console.0.0.30-alpha.3.DWrfRWs9.css} +0 -0
- /package/dist/interface/assets/{FirstSteps.0.0.30-alpha.0.B3-pv8-a.css → FirstSteps.0.0.30-alpha.3.B3-pv8-a.css} +0 -0
- /package/dist/interface/assets/{NewCamera.0.0.30-alpha.0.DJ3tUBT_.css → NewCamera.0.0.30-alpha.3.DJ3tUBT_.css} +0 -0
- /package/dist/interface/assets/{Plugin.0.0.30-alpha.0.BtRA6zDt.css → Plugin.0.0.30-alpha.3.BtRA6zDt.css} +0 -0
- /package/dist/interface/assets/{Plugins.0.0.30-alpha.0.Cwu0aGUO.css → Plugins.0.0.30-alpha.3.Cwu0aGUO.css} +0 -0
- /package/dist/interface/assets/{Settings.0.0.30-alpha.0.DC_-E3CR.css → Settings.0.0.30-alpha.3.DC_-E3CR.css} +0 -0
- /package/dist/interface/assets/{User.0.0.30-alpha.0.DPDcJbx8.css → User.0.0.30-alpha.3.DPDcJbx8.css} +0 -0
- /package/dist/interface/assets/{VConsole.0.0.30-alpha.0.BZT1WyS-.css → VConsole.0.0.30-alpha.3.BZT1WyS-.css} +0 -0
- /package/dist/interface/assets/{VPlayer.0.0.30-alpha.0.CZXlTn4I.css → VPlayer.0.0.30-alpha.3.CZXlTn4I.css} +0 -0
- /package/dist/interface/assets/{VPluginCard.0.0.30-alpha.0.CIL48ca_.css → VPluginCard.0.0.30-alpha.3.CIL48ca_.css} +0 -0
- /package/dist/interface/assets/{highlight.0.0.30-alpha.0.DgoK_Xib.css → highlight.0.0.30-alpha.3.DgoK_Xib.css} +0 -0
- /package/dist/interface/assets/{logo-256.0.0.30-alpha.0.BCQk9H1-.png → logo-256.0.0.30-alpha.3.BCQk9H1-.png} +0 -0
- /package/dist/interface/assets/{logo-512.0.0.30-alpha.0.DLKVOU2S.png → logo-512.0.0.30-alpha.3.DLKVOU2S.png} +0 -0
- /package/dist/interface/assets/{logo.0.0.30-alpha.0.DmEiRk0z.png → logo.0.0.30-alpha.3.DmEiRk0z.png} +0 -0
- /package/dist/interface/assets/{main.0.0.30-alpha.0.BOf8IWhK.css → main.0.0.30-alpha.3.BOf8IWhK.css} +0 -0
- /package/dist/interface/assets/{mode-json.0.0.30-alpha.0.Br7xisR1.js → mode-json.0.0.30-alpha.3.Br7xisR1.js} +0 -0
- /package/dist/interface/assets/{mode-yaml.0.0.30-alpha.0.CIYL8U3d.js → mode-yaml.0.0.30-alpha.3.CIYL8U3d.js} +0 -0
- /package/dist/interface/assets/{v-calendar.0.0.30-alpha.0.CtSuDYZU.css → v-calendar.0.0.30-alpha.3.CtSuDYZU.css} +0 -0
- /package/dist/interface/assets/{vue3-toastify.0.0.30-alpha.0.DTY1DMRs.css → vue3-toastify.0.0.30-alpha.3.DTY1DMRs.css} +0 -0
- /package/dist/interface/assets/{vuetify.0.0.30-alpha.0.Cd1awv3t.css → vuetify.0.0.30-alpha.3.Cd1awv3t.css} +0 -0
- /package/dist/interface/{axios.C-n2IhIP.0.0.30-alpha.0.js → axios.C-n2IhIP.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{compare-versions.DqEOhma6.0.0.30-alpha.0.js → compare-versions.DqEOhma6.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{dijkstrajs.D_NXgYpA.0.0.30-alpha.0.js → dijkstrajs.D_NXgYpA.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{engine.io-parser.BiEtp6m2.0.0.30-alpha.0.js → engine.io-parser.BiEtp6m2.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{entities.C20TfXL6.0.0.30-alpha.0.js → entities.C20TfXL6.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{get-size.D1dS-IaP.0.0.30-alpha.0.js → get-size.D1dS-IaP.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{mdurl.k9Sl0PQj.0.0.30-alpha.0.js → mdurl.k9Sl0PQj.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{punycode.js.Dj65hjkv.0.0.30-alpha.0.js → punycode.js.Dj65hjkv.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{react-dnd-html5-backend.1HQjlkwI.0.0.30-alpha.0.js → react-dnd-html5-backend.1HQjlkwI.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{redux.CuxFRhX_.0.0.30-alpha.0.js → redux.CuxFRhX_.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{tslib.9k7AwCpt.0.0.30-alpha.0.js → tslib.9k7AwCpt.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{uc.micro.kMc2yuuw.0.0.30-alpha.0.js → uc.micro.kMc2yuuw.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{uuid.DvF23Exx.0.0.30-alpha.0.js → uuid.DvF23Exx.0.0.30-alpha.3.js} +0 -0
- /package/dist/interface/{vue.l0sNRNKZ.0.0.30-alpha.0.js → vue.l0sNRNKZ.0.0.30-alpha.3.js} +0 -0
|
@@ -1,1599 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import inspect
|
|
3
|
-
import traceback
|
|
4
|
-
from collections.abc import AsyncGenerator
|
|
5
|
-
from contextlib import suppress
|
|
6
|
-
from copy import deepcopy
|
|
7
|
-
from datetime import datetime
|
|
8
|
-
from typing import Any, Optional, Union, cast
|
|
9
|
-
from uuid import uuid4
|
|
10
|
-
|
|
11
|
-
import aiohttp
|
|
12
|
-
from cachetools import LRUCache, cached
|
|
13
|
-
from camera.iou import merge_detections
|
|
14
|
-
from camera.polygon import are_motion_detections_valid, are_object_detections_valid
|
|
15
|
-
from camera.video_frame import MotionFrame, VideoFrame
|
|
16
|
-
from camera_ui_types import (
|
|
17
|
-
AudioSetEvent,
|
|
18
|
-
AudioState,
|
|
19
|
-
BatterySetEvent,
|
|
20
|
-
BatteryState,
|
|
21
|
-
Camera,
|
|
22
|
-
CameraActivitySettings,
|
|
23
|
-
CameraConfigInputSettings,
|
|
24
|
-
CameraConfigInputSettingsPartial,
|
|
25
|
-
CameraDelegate,
|
|
26
|
-
CameraDelegateMethodNames,
|
|
27
|
-
CameraFrameWorkerSettings,
|
|
28
|
-
CameraInformation,
|
|
29
|
-
CameraInput,
|
|
30
|
-
CameraPrebufferDelegate,
|
|
31
|
-
CameraPrebufferDelegateMethodNames,
|
|
32
|
-
CameraPropertyObservableObject,
|
|
33
|
-
CameraPTZDelegate,
|
|
34
|
-
CameraPTZDelegateMethodNames,
|
|
35
|
-
CameraPublicProperties,
|
|
36
|
-
CameraType,
|
|
37
|
-
Container,
|
|
38
|
-
DetectionZone,
|
|
39
|
-
DoorbellSetEvent,
|
|
40
|
-
DoorbellState,
|
|
41
|
-
FrameData,
|
|
42
|
-
FrameMetadata,
|
|
43
|
-
FrameState,
|
|
44
|
-
LightSetEvent,
|
|
45
|
-
LightState,
|
|
46
|
-
MotionSetEvent,
|
|
47
|
-
MotionState,
|
|
48
|
-
ObjectSetEvent,
|
|
49
|
-
ObjectState,
|
|
50
|
-
PrebufferState,
|
|
51
|
-
SetValue,
|
|
52
|
-
SirenSetEvent,
|
|
53
|
-
SirenState,
|
|
54
|
-
StateNames,
|
|
55
|
-
StateValue,
|
|
56
|
-
StreamInfo,
|
|
57
|
-
)
|
|
58
|
-
from decoder.typings import AuthConfig, PingMessage, PongMessage, SignalingRequest, SignalingResponse
|
|
59
|
-
from deepdiff import DeepDiff
|
|
60
|
-
from message_queue import MessageQueue
|
|
61
|
-
from nats.aio.msg import Msg
|
|
62
|
-
from plugin_api import PluginAPI
|
|
63
|
-
from plugin_logger import PluginLogger
|
|
64
|
-
from reactivex import Observable
|
|
65
|
-
from reactivex import operators as ops
|
|
66
|
-
from reactivex.subject.behaviorsubject import BehaviorSubject
|
|
67
|
-
from typing_extensions import Literal, overload
|
|
68
|
-
from typings import (
|
|
69
|
-
CameraDeviceProxyMethodNames,
|
|
70
|
-
ClientType,
|
|
71
|
-
Delegates,
|
|
72
|
-
DeserializedError,
|
|
73
|
-
FrameSubscribtion,
|
|
74
|
-
PluginInfo,
|
|
75
|
-
ProxyMessageStructure,
|
|
76
|
-
)
|
|
77
|
-
from utilities.connection import ProxyConnection
|
|
78
|
-
from utilities.packer import pack, unpack
|
|
79
|
-
from utilities.subscriptions import ProxySubscription
|
|
80
|
-
from utilities.task import TaskSet
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class CameraSource:
|
|
84
|
-
def __init__(self, source: CameraInput, parent: Any):
|
|
85
|
-
self.__parent: CameraDeviceProxy = parent
|
|
86
|
-
|
|
87
|
-
self.id = source["_id"]
|
|
88
|
-
self.name = source["name"]
|
|
89
|
-
self.roles = source["roles"]
|
|
90
|
-
self.urls = source["urls"]
|
|
91
|
-
|
|
92
|
-
async def get_prebuffering_state(self, container: Container) -> Optional[PrebufferState]:
|
|
93
|
-
return await self.__parent.prebufferDelegate.getPrebufferingState(self.name, container)
|
|
94
|
-
|
|
95
|
-
async def get_stream_info(self) -> Optional[StreamInfo]:
|
|
96
|
-
return await self.__parent.prebufferDelegate.getStreamInfo(self.name)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
class CameraDeviceProxy:
|
|
100
|
-
def __init__(
|
|
101
|
-
self,
|
|
102
|
-
api: PluginAPI,
|
|
103
|
-
logger: PluginLogger,
|
|
104
|
-
camera: Camera,
|
|
105
|
-
plugin: PluginInfo,
|
|
106
|
-
proxy_endpoints: list[str],
|
|
107
|
-
auth: AuthConfig,
|
|
108
|
-
):
|
|
109
|
-
self.snapshot_cache = LRUCache(maxsize=100)
|
|
110
|
-
self.camera_subject = BehaviorSubject(camera)
|
|
111
|
-
|
|
112
|
-
self.camera_state = BehaviorSubject[bool](False)
|
|
113
|
-
self.light_state = BehaviorSubject[LightState](self.__get_light_state({"state": False}, True))
|
|
114
|
-
self.motion_state = BehaviorSubject[MotionState](
|
|
115
|
-
self.__get_motion_state({"detections": [], "state": False}, True)
|
|
116
|
-
)
|
|
117
|
-
self.audio_state = BehaviorSubject[AudioState](
|
|
118
|
-
self.__get_audio_state({"state": False, "db": 0}, True)
|
|
119
|
-
)
|
|
120
|
-
self.object_state = BehaviorSubject[ObjectState](self.__get_object_state({"detections": []}, True))
|
|
121
|
-
self.doorbell_state = BehaviorSubject[DoorbellState](
|
|
122
|
-
self.__get_doorbell_state({"state": False}, True)
|
|
123
|
-
)
|
|
124
|
-
self.siren_state = BehaviorSubject[SirenState](
|
|
125
|
-
self.__get_siren_state({"state": False, "level": 0}, True)
|
|
126
|
-
)
|
|
127
|
-
self.battery_state = BehaviorSubject[BatteryState](
|
|
128
|
-
self.__get_battery_state({"level": 100, "charging": False, "lowBattery": False}, True)
|
|
129
|
-
)
|
|
130
|
-
self.__frame_state = BehaviorSubject[FrameState](
|
|
131
|
-
{
|
|
132
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
133
|
-
"detections": [],
|
|
134
|
-
"frameData": cast(FrameData, {}),
|
|
135
|
-
"metadata": cast(FrameMetadata, {}),
|
|
136
|
-
},
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
self.on_connected: Observable[bool] = self.__create_state_observable(self.camera_state)
|
|
140
|
-
self.on_light_switched: Observable[LightState] = self.__create_state_observable(self.light_state)
|
|
141
|
-
self.on_motion_detected: Observable[MotionState] = self.__create_state_observable(self.motion_state)
|
|
142
|
-
self.on_audio_detected: Observable[AudioState] = self.__create_state_observable(self.audio_state)
|
|
143
|
-
self.on_object_detected: Observable[ObjectState] = self.__create_state_observable(self.object_state)
|
|
144
|
-
self.on_doorbell_pressed: Observable[DoorbellState] = self.__create_state_observable(
|
|
145
|
-
self.doorbell_state
|
|
146
|
-
)
|
|
147
|
-
self.on_siren_detected: Observable[SirenState] = self.__create_state_observable(self.siren_state)
|
|
148
|
-
self.on_battery_changed: Observable[BatteryState] = self.__create_state_observable(self.battery_state)
|
|
149
|
-
self.__on_frame: Observable[FrameState] = self.__create_motion_frame_observable()
|
|
150
|
-
|
|
151
|
-
if camera["pluginId"] == "native":
|
|
152
|
-
self.camera_state.on_next(True)
|
|
153
|
-
|
|
154
|
-
self.initialized = False
|
|
155
|
-
|
|
156
|
-
self.api = api
|
|
157
|
-
self.logger = logger
|
|
158
|
-
|
|
159
|
-
self.auth = auth
|
|
160
|
-
self.proxy_endpoints = proxy_endpoints
|
|
161
|
-
self.plugin = plugin
|
|
162
|
-
|
|
163
|
-
from camera.interfaces.camera import CameraInterface
|
|
164
|
-
from camera.interfaces.prebuffer import CameraPrebufferInterface
|
|
165
|
-
from camera.interfaces.ptz import CameraPTZInterface
|
|
166
|
-
|
|
167
|
-
self.cameraDelegate = CameraInterface(self, logger)
|
|
168
|
-
self.ptzDelegate = CameraPTZInterface(self, logger)
|
|
169
|
-
self.prebufferDelegate = CameraPrebufferInterface(self, logger)
|
|
170
|
-
|
|
171
|
-
self.subject = f"{self.plugin['id']}.camera.{self.id}"
|
|
172
|
-
self.camera_subscriber_subject = f"{self.id}.camera"
|
|
173
|
-
self.camera_plugin_subscriber_subject = f"{self.id}.camera.{self.plugin['id']}"
|
|
174
|
-
self.frame_subject = f"{self.id}.frameReceiver"
|
|
175
|
-
self.motion_frame_subject = f"{self.id}.frameGenerator.motionFrame"
|
|
176
|
-
self.signaling_subject = f"{self.plugin['id']}.camera.{self.id}.signaling"
|
|
177
|
-
self.signaling_target_subject = f"{self.id}.frameGenerator.signaling"
|
|
178
|
-
|
|
179
|
-
self.publisher: Optional[ProxyConnection] = None
|
|
180
|
-
self.camera_publisher: Optional[ProxyConnection] = None
|
|
181
|
-
self.frame_publisher: Optional[ProxyConnection] = None
|
|
182
|
-
self.motion_frame_publisher: Optional[ProxyConnection] = None
|
|
183
|
-
self.signaling_publisher: Optional[ProxyConnection] = None
|
|
184
|
-
|
|
185
|
-
self.subscriber: Optional[ProxySubscription] = None
|
|
186
|
-
self.camera_subscriber: Optional[ProxySubscription] = None
|
|
187
|
-
self.camera_plugin_subscriber: Optional[ProxySubscription] = None
|
|
188
|
-
self.signaling_subscriber: Optional[ProxySubscription] = None
|
|
189
|
-
self.frame_subscribers: list[FrameSubscribtion] = []
|
|
190
|
-
self.motion_frame_subscribers: list[FrameSubscribtion] = []
|
|
191
|
-
|
|
192
|
-
self.tasks: TaskSet = TaskSet(f"{self.plugin['name']} - {self.name} - CameraDeviceProxy")
|
|
193
|
-
self.message_queue: Optional[MessageQueue] = None
|
|
194
|
-
self.active_requests: set[str] = set()
|
|
195
|
-
self.active_motion_requests: set[str] = set()
|
|
196
|
-
|
|
197
|
-
# print(("INIT camera device with clientSubject", self.subject))
|
|
198
|
-
|
|
199
|
-
self.__on_frame.subscribe(self.__on_motion_frame)
|
|
200
|
-
|
|
201
|
-
self.api.once("shutdown", self.cleanup)
|
|
202
|
-
|
|
203
|
-
@property
|
|
204
|
-
def camera_object(self) -> Camera:
|
|
205
|
-
return deepcopy(self.camera_subject.value)
|
|
206
|
-
|
|
207
|
-
@property
|
|
208
|
-
def id(self) -> str:
|
|
209
|
-
return self.camera_subject.value.get("_id")
|
|
210
|
-
|
|
211
|
-
@property
|
|
212
|
-
def native_id(self) -> Optional[str]:
|
|
213
|
-
return self.camera_subject.value.get("nativeId")
|
|
214
|
-
|
|
215
|
-
@property
|
|
216
|
-
def plugin_id(self) -> str:
|
|
217
|
-
return self.camera_subject.value.get("pluginId")
|
|
218
|
-
|
|
219
|
-
@property
|
|
220
|
-
def connected(self) -> bool:
|
|
221
|
-
return self.camera_state.value or False
|
|
222
|
-
|
|
223
|
-
@property
|
|
224
|
-
def disabled(self) -> bool:
|
|
225
|
-
return self.camera_subject.value.get("disabled")
|
|
226
|
-
|
|
227
|
-
@property
|
|
228
|
-
def name(self) -> str:
|
|
229
|
-
return self.camera_subject.value.get("name")
|
|
230
|
-
|
|
231
|
-
@property
|
|
232
|
-
def type(self) -> CameraType:
|
|
233
|
-
return self.camera_subject.value.get("type")
|
|
234
|
-
|
|
235
|
-
@property
|
|
236
|
-
def info(self) -> CameraInformation:
|
|
237
|
-
return deepcopy(self.camera_subject.value.get("info"))
|
|
238
|
-
|
|
239
|
-
@property
|
|
240
|
-
def is_cloud_camera(self) -> bool:
|
|
241
|
-
return self.camera_subject.value.get("isCloud")
|
|
242
|
-
|
|
243
|
-
@property
|
|
244
|
-
def has_light(self) -> bool:
|
|
245
|
-
return self.camera_subject.value.get("hasLight")
|
|
246
|
-
|
|
247
|
-
@property
|
|
248
|
-
def has_siren(self) -> bool:
|
|
249
|
-
return self.camera_subject.value.get("hasSiren")
|
|
250
|
-
|
|
251
|
-
@property
|
|
252
|
-
def has_binary_sensor(self) -> bool:
|
|
253
|
-
return self.camera_subject.value.get("hasBinarySensor")
|
|
254
|
-
|
|
255
|
-
@property
|
|
256
|
-
def has_battery(self) -> bool:
|
|
257
|
-
return self.camera_subject.value.get("hasBattery")
|
|
258
|
-
|
|
259
|
-
@property
|
|
260
|
-
def has_motion_detector(self) -> bool:
|
|
261
|
-
return self.camera_subject.value.get("hasMotionDetector")
|
|
262
|
-
|
|
263
|
-
@property
|
|
264
|
-
def has_audio_detector(self) -> bool:
|
|
265
|
-
return self.camera_subject.value.get("hasAudioDetector")
|
|
266
|
-
|
|
267
|
-
@property
|
|
268
|
-
def has_object_detector(self) -> bool:
|
|
269
|
-
return self.camera_subject.value.get("hasObjectDetector")
|
|
270
|
-
|
|
271
|
-
@property
|
|
272
|
-
def has_ptz(self) -> bool:
|
|
273
|
-
return self.camera_subject.value.get("hasPtz")
|
|
274
|
-
|
|
275
|
-
@property
|
|
276
|
-
def has_prebuffer(self) -> bool:
|
|
277
|
-
return self.camera_subject.value.get("hasPrebuffer")
|
|
278
|
-
|
|
279
|
-
@property
|
|
280
|
-
def activity_zones(self) -> list[DetectionZone]:
|
|
281
|
-
return deepcopy(self.camera_subject.value.get("activityZones"))
|
|
282
|
-
|
|
283
|
-
@property
|
|
284
|
-
def activity_settings(self) -> CameraActivitySettings:
|
|
285
|
-
return deepcopy(self.camera_subject.value.get("activitySettings"))
|
|
286
|
-
|
|
287
|
-
@property
|
|
288
|
-
def frameworker_settings(self) -> CameraFrameWorkerSettings:
|
|
289
|
-
return deepcopy(self.camera_subject.value.get("frameWorkerSettings"))
|
|
290
|
-
|
|
291
|
-
@property
|
|
292
|
-
def sources(self) -> list[CameraSource]:
|
|
293
|
-
sources = deepcopy(self.camera_subject.value.get("sources"))
|
|
294
|
-
return [CameraSource(source, self) for source in sources]
|
|
295
|
-
|
|
296
|
-
@property
|
|
297
|
-
def stream_source(self) -> CameraSource:
|
|
298
|
-
source = self.high_resolution_source or self.mid_resolution_source or self.low_resolution_source
|
|
299
|
-
return cast(CameraSource, source)
|
|
300
|
-
|
|
301
|
-
@property
|
|
302
|
-
def snapshot_source(self) -> Optional[CameraSource]:
|
|
303
|
-
return next(source for source in self.sources if "snapshot" in source.roles)
|
|
304
|
-
|
|
305
|
-
@property
|
|
306
|
-
def high_resolution_source(self) -> Optional[CameraSource]:
|
|
307
|
-
return next(source for source in self.sources if "high-resolution" in source.roles)
|
|
308
|
-
|
|
309
|
-
@property
|
|
310
|
-
def mid_resolution_source(self) -> Optional[CameraSource]:
|
|
311
|
-
return next(source for source in self.sources if "mid-resolution" in source.roles)
|
|
312
|
-
|
|
313
|
-
@property
|
|
314
|
-
def low_resolution_source(self) -> Optional[CameraSource]:
|
|
315
|
-
return next(source for source in self.sources if "low-resolution" in source.roles)
|
|
316
|
-
|
|
317
|
-
@property
|
|
318
|
-
def ptz(self) -> CameraPTZDelegate:
|
|
319
|
-
return self.ptzDelegate
|
|
320
|
-
|
|
321
|
-
async def init(self):
|
|
322
|
-
if self.initialized:
|
|
323
|
-
return
|
|
324
|
-
|
|
325
|
-
self.initialized = True
|
|
326
|
-
|
|
327
|
-
self.publisher = ProxyConnection(self.subject, self.proxy_endpoints, self.auth)
|
|
328
|
-
await self.publisher.connect()
|
|
329
|
-
|
|
330
|
-
self.camera_publisher = ProxyConnection(
|
|
331
|
-
self.camera_subscriber_subject, self.proxy_endpoints, self.auth
|
|
332
|
-
)
|
|
333
|
-
await self.camera_publisher.connect()
|
|
334
|
-
|
|
335
|
-
self.signaling_publisher = ProxyConnection(self.signaling_subject, self.proxy_endpoints, self.auth)
|
|
336
|
-
await self.signaling_publisher.connect()
|
|
337
|
-
|
|
338
|
-
self.frame_publisher = ProxyConnection(self.frame_subject, self.proxy_endpoints, self.auth)
|
|
339
|
-
await self.frame_publisher.connect()
|
|
340
|
-
|
|
341
|
-
self.motion_frame_publisher = ProxyConnection(
|
|
342
|
-
self.motion_frame_subject, self.proxy_endpoints, self.auth
|
|
343
|
-
)
|
|
344
|
-
await self.motion_frame_publisher.connect()
|
|
345
|
-
|
|
346
|
-
self.subscriber = await self.publisher.subscribe(subject=self.subject)
|
|
347
|
-
self.message_queue = MessageQueue(
|
|
348
|
-
self.logger,
|
|
349
|
-
self.publisher,
|
|
350
|
-
self.subscriber,
|
|
351
|
-
self.__request_handler,
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
self.signaling_subscriber = await self.signaling_publisher.subscribe(subject=self.signaling_subject)
|
|
355
|
-
self.signaling_subscriber.on("message", self.__on_signaling_message)
|
|
356
|
-
|
|
357
|
-
self.camera_subscriber = await self.camera_publisher.subscribe(subject=self.camera_subscriber_subject)
|
|
358
|
-
self.camera_subscriber.on("message", self.__on_proxy_message)
|
|
359
|
-
|
|
360
|
-
self.camera_plugin_subscriber = await self.camera_publisher.subscribe(
|
|
361
|
-
subject=self.camera_plugin_subscriber_subject
|
|
362
|
-
)
|
|
363
|
-
self.camera_plugin_subscriber.on("message", self.__on_proxy_message)
|
|
364
|
-
|
|
365
|
-
await self.refresh_states()
|
|
366
|
-
|
|
367
|
-
@overload
|
|
368
|
-
def set_delegate(self, name: Literal["cameraDelegate"], delegate: CameraDelegate) -> None: ...
|
|
369
|
-
@overload
|
|
370
|
-
def set_delegate(self, name: Literal["prebufferDelegate"], delegate: CameraPrebufferDelegate) -> None: ...
|
|
371
|
-
@overload
|
|
372
|
-
def set_delegate(self, name: Literal["ptzDelegate"], delegate: CameraPTZDelegate) -> None: ...
|
|
373
|
-
def set_delegate(self, name: Delegates, delegate: Any) -> None:
|
|
374
|
-
delegate = getattr(self, name, None)
|
|
375
|
-
|
|
376
|
-
if delegate:
|
|
377
|
-
delegate.delegate = delegate
|
|
378
|
-
|
|
379
|
-
async def connect(self) -> None:
|
|
380
|
-
return await self.on_request("cameraFn", "connect")
|
|
381
|
-
|
|
382
|
-
async def disconnect(self) -> None:
|
|
383
|
-
return await self.on_request("cameraFn", "disconnect")
|
|
384
|
-
|
|
385
|
-
@cached(cache=lambda self: self.snapshot_cache) # type: ignore
|
|
386
|
-
async def snapshot(self, force_new: Optional[bool] = None) -> Optional[bytes]:
|
|
387
|
-
source = self.snapshot_source or self.stream_source
|
|
388
|
-
cache_key = source.id
|
|
389
|
-
|
|
390
|
-
snapshot_url = source.urls["www"]["jpegSnapshot"]
|
|
391
|
-
from_cache: Any = self.snapshot_cache.get(snapshot_url) if cache_key in self.snapshot_cache else None
|
|
392
|
-
|
|
393
|
-
if from_cache and not force_new:
|
|
394
|
-
return from_cache
|
|
395
|
-
|
|
396
|
-
if "snapshot" not in source.roles and self.camera_object["pluginId"] != "native":
|
|
397
|
-
snapshot = await self.cameraDelegate.snapshot()
|
|
398
|
-
|
|
399
|
-
if snapshot and len(snapshot) > 0:
|
|
400
|
-
self.snapshot_cache[cache_key] = snapshot
|
|
401
|
-
|
|
402
|
-
return snapshot
|
|
403
|
-
|
|
404
|
-
async with aiohttp.ClientSession() as session, session.get(snapshot_url) as response:
|
|
405
|
-
if response.status != 200:
|
|
406
|
-
raise Exception(f"Status Code: {response.status}")
|
|
407
|
-
|
|
408
|
-
snapshot = await response.read()
|
|
409
|
-
|
|
410
|
-
if len(snapshot) > 0:
|
|
411
|
-
self.snapshot_cache[cache_key] = snapshot
|
|
412
|
-
|
|
413
|
-
return snapshot
|
|
414
|
-
|
|
415
|
-
async def get_frames(self, prebuffer_duration: int = 0) -> AsyncGenerator[VideoFrame, None]:
|
|
416
|
-
if not self.frame_publisher:
|
|
417
|
-
raise Exception("Frame Publisher is not initialized")
|
|
418
|
-
|
|
419
|
-
request_type: Literal["frame", "prebuffer"] = "frame"
|
|
420
|
-
prebuffer_duration = abs(prebuffer_duration)
|
|
421
|
-
|
|
422
|
-
if prebuffer_duration > 0:
|
|
423
|
-
request_type = "prebuffer"
|
|
424
|
-
prebuffer_duration = min(prebuffer_duration, 5)
|
|
425
|
-
|
|
426
|
-
request_id = f"{str(uuid4())}-{request_type}"
|
|
427
|
-
|
|
428
|
-
try:
|
|
429
|
-
metadata = await self.__connect_to_decoder(request_id)
|
|
430
|
-
frame_subscriber = await self.frame_publisher.subscribe(self.frame_subject)
|
|
431
|
-
|
|
432
|
-
self.frame_subscribers.append({"request_id": request_id, "subscriber": frame_subscriber})
|
|
433
|
-
|
|
434
|
-
try:
|
|
435
|
-
async for msg in frame_subscriber.subscriber.messages:
|
|
436
|
-
if (
|
|
437
|
-
not self.initialized
|
|
438
|
-
or len(self.active_requests) == 0
|
|
439
|
-
or request_id not in self.active_requests
|
|
440
|
-
):
|
|
441
|
-
return
|
|
442
|
-
|
|
443
|
-
if len(msg.data) == 0:
|
|
444
|
-
continue
|
|
445
|
-
|
|
446
|
-
frame_data: FrameData = unpack(msg.data)
|
|
447
|
-
|
|
448
|
-
yield VideoFrame(self.id, self.frame_publisher, frame_data, metadata, prebuffer_duration)
|
|
449
|
-
|
|
450
|
-
except GeneratorExit:
|
|
451
|
-
return
|
|
452
|
-
|
|
453
|
-
except asyncio.CancelledError:
|
|
454
|
-
return
|
|
455
|
-
except Exception as e:
|
|
456
|
-
if self.initialized:
|
|
457
|
-
self.logger.error("Error while generating frames:", e)
|
|
458
|
-
raise
|
|
459
|
-
finally:
|
|
460
|
-
await self.__disconnect_from_decoder(request_id)
|
|
461
|
-
|
|
462
|
-
async def get_motion_frames(self) -> AsyncGenerator[MotionFrame, None]:
|
|
463
|
-
if not self.motion_frame_publisher:
|
|
464
|
-
raise Exception("Motion Frame Publisher is not initialized")
|
|
465
|
-
|
|
466
|
-
request_id = f"{str(uuid4())}-motion"
|
|
467
|
-
|
|
468
|
-
try:
|
|
469
|
-
self.active_motion_requests.add(request_id)
|
|
470
|
-
|
|
471
|
-
motion_frame_subscriber = await self.motion_frame_publisher.subscribe(self.motion_frame_subject)
|
|
472
|
-
|
|
473
|
-
self.motion_frame_subscribers.append(
|
|
474
|
-
{"request_id": request_id, "subscriber": motion_frame_subscriber}
|
|
475
|
-
)
|
|
476
|
-
|
|
477
|
-
try:
|
|
478
|
-
async for msg in motion_frame_subscriber.subscriber.messages:
|
|
479
|
-
if (
|
|
480
|
-
not self.initialized
|
|
481
|
-
or len(self.active_motion_requests) == 0
|
|
482
|
-
or request_id not in self.active_motion_requests
|
|
483
|
-
):
|
|
484
|
-
break
|
|
485
|
-
|
|
486
|
-
if not msg or not msg.data or len(msg.data) == 0:
|
|
487
|
-
continue
|
|
488
|
-
|
|
489
|
-
motion_frame: FrameState = unpack(msg.data)
|
|
490
|
-
motion_state: MotionState = {
|
|
491
|
-
"timestamp": motion_frame["timestamp"],
|
|
492
|
-
"detections": motion_frame["detections"],
|
|
493
|
-
"lastEvent": motion_frame.get("lastEvent", None),
|
|
494
|
-
"state": motion_frame.get("state", False),
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
yield MotionFrame(
|
|
498
|
-
self.id,
|
|
499
|
-
self.motion_frame_publisher,
|
|
500
|
-
motion_frame["frameData"],
|
|
501
|
-
motion_state,
|
|
502
|
-
motion_frame["metadata"],
|
|
503
|
-
)
|
|
504
|
-
|
|
505
|
-
except GeneratorExit:
|
|
506
|
-
return
|
|
507
|
-
|
|
508
|
-
except asyncio.CancelledError:
|
|
509
|
-
pass
|
|
510
|
-
except Exception as e:
|
|
511
|
-
if self.initialized:
|
|
512
|
-
self.logger.error("Error while generating motion frames:", e)
|
|
513
|
-
raise
|
|
514
|
-
finally:
|
|
515
|
-
if request_id in self.active_motion_requests:
|
|
516
|
-
self.active_motion_requests.remove(request_id)
|
|
517
|
-
|
|
518
|
-
motion_frame_subscribtion = next(
|
|
519
|
-
(sub for sub in self.motion_frame_subscribers if sub["request_id"] == request_id), None
|
|
520
|
-
)
|
|
521
|
-
|
|
522
|
-
if motion_frame_subscribtion:
|
|
523
|
-
self.motion_frame_subscribers.remove(motion_frame_subscribtion)
|
|
524
|
-
await motion_frame_subscribtion["subscriber"].close()
|
|
525
|
-
|
|
526
|
-
if len(self.motion_frame_subscribers) == 0:
|
|
527
|
-
await self.__close_motion_frame_subscribers()
|
|
528
|
-
|
|
529
|
-
@overload
|
|
530
|
-
def get_value(self, state_name: Literal["light"]) -> LightState: ...
|
|
531
|
-
@overload
|
|
532
|
-
def get_value(self, state_name: Literal["motion"]) -> MotionState: ...
|
|
533
|
-
@overload
|
|
534
|
-
def get_value(self, state_name: Literal["audio"]) -> AudioState: ...
|
|
535
|
-
@overload
|
|
536
|
-
def get_value(self, state_name: Literal["object"]) -> ObjectState: ...
|
|
537
|
-
@overload
|
|
538
|
-
def get_value(self, state_name: Literal["doorbell"]) -> DoorbellState: ...
|
|
539
|
-
@overload
|
|
540
|
-
def get_value(self, state_name: Literal["siren"]) -> SirenState: ...
|
|
541
|
-
@overload
|
|
542
|
-
def get_value(self, state_name: Literal["battery"]) -> BatteryState: ...
|
|
543
|
-
def get_value(
|
|
544
|
-
self, state_name: str
|
|
545
|
-
) -> Union[
|
|
546
|
-
LightState,
|
|
547
|
-
MotionState,
|
|
548
|
-
AudioState,
|
|
549
|
-
ObjectState,
|
|
550
|
-
DoorbellState,
|
|
551
|
-
SirenState,
|
|
552
|
-
BatteryState,
|
|
553
|
-
]:
|
|
554
|
-
if state_name == "light":
|
|
555
|
-
return deepcopy(self.light_state.value)
|
|
556
|
-
elif state_name == "motion":
|
|
557
|
-
return deepcopy(self.motion_state.value)
|
|
558
|
-
elif state_name == "audio":
|
|
559
|
-
return deepcopy(self.audio_state.value)
|
|
560
|
-
elif state_name == "object":
|
|
561
|
-
return deepcopy(self.object_state.value)
|
|
562
|
-
elif state_name == "doorbell":
|
|
563
|
-
return deepcopy(self.doorbell_state.value)
|
|
564
|
-
elif state_name == "siren":
|
|
565
|
-
return deepcopy(self.siren_state.value)
|
|
566
|
-
elif state_name == "battery":
|
|
567
|
-
return deepcopy(self.battery_state.value)
|
|
568
|
-
else:
|
|
569
|
-
raise Exception(f"Unknown state: {state_name}")
|
|
570
|
-
|
|
571
|
-
@overload
|
|
572
|
-
async def update_state(
|
|
573
|
-
self,
|
|
574
|
-
state_name: Literal["light"],
|
|
575
|
-
event_data: LightSetEvent,
|
|
576
|
-
) -> None: ...
|
|
577
|
-
@overload
|
|
578
|
-
async def update_state(
|
|
579
|
-
self,
|
|
580
|
-
state_name: Literal["motion"],
|
|
581
|
-
event_data: MotionSetEvent,
|
|
582
|
-
frame: Optional[VideoFrame] = None,
|
|
583
|
-
) -> None: ...
|
|
584
|
-
@overload
|
|
585
|
-
async def update_state(
|
|
586
|
-
self,
|
|
587
|
-
state_name: Literal["audio"],
|
|
588
|
-
event_data: AudioSetEvent,
|
|
589
|
-
) -> None: ...
|
|
590
|
-
@overload
|
|
591
|
-
async def update_state(
|
|
592
|
-
self,
|
|
593
|
-
state_name: Literal["object"],
|
|
594
|
-
event_data: ObjectSetEvent,
|
|
595
|
-
) -> None: ...
|
|
596
|
-
@overload
|
|
597
|
-
async def update_state(
|
|
598
|
-
self,
|
|
599
|
-
state_name: Literal["doorbell"],
|
|
600
|
-
event_data: DoorbellSetEvent,
|
|
601
|
-
) -> None: ...
|
|
602
|
-
@overload
|
|
603
|
-
async def update_state(
|
|
604
|
-
self,
|
|
605
|
-
state_name: Literal["siren"],
|
|
606
|
-
event_data: SirenSetEvent,
|
|
607
|
-
) -> None: ...
|
|
608
|
-
@overload
|
|
609
|
-
async def update_state(
|
|
610
|
-
self,
|
|
611
|
-
state_name: Literal["battery"],
|
|
612
|
-
event_data: BatterySetEvent,
|
|
613
|
-
) -> None: ...
|
|
614
|
-
async def update_state(
|
|
615
|
-
self,
|
|
616
|
-
state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
|
|
617
|
-
event_data: Union[
|
|
618
|
-
LightSetEvent,
|
|
619
|
-
MotionSetEvent,
|
|
620
|
-
AudioSetEvent,
|
|
621
|
-
ObjectSetEvent,
|
|
622
|
-
DoorbellSetEvent,
|
|
623
|
-
SirenSetEvent,
|
|
624
|
-
BatterySetEvent,
|
|
625
|
-
],
|
|
626
|
-
frame: Optional[VideoFrame] = None,
|
|
627
|
-
) -> None:
|
|
628
|
-
changed, event = cast(
|
|
629
|
-
tuple[
|
|
630
|
-
bool,
|
|
631
|
-
Union[
|
|
632
|
-
LightSetEvent,
|
|
633
|
-
MotionSetEvent,
|
|
634
|
-
AudioSetEvent,
|
|
635
|
-
ObjectSetEvent,
|
|
636
|
-
DoorbellSetEvent,
|
|
637
|
-
SirenSetEvent,
|
|
638
|
-
BatterySetEvent,
|
|
639
|
-
],
|
|
640
|
-
],
|
|
641
|
-
self.__check_state_internal(cast(Any, state_name), cast(Any, event_data)),
|
|
642
|
-
)
|
|
643
|
-
|
|
644
|
-
if not changed:
|
|
645
|
-
return
|
|
646
|
-
|
|
647
|
-
if state_name == "motion" and frame:
|
|
648
|
-
motion_event = cast(MotionState, event)
|
|
649
|
-
self.__frame_state.on_next(
|
|
650
|
-
{**motion_event, "frameData": frame.frame_data, "metadata": frame.metadata}
|
|
651
|
-
)
|
|
652
|
-
|
|
653
|
-
self.__update_state_internal(cast(Any, state_name), cast(Any, event), True)
|
|
654
|
-
await self.on_request("cameraFn", "updateState", [state_name, event], 0)
|
|
655
|
-
|
|
656
|
-
async def add_camera_source(self, source: CameraConfigInputSettings) -> None:
|
|
657
|
-
return await self.on_request("cameraFn", "addCameraSource", [source])
|
|
658
|
-
|
|
659
|
-
async def update_camera_source(self, source_id: str, source: CameraConfigInputSettingsPartial) -> None:
|
|
660
|
-
return await self.on_request("cameraFn", "updateCameraSource", [source_id, source])
|
|
661
|
-
|
|
662
|
-
async def remove_camera_source(self, source_id: str) -> None:
|
|
663
|
-
return await self.on_request("cameraFn", "removeCameraSource", [source_id])
|
|
664
|
-
|
|
665
|
-
async def refresh_states(self) -> None:
|
|
666
|
-
response = await self.on_request("cameraFn", "refreshStates")
|
|
667
|
-
|
|
668
|
-
self.update_camera(response["camera"])
|
|
669
|
-
self.update_camera_state(response["cameraState"])
|
|
670
|
-
|
|
671
|
-
for key, value in response["states"].items():
|
|
672
|
-
self.__update_state_internal(key, value, True)
|
|
673
|
-
|
|
674
|
-
def update_camera(self, camera: Camera) -> None:
|
|
675
|
-
self.camera_subject.on_next(camera)
|
|
676
|
-
|
|
677
|
-
def update_camera_state(self, state: bool) -> None:
|
|
678
|
-
self.camera_state.on_next(state)
|
|
679
|
-
|
|
680
|
-
def remove_all_listeners(self) -> None:
|
|
681
|
-
self.__frame_state.on_completed()
|
|
682
|
-
self.light_state.on_completed()
|
|
683
|
-
self.motion_state.on_completed()
|
|
684
|
-
self.audio_state.on_completed()
|
|
685
|
-
self.object_state.on_completed()
|
|
686
|
-
self.doorbell_state.on_completed()
|
|
687
|
-
self.siren_state.on_completed()
|
|
688
|
-
self.battery_state.on_completed()
|
|
689
|
-
self.camera_subject.on_completed()
|
|
690
|
-
self.camera_state.on_completed()
|
|
691
|
-
|
|
692
|
-
async def cleanup(self) -> None:
|
|
693
|
-
self.initialized = False
|
|
694
|
-
self.remove_all_listeners()
|
|
695
|
-
self.api.remove_listener("shutdown", self.cleanup)
|
|
696
|
-
self.active_requests.clear()
|
|
697
|
-
|
|
698
|
-
if self.message_queue:
|
|
699
|
-
self.message_queue.abort_queue()
|
|
700
|
-
|
|
701
|
-
with suppress(Exception):
|
|
702
|
-
if self.publisher:
|
|
703
|
-
await self.publisher.close()
|
|
704
|
-
|
|
705
|
-
if self.camera_publisher:
|
|
706
|
-
await self.camera_publisher.close()
|
|
707
|
-
|
|
708
|
-
if self.signaling_publisher:
|
|
709
|
-
await self.signaling_publisher.close()
|
|
710
|
-
|
|
711
|
-
if self.frame_publisher:
|
|
712
|
-
await self.frame_publisher.close()
|
|
713
|
-
|
|
714
|
-
if self.motion_frame_publisher:
|
|
715
|
-
await self.motion_frame_publisher.close()
|
|
716
|
-
|
|
717
|
-
@overload
|
|
718
|
-
def on_state_change(self, state_name: Literal["light"]) -> Observable[tuple[LightState, LightState]]: ...
|
|
719
|
-
@overload
|
|
720
|
-
def on_state_change(
|
|
721
|
-
self, state_name: Literal["motion"]
|
|
722
|
-
) -> Observable[tuple[MotionState, MotionState]]: ...
|
|
723
|
-
@overload
|
|
724
|
-
def on_state_change(self, state_name: Literal["audio"]) -> Observable[tuple[AudioState, AudioState]]: ...
|
|
725
|
-
@overload
|
|
726
|
-
def on_state_change(
|
|
727
|
-
self, state_name: Literal["doorbell"]
|
|
728
|
-
) -> Observable[tuple[DoorbellState, DoorbellState]]: ...
|
|
729
|
-
@overload
|
|
730
|
-
def on_state_change(self, state_name: Literal["siren"]) -> Observable[tuple[SirenState, SirenState]]: ...
|
|
731
|
-
@overload
|
|
732
|
-
def on_state_change(
|
|
733
|
-
self, state_name: Literal["battery"]
|
|
734
|
-
) -> Observable[tuple[BatteryState, BatteryState]]: ...
|
|
735
|
-
@overload
|
|
736
|
-
def on_state_change(
|
|
737
|
-
self, state_name: Literal["object"]
|
|
738
|
-
) -> Observable[tuple[ObjectState, ObjectState]]: ...
|
|
739
|
-
def on_state_change(self, state_name: StateNames) -> Observable[tuple[StateValue, StateValue]]:
|
|
740
|
-
state: Union[BehaviorSubject[StateValue], None] = getattr(self, f"{state_name}_state", None)
|
|
741
|
-
|
|
742
|
-
if not state:
|
|
743
|
-
raise Exception(f"{state_name}_state not found")
|
|
744
|
-
|
|
745
|
-
def filter_fn(states: tuple[StateValue, StateValue]) -> bool:
|
|
746
|
-
old_state = states[0]
|
|
747
|
-
new_state = states[1]
|
|
748
|
-
|
|
749
|
-
if isinstance(old_state, bool) or isinstance(new_state, bool):
|
|
750
|
-
return old_state != new_state
|
|
751
|
-
else:
|
|
752
|
-
return self.__state_changed(old_state, new_state, state_name)
|
|
753
|
-
|
|
754
|
-
return state.pipe(
|
|
755
|
-
ops.pairwise(),
|
|
756
|
-
ops.filter(filter_fn),
|
|
757
|
-
ops.share(),
|
|
758
|
-
)
|
|
759
|
-
|
|
760
|
-
def on_property_change(
|
|
761
|
-
self, property: Union[CameraPublicProperties, list[CameraPublicProperties]]
|
|
762
|
-
) -> Observable[CameraPropertyObservableObject]:
|
|
763
|
-
def map_fn(
|
|
764
|
-
cameras: tuple[Camera, Camera],
|
|
765
|
-
) -> list[Any]:
|
|
766
|
-
properties = property if isinstance(property, list) else [property]
|
|
767
|
-
return [
|
|
768
|
-
{
|
|
769
|
-
"property": prop,
|
|
770
|
-
"old_state": cameras[0].get(prop),
|
|
771
|
-
"new_state": cameras[1].get(prop),
|
|
772
|
-
}
|
|
773
|
-
for prop in properties
|
|
774
|
-
]
|
|
775
|
-
|
|
776
|
-
def filter_fn(
|
|
777
|
-
cameras: tuple[CameraPropertyObservableObject, CameraPropertyObservableObject],
|
|
778
|
-
) -> bool:
|
|
779
|
-
return (
|
|
780
|
-
DeepDiff(
|
|
781
|
-
cameras[0]["old_state"],
|
|
782
|
-
cameras[1]["new_state"],
|
|
783
|
-
ignore_order=True,
|
|
784
|
-
)
|
|
785
|
-
!= {}
|
|
786
|
-
)
|
|
787
|
-
|
|
788
|
-
return self.camera_subject.pipe(
|
|
789
|
-
ops.pairwise(),
|
|
790
|
-
ops.flat_map(map_fn),
|
|
791
|
-
ops.filter(filter_fn),
|
|
792
|
-
ops.share(),
|
|
793
|
-
)
|
|
794
|
-
|
|
795
|
-
def __on_motion_frame(self, motion_frame: FrameState) -> None:
|
|
796
|
-
if not self.frame_publisher:
|
|
797
|
-
return
|
|
798
|
-
|
|
799
|
-
self.tasks.add(self.__send_motion_frame(motion_frame))
|
|
800
|
-
|
|
801
|
-
async def __send_motion_frame(self, frame: FrameState) -> None:
|
|
802
|
-
if not self.frame_publisher:
|
|
803
|
-
return
|
|
804
|
-
|
|
805
|
-
await self.frame_publisher.publish(self.motion_frame_subject, frame)
|
|
806
|
-
|
|
807
|
-
@overload
|
|
808
|
-
def __check_state_internal(
|
|
809
|
-
self, state_name: Literal["light"], event_data: LightSetEvent
|
|
810
|
-
) -> tuple[bool, LightState]: ...
|
|
811
|
-
@overload
|
|
812
|
-
def __check_state_internal(
|
|
813
|
-
self, state_name: Literal["motion"], event_data: MotionSetEvent
|
|
814
|
-
) -> tuple[bool, MotionState]: ...
|
|
815
|
-
@overload
|
|
816
|
-
def __check_state_internal(
|
|
817
|
-
self, state_name: Literal["audio"], event_data: AudioSetEvent
|
|
818
|
-
) -> tuple[bool, AudioState]: ...
|
|
819
|
-
@overload
|
|
820
|
-
def __check_state_internal(
|
|
821
|
-
self, state_name: Literal["object"], event_data: ObjectSetEvent
|
|
822
|
-
) -> tuple[bool, ObjectState]: ...
|
|
823
|
-
@overload
|
|
824
|
-
def __check_state_internal(
|
|
825
|
-
self, state_name: Literal["doorbell"], event_data: DoorbellSetEvent
|
|
826
|
-
) -> tuple[bool, DoorbellState]: ...
|
|
827
|
-
@overload
|
|
828
|
-
def __check_state_internal(
|
|
829
|
-
self, state_name: Literal["siren"], event_data: SirenSetEvent
|
|
830
|
-
) -> tuple[bool, SirenState]: ...
|
|
831
|
-
@overload
|
|
832
|
-
def __check_state_internal(
|
|
833
|
-
self, state_name: Literal["battery"], event_data: BatterySetEvent
|
|
834
|
-
) -> tuple[bool, BatteryState]: ...
|
|
835
|
-
def __check_state_internal(
|
|
836
|
-
self,
|
|
837
|
-
state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
|
|
838
|
-
event_data: Union[
|
|
839
|
-
LightSetEvent,
|
|
840
|
-
MotionSetEvent,
|
|
841
|
-
AudioSetEvent,
|
|
842
|
-
ObjectSetEvent,
|
|
843
|
-
DoorbellSetEvent,
|
|
844
|
-
SirenSetEvent,
|
|
845
|
-
BatterySetEvent,
|
|
846
|
-
],
|
|
847
|
-
) -> tuple[
|
|
848
|
-
bool,
|
|
849
|
-
Union[
|
|
850
|
-
LightState,
|
|
851
|
-
MotionState,
|
|
852
|
-
AudioState,
|
|
853
|
-
ObjectState,
|
|
854
|
-
DoorbellState,
|
|
855
|
-
SirenState,
|
|
856
|
-
BatteryState,
|
|
857
|
-
],
|
|
858
|
-
]:
|
|
859
|
-
changed = False
|
|
860
|
-
target_state = None
|
|
861
|
-
|
|
862
|
-
if state_name == "audio":
|
|
863
|
-
audio_event = cast(AudioSetEvent, event_data)
|
|
864
|
-
target_state = self.__get_audio_state(audio_event)
|
|
865
|
-
changed = self.__state_changed(self.get_value("audio"), target_state, "audio")
|
|
866
|
-
|
|
867
|
-
elif state_name == "light":
|
|
868
|
-
light_event = cast(LightSetEvent, event_data)
|
|
869
|
-
target_state = self.__get_light_state(light_event)
|
|
870
|
-
changed = self.__state_changed(self.get_value("light"), target_state, "light")
|
|
871
|
-
|
|
872
|
-
elif state_name == "motion":
|
|
873
|
-
motion_event = cast(MotionSetEvent, event_data)
|
|
874
|
-
|
|
875
|
-
if motion_event.get("state", None) is not None:
|
|
876
|
-
motion_event["detections"] = []
|
|
877
|
-
|
|
878
|
-
# fix bounding box type to to tuple, do we need?
|
|
879
|
-
for det in motion_event["detections"]:
|
|
880
|
-
det["boundingBox"] = cast(tuple[int, int, int, int], tuple(det["boundingBox"]))
|
|
881
|
-
det["confidence"] = float(det["confidence"])
|
|
882
|
-
|
|
883
|
-
motion_event["detections"] = merge_detections(motion_event["detections"])
|
|
884
|
-
|
|
885
|
-
motion_event["detections"] = are_motion_detections_valid(
|
|
886
|
-
motion_event["detections"], self.activity_zones, self.activity_settings
|
|
887
|
-
)
|
|
888
|
-
|
|
889
|
-
target_state = self.__get_motion_state(motion_event)
|
|
890
|
-
changed = self.__state_changed(self.get_value("motion"), target_state, "motion")
|
|
891
|
-
|
|
892
|
-
elif state_name == "object":
|
|
893
|
-
object_event = cast(ObjectSetEvent, event_data)
|
|
894
|
-
|
|
895
|
-
# fix bounding box type to to tuple
|
|
896
|
-
for det in object_event["detections"]:
|
|
897
|
-
det["boundingBox"] = tuple(det["boundingBox"]) # type: ignore
|
|
898
|
-
det["confidence"] = float(det["confidence"])
|
|
899
|
-
|
|
900
|
-
object_event["detections"] = are_object_detections_valid(
|
|
901
|
-
object_event["detections"], self.activity_zones, self.activity_settings
|
|
902
|
-
)
|
|
903
|
-
|
|
904
|
-
target_state = self.__get_object_state(object_event)
|
|
905
|
-
changed = self.__state_changed(self.get_value("object"), target_state, "object")
|
|
906
|
-
|
|
907
|
-
elif state_name == "doorbell":
|
|
908
|
-
doorbell_event = cast(DoorbellSetEvent, event_data)
|
|
909
|
-
target_state = self.__get_doorbell_state(doorbell_event)
|
|
910
|
-
changed = self.__state_changed(self.get_value("doorbell"), target_state, "doorbell")
|
|
911
|
-
|
|
912
|
-
elif state_name == "siren":
|
|
913
|
-
siren_event = cast(SirenSetEvent, event_data)
|
|
914
|
-
target_state = self.__get_siren_state(siren_event)
|
|
915
|
-
changed = self.__state_changed(self.get_value("siren"), target_state, "siren")
|
|
916
|
-
|
|
917
|
-
elif state_name == "battery":
|
|
918
|
-
battery_event = cast(BatterySetEvent, event_data)
|
|
919
|
-
target_state = self.__get_battery_state(battery_event)
|
|
920
|
-
changed = self.__state_changed(self.get_value("battery"), target_state, "battery")
|
|
921
|
-
|
|
922
|
-
else:
|
|
923
|
-
raise Exception(f"Unknown state: {state_name}")
|
|
924
|
-
|
|
925
|
-
return changed, target_state
|
|
926
|
-
|
|
927
|
-
@overload
|
|
928
|
-
def __update_state_internal(
|
|
929
|
-
self, state_name: Literal["light"], event_data: LightSetEvent, skip_check: Optional[bool] = None
|
|
930
|
-
) -> None: ...
|
|
931
|
-
@overload
|
|
932
|
-
def __update_state_internal(
|
|
933
|
-
self, state_name: Literal["motion"], event_data: MotionSetEvent, skip_check: Optional[bool] = None
|
|
934
|
-
) -> None: ...
|
|
935
|
-
@overload
|
|
936
|
-
def __update_state_internal(
|
|
937
|
-
self, state_name: Literal["audio"], event_data: AudioSetEvent, skip_check: Optional[bool] = None
|
|
938
|
-
) -> None: ...
|
|
939
|
-
@overload
|
|
940
|
-
def __update_state_internal(
|
|
941
|
-
self, state_name: Literal["object"], event_data: ObjectSetEvent, skip_check: Optional[bool] = None
|
|
942
|
-
) -> None: ...
|
|
943
|
-
@overload
|
|
944
|
-
def __update_state_internal(
|
|
945
|
-
self, state_name: Literal["doorbell"], event_data: DoorbellSetEvent, skip_check: Optional[bool] = None
|
|
946
|
-
) -> None: ...
|
|
947
|
-
@overload
|
|
948
|
-
def __update_state_internal(
|
|
949
|
-
self, state_name: Literal["siren"], event_data: SirenSetEvent, skip_check: Optional[bool] = None
|
|
950
|
-
) -> None: ...
|
|
951
|
-
@overload
|
|
952
|
-
def __update_state_internal(
|
|
953
|
-
self, state_name: Literal["battery"], event_data: BatterySetEvent, skip_check: Optional[bool] = None
|
|
954
|
-
) -> None: ...
|
|
955
|
-
def __update_state_internal(
|
|
956
|
-
self,
|
|
957
|
-
state_name: Literal["light", "motion", "audio", "object", "doorbell", "siren", "battery"],
|
|
958
|
-
event_data: Union[
|
|
959
|
-
LightSetEvent,
|
|
960
|
-
MotionSetEvent,
|
|
961
|
-
AudioSetEvent,
|
|
962
|
-
ObjectSetEvent,
|
|
963
|
-
DoorbellSetEvent,
|
|
964
|
-
SirenSetEvent,
|
|
965
|
-
BatterySetEvent,
|
|
966
|
-
],
|
|
967
|
-
skip_check: Optional[bool] = None,
|
|
968
|
-
) -> None:
|
|
969
|
-
if skip_check:
|
|
970
|
-
changed = True
|
|
971
|
-
event = event_data
|
|
972
|
-
else:
|
|
973
|
-
changed, event = cast(
|
|
974
|
-
tuple[
|
|
975
|
-
bool,
|
|
976
|
-
Union[
|
|
977
|
-
LightSetEvent,
|
|
978
|
-
MotionSetEvent,
|
|
979
|
-
AudioSetEvent,
|
|
980
|
-
ObjectSetEvent,
|
|
981
|
-
DoorbellSetEvent,
|
|
982
|
-
SirenSetEvent,
|
|
983
|
-
BatterySetEvent,
|
|
984
|
-
],
|
|
985
|
-
],
|
|
986
|
-
self.__check_state_internal(cast(Any, state_name), cast(Any, event_data)),
|
|
987
|
-
)
|
|
988
|
-
|
|
989
|
-
if not changed:
|
|
990
|
-
return
|
|
991
|
-
|
|
992
|
-
if state_name == "light":
|
|
993
|
-
self.light_state.on_next(self.__get_light_state(cast(LightSetEvent, event)))
|
|
994
|
-
elif state_name == "motion":
|
|
995
|
-
self.motion_state.on_next(self.__get_motion_state(cast(MotionSetEvent, event)))
|
|
996
|
-
elif state_name == "audio":
|
|
997
|
-
self.audio_state.on_next(self.__get_audio_state(cast(AudioSetEvent, event)))
|
|
998
|
-
elif state_name == "object":
|
|
999
|
-
self.object_state.on_next(self.__get_object_state(cast(ObjectSetEvent, event)))
|
|
1000
|
-
elif state_name == "doorbell":
|
|
1001
|
-
self.doorbell_state.on_next(self.__get_doorbell_state(cast(DoorbellSetEvent, event)))
|
|
1002
|
-
elif state_name == "siren":
|
|
1003
|
-
self.siren_state.on_next(self.__get_siren_state(cast(SirenSetEvent, event)))
|
|
1004
|
-
elif state_name == "battery" and self.has_battery:
|
|
1005
|
-
self.battery_state.on_next(self.__get_battery_state(cast(BatterySetEvent, event)))
|
|
1006
|
-
|
|
1007
|
-
def __create_motion_frame_observable(self) -> Observable[FrameState]:
|
|
1008
|
-
return self.__frame_state.pipe(ops.share())
|
|
1009
|
-
|
|
1010
|
-
def __create_state_observable(self, state_subject: BehaviorSubject[Any]) -> Observable[Any]:
|
|
1011
|
-
return state_subject.pipe(ops.share())
|
|
1012
|
-
|
|
1013
|
-
def __state_changed(
|
|
1014
|
-
self,
|
|
1015
|
-
old_state: Optional[SetValue],
|
|
1016
|
-
new_state: Optional[SetValue],
|
|
1017
|
-
type: Optional[StateNames],
|
|
1018
|
-
) -> bool:
|
|
1019
|
-
if not old_state or not new_state or not type:
|
|
1020
|
-
return False
|
|
1021
|
-
|
|
1022
|
-
if type == "audio":
|
|
1023
|
-
if not self.has_audio_detector:
|
|
1024
|
-
return False
|
|
1025
|
-
|
|
1026
|
-
old_state = cast(AudioSetEvent, old_state)
|
|
1027
|
-
new_state = cast(AudioSetEvent, new_state)
|
|
1028
|
-
|
|
1029
|
-
return old_state["state"] != new_state["state"] or old_state.get("db") != new_state.get("db")
|
|
1030
|
-
elif type == "motion":
|
|
1031
|
-
if not self.has_motion_detector:
|
|
1032
|
-
return False
|
|
1033
|
-
|
|
1034
|
-
old_state = cast(MotionSetEvent, old_state)
|
|
1035
|
-
new_state = cast(MotionSetEvent, new_state)
|
|
1036
|
-
|
|
1037
|
-
if new_state.get("state", None) is not None:
|
|
1038
|
-
return old_state.get("state", False) != new_state.get("state", False)
|
|
1039
|
-
|
|
1040
|
-
# if len(new_state["detections"]) == 0:
|
|
1041
|
-
# return False
|
|
1042
|
-
|
|
1043
|
-
return (
|
|
1044
|
-
DeepDiff(
|
|
1045
|
-
old_state["detections"],
|
|
1046
|
-
new_state["detections"],
|
|
1047
|
-
ignore_order=True,
|
|
1048
|
-
)
|
|
1049
|
-
!= {}
|
|
1050
|
-
)
|
|
1051
|
-
elif type == "object":
|
|
1052
|
-
if not self.has_object_detector:
|
|
1053
|
-
return False
|
|
1054
|
-
|
|
1055
|
-
old_state = cast(ObjectSetEvent, old_state)
|
|
1056
|
-
new_state = cast(ObjectSetEvent, new_state)
|
|
1057
|
-
|
|
1058
|
-
# if len(new_state["detections"]) == 0:
|
|
1059
|
-
# return False
|
|
1060
|
-
|
|
1061
|
-
return (
|
|
1062
|
-
DeepDiff(
|
|
1063
|
-
old_state["detections"],
|
|
1064
|
-
new_state["detections"],
|
|
1065
|
-
ignore_order=True,
|
|
1066
|
-
)
|
|
1067
|
-
!= {}
|
|
1068
|
-
)
|
|
1069
|
-
elif type == "siren":
|
|
1070
|
-
if not self.has_siren:
|
|
1071
|
-
return False
|
|
1072
|
-
|
|
1073
|
-
old_state = cast(SirenSetEvent, old_state)
|
|
1074
|
-
new_state = cast(SirenSetEvent, new_state)
|
|
1075
|
-
|
|
1076
|
-
return old_state["state"] != new_state["state"] or old_state.get("level") != new_state.get(
|
|
1077
|
-
"level"
|
|
1078
|
-
)
|
|
1079
|
-
elif type == "battery":
|
|
1080
|
-
if not self.has_battery:
|
|
1081
|
-
return False
|
|
1082
|
-
|
|
1083
|
-
old_state = cast(BatterySetEvent, old_state)
|
|
1084
|
-
new_state = cast(BatterySetEvent, new_state)
|
|
1085
|
-
|
|
1086
|
-
return (
|
|
1087
|
-
old_state["level"] != new_state["level"]
|
|
1088
|
-
or old_state.get("lowBattery") != new_state.get("lowBattery")
|
|
1089
|
-
or old_state.get("charging") != new_state.get("charging")
|
|
1090
|
-
)
|
|
1091
|
-
elif type == "doorbell":
|
|
1092
|
-
if not self.has_binary_sensor:
|
|
1093
|
-
return False
|
|
1094
|
-
|
|
1095
|
-
old_state = cast(DoorbellSetEvent, old_state)
|
|
1096
|
-
new_state = cast(DoorbellSetEvent, new_state)
|
|
1097
|
-
|
|
1098
|
-
return old_state["state"] != new_state["state"]
|
|
1099
|
-
elif type == "light":
|
|
1100
|
-
if not self.has_light:
|
|
1101
|
-
return False
|
|
1102
|
-
|
|
1103
|
-
old_state = cast(LightSetEvent, old_state)
|
|
1104
|
-
new_state = cast(LightSetEvent, new_state)
|
|
1105
|
-
|
|
1106
|
-
return old_state["state"] != new_state["state"]
|
|
1107
|
-
else:
|
|
1108
|
-
return False
|
|
1109
|
-
|
|
1110
|
-
def __get_audio_state(self, event: AudioSetEvent, ignore_last_event: bool = False) -> AudioState:
|
|
1111
|
-
last_event: Optional[AudioState] = None
|
|
1112
|
-
|
|
1113
|
-
if ignore_last_event is False:
|
|
1114
|
-
last_state = self.get_value("audio")
|
|
1115
|
-
|
|
1116
|
-
if last_state["state"]:
|
|
1117
|
-
last_event = last_state
|
|
1118
|
-
elif "lastEvent" in last_state and last_state["lastEvent"] and last_state["lastEvent"]["state"]:
|
|
1119
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1120
|
-
|
|
1121
|
-
if last_event and "lastEvent" in last_event:
|
|
1122
|
-
del last_event["lastEvent"]
|
|
1123
|
-
|
|
1124
|
-
new_state: AudioState
|
|
1125
|
-
|
|
1126
|
-
if "timestamp" in event:
|
|
1127
|
-
new_state = event
|
|
1128
|
-
else:
|
|
1129
|
-
state = cast(AudioState, event).copy()
|
|
1130
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1131
|
-
|
|
1132
|
-
new_state = {
|
|
1133
|
-
"state": event["state"],
|
|
1134
|
-
"db": event.get("db", None) or last_event.get("db", None) if last_event else 0,
|
|
1135
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1136
|
-
"lastEvent": last_event if last_event else state if state["state"] else None,
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
return new_state
|
|
1140
|
-
|
|
1141
|
-
def __get_motion_state(self, event: MotionSetEvent, ignore_last_event: bool = False) -> MotionState:
|
|
1142
|
-
last_event: Optional[MotionState] = None
|
|
1143
|
-
|
|
1144
|
-
if ignore_last_event is False:
|
|
1145
|
-
last_state = self.get_value("motion")
|
|
1146
|
-
|
|
1147
|
-
if len(last_state["detections"]) > 0:
|
|
1148
|
-
last_event = last_state
|
|
1149
|
-
elif (
|
|
1150
|
-
"lastEvent" in last_state
|
|
1151
|
-
and last_state["lastEvent"] is not None
|
|
1152
|
-
and len(last_state["lastEvent"]["detections"]) > 0
|
|
1153
|
-
):
|
|
1154
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1155
|
-
|
|
1156
|
-
if last_event and "lastEvent" in last_event:
|
|
1157
|
-
del last_event["lastEvent"]
|
|
1158
|
-
|
|
1159
|
-
new_state: MotionState
|
|
1160
|
-
|
|
1161
|
-
if "timestamp" in event:
|
|
1162
|
-
new_state = event
|
|
1163
|
-
else:
|
|
1164
|
-
state = cast(MotionState, event).copy()
|
|
1165
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1166
|
-
|
|
1167
|
-
new_state = {
|
|
1168
|
-
"detections": event["detections"],
|
|
1169
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1170
|
-
"lastEvent": last_event if last_event else state if len(state["detections"]) > 0 else None,
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
return new_state
|
|
1174
|
-
|
|
1175
|
-
def __get_object_state(self, event: ObjectSetEvent, ignore_last_event: bool = False) -> ObjectState:
|
|
1176
|
-
last_event: Optional[ObjectState] = None
|
|
1177
|
-
|
|
1178
|
-
if ignore_last_event is False:
|
|
1179
|
-
last_state = self.get_value("object")
|
|
1180
|
-
|
|
1181
|
-
if len(last_state["detections"]) > 0:
|
|
1182
|
-
last_event = last_state
|
|
1183
|
-
elif (
|
|
1184
|
-
"lastEvent" in last_state
|
|
1185
|
-
and last_state["lastEvent"]
|
|
1186
|
-
and len(last_state["lastEvent"]["detections"]) > 0
|
|
1187
|
-
):
|
|
1188
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1189
|
-
|
|
1190
|
-
if last_event and "lastEvent" in last_event:
|
|
1191
|
-
del last_event["lastEvent"]
|
|
1192
|
-
|
|
1193
|
-
new_state: ObjectState
|
|
1194
|
-
|
|
1195
|
-
if "timestamp" in event:
|
|
1196
|
-
new_state = event
|
|
1197
|
-
else:
|
|
1198
|
-
state = cast(ObjectState, event).copy()
|
|
1199
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1200
|
-
|
|
1201
|
-
new_state = {
|
|
1202
|
-
"detections": event["detections"],
|
|
1203
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1204
|
-
"lastEvent": last_event if last_event else state if len(state["detections"]) > 0 else None,
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
return new_state
|
|
1208
|
-
|
|
1209
|
-
def __get_doorbell_state(self, event: DoorbellSetEvent, ignore_last_event: bool = False) -> DoorbellState:
|
|
1210
|
-
last_event: Optional[DoorbellState] = None
|
|
1211
|
-
|
|
1212
|
-
if ignore_last_event is False:
|
|
1213
|
-
last_state = self.get_value("doorbell")
|
|
1214
|
-
|
|
1215
|
-
if last_state["state"]:
|
|
1216
|
-
last_event = last_state
|
|
1217
|
-
elif "lastEvent" in last_state and last_state["lastEvent"] and last_state["lastEvent"]["state"]:
|
|
1218
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1219
|
-
|
|
1220
|
-
if last_event and "lastEvent" in last_event:
|
|
1221
|
-
del last_event["lastEvent"]
|
|
1222
|
-
|
|
1223
|
-
new_state: DoorbellState
|
|
1224
|
-
|
|
1225
|
-
if "timestamp" in event:
|
|
1226
|
-
new_state = event
|
|
1227
|
-
else:
|
|
1228
|
-
state = cast(DoorbellState, event).copy()
|
|
1229
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1230
|
-
|
|
1231
|
-
new_state = {
|
|
1232
|
-
"state": event["state"],
|
|
1233
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1234
|
-
"lastEvent": last_event if last_event else state if state["state"] else None,
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
return new_state
|
|
1238
|
-
|
|
1239
|
-
def __get_light_state(self, event: LightSetEvent, ignore_last_event: bool = False) -> LightState:
|
|
1240
|
-
last_event: Optional[LightState] = None
|
|
1241
|
-
|
|
1242
|
-
if ignore_last_event is False:
|
|
1243
|
-
last_state = self.get_value("light")
|
|
1244
|
-
|
|
1245
|
-
if last_state["state"]:
|
|
1246
|
-
last_event = last_state
|
|
1247
|
-
elif "lastEvent" in last_state and last_state["lastEvent"] and last_state["lastEvent"]["state"]:
|
|
1248
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1249
|
-
|
|
1250
|
-
if last_event and "lastEvent" in last_event:
|
|
1251
|
-
del last_event["lastEvent"]
|
|
1252
|
-
|
|
1253
|
-
new_state: LightState
|
|
1254
|
-
|
|
1255
|
-
if "timestamp" in event:
|
|
1256
|
-
new_state = event
|
|
1257
|
-
else:
|
|
1258
|
-
state = cast(LightState, event).copy()
|
|
1259
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1260
|
-
|
|
1261
|
-
new_state = {
|
|
1262
|
-
**state,
|
|
1263
|
-
"lastEvent": last_event if last_event else state if state["state"] else None,
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
return new_state
|
|
1267
|
-
|
|
1268
|
-
def __get_siren_state(self, event: SirenSetEvent, ignore_last_event: bool = False) -> SirenState:
|
|
1269
|
-
last_event: Optional[SirenState] = None
|
|
1270
|
-
|
|
1271
|
-
if ignore_last_event is False:
|
|
1272
|
-
last_state = self.get_value("siren")
|
|
1273
|
-
|
|
1274
|
-
if last_state["state"]:
|
|
1275
|
-
last_event = last_state
|
|
1276
|
-
elif "lastEvent" in last_state and last_state["lastEvent"] and last_state["lastEvent"]["state"]:
|
|
1277
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1278
|
-
|
|
1279
|
-
if last_event and "lastEvent" in last_event:
|
|
1280
|
-
del last_event["lastEvent"]
|
|
1281
|
-
|
|
1282
|
-
new_state: SirenState
|
|
1283
|
-
|
|
1284
|
-
if "timestamp" in event:
|
|
1285
|
-
new_state = event
|
|
1286
|
-
else:
|
|
1287
|
-
state = cast(SirenState, event).copy()
|
|
1288
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1289
|
-
|
|
1290
|
-
new_state = {
|
|
1291
|
-
"state": event["state"],
|
|
1292
|
-
"level": event.get("level", None) or last_event.get("level", None) if last_event else 0,
|
|
1293
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1294
|
-
"lastEvent": last_event if last_event else state if state["state"] else None,
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
return new_state
|
|
1298
|
-
|
|
1299
|
-
def __get_battery_state(self, event: BatterySetEvent, ignore_last_event: bool = False) -> BatteryState:
|
|
1300
|
-
last_event: Optional[BatteryState] = None
|
|
1301
|
-
|
|
1302
|
-
if ignore_last_event is False:
|
|
1303
|
-
last_state = self.get_value("battery")
|
|
1304
|
-
|
|
1305
|
-
if self.__state_changed(last_state, event, "battery"):
|
|
1306
|
-
last_event = last_state
|
|
1307
|
-
elif (
|
|
1308
|
-
"lastEvent" in last_state
|
|
1309
|
-
and last_state["lastEvent"]
|
|
1310
|
-
and self.__state_changed(last_state["lastEvent"], event, "battery")
|
|
1311
|
-
):
|
|
1312
|
-
last_event = last_state["lastEvent"] # type: ignore
|
|
1313
|
-
|
|
1314
|
-
if last_event and "lastEvent" in last_event:
|
|
1315
|
-
del last_event["lastEvent"]
|
|
1316
|
-
|
|
1317
|
-
new_state: BatteryState
|
|
1318
|
-
|
|
1319
|
-
if "timestamp" in event:
|
|
1320
|
-
new_state = event
|
|
1321
|
-
else:
|
|
1322
|
-
state = cast(BatteryState, event).copy()
|
|
1323
|
-
state["timestamp"] = int(datetime.now().timestamp() * 1000)
|
|
1324
|
-
|
|
1325
|
-
new_state = {
|
|
1326
|
-
"level": event["level"],
|
|
1327
|
-
"charging": event.get("charging", None) or last_event.get("charging", None)
|
|
1328
|
-
if last_event
|
|
1329
|
-
else False,
|
|
1330
|
-
"lowBattery": event.get("lowBattery", None) or last_event.get("lowBattery", None)
|
|
1331
|
-
if last_event
|
|
1332
|
-
else False,
|
|
1333
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1334
|
-
"lastEvent": last_event if last_event else state,
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
return new_state
|
|
1338
|
-
|
|
1339
|
-
async def __connect_to_decoder(self, request_id: str) -> FrameMetadata:
|
|
1340
|
-
if not self.signaling_publisher:
|
|
1341
|
-
raise Exception("Signaling Publisher not initialized")
|
|
1342
|
-
|
|
1343
|
-
message: SignalingRequest = {
|
|
1344
|
-
"type": "connect",
|
|
1345
|
-
"requestId": request_id,
|
|
1346
|
-
"cameraId": self.id,
|
|
1347
|
-
"pluginId": self.plugin["id"],
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
await self.signaling_publisher.publish(self.signaling_target_subject, message)
|
|
1351
|
-
|
|
1352
|
-
self.active_requests.add(request_id)
|
|
1353
|
-
|
|
1354
|
-
metadata = await self.__get_metadata(request_id, 60)
|
|
1355
|
-
|
|
1356
|
-
if not metadata:
|
|
1357
|
-
raise Exception("Invalid metadata response")
|
|
1358
|
-
|
|
1359
|
-
return metadata
|
|
1360
|
-
|
|
1361
|
-
async def __get_metadata(self, request_id: str, timeout: int) -> Union[FrameMetadata, None]:
|
|
1362
|
-
if not self.signaling_publisher:
|
|
1363
|
-
raise Exception("Signaling Publisher not initialized")
|
|
1364
|
-
|
|
1365
|
-
try:
|
|
1366
|
-
metadata_request: SignalingRequest = {
|
|
1367
|
-
"type": "metadata",
|
|
1368
|
-
"requestId": request_id,
|
|
1369
|
-
"cameraId": self.id,
|
|
1370
|
-
"pluginId": self.plugin["id"],
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
metadata_response: SignalingResponse = await self.signaling_publisher.request(
|
|
1374
|
-
self.signaling_target_subject,
|
|
1375
|
-
metadata_request,
|
|
1376
|
-
timeout=timeout,
|
|
1377
|
-
)
|
|
1378
|
-
|
|
1379
|
-
metadata = metadata_response.get("metadata")
|
|
1380
|
-
|
|
1381
|
-
return metadata
|
|
1382
|
-
except Exception as e:
|
|
1383
|
-
self.logger.error("Failed to get metadata! Frame Worker FFmpeg process might not be running", e)
|
|
1384
|
-
|
|
1385
|
-
async def __disconnect_from_decoder(self, request_id: str) -> None:
|
|
1386
|
-
if request_id in self.active_requests:
|
|
1387
|
-
self.active_requests.remove(request_id)
|
|
1388
|
-
|
|
1389
|
-
frame_subscription = next(
|
|
1390
|
-
(sub for sub in self.frame_subscribers if sub["request_id"] == request_id), None
|
|
1391
|
-
)
|
|
1392
|
-
|
|
1393
|
-
if frame_subscription:
|
|
1394
|
-
self.frame_subscribers.remove(frame_subscription)
|
|
1395
|
-
await frame_subscription["subscriber"].close()
|
|
1396
|
-
|
|
1397
|
-
if self.signaling_publisher:
|
|
1398
|
-
message: SignalingRequest = {
|
|
1399
|
-
"type": "disconnect",
|
|
1400
|
-
"requestId": request_id,
|
|
1401
|
-
"cameraId": self.id,
|
|
1402
|
-
"pluginId": self.plugin["id"],
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
await self.signaling_publisher.publish(self.signaling_target_subject, message)
|
|
1406
|
-
|
|
1407
|
-
async def __close_frame_subscribers(self) -> None:
|
|
1408
|
-
self.active_requests.clear()
|
|
1409
|
-
|
|
1410
|
-
for sub in self.frame_subscribers:
|
|
1411
|
-
with suppress(Exception):
|
|
1412
|
-
await sub["subscriber"].close()
|
|
1413
|
-
|
|
1414
|
-
self.frame_subscribers.clear()
|
|
1415
|
-
|
|
1416
|
-
async def __close_motion_frame_subscribers(self) -> None:
|
|
1417
|
-
self.active_motion_requests.clear()
|
|
1418
|
-
|
|
1419
|
-
for sub in self.motion_frame_subscribers:
|
|
1420
|
-
with suppress(Exception):
|
|
1421
|
-
await sub["subscriber"].close()
|
|
1422
|
-
|
|
1423
|
-
self.motion_frame_subscribers.clear()
|
|
1424
|
-
|
|
1425
|
-
async def __request_handler(self, message: ProxyMessageStructure) -> None:
|
|
1426
|
-
if not self.message_queue:
|
|
1427
|
-
raise Exception("Message queue not initialized")
|
|
1428
|
-
|
|
1429
|
-
reply = message.copy()
|
|
1430
|
-
reply["type"] = "reply"
|
|
1431
|
-
|
|
1432
|
-
try:
|
|
1433
|
-
if (
|
|
1434
|
-
message["client"] == "cameraDelegate"
|
|
1435
|
-
or message["client"] == "prebufferDelegate"
|
|
1436
|
-
or message["client"] == "ptzDelegate"
|
|
1437
|
-
):
|
|
1438
|
-
delegate = getattr(self, message["client"], None)
|
|
1439
|
-
|
|
1440
|
-
if not delegate:
|
|
1441
|
-
raise Exception(f"Delegate not set: {message['client']}")
|
|
1442
|
-
|
|
1443
|
-
fn: Any = message.get("fn")
|
|
1444
|
-
args = message.get("args", [])
|
|
1445
|
-
|
|
1446
|
-
if not hasattr(delegate, fn) and not callable(getattr(delegate, fn)):
|
|
1447
|
-
raise Exception(f"Unknown delegate function: {message['client']} ({fn})")
|
|
1448
|
-
|
|
1449
|
-
method_to_call = getattr(delegate, fn)
|
|
1450
|
-
|
|
1451
|
-
if inspect.iscoroutinefunction(method_to_call):
|
|
1452
|
-
reply["response"] = await method_to_call(*args)
|
|
1453
|
-
else:
|
|
1454
|
-
reply["response"] = method_to_call(*args)
|
|
1455
|
-
elif message.get("client") == "cameraFn":
|
|
1456
|
-
fn: Any = message.get("fn")
|
|
1457
|
-
args = message.get("args", [])
|
|
1458
|
-
|
|
1459
|
-
if not hasattr(self, fn) and not callable(getattr(self, fn)):
|
|
1460
|
-
raise Exception(f"Unknown camera function: {fn}")
|
|
1461
|
-
|
|
1462
|
-
method_to_call = getattr(self, fn)
|
|
1463
|
-
|
|
1464
|
-
if inspect.iscoroutinefunction(method_to_call):
|
|
1465
|
-
reply["response"] = await method_to_call(*args)
|
|
1466
|
-
else:
|
|
1467
|
-
reply["response"] = method_to_call(*args)
|
|
1468
|
-
else:
|
|
1469
|
-
raise Exception(f"Unknown client: {message['client']}")
|
|
1470
|
-
|
|
1471
|
-
except Exception as e:
|
|
1472
|
-
deserialized_error: DeserializedError = {
|
|
1473
|
-
"name": type(e).__name__,
|
|
1474
|
-
"message": str(e),
|
|
1475
|
-
"stack": traceback.format_exc(),
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
reply["error"] = deserialized_error
|
|
1479
|
-
|
|
1480
|
-
if reply["timeout"] == 0:
|
|
1481
|
-
return
|
|
1482
|
-
else:
|
|
1483
|
-
await self.message_queue.enqueue(reply)
|
|
1484
|
-
|
|
1485
|
-
async def __on_proxy_message(self, msg: Msg) -> None:
|
|
1486
|
-
if not self.initialized:
|
|
1487
|
-
return
|
|
1488
|
-
|
|
1489
|
-
message = unpack(msg.data)
|
|
1490
|
-
|
|
1491
|
-
if "type" in message:
|
|
1492
|
-
type = message["type"]
|
|
1493
|
-
if type == "removed":
|
|
1494
|
-
await self.cleanup()
|
|
1495
|
-
elif type == "updated":
|
|
1496
|
-
self.update_camera(message["data"])
|
|
1497
|
-
elif type == "cameraState":
|
|
1498
|
-
self.update_camera_state(message["data"])
|
|
1499
|
-
else:
|
|
1500
|
-
state_name = message["stateName"]
|
|
1501
|
-
new_data = message["data"]["newEvent"]
|
|
1502
|
-
|
|
1503
|
-
self.__update_state_internal(state_name, new_data, True)
|
|
1504
|
-
|
|
1505
|
-
async def __on_signaling_message(self, msg: Msg) -> None:
|
|
1506
|
-
if not self.initialized:
|
|
1507
|
-
return
|
|
1508
|
-
|
|
1509
|
-
message: Union[SignalingResponse, PingMessage] = unpack(msg.data)
|
|
1510
|
-
|
|
1511
|
-
if message["type"] == "ping":
|
|
1512
|
-
if message["requestId"] in self.active_requests:
|
|
1513
|
-
self.tasks.add(self.__respond_to_signaling_message(msg, message))
|
|
1514
|
-
|
|
1515
|
-
elif message["type"] == "disconnect":
|
|
1516
|
-
if message["requestId"] in self.active_requests:
|
|
1517
|
-
self.active_requests.remove(message["requestId"])
|
|
1518
|
-
|
|
1519
|
-
frame_subscribtion = next(
|
|
1520
|
-
(sub for sub in self.frame_subscribers if sub["request_id"] == message["requestId"]), None
|
|
1521
|
-
)
|
|
1522
|
-
|
|
1523
|
-
if frame_subscribtion:
|
|
1524
|
-
self.frame_subscribers.remove(frame_subscribtion)
|
|
1525
|
-
await frame_subscribtion["subscriber"].close()
|
|
1526
|
-
|
|
1527
|
-
if len(self.active_requests) == 0:
|
|
1528
|
-
self.tasks.add(self.__close_frame_subscribers())
|
|
1529
|
-
|
|
1530
|
-
async def __respond_to_signaling_message(self, msg: Msg, message: PingMessage) -> None:
|
|
1531
|
-
try:
|
|
1532
|
-
pong_message: PongMessage = {
|
|
1533
|
-
"type": "pong",
|
|
1534
|
-
"requestId": message["requestId"],
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
await msg.respond(pack(pong_message))
|
|
1538
|
-
except Exception as e:
|
|
1539
|
-
if self.initialized:
|
|
1540
|
-
self.logger.error("Error while processing singaling respond:", e)
|
|
1541
|
-
|
|
1542
|
-
@overload
|
|
1543
|
-
async def on_request(
|
|
1544
|
-
self,
|
|
1545
|
-
client: Literal["cameraFn"],
|
|
1546
|
-
fn: CameraDeviceProxyMethodNames,
|
|
1547
|
-
args: list[Any] = [],
|
|
1548
|
-
timeout: int = 5000,
|
|
1549
|
-
) -> Any: ...
|
|
1550
|
-
@overload
|
|
1551
|
-
async def on_request(
|
|
1552
|
-
self,
|
|
1553
|
-
client: Literal["cameraDelegate"],
|
|
1554
|
-
fn: CameraDelegateMethodNames,
|
|
1555
|
-
args: list[Any] = [],
|
|
1556
|
-
timeout: int = 5000,
|
|
1557
|
-
) -> Any: ...
|
|
1558
|
-
@overload
|
|
1559
|
-
async def on_request(
|
|
1560
|
-
self,
|
|
1561
|
-
client: Literal["prebufferDelegate"],
|
|
1562
|
-
fn: CameraPrebufferDelegateMethodNames,
|
|
1563
|
-
args: list[Any] = [],
|
|
1564
|
-
timeout: int = 5000,
|
|
1565
|
-
) -> Any: ...
|
|
1566
|
-
@overload
|
|
1567
|
-
async def on_request(
|
|
1568
|
-
self,
|
|
1569
|
-
client: Literal["ptzDelegate"],
|
|
1570
|
-
fn: CameraPTZDelegateMethodNames,
|
|
1571
|
-
args: list[Any] = [],
|
|
1572
|
-
timeout: int = 5000,
|
|
1573
|
-
) -> Any: ...
|
|
1574
|
-
async def on_request(
|
|
1575
|
-
self,
|
|
1576
|
-
client: ClientType,
|
|
1577
|
-
fn: Any,
|
|
1578
|
-
args: list[Any] = [],
|
|
1579
|
-
timeout: int = 5000,
|
|
1580
|
-
) -> Any:
|
|
1581
|
-
if not self.message_queue:
|
|
1582
|
-
raise Exception("Message queue not initialized")
|
|
1583
|
-
|
|
1584
|
-
message: ProxyMessageStructure = {
|
|
1585
|
-
"requestId": str(uuid4()),
|
|
1586
|
-
"targetId": self.subject,
|
|
1587
|
-
"targetName": self.name,
|
|
1588
|
-
"pluginId": self.plugin["id"],
|
|
1589
|
-
"cameraId": self.id,
|
|
1590
|
-
"type": "request",
|
|
1591
|
-
"proxy": "camera",
|
|
1592
|
-
"client": "cameraFn",
|
|
1593
|
-
"fn": fn,
|
|
1594
|
-
"args": args,
|
|
1595
|
-
"timestamp": int(datetime.now().timestamp() * 1000),
|
|
1596
|
-
"timeout": timeout,
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
return await self.message_queue.enqueue(message)
|