diff --git a/platypush/backend/http/app/routes/plugins/camera/ir/__init__.py b/platypush/backend/http/app/routes/plugins/camera/ir/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py b/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py
new file mode 100644
index 000000000..cd2787713
--- /dev/null
+++ b/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py
@@ -0,0 +1,60 @@
+import base64
+import os
+import tempfile
+import time
+
+from flask import Response, request, Blueprint, send_from_directory
+
+from platypush.backend.http.app import template_folder
+from platypush.backend.http.app.utils import authenticate, send_request
+
+camera_ir_mlx90640 = Blueprint('camera.ir.mlx90640', __name__, template_folder=template_folder)
+
+# Declare routes list
+__routes__ = [
+ camera_ir_mlx90640,
+]
+
+
+def get_feed(**args):
+ try:
+ while True:
+ frame = send_request(action='camera.ir.mlx90640.capture', **args).output[0]
+ frame = base64.decodebytes(frame.encode())
+ yield (b'--frame\r\n'
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
+ finally:
+ send_request(action='camera.ir.mlx90640.stop')
+
+
+@camera_ir_mlx90640.route('/camera/ir/mlx90640/frame', methods=['GET'])
+@authenticate()
+def get_frame_route():
+ f = tempfile.NamedTemporaryFile(prefix='ir_camera_frame_', suffix='.jpg', delete=False)
+ args = {
+ 'grayscale': bool(int(request.args.get('grayscale', 0))),
+ 'scale_factor': int(request.args.get('scale_factor', 1)),
+ 'rotate': int(request.args.get('rotate', 0)),
+ 'output_file': f.name,
+ }
+
+ send_request(action='camera.ir.mlx90640.capture', **args)
+ return send_from_directory(os.path.dirname(f.name),
+ os.path.basename(f.name))
+
+
+@camera_ir_mlx90640.route('/camera/ir/mlx90640/stream', methods=['GET'])
+@authenticate()
+def get_feed_route():
+ args = {
+ 'grayscale': bool(int(request.args.get('grayscale', 0))),
+ 'scale_factor': int(request.args.get('scale_factor', 1)),
+ 'rotate': int(request.args.get('rotate', 0)),
+ 'format': 'jpeg',
+ }
+
+ return Response(get_feed(**args),
+ mimetype='multipart/x-mixed-replace; boundary=frame')
+
+
+# vim:sw=4:ts=4:et:
diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/camera/index.scss b/platypush/backend/http/static/css/source/webpanel/plugins/camera/index.scss
index 9b3693499..43387330c 100644
--- a/platypush/backend/http/static/css/source/webpanel/plugins/camera/index.scss
+++ b/platypush/backend/http/static/css/source/webpanel/plugins/camera/index.scss
@@ -1,9 +1,9 @@
@import 'common/vars';
.camera {
- height: 90%;
- margin-top: 7%;
- overflow: hidden;
+ min-height: 90%;
+ margin-top: 4%;
+ overflow: auto;
display: flex;
flex-direction: column;
align-items: center;
diff --git a/platypush/backend/http/static/js/plugins/camera.ir.mlx90640/index.js b/platypush/backend/http/static/js/plugins/camera.ir.mlx90640/index.js
index d081c70f7..f26fe528f 100644
--- a/platypush/backend/http/static/js/plugins/camera.ir.mlx90640/index.js
+++ b/platypush/backend/http/static/js/plugins/camera.ir.mlx90640/index.js
@@ -17,22 +17,43 @@ Vue.component('camera-ir-mlx90640', {
return;
this.capturing = true;
-
- while (this.capturing) {
- const img = await request('camera.ir.mlx90640.capture', {
- format: 'png',
- rotate: this.rotate,
- grayscale: this.grayscale,
- });
-
- this.$refs.frame.setAttribute('src', 'data:image/png;base64,' + img);
- }
+ this.$refs.frame.setAttribute('src', '/camera/ir/mlx90640/stream?rotate='
+ + this.rotate + '&grayscale=' + (this.grayscale ? 1 : 0) + '&t='
+ + (new Date()).getTime());
},
stopStreaming: async function() {
await request('camera.ir.mlx90640.stop');
+ this.$refs.frame.removeAttribute('src');
this.capturing = false;
},
+
+ onRotationChange: function() {
+ this.rotate = parseInt(this.$refs.rotate.value);
+ const cameraContainer = this.$el.querySelector('.camera-container');
+
+ switch (this.rotate) {
+ case 0:
+ case 180:
+ cameraContainer.style.width = '640px';
+ cameraContainer.style.minWidth = '640px';
+ cameraContainer.style.height = '480px';
+ cameraContainer.style.minHeight = '480px';
+ break;
+
+ case 90:
+ case 270:
+ cameraContainer.style.width = '480px';
+ cameraContainer.style.minWidth = '480px';
+ cameraContainer.style.height = '640px';
+ cameraContainer.style.minHeight = '640px';
+ break;
+ }
+ },
+ },
+
+ mounted: function() {
+ this.onRotationChange();
},
});
diff --git a/platypush/backend/http/templates/plugins/camera.ir.mlx90640/index.html b/platypush/backend/http/templates/plugins/camera.ir.mlx90640/index.html
index 6b7df9226..d09e0ba74 100644
--- a/platypush/backend/http/templates/plugins/camera.ir.mlx90640/index.html
+++ b/platypush/backend/http/templates/plugins/camera.ir.mlx90640/index.html
@@ -14,7 +14,7 @@
Stop streaming
-