PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Raspi mit Bottle (Python) und Kamera



toto1975
07.07.2019, 20:09
Hallo in die Runde,

ich möchte gerne meinen Roboter übers Web steuern und auch sehen wohin ich gerade fahre. Hier habe ich zwei schöne Python Scripte gefunden die einzeln auch super funktionieren nur kann ich beide nicht "vereinen" ich bekomme immer folgende Fehlermeldung beim drücken des Button zurück:
192.xxx.xxx.21 - - [07/Jul/2019 19:32:32] code 501, message Unsupported method ('POST')
192.xxx.xxx.21 - - [07/Jul/2019 19:32:32] "POST /zurueck HTTP/1.1" 501 -

Hier mal mein jetziger Code (am ende sind beide einzelne Codes die auch funktionieren)

#!/usr/bin/env python

import sys
import io
import os
import shutil
from subprocess import Popen, PIPE
from string import Template
from struct import Struct
from threading import Thread
from time import sleep, time
from http.server import HTTPServer, BaseHTTPRequestHandler
from wsgiref.simple_server import make_server

import picamera
from ws4py.websocket import WebSocket
from ws4py.server.wsgirefserver import (
WSGIServer,
WebSocketWSGIHandler,
WebSocketWSGIRequestHandler,
)
from ws4py.server.wsgiutils import WebSocketWSGIApplication

#mein Code Anfang
import bottle
import RPi.GPIO as GPIO
#import time
import smbus
bus = smbus.SMBus(1)
address = 0x05
#mein Code Ende

###########################################
# CONFIGURATION
WIDTH = 768
HEIGHT = 576
FRAMERATE = 24
HTTP_PORT = 8082
WS_PORT = 8084
COLOR = u'#444'
BGCOLOR = u'#333'
JSMPEG_MAGIC = b'jsmp'
JSMPEG_HEADER = Struct('>4sHH')
VFLIP = False
HFLIP = False

###########################################
########################mein Code Anfang##################
def writeNumber(value):
bus.write_byte(address, int(value))
return -1

app = bottle.Bottle()

@app.post('/zurueck') #*******************************zurueck*********** ************
def switch_gpio_zurueck():
action = bottle.request.forms.get('action')
if action == 'on':
print('GPIO an')
writeNumber(1)
#GPIO.output(14, GPIO.HIGH)
return {'gpio state': 'on'}
elif action == 'off':
print('GPIO aus')
writeNumber(9)
#GPIO.output(14, GPIO.LOW)
return {'gpio state': 'off'}

########################mein Code Ende####################

class StreamingHttpHandler(BaseHTTPRequestHandler):
def do_HEAD(self):
self.do_GET()

def do_GET(self):
if self.path == '/':
self.send_response(301)
self.send_header('Location', '/index.html')
self.end_headers()
return
elif self.path == '/jsmpg.js':
content_type = 'application/javascript'
content = self.server.jsmpg_content
elif self.path == '/index.html':
content_type = 'text/html; charset=utf-8'
tpl = Template(self.server.index_template)
content = tpl.safe_substitute(dict(
WS_PORT=WS_PORT, WIDTH=WIDTH, HEIGHT=HEIGHT, COLOR=COLOR,
BGCOLOR=BGCOLOR))
else:
self.send_error(404, 'File not found')
return
content = content.encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', content_type)
self.send_header('Content-Length', len(content))
self.send_header('Last-Modified', self.date_time_string(time()))
self.end_headers()
if self.command == 'GET':
self.wfile.write(content)


class StreamingHttpServer(HTTPServer):
def __init__(self):
super(StreamingHttpServer, self).__init__(
('', HTTP_PORT), StreamingHttpHandler)
with io.open('index.html', 'r') as f:
self.index_template = f.read()
with io.open('jsmpg.js', 'r') as f:
self.jsmpg_content = f.read()


class StreamingWebSocket(WebSocket):
def opened(self):
self.send(JSMPEG_HEADER.pack(JSMPEG_MAGIC, WIDTH, HEIGHT), binary=True)


class BroadcastOutput(object):
def __init__(self, camera):
print('Spawning background conversion process')
self.converter = Popen([
'ffmpeg',
'-f', 'rawvideo',
'-pix_fmt', 'yuv420p',
'-s', '%dx%d' % camera.resolution,
'-r', str(float(camera.framerate)),
'-i', '-',
'-f', 'mpeg1video',
'-b', '800k',
'-r', str(float(camera.framerate)),
'-'],
stdin=PIPE, stdout=PIPE, stderr=io.open(os.devnull, 'wb'),
shell=False, close_fds=True)

def write(self, b):
self.converter.stdin.write(b)

def flush(self):
print('Waiting for background conversion process to exit')
self.converter.stdin.close()
self.converter.wait()


class BroadcastThread(Thread):
def __init__(self, converter, websocket_server):
super(BroadcastThread, self).__init__()
self.converter = converter
self.websocket_server = websocket_server

def run(self):
try:
while True:
buf = self.converter.stdout.read1(32768)
if buf:
self.websocket_server.manager.broadcast(buf, binary=True)
elif self.converter.poll() is not None:
break
finally:
self.converter.stdout.close()

def main():
print('Initializing camera')
with picamera.PiCamera() as camera:
camera.resolution = (WIDTH, HEIGHT)
camera.framerate = FRAMERATE
camera.vflip = VFLIP # flips image rightside up, as needed
camera.hflip = HFLIP # flips image left-right, as needed
sleep(1) # camera warm-up time
print('Initializing websockets server on port %d' % WS_PORT)
WebSocketWSGIHandler.http_version = '1.1'
websocket_server = make_server(
'', WS_PORT,
server_class=WSGIServer,
handler_class=WebSocketWSGIRequestHandler,
app=WebSocketWSGIApplication(handler_cls=Streaming WebSocket))
websocket_server.initialize_websockets_manager()
websocket_thread = Thread(target=websocket_server.serve_forever)
print('Initializing HTTP server on port %d' % HTTP_PORT)
http_server = StreamingHttpServer()
http_thread = Thread(target=http_server.serve_forever)
print('Initializing broadcast thread')
output = BroadcastOutput(camera)
broadcast_thread = BroadcastThread(output.converter, websocket_server)
print('Starting recording')
camera.start_recording(output, 'yuv')
try:
print('Starting websockets thread')
websocket_thread.start()
print('Starting HTTP server thread')
http_thread.start()
print('Starting broadcast thread')
broadcast_thread.start()
while True:
camera.wait_recording(1)
except KeyboardInterrupt:
pass
finally:
print('Stopping recording')
camera.stop_recording()
print('Waiting for broadcast thread to finish')
broadcast_thread.join()
print('Shutting down HTTP server')
http_server.shutdown()
print('Shutting down websockets server')
websocket_server.shutdown()
print('Waiting for HTTP server thread to finish')
http_thread.join()
print('Waiting for websockets thread to finish')
websocket_thread.join()





if __name__ == '__main__':
main()


Hier noch die index.html


<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=${WIDTH}, initial-scale=1"/>
<title>jsmpeg streaming</title>
<style type="text/css">
body {
background: ${BGCOLOR};
text-align: center;
margin-top: 10%;
}
#videoCanvas {
/* Always stretch the canvas to 640x480, regardless of its
internal size. */
width: ${WIDTH}px;
height: ${HEIGHT}px;
}
</style>

</head>
<body>
<!-- The Canvas size specified here is the "initial" internal resolution. jsmpeg will
change this internal resolution to whatever the source provides. The size the
canvas is displayed on the website is dictated by the CSS style.
-->

<!-- Code von mir -->
<table>
<tr>
<td><td align="center"><button id="vor">Vorwärts</button></td></td>
</tr>
<tr>
<td align="center"><button id="links">Links</button></td><td></td><td align="center"><button id="rechts">Rechts</button></td>
</tr>
<tr>
<td><td align="center"><button id="zurueck">Zurück</button></td></td>
</tr>
</table>
<!-- Code ende -->


<canvas id="videoCanvas" width="${WIDTH}" height="${HEIGHT}">
<p>
Please use a browser that supports the Canvas Element, like
<a href="http://www.google.com/chrome">Chrome</a>,
<a href="http://www.mozilla.com/firefox/">Firefox</a>,
<a href="http://www.apple.com/safari/">Safari</a> or Internet Explorer 10
</p>
</canvas>

<script>
var elem = document.getElementById('zurueck');
elem.addEventListener('mousedown', mouseDown_zurueck);
elem.addEventListener('mouseup', mouseUp_zurueck);

function mouseDown_zurueck() {
let formData = new FormData();
formData.append('action', 'on');
fetch('/zurueck', {
method: 'POST',
body: formData
})
};
function mouseUp_zurueck() {
let formData = new FormData();
formData.append('action', 'off');
fetch('/zurueck', {
method: 'POST',
body: formData
})
};
</script>


<script type="text/javascript" src="jsmpg.js"></script>
<script type="text/javascript">
// Show loading notice
var canvas = document.getElementById('videoCanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = '${COLOR}';
ctx.fillText('Loading...', canvas.width/2-30, canvas.height/3);
// Setup the WebSocket connection and start the player
var client = new WebSocket('ws://' + window.location.hostname + ':${WS_PORT}/');
var player = new jsmpeg(client, {canvas:canvas});


</script>
</body>
</html>


Die Webseite sieht so weit gut aus... Ich bekomme also keine Fehlermeldungen angezeigt.

Hier jetzt der einzelne Code für das Live Bild. Dies ist auch hier zu finden (https://github.com/waveform80/pistreaminghttp://)


#!/usr/bin/env python

import sys
import io
import os
import shutil
from subprocess import Popen, PIPE
from string import Template
from struct import Struct
from threading import Thread
from time import sleep, time
from http.server import HTTPServer, BaseHTTPRequestHandler
from wsgiref.simple_server import make_server

import picamera
from ws4py.websocket import WebSocket
from ws4py.server.wsgirefserver import (
WSGIServer,
WebSocketWSGIHandler,
WebSocketWSGIRequestHandler,
)
from ws4py.server.wsgiutils import WebSocketWSGIApplication

#mein Code Anfang
import bottle
#mein Code Ende

###########################################
# CONFIGURATION
WIDTH = 768
HEIGHT = 576
FRAMERATE = 24
HTTP_PORT = 8082
WS_PORT = 8084
COLOR = u'#444'
BGCOLOR = u'#333'
JSMPEG_MAGIC = b'jsmp'
JSMPEG_HEADER = Struct('>4sHH')
VFLIP = False
HFLIP = False

###########################################



class StreamingHttpHandler(BaseHTTPRequestHandler):
def do_HEAD(self):
self.do_GET()

def do_GET(self):
if self.path == '/':
self.send_response(301)
self.send_header('Location', '/index.html')
self.end_headers()
return
elif self.path == '/jsmpg.js':
content_type = 'application/javascript'
content = self.server.jsmpg_content
elif self.path == '/index.html':
content_type = 'text/html; charset=utf-8'
tpl = Template(self.server.index_template)
content = tpl.safe_substitute(dict(
WS_PORT=WS_PORT, WIDTH=WIDTH, HEIGHT=HEIGHT, COLOR=COLOR,
BGCOLOR=BGCOLOR))
else:
self.send_error(404, 'File not found')
return
content = content.encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', content_type)
self.send_header('Content-Length', len(content))
self.send_header('Last-Modified', self.date_time_string(time()))
self.end_headers()
if self.command == 'GET':
self.wfile.write(content)


class StreamingHttpServer(HTTPServer):
def __init__(self):
super(StreamingHttpServer, self).__init__(
('', HTTP_PORT), StreamingHttpHandler)
with io.open('index.html', 'r') as f:
self.index_template = f.read()
with io.open('jsmpg.js', 'r') as f:
self.jsmpg_content = f.read()


class StreamingWebSocket(WebSocket):
def opened(self):
self.send(JSMPEG_HEADER.pack(JSMPEG_MAGIC, WIDTH, HEIGHT), binary=True)


class BroadcastOutput(object):
def __init__(self, camera):
print('Spawning background conversion process')
self.converter = Popen([
'ffmpeg',
'-f', 'rawvideo',
'-pix_fmt', 'yuv420p',
'-s', '%dx%d' % camera.resolution,
'-r', str(float(camera.framerate)),
'-i', '-',
'-f', 'mpeg1video',
'-b', '800k',
'-r', str(float(camera.framerate)),
'-'],
stdin=PIPE, stdout=PIPE, stderr=io.open(os.devnull, 'wb'),
shell=False, close_fds=True)

def write(self, b):
self.converter.stdin.write(b)

def flush(self):
print('Waiting for background conversion process to exit')
self.converter.stdin.close()
self.converter.wait()


class BroadcastThread(Thread):
def __init__(self, converter, websocket_server):
super(BroadcastThread, self).__init__()
self.converter = converter
self.websocket_server = websocket_server

def run(self):
try:
while True:
buf = self.converter.stdout.read1(32768)
if buf:
self.websocket_server.manager.broadcast(buf, binary=True)
elif self.converter.poll() is not None:
break
finally:
self.converter.stdout.close()


def main():
print('Initializing camera')
with picamera.PiCamera() as camera:
camera.resolution = (WIDTH, HEIGHT)
camera.framerate = FRAMERATE
camera.vflip = VFLIP # flips image rightside up, as needed
camera.hflip = HFLIP # flips image left-right, as needed
sleep(1) # camera warm-up time
print('Initializing websockets server on port %d' % WS_PORT)
WebSocketWSGIHandler.http_version = '1.1'
websocket_server = make_server(
'', WS_PORT,
server_class=WSGIServer,
handler_class=WebSocketWSGIRequestHandler,
app=WebSocketWSGIApplication(handler_cls=Streaming WebSocket))
websocket_server.initialize_websockets_manager()
websocket_thread = Thread(target=websocket_server.serve_forever)
print('Initializing HTTP server on port %d' % HTTP_PORT)
http_server = StreamingHttpServer()
http_thread = Thread(target=http_server.serve_forever)
print('Initializing broadcast thread')
output = BroadcastOutput(camera)
broadcast_thread = BroadcastThread(output.converter, websocket_server)
print('Starting recording')
camera.start_recording(output, 'yuv')
try:
print('Starting websockets thread')
websocket_thread.start()
print('Starting HTTP server thread')
http_thread.start()
print('Starting broadcast thread')
broadcast_thread.start()
while True:
camera.wait_recording(1)
except KeyboardInterrupt:
pass
finally:
print('Stopping recording')
camera.stop_recording()
print('Waiting for broadcast thread to finish')
broadcast_thread.join()
print('Shutting down HTTP server')
http_server.shutdown()
print('Shutting down websockets server')
websocket_server.shutdown()
print('Waiting for HTTP server thread to finish')
http_thread.join()
print('Waiting for websockets thread to finish')
websocket_thread.join()
if __name__ == '__main__':
main()



und die entsprechende html Datei

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=${WIDTH}, initial-scale=1"/>
<title>jsmpeg streaming</title>
<style type="text/css">
body {
background: ${BGCOLOR};
text-align: center;
margin-top: 10%;
}
#videoCanvas {
/* Always stretch the canvas to 640x480, regardless of its
internal size. */
width: ${WIDTH}px;
height: ${HEIGHT}px;
}
</style>
</head>
<body>
<!-- The Canvas size specified here is the "initial" internal resolution. jsmpeg will
change this internal resolution to whatever the source provides. The size the
canvas is displayed on the website is dictated by the CSS style.
-->
<canvas id="videoCanvas" width="${WIDTH}" height="${HEIGHT}">
<p>
Please use a browser that supports the Canvas Element, like
<a href="http://www.google.com/chrome">Chrome</a>,
<a href="http://www.mozilla.com/firefox/">Firefox</a>,
<a href="http://www.apple.com/safari/">Safari</a> or Internet Explorer 10
</p>
</canvas>
<script type="text/javascript" src="jsmpg.js"></script>
<script type="text/javascript">
// Show loading notice
var canvas = document.getElementById('videoCanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = '${COLOR}';
ctx.fillText('Loading...', canvas.width/2-30, canvas.height/3);
// Setup the WebSocket connection and start the player
var client = new WebSocket('ws://' + window.location.hostname + ':${WS_PORT}/');
var player = new jsmpeg(client, {canvas:canvas});
</script>
</body>
</html>


Die original Steuerung sieht wie folgt aus und ist hier zu finden (https://forum-raspberrypi.de/forum/thread/40485-gpio-websteuerung/)



import RPi.GPIO as GPIO
import time
import bottle

import smbus
bus = smbus.SMBus(1)
address = 0x05

#GPIO.setmode(GPIO.BCM)
#GPIO.setup(14, GPIO.OUT)

def writeNumber(value):
bus.write_byte(address, int(value))
return -1

app = bottle.Bottle()
@app.route('/')
def index():
return bottle.template('index.html')
@app.post('/zurueck') #*******************************zurueck*********** ************
def switch_gpio_zurueck():
action = bottle.request.forms.get('action')
if action == 'on':
print('GPIO an')
writeNumber(1)
#GPIO.output(14, GPIO.HIGH)
return {'gpio state': 'on'}
elif action == 'off':
print('GPIO aus')
writeNumber(9)
#GPIO.output(14, GPIO.LOW)
return {'gpio state': 'off'}

@app.post('/rechts') #*******************************rechts************ ***********
def switch_gpio_rechts():
action = bottle.request.forms.get('action')
if action == 'on':
print('GPIO an')
writeNumber(1)
#GPIO.output(14, GPIO.HIGH)
return {'gpio state': 'on'}
elif action == 'off':
print('GPIO aus')
writeNumber(9)
#GPIO.output(14, GPIO.LOW)
return {'gpio state': 'off'}

@app.post('/links') #*******************************links************* **********
def switch_gpio_links():
action = bottle.request.forms.get('action')
if action == 'on':
print('GPIO an')
writeNumber(1)
#GPIO.output(14, GPIO.HIGH)
return {'gpio state': 'on'}
elif action == 'off':
print('GPIO aus')
writeNumber(5)
#GPIO.output(14, GPIO.LOW)
return {'gpio state': 'off'}

@app.post('/vorwaerts')#****************************vor******* ****************************
def switch_gpio_vor():
action = bottle.request.forms.get('action')
if action == 'on':
print('GPIO an')
writeNumber(1)
#GPIO.output(14, GPIO.HIGH)
return {'gpio state': 'on'}
elif action == 'off':
print('GPIO aus')
writeNumber(9)
#GPIO.output(14, GPIO.LOW)
return {'gpio state': 'off'}

if __name__ == '__main__':
bottle.run(app, host='192.168.178.28', port=8080, reloader=True, debug=True)


und auch hier die Index.html


<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJAX minimalistisch</title>
</head>
<body>
<table>
<tr>
<td><td align="center"><button id="vor">Vorwärts</button></td></td>
</tr>
<tr>
<td align="center"><button id="links">Links</button></td><td></td><td align="center"><button id="rechts">Rechts</button></td>
</tr>
<tr>
<td><td align="center"><button id="zurueck">Zurück</button></td></td>
</tr>
</table>
</body>
<script>
//****************zurueck***************************
var elem = document.getElementById('zurueck');
elem.addEventListener('mousedown', mouseDown_zurueck);
elem.addEventListener('mouseup', mouseUp_zurueck);

function mouseDown_zurueck() {
let formData = new FormData();
formData.append('action', 'on');
fetch('/zurueck', {
method: 'POST',
body: formData
})
};
function mouseUp_zurueck() {
let formData = new FormData();
formData.append('action', 'off');
fetch('/zurueck', {
method: 'POST',
body: formData
})
};

//****************rechts***************************
var elem = document.getElementById('rechts');
elem.addEventListener('mousedown', mouseDown_rechts);
elem.addEventListener('mouseup', mouseUp_rechts);

function mouseDown_rechts() {
let formData = new FormData();
formData.append('action', 'on');
fetch('/rechts', {
method: 'POST',
body: formData
})
};
function mouseUp_rechts() {
let formData = new FormData();
formData.append('action', 'off');
fetch('/rechts', {
method: 'POST',
body: formData
})
};

//****************links***************************
var elem = document.getElementById('links');
elem.addEventListener('mousedown', mouseDown_links);
elem.addEventListener('mouseup', mouseUp_links);

function mouseDown_links() {
let formData = new FormData();
formData.append('action', 'on');
fetch('/links', {
method: 'POST',
body: formData
})
};
function mouseUp_links() {
let formData = new FormData();
formData.append('action', 'off');
fetch('/links', {
method: 'POST',
body: formData
})
};


//****************vor******************************
var elem = document.getElementById('vor');
elem.addEventListener('mousedown', mouseDown_vor);
elem.addEventListener('mouseup', mouseUp_vor);

function mouseDown_vor() {
let formData = new FormData();
formData.append('action', 'on');
fetch('/vorwaerts', {
method: 'POST',
body: formData
})
};
function mouseUp_vor() {
let formData = new FormData();
formData.append('action', 'off');
fetch('/vorwaerts', {
method: 'POST',
body: formData
})
};
</script>
</html>



Ich bin für jeden Tipp echt dankbar.

Viele Grüße
Torsten