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)
Hier noch die index.htmlCode:#!/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=StreamingWebSocket)) 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()
Die Webseite sieht so weit gut aus... Ich bekomme also keine Fehlermeldungen angezeigt.HTML-Code:<!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>
Hier jetzt der einzelne Code für das Live Bild. Dies ist auch hier zu finden
und die entsprechende html DateiCode:#!/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=StreamingWebSocket)) 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()
Die original Steuerung sieht wie folgt aus und ist hier zu findenHTML-Code:<!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>
und auch hier die Index.htmlCode: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)
Ich bin für jeden Tipp echt dankbar.HTML-Code:<!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>
Viele Grüße
Torsten
Lesezeichen