Mit Hilfe von ArduRPC lassen sich Befehle an einen Arduino oder kompatiblen Mikrocontroller senden. In Python lässt sich in wenigen Schritten ein Rest-Schnittstelle programmieren.
Das in diesem Beitrag gezeigte Beispiel ist sehr minimalistisch gehalten und soll in erster Linie als Anregung für eigene Entwicklungen dienen.
Der Webserver wird mit Hilfe des in Python geschriebene Micro-Frameworks Flask umgesetzt. Zusätzlich kommt das im Rahmen des ArduRPC Projekts bereitgestellte Python Modul ArduRPC zum Einsatz. Da der Arduino über eine serielle Verbindung angesprochen werden soll, wird zusätzlich noch pySerial benötigt. Diese Pakete müssen zunächst installiert werden. Das folgende Beispiel zeigt wie dies umgesetzt werden kann.
$ pip install flask
Collecting flask
Downloading Flask-0.10.1.tar.gz (544kB)
100% |████████████████████████████████| 544kB 508kB/s
Collecting Werkzeug>=0.7 (from flask)
Downloading Werkzeug-0.10.4-py2.py3-none-any.whl (293kB)
100% |████████████████████████████████| 294kB 981kB/s
Collecting Jinja2>=2.4 (from flask)
Downloading Jinja2-2.7.3.tar.gz (378kB)
100% |████████████████████████████████| 380kB 1.1MB/s
Collecting itsdangerous>=0.21 (from flask)
Downloading itsdangerous-0.24.tar.gz (46kB)
100% |████████████████████████████████| 49kB 2.8MB/s
Collecting markupsafe (from Jinja2>=2.4->flask)
Downloading MarkupSafe-0.23.tar.gz
Installing collected packages: Werkzeug, markupsafe, Jinja2, itsdangerous, flask
Running setup.py install for markupsafe
Running setup.py install for Jinja2
Running setup.py install for itsdangerous
Running setup.py install for flask
Successfully installed Jinja2-2.7.3 Werkzeug-0.10.4 flask-0.10.1 itsdangerous-0.24 markupsafe-0.23
$ pip install ardurpc
Collecting ardurpc
Downloading ardurpc-0.3.tar.gz
Installing collected packages: ardurpc
Running setup.py install for ardurpc
Successfully installed ardurpc-0.3
$ pip install pyserial
Collecting pyserial
Using cached pyserial-2.7.tar.gz
Installing collected packages: pyserial
Running setup.py install for pyserial
Successfully installed pyserial-2.7
Im folgenden Beispiel ist die eigentliche Umsetzung des Webservers zu sehen, welcher auch über server.py heruntergeladen werden kann.
#!/usr/bin/env python
import argparse
import json
from flask import Flask
from flask import request
from ardurpc import ArduRPC
from ardurpc.connector.serial_con import Serial
app = Flask(__name__)
con = None
rpc = None
@app.route("/<handler>/<command>", methods=["POST", "GET"])
def do(handler, command):
# Try to find the handle with the given name
h = rpc.get_handler_by_name(handler)
if h is None:
return "Unable to find handler '%s'" % handler
# Check for internal commands
if command.startswith("_") or command.endswith("_"):
return "Command might be an internal Python command"
# Parse data
data = []
if request.method == "POST":
tmp = request.get_data()
try:
data = json.loads(tmp.decode("utf-8"))
except ValueError as e:
return "Unable to parse json data: '%s'" % str(e)
elif request.method == "GET":
data = []
# Get command function from handler object
try:
func = getattr(h, command)
except AttributeError:
func = None
if func is None:
return "Unable to find command '%s'" % command
# Call function and ...
try:
result = func(*data)
except TypeError as e:
return "Unable to call function: '%s'" % str(e)
# ... return result
try:
return json.dumps({"result": result})
except TypeError as e:
return "Unable to serialize result"
def main():
global con, rpc
parser = argparse.ArgumentParser(description="ArduRPC HTTP Rest API")
parser.add_argument(
"-b",
"--baud",
default=9600,
dest="baud",
help="Baud",
metavar="N",
type=int,
)
parser.add_argument(
"-D",
"--device",
default="/dev/ttyUSB0",
dest="device",
help="Serial Device",
type=str,
)
parser.add_argument(
"--debug",
action="store_true",
default=False,
dest="debug",
help="Enable debug mode",
)
# Parse commandline arguments
args = parser.parse_args()
# Connect to Arduino and initialize ArduRPC interface
con = Serial(args.device, args.baud)
rpc = ArduRPC(connector=con)
# Start HTTP Server
app.run(debug=args.debug)
if __name__ == "__main__":
main()
In der Funktion main()
werden übergebene Kommandozeilenparameter ausgewertet, eine Verbindung zum Arduino aufgebaut und die Webanwendung gestartet. Die Funktion do()
ist für die Verarbeitung der Anfragen notwendig. Sie nimmt die Anfragen entgegen, wertet eventuell per Post-Methode übergebene Parameter aus, ermittelt die für den angegeben Befehl benötigte Funktion, führt den Befehl aus und gibt das Ergebnis zurück.
Der Webserver kann mit dem folgenden Befehl gestartet werden.
$ python server.py
Mit Hilfe der Tastenkombination Strg. + C kann der Server wieder beendet werden.
Je nach verwendetem Arduino müssen eventuell die Angabe für den seriellen Port oder die Baudrate angepasst werden. Welche Optionen zur Verfügung stehen kann wie folgt in Erfahrung gebracht werden.
$ python server.py --help
usage: server.py [-h] [-b--baud N] [-D--device DEVICE] [--debug]
ArduRPC HTTP Rest API
optional arguments:
-h, --help show this help message and exit
-b--baud N Baud
-D--device DEVICE Serial Device
--debug Enable debug mode
Anschließend kann der Arduino zum Beispiel per curl
gesteuert werden.
Die Temperatur eines angeschlossenen Sensors lässt sich zum Beispiel wie folgt abfragen.
$ curl http://localhost:5000/sensor/getTemperature
{"result": 20.0}
Ist zum Beispiel eine LED-Matrix angeschlossen lässt sich mit dem folgenden Befehl ein rote Linie zeichnen.
$ curl -X POST -d '[0,0,0,4,[255,0,0]]' http://localhost:5000/matrix/drawLine
{"result": 0}