Source code for panoptes.pocs.camera.gphoto.remote
from collections import deque
from threading import Thread
from typing import List, Union
import requests
from pydantic import AnyHttpUrl
from panoptes.pocs.camera.gphoto.canon import Camera as CanonCamera
[docs]
class Camera(CanonCamera):
"""A remote gphoto2 camera class."""
def __init__(self, endpoint: AnyHttpUrl = 'http://localhost:6565', *args, **kwargs):
"""Control a remote gphoto2 camera via the pocs service.
Interact with a camera via `panoptes.pocs.utils.service.camera`.
"""
self.endpoint = endpoint
self.response_queue: deque = deque(maxlen=1)
super().__init__(*args, **kwargs)
@property
def is_exposing(self):
if self._command_proc is not None and self._command_proc.is_alive() is False:
self._is_exposing_event.clear()
return self._is_exposing_event.is_set()
[docs]
def command(self, cmd, endpoint: AnyHttpUrl = None):
"""Run the gphoto2 command remotely.
This assumes the remote camera service is running at the endpoint specified
on the camera object or passed to the method.
"""
endpoint = endpoint or self.endpoint
arguments = ' '.join(cmd)
# Add the port
if '--port' not in arguments:
arguments = f'--port {self.port} {arguments}'
self.logger.debug(f'Running remote gphoto2 on {endpoint=} with {arguments=}')
def do_command():
response = requests.post(endpoint, json=dict(arguments=arguments))
self.logger.debug(f'Remote gphoto2 {response=!r}')
if response.ok:
output = response.json()
self.logger.debug(f'Response {output=!r}')
self.response_queue.append(output)
self._is_exposing_event.clear()
else:
self.logger.error(f'Error in remote camera service: {response.content}')
self._command_proc = Thread(target=do_command, name='RemoteGphoto2Command')
self._command_proc.start()
[docs]
def get_command_result(self, timeout: float = 10) -> Union[List[str], None]:
"""Get the output from the remote camera service."""
output = None
try:
self._command_proc.join(timeout=self.timeout)
if self._command_proc.is_alive():
raise TimeoutError
except TimeoutError:
self.logger.warning(f'Timeout on exposure process for {self.name}')
else:
response = self.response_queue.pop()
if response['output'] > '':
output = response['output'].split('\n')
self.logger.debug(f'Remote gphoto2 output: {output!r}')
if response['error'] > '':
error = response['error'].split('\n')
self.logger.debug(f'Remote gphoto2 error: {error!r}')
return output
def _create_fits_header(self, seconds, dark=None, metadata=None) -> dict:
fits_header = super(Camera, self)._create_fits_header(seconds, dark=dark, metadata=metadata)
return {k.lower(): v for k, v in dict(fits_header).items()}