Pi Camera backend version 1.0, now properly controllable

This commit is contained in:
Fabio Manganiello 2018-06-14 12:37:09 +02:00
parent 2b73f71803
commit 81d29928b0
3 changed files with 73 additions and 26 deletions

View File

@ -1,13 +1,26 @@
import json
import socket
import time
import picamera
from threading import Event
from enum import Enum
from redis import Redis
from threading import Thread
from platypush.backend import Backend
class CameraPiBackend(Backend):
class CameraAction(Enum):
START_RECORDING = 'START_RECORDING'
STOP_RECORDING = 'STOP_RECORDING'
TAKE_PICTURE = 'TAKE_PICTURE'
def __eq__(self, other):
return self.value == other
def __init__(self, listen_port, x_resolution=640, y_resolution=480,
redis_queue='platypush_mq_camera',
start_recording_on_startup=True,
framerate=24, hflip=False, vflip=False,
sharpness=0, contrast=0, brightness=50,
video_stabilization=False, ISO=0, exposure_compensation=0,
@ -42,25 +55,63 @@ class CameraPiBackend(Backend):
self.camera.color_effects = color_effects
self.camera.rotation = rotation
self.camera.crop = crop
self.start_recording_on_startup = start_recording_on_startup
self.redis = Redis()
self.redis_queue = redis_queue
self._recording_thread = None
if self.start_recording_on_startup:
self.send_camera_action(self.CameraAction.START_RECORDING)
self.logger.info('Initialized Pi camera backend')
def send_camera_action(self, action, **kwargs):
action = {
'action': action.value,
**kwargs
}
self.redis.rpush(self.redis_queue, json.dumps(action))
def take_picture(self, image_file):
self.logger.info('Capturing camera snapshot to {}'.format(image_file))
self.camera.capture(image_file)
self.logger.info('Captured camera snapshot to {}'.format(image_file))
def start_recording(self, video_file=None, format='h264'):
def recording_thread():
if video_file:
self.camera.start_recording(videofile, format=format)
while True:
self.camera.wait_recording(60)
else:
connection = self.server_socket.accept()[0].makefile('wb')
self.logger.info('Accepted client connection on port {}'.
format(self.listen_port))
try:
self.camera.start_recording(connection, format=format)
while True:
self.camera.wait_recording(60)
except ConnectionError:
self.logger.info('Client closed connection')
try:
self.stop_recording()
connection.close()
except:
pass
self.send_camera_action(self.CameraAction.START_RECORDING)
self._recording_thread = None
if self._recording_thread:
self._recording_thread.join()
self.logger.info('Starting camera recording')
self._recording_thread = Thread(target=recording_thread)
self._recording_thread.start()
if video_file:
self.camera.start_recording(videofile, format=format)
else:
connection = self.server_socket.accept()[0].makefile('wb')
self.logger.info('Accepted client connection on port {}'.
format(self.listen_port))
self.camera.start_recording(connection, format=format)
def stop_recording(self):
self.logger.info('Stopping camera recording')
@ -73,20 +124,15 @@ class CameraPiBackend(Backend):
def run(self):
super().run()
while True:
restart = True
while not self.should_stop():
msg = json.loads(self.redis.blpop(self.redis_queue)[1].decode())
try:
if msg.get('action') == self.CameraAction.START_RECORDING:
self.start_recording()
while True:
self.camera.wait_recording(60)
except ConnectionError:
self.logger.info('Client closed connection')
finally:
try:
self.stop_recording()
except Exception as e:
self.logger.exception(e)
elif msg.get('action') == self.CameraAction.STOP_RECORDING:
self.stop_recording()
elif msg.get('action') == self.CameraAction.TAKE_PICTURE:
self.take_picture(image_file=msg.get('image_file'))
# vim:sw=4:ts=4:et:

View File

@ -7,17 +7,17 @@ from platypush.plugins import Plugin
class CameraPiPlugin(Plugin):
def start_recording(self):
camera = get_backend('camera.pi')
camera.start_recording()
camera.send_camera_action(camera.CameraAction.START_RECORDING)
return Response(output={'status':'ok'})
def stop_recording(self):
camera = get_backend('camera.pi')
camera.stop_recording()
camera.send_camera_action(camera.CameraAction.STOP_RECORDING)
return Response(output={'status':'ok'})
def take_picture(self, image_file):
camera = get_backend('camera.pi')
camera.take_picture(image_file)
camera.send_camera_action(camera.CameraAction.TAKE_PICTURE, image_file=image_file)
return Response(output={'image_file':image_file})

View File

@ -60,11 +60,12 @@ setup(
install_requires = [
'pyyaml',
'requires',
'redis',
],
extras_require = {
'Support for Apache Kafka backend': ['kafka-python'],
'Support for Pushbullet backend': ['requests', 'websocket-client'],
'Support for HTTP backend': ['flask','websockets','redis'],
'Support for HTTP backend': ['flask','websockets'],
'Support for HTTP poll backend': ['frozendict'],
'Support for database plugin': ['sqlalchemy'],
'Support for RSS feeds': ['feedparser'],
@ -86,7 +87,7 @@ setup(
'Support for MCP3008 analog-to-digital converter plugin': ['adafruit-mcp3008'],
'Support for smart cards detection': ['pyscard'],
'Support for ICal calendars': ['icalendar', 'python-dateutil'],
# 'Support for Leap Motion backend': ['git+ssh://git@github.com:BlackLight/leap-sdk-python3.git', 'redis'],
# 'Support for Leap Motion backend': ['git+ssh://git@github.com:BlackLight/leap-sdk-python3.git'],
# 'Support for Flic buttons': ['git+ssh://git@github.com/50ButtonsEach/fliclib-linux-hci']
},
)