Removed python based webcam support (didn't work well with the raspi), switched instead to external stream (mjpg-streamer being the preferred webcam server)
parent
8dc5e249d5
commit
4e4eed84bb
59
README.md
59
README.md
|
@ -12,6 +12,7 @@ allows
|
|||
* reading the communication log and send arbitrary codes to be executed by the printer
|
||||
* moving the X, Y and Z axis (jog controls, although very ugly ones right now)
|
||||
* changing the speed modifiers for inner & outer wall, fill and support
|
||||
* optional: visual monitoring of the printer via webcam stream integrated into the UI (using MJPG-Streamer)
|
||||
|
||||
The intended usecase is to run the Printer WebUI on a single-board computer like the Raspberry Pi and a WiFi module,
|
||||
connect the printer to the server and therefore create a WiFi-enabled 3D printer.
|
||||
|
@ -61,6 +62,60 @@ The following example config should explain the available options:
|
|||
# use this option to define the port to which to bind the server, defaults to 5000
|
||||
port = 5000
|
||||
|
||||
[webcam]
|
||||
# use this option to enable display of a webcam stream in the UI, e.g. via MJPG-Streamer
|
||||
stream = http://10.0.0.2:8080/?action=stream
|
||||
|
||||
Setup on a Raspberry Pi running Raspbian
|
||||
----------------------------------------
|
||||
|
||||
I currently run the Printer WebUI on a Raspberry Pi running Raspbian (http://www.raspbian.org/). For the basic
|
||||
package you'll need Python 2.7 (should be installed by default), pip and flask:
|
||||
|
||||
cd ~
|
||||
sudo apt-get install python-pip git
|
||||
git clone https://github.com/foosel/PrinterWebUI.git
|
||||
cd PrinterWebUI
|
||||
pip install -r requirements.txt
|
||||
|
||||
You should then be able to start the WebUI server:
|
||||
|
||||
pi@raspberrypi ~/PrinterWebUI $ python -m printer_webui.server
|
||||
* Running on http://0.0.0.0:5000/
|
||||
|
||||
If you also want webcam support, you'll need to download and compile MJPG-Streamer:
|
||||
|
||||
cd ~
|
||||
sudo apt-get install libjpeg8-dev imagemagick
|
||||
wget -Omjpg-streamer.tar.gz http://mjpg-streamer.svn.sourceforge.net/viewvc/mjpg-streamer/mjpg-streamer/?view=tar
|
||||
tar xfz mjpg-streamer.tar.gz
|
||||
cd mjpg-streamer
|
||||
make
|
||||
|
||||
This should hopefully run through without any compilation errors. You should then be able to start the webcam server:
|
||||
|
||||
pi@raspberrypi ~/mjpg-streamer $ ./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so"
|
||||
MJPG Streamer Version: svn rev:
|
||||
i: Using V4L2 device.: /dev/video0
|
||||
i: Desired Resolution: 640 x 480
|
||||
i: Frames Per Second.: 5
|
||||
i: Format............: MJPEG
|
||||
[...]
|
||||
o: www-folder-path...: disabled
|
||||
o: HTTP TCP port.....: 8080
|
||||
o: username:password.: disabled
|
||||
o: commands..........: enabled
|
||||
|
||||
If you now point your browser to http://<your Raspi's IP>:8080/?action=stream, you should see a moving picture at 5fps.
|
||||
Open `~/.printerwebui/config.ini` and add the following lines to it:
|
||||
|
||||
[webcam]
|
||||
stream = http://<your Raspi's IP>:8080/?action=stream
|
||||
|
||||
Restart the WebUI server and reload its frontend. You should now see a Webcam tab with content.
|
||||
|
||||
If everything works, add the startup commands to `/etc/rc.local`.
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
|
@ -76,3 +131,7 @@ It also uses the following libraries and frameworks for backend and frontend:
|
|||
* Knockout.js: http://knockoutjs.com/
|
||||
* Flot: http://www.flotcharts.org/
|
||||
* jQuery File Upload: http://blueimp.github.com/jQuery-File-Upload/
|
||||
|
||||
And this for Webcam support:
|
||||
|
||||
* MJPG-Streamer: http://sourceforge.net/apps/mediawiki/mjpg-streamer/index.php?title=Main_Page
|
||||
|
|
|
@ -7,7 +7,6 @@ from werkzeug import secure_filename
|
|||
|
||||
from printer_webui.printer import Printer, getConnectionOptions
|
||||
from printer_webui.settings import settings
|
||||
from printer_webui.webcam import hasWebcamSupport, Webcam
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
@ -28,14 +27,10 @@ if not os.path.isdir(WEBCAM_FOLDER):
|
|||
|
||||
app = Flask("printer_webui")
|
||||
printer = Printer()
|
||||
if hasWebcamSupport():
|
||||
webcam = Webcam()
|
||||
else:
|
||||
webcam = None
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html")
|
||||
return render_template("index.html", webcamStream = settings().get("webcam", "stream"))
|
||||
|
||||
#~~ Printer state
|
||||
|
||||
|
@ -261,19 +256,6 @@ def setSettings():
|
|||
s.save()
|
||||
return getSettings()
|
||||
|
||||
#~~ webcam
|
||||
|
||||
@app.route(BASEURL + "webcam/image", methods=["GET"])
|
||||
def getImage():
|
||||
if webcam is None:
|
||||
abort(404)
|
||||
|
||||
image = webcam.get()
|
||||
strIO = StringIO.StringIO()
|
||||
image.save(strIO, "JPEG", quality=80)
|
||||
strIO.seek(0)
|
||||
return send_file(strIO, mimetype="image/jpeg")
|
||||
|
||||
#~~ helper functions
|
||||
|
||||
def sizeof_fmt(num):
|
||||
|
|
|
@ -24,6 +24,9 @@ default_settings = {
|
|||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 5000
|
||||
},
|
||||
"webcam": {
|
||||
"stream": None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,12 +97,4 @@ table th.gcode_files_action, table td.gcode_files_action {
|
|||
#webcam_container {
|
||||
height: 440px;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
#webcam_placeholder {
|
||||
height: 440px;
|
||||
line-height: 440px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
|
@ -438,32 +438,6 @@ function DataUpdater(connectionViewModel, printerStateViewModel, temperatureView
|
|||
}
|
||||
var dataUpdater = new DataUpdater(connectionViewModel, printerStateViewModel, temperatureViewModel, speedViewModel, terminalViewModel);
|
||||
|
||||
function WebcamViewModel() {
|
||||
var self = this;
|
||||
|
||||
self.webcamUpdateInterval = 5000;
|
||||
self.offlineUrl = "/static/img/webcam-offline.png";
|
||||
|
||||
self.url = ko.observable(undefined);
|
||||
self.enabled = ko.observable(undefined);
|
||||
|
||||
self.enabled.subscribe(function(newValue) {
|
||||
if (newValue) {
|
||||
self.requestData();
|
||||
} else {
|
||||
$("#webcam_image")
|
||||
}
|
||||
});
|
||||
|
||||
self.requestData = function() {
|
||||
if (!self.enabled())
|
||||
return;
|
||||
self.url(AJAX_BASEURL + "webcam/image?" + (new Date()).getTime());
|
||||
setTimeout(self.requestData, self.webcamUpdateInterval);
|
||||
}
|
||||
}
|
||||
var webcamViewModel = new WebcamViewModel();
|
||||
|
||||
$(function() {
|
||||
|
||||
//~~ Print job control
|
||||
|
@ -603,7 +577,6 @@ $(function() {
|
|||
ko.applyBindings(printerStateViewModel, document.getElementById("jog"));
|
||||
ko.applyBindings(terminalViewModel, document.getElementById("term"));
|
||||
ko.applyBindings(speedViewModel, document.getElementById("speed"));
|
||||
ko.applyBindings(webcamViewModel, document.getElementById("webcam"));
|
||||
|
||||
//~~ startup commands
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
<li><a href="#jog" data-toggle="tab">Jog</a></li>
|
||||
<li><a href="#speed" data-toggle="tab">Speed</a></li>
|
||||
<li><a href="#term" data-toggle="tab">Term</a></li>
|
||||
<li><a href="#webcam" data-toggle="tab">Webcam</a></li>
|
||||
{% if webcamStream %}<li><a href="#webcam" data-toggle="tab">Webcam</a></li>{% endif %}
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
|
@ -216,15 +216,13 @@
|
|||
<button class="btn" type="button" id="terminal-send">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
{% if webcamStream %}
|
||||
<div class="tab-pane" id="webcam">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="webcam_enable" data-bind="checked: enabled"> Enable webcam
|
||||
</label>
|
||||
<div id="webcam_container">
|
||||
<img id="webcam_image" data-bind="attr: { src: url }, visible: enabled()">
|
||||
<div id="webcam_placeholder" data-bind="visible: !enabled()">Offline</div>
|
||||
<img id="webcam_image" src="{{ webcamStream }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
# coding=utf-8
|
||||
__author__ = "Gina Häußge <osd@foosel.net>"
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
|
||||
try:
|
||||
#Try to find the OpenCV library for video capture.
|
||||
import cv
|
||||
except:
|
||||
cv = None
|
||||
|
||||
try:
|
||||
import VideoCapture as win32vidcap
|
||||
except:
|
||||
win32vidcap = None
|
||||
|
||||
import PIL
|
||||
|
||||
def hasWebcamSupport():
|
||||
if cv == None and win32vidcap == None:
|
||||
return False
|
||||
return True
|
||||
|
||||
class Webcam(object):
|
||||
def __init__(self):
|
||||
self._cam = None
|
||||
if cv != None:
|
||||
self._cam = cv.CreateCameraCapture(-1)
|
||||
elif win32vidcap != None:
|
||||
try:
|
||||
self._cam = win32vidcap.Device()
|
||||
self._cam.setResolution(640, 480)
|
||||
except:
|
||||
pass
|
||||
|
||||
def get(self):
|
||||
if self._cam is None:
|
||||
return None
|
||||
|
||||
if cv is not None:
|
||||
frame = cv.QueryFrame(self._cam)
|
||||
image = PIL.Image.fromstring("L", frame.GetSize(), frame.tostring())
|
||||
return image
|
||||
elif win32vidcap is not None:
|
||||
image = self._cam.getImage()
|
||||
return image
|
||||
else:
|
||||
return None
|
||||
|
||||
def save(self, filename):
|
||||
if self._cam is None:
|
||||
return
|
||||
|
||||
if cv is not None:
|
||||
frame = cv.QueryFrame(self._cam)
|
||||
cv.SaveImage(filename, frame)
|
||||
elif win32vidcap is not None:
|
||||
self._cam.saveSnapshot(filename)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from printer_webui.settings import settings
|
||||
import os
|
||||
|
||||
webcam = Webcam()
|
||||
webcam.save(os.path.join(settings().settings_dir, "image.png"))
|
Loading…
Reference in New Issue