diff --git a/phytopi/__init__.py b/phytopi/__init__.py index 51df99e..ee384c0 100644 --- a/phytopi/__init__.py +++ b/phytopi/__init__.py @@ -3,6 +3,7 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from phytopi.config import Config +# from phytopi.camera.camera_pi import Camera app = Flask(__name__, instance_relative_config=True) @@ -10,11 +11,6 @@ app.config.from_object(Config) db = SQLAlchemy(app) migrate = Migrate(app, db) - -from phytopi.errors import bp as errors_bp -from phytopi.camera import bp as camera_bp - -app.register_blueprint(errors_bp) -app.register_blueprint(camera_bp) +# camera = Camera(app=app) from phytopi import routes, models diff --git a/phytopi/camera/__init__.py b/phytopi/camera/__init__.py index 9614332..e69de29 100644 --- a/phytopi/camera/__init__.py +++ b/phytopi/camera/__init__.py @@ -1,5 +0,0 @@ -from flask import Blueprint - -bp = Blueprint('camera', __name__) - -from phytopi.camera import camera \ No newline at end of file diff --git a/phytopi/camera_old/base_camera.py b/phytopi/camera/base_camera.py similarity index 100% rename from phytopi/camera_old/base_camera.py rename to phytopi/camera/base_camera.py diff --git a/phytopi/camera/camera.py b/phytopi/camera/camera.py deleted file mode 100644 index 2e001f6..0000000 --- a/phytopi/camera/camera.py +++ /dev/null @@ -1,90 +0,0 @@ -import io -import os -import sys -import stat -import subprocess -import signal - -from time import sleep -from enum import Enum -from PIL import Image -from phytopi import db, models -from phytopi.models import CameraSettings - -class CameraActionError(Exception): - pass - -class CameraStatus(Enum): - STOPPED = 0 - IDLE = 1 - TIMELAPSE = 2 - VIDEO = 3 - SHOT = 4 - -class CameraWorker(object): - def __init__(self, pidfile='/tmp/raspimjpeg.pid', executable='/usr/local/bin/raspimjpeg', fifo='/dev/shm/mjpeg/FIFO'): - self.pidfile = pidfile - self.executable = executable - self.fifo = fifo - self.proc = None - self.pid = None - self.status = CameraStatus.STOPPED - - def start(self): - # check if process is already running - if os.path.isfile(self.pidfile): - with open(self.pidfile, 'r') as fh: - self.pid = int(fh.read()) - self.status = CameraStatus.IDLE - return - - # create FIFO, if not existent - try: - os.mkfifo(self.fifo) - except FileExistsError: - pass - - # if not, spawn new process and create pid file - self.proc = subprocess.Popen([self.executable], preexec_fn=os.setsid) - self.pid = self.proc.pid - with open(self.pidfile, 'w') as fh: - fh.write(str(self.pid)) - self.status = CameraStatus.IDLE - - def stop(self): - os.killpg(os.getpgid(self.pid), signal.SIGTERM) - os.unlink(self.fifo) - os.unlink(self.pidfile) - self.status = CameraStatus.STOPPED - - def _send_cmd(self, cmd): - with open(self.fifo, 'w') as fh: - fh.write('{}\n'.format(cmd)) - - def _send_cmds(self, cmds): - for cmd in cmds: - self._send_cmd(cmd) - # don't flood the fifo - sleep(1) - - def start_timelapse(self, interval=300): - if self.status == CameraStatus.IDLE: - cmds = ['tv {}'.format(interval), 'tl 1'] - self._send_cmds(cmds) - self.status = CameraStatus.TIMELAPSE - else: - raise CameraActionError('Camera not idle!') - - def stop_timelapse(self): - if self.status == CameraStatus.TIMELAPSE: - self._send_cmd('tl 0') - self.status = CameraStatus.IDLE - else: - raise CameraActionError('Camera not in timelapse mode!') - - def get_frame(self, thumbnail=False): - output = io.BytesIO() - img = Image.open('/dev/shm/mjpeg/cam.jpg') - img.save(output, format='JPEG') - output.seek(0, 0) - return output.getvalue() \ No newline at end of file diff --git a/phytopi/camera_old/camera_pi.py b/phytopi/camera/camera_pi.py similarity index 100% rename from phytopi/camera_old/camera_pi.py rename to phytopi/camera/camera_pi.py diff --git a/phytopi/camera_old/__init__.py b/phytopi/camera_daemon/__init__.py similarity index 100% rename from phytopi/camera_old/__init__.py rename to phytopi/camera_daemon/__init__.py diff --git a/phytopi/errors/handlers.py b/phytopi/camera_daemon/camera_daemon.py similarity index 100% rename from phytopi/errors/handlers.py rename to phytopi/camera_daemon/camera_daemon.py diff --git a/phytopi/errors/__init__.py b/phytopi/errors/__init__.py deleted file mode 100644 index 5d1beb0..0000000 --- a/phytopi/errors/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from flask import Blueprint - -bp = Blueprint('errors', __name__) - -from phytopi.errors import handlers \ No newline at end of file diff --git a/phytopi/models.py b/phytopi/models.py index 828ddc2..b49e45f 100644 --- a/phytopi/models.py +++ b/phytopi/models.py @@ -1,8 +1,6 @@ from datetime import datetime from phytopi import db - - class Dataset(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(64), index=True) @@ -31,16 +29,17 @@ class CameraSettings(db.Model): fps = db.Column(db.Integer, default=5) width = db.Column(db.Integer, default=3280) height = db.Column(db.Integer, default=2464) - exposure_mode = db.Column(db.String(64), default='auto') + fix_shutter = db.Column(db.Boolean, default=False) + fix_wb = db.Column(db.Boolean, default=False) - def __init__(self, name, iso=100, fps=5, width=3280, height=2464, exposure_mode='auto'): + def __init__(self, name, iso=100, fps=5, width=3280, height=2464, fix_shutter=False, fix_wb=False): self.name = name self.iso = iso self.fps = fps self.width = width self.height = height - self.exposure_mode = exposure_mode - + self.fix_shutter = fix_shutter + self.fix_wb = fix_wb def __repr__(self): return ''.format(self.name) \ No newline at end of file diff --git a/phytopi/phytopi.db b/phytopi/phytopi.db new file mode 100644 index 0000000..0519c72 Binary files /dev/null and b/phytopi/phytopi.db differ diff --git a/phytopi/routes.py b/phytopi/routes.py index a8a6010..35e73b6 100644 --- a/phytopi/routes.py +++ b/phytopi/routes.py @@ -1,6 +1,6 @@ from flask import render_template, Response, flash, jsonify, request, stream_with_context, send_file -from phytopi.camera.camera import CameraWorker, CameraStatus +from phytopi.camera.camera_pi import Camera from phytopi.forms import CameraSettingsForm from phytopi import app @@ -10,59 +10,46 @@ from phytopi.models import Dataset from io import BytesIO import zipstream -camera = CameraWorker(app=app) -camera.start() - +camera = Camera(app=app) +# camera = app.camera +save_frames = False @app.route('/') @app.route('/index') def index(): - global camera - if camera.status == CameraStatus.TIMELAPSE: - timelapse = True - else: - timelapse = False - content = {'timelapse': timelapse} + content = {'timelapse': save_frames} return render_template('index.html', content=content) @app.route('/toggle_timelapse', methods=['GET', 'POST']) def start_stop_timelapse(): - # global save_frames + global save_frames global current_dataset global camera - # if save_frames: - # save_frames = False - # timelapse_interval = None - # btn_text = "Start" - # btn_class = 'btn-primary' - # camera.current_dataset = None - # camera.last_saved = None - # print(" > switched off timelapse mode") - # else: - # save_frames = True - # timelapse_interval = 1200 - # btn_text = "Stop" - # btn_class = 'btn-danger' - # dataset = Dataset() - # db.session.add(dataset) - # db.session.commit() - # camera.current_dataset = dataset.id - # print(" > switched on timelapse mode") - - # camera.set_timelapse_interval(timelapse_interval) - if camera.status == CameraStatus.IDLE: - btn_text = "Stop" - btn_class = 'btn-danger' - camera.start_timelapse() - elif camera.status == CameraStatus.TIMELAPSE: + if save_frames: + save_frames = False + timelapse_interval = None btn_text = "Start" btn_class = 'btn-primary' - camera.stop_timelapse() + camera.current_dataset = None + camera.last_saved = None + print(" > switched off timelapse mode") + else: + save_frames = True + timelapse_interval = 1200 + btn_text = "Stop" + btn_class = 'btn-danger' + dataset = Dataset() + db.session.add(dataset) + db.session.commit() + camera.current_dataset = dataset.id + print(" > switched on timelapse mode") + camera.set_timelapse_interval(timelapse_interval) return jsonify(btn_text=btn_text, btn_class=btn_class) def gen(camera): +# def gen(): """Video streaming generator function.""" while True: frame = camera.get_frame(thumbnail=True) diff --git a/requirements_pi.txt b/requirements_pi.txt new file mode 100644 index 0000000..abee2bc --- /dev/null +++ b/requirements_pi.txt @@ -0,0 +1,19 @@ +alembic>=1.0.1 +Click>=7.0 +Flask>=1.0.2 +Flask-Migrate>=2.3.0 +Flask-SQLAlchemy>=2.3.2 +Flask-WTF>=0.14.2 +itsdangerous>=1.1.0 +Jinja2>=2.10 +Mako>=1.0.7 +MarkupSafe>=1.0 +picamera>=1.13 +Pillow>=5.3.0 +python-dateutil>=2.7.5 +python-editor>=1.0.3 +six>=1.11.0 +SQLAlchemy>=1.2.12 +Werkzeug>=0.14.1 +WTForms>=2.2.1 +zipstream>=1.1.4