Имеется PiCamera с RPi. Пытаюсь написать Python код для управления камерой с помощью веб. В данный момент мой код выглядит вот так
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Test version
'''
from flask import Flask
from datetime import datetime
import io
import time
import picamera
import logging
import sys
import os
app = Flask(__name__)
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)-8s '
+ '[%(filename)s:%(lineno)s:%(funcName)s()] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
@app.route("/start", methods=['POST'])
def start_capture():
with picamera.PiCamera() as camera:
camera.resolution = (1920, 1080)
camera.start_preview()
time.sleep(300)
@app.route("/stop", method=['POST'])
def stop_capture():
with picamera.PiCamera() as camera:
camera.stop_preview()
@app.route("/screenshot", methods=['POST'])
def screenshot():
with picamera.PiCamera() as camera:
camera.capture('foo.jpg', use_video_port=True)
if __name__ == "__main__":
app.run(host='192.168.0.198', port='8080')
Первое что не работает правильно - если я отправляю POST запрос к примеру на 192.168.192:8080/start, запрос отправляется бесконечно.
Далее есть после старта, отправить запрос на стоп, ничего не происходит. Где я что, сделал не правильно? Есть ли способ, каким-то образом записать все в одну функцию, но при это вызывать разным запросом определенные части функции?
Ответ
Попробую угадать ответ по документации picamera. Согласно ей, при входе в with-блок камера включается, а при выходе выключается, то есть получается:
@app.route("/start", methods=['POST'])
def start_capture():
with picamera.PiCamera() as camera: # Включили камеру
camera.resolution = (1920, 1080)
camera.start_preview()
# with закончился — выключили камеру
Отсюда вывод: надо как-то держать камеру постоянно включенной независимо от http-запросов. Простейший способ — вынести camera в глобальную переменную, где она и будет лежать включенная независимо от http-запросов:
from threading import Lock
import picamera
camera = None # Сразу после запуска камера выключена
camlock = Lock() # Блокировка нужна, чтобы нельзя было
# лезть в камеру из нескольких запросов одновременно
# ... app = Flask(__name__) logging всё такое скопировать сюда из вопроса #
@app.route("/start", methods=['POST'])
def start_capture():
global camera
with camlock:
if camera:
return 'already started'
camera = picamera.PiCamera()
camera.resolution = (1920, 1080)
return 'ok'
@app.route("/stop", methods=['POST'])
def stop_capture():
global camera
with camlock:
if not camera:
return 'already stopped'
camera.close()
camera = None
return 'ok'
@app.route("/screenshot", methods=['POST'])
def screenshot():
# Переменную не меняем — global необязателен
with camlock:
if not camera:
return 'camera is not started'
camera.capture('foo.jpg', use_video_port=True)
return 'saved to foo.jpg'
if __name__ == "__main__":
try:
app.run(host='192.168.0.198', port='8080')
finally:
# При завершении работы http-сервера камеру стоит выключить
with camlock:
if camera:
camera.close()
Raspberry Pi не имею и проверить работоспособность кода не могу, но вроде не должен был накосячить.
(Замечание 1: глобальные переменные — довольно опасная штука, и при увеличении сложности проекта от них можно начать получать множество проблем, когда они начнут меняться непредсказуемо и всё такое.)
(Замечание 2: возможно, более хорошим решением будет запуск второго потока, который и будет обслуживать камеру (без глобальной переменной) и принимать сообщения-команды от http-сервера из первого потока вместо непосредственного доступа к камере, но это увеличивает сложность и не факт что целесообразно в данном случае.)
Комментариев нет:
Отправить комментарий