summaryrefslogtreecommitdiff
path: root/bin/camera_node.py
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2023-09-27 00:54:57 +0300
committerEvgeny Zinoviev <me@ch1p.io>2023-09-27 00:54:57 +0300
commitd3a295872c49defb55fc8e4e43e55550991e0927 (patch)
treeb9dca15454f9027d5a9dad0d4443a20de04dbc5d /bin/camera_node.py
parentb7cbc2571c1870b4582ead45277d0aa7f961bec8 (diff)
parentbdbb296697f55f4c3a07af43c9aaf7a9ea86f3d0 (diff)
Merge branch 'master' of ch1p.io:homekit
Diffstat (limited to 'bin/camera_node.py')
-rwxr-xr-xbin/camera_node.py89
1 files changed, 89 insertions, 0 deletions
diff --git a/bin/camera_node.py b/bin/camera_node.py
new file mode 100755
index 0000000..1485557
--- /dev/null
+++ b/bin/camera_node.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+import asyncio
+import time
+import __py_include
+
+from homekit.config import config
+from homekit.media import MediaNodeServer, ESP32CameraRecordStorage, CameraRecorder
+from homekit.camera import CameraType, esp32
+from homekit.util import Addr
+from homekit import http
+
+
+# Implements HTTP API for a camera.
+# ---------------------------------
+
+class ESP32CameraNodeServer(MediaNodeServer):
+ def __init__(self, web_addr: Addr, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.last_settings_sync = 0
+
+ self.web = esp32.WebClient(web_addr)
+ self.get('/capture/', self.capture)
+
+ async def capture(self, req: http.Request):
+ await self.sync_settings_if_needed()
+
+ try:
+ with_flash = int(req.query['with_flash'])
+ except KeyError:
+ with_flash = 0
+
+ if with_flash:
+ await self.web.setflash(True)
+ await asyncio.sleep(0.5)
+
+ bytes = (await self.web.capture()).read()
+
+ if with_flash:
+ await asyncio.sleep(0.5)
+ await self.web.setflash(False)
+
+ res = http.StreamResponse()
+ res.content_type = 'image/jpeg'
+ res.content_length = len(bytes)
+
+ await res.prepare(req)
+ await res.write(bytes)
+ await res.write_eof()
+
+ return res
+
+ async def do_record(self, request: http.Request):
+ await self.sync_settings_if_needed()
+
+ # sync settings
+ return await super().do_record(request)
+
+ async def sync_settings_if_needed(self):
+ if self.last_settings_sync != 0 and time.time() - self.last_settings_sync < 300:
+ return
+ changed = await self.web.syncsettings(config['camera']['settings'])
+ if changed:
+ self.logger.debug('sync_settings_if_needed: some settings were changed, sleeping for 0.4 sec')
+ await asyncio.sleep(0.4)
+ self.last_settings_sync = time.time()
+
+
+if __name__ == '__main__':
+ config.load_app('camera_node')
+
+ recorder_kwargs = {}
+ camera_type = CameraType(config['camera']['type'])
+ if camera_type == CameraType.ESP32:
+ recorder_kwargs['stream_addr'] = config.get_addr('camera.web_addr') # this is not a mistake, we don't use stream_addr for esp32-cam anymore
+ storage = ESP32CameraRecordStorage(config['node']['storage'])
+ else:
+ raise RuntimeError(f'unsupported camera type {camera_type}')
+
+ recorder = CameraRecorder(storage=storage,
+ camera_type=camera_type,
+ **recorder_kwargs)
+ recorder.start_thread()
+
+ server = ESP32CameraNodeServer(
+ recorder=recorder,
+ storage=storage,
+ web_addr=config.get_addr('camera.web_addr'),
+ addr=config.get_addr('node.listen'))
+ server.run()