Seite 1 von 1
Flask Request.data
Verfasst: Dienstag 11. September 2018, 18:07
von Hypec
Hallo,
ich versuche von einem Arduino über http an meinen Flaskserver 5 Daten Stündlich zu schicken. Jetzt meine Frage wie kann ich die Daten am besten empfangen und in 5 Variabeln schreiben um sie dann auf dem Server zu nützen?
Beispiel Inhalt der 5 Daten:
Code: Alles auswählen
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
if request.method == 'POST':
data = request.data
return data
return render_template('getdata.html')
Re: Flask Request.data
Verfasst: Dienstag 11. September 2018, 18:21
von __blackjack__
@Hypec: Für den Arduino am einfachsten dürfte es sein wenn die POST-Anfrage als Content-Type 'text/plain' verwendet und du die Daten wie gezeigt durch Zeilenenden oder Leerzeichen getrennt als Text schickst. Das lässt sich in der Webanwendung dann ja auch einfach wieder mit `split()` und `float()` (ggf. auch `int()`) in 5 Werte zerlegen mit denen man dann weiter arbeiten kann.
Re: Flask Request.data
Verfasst: Sonntag 16. September 2018, 18:32
von Hypec
Was mache ich hier falsch, dass der String nicht in bytes umgewandelt wird?
Code: Alles auswählen
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
global luftfeuchtigkeitdrin
global temperaturdrin
global luftfeuchtigkeitausen
global temperaturausen
global erdfeuchtigkeit
global lux
if request.method == 'POST':
data = request.data
bdata = bytes(data)
bdata.split(',')
a,b,c,d,e,f = bdata.split(',')
luftfeuchtigkeitdrin = a
temperaturdrin = b
luftfeuchtigkeitausen = c
temperaturausen = d
erdfeuchtigkeit = e
lux = f
write_data()
return data
return render_template('getdata.html')
Code: Alles auswählen
2018-09-16T17:28:05.929988+00:00 app[web.1]: File "/app/app.py", line 47, in getdata
2018-09-16T17:28:05.929990+00:00 app[web.1]: bdata = bytes(data)
2018-09-16T17:28:05.935929+00:00 app[web.1]: TypeError: 'module' object is not callable
Re: Flask Request.data
Verfasst: Sonntag 16. September 2018, 18:41
von __blackjack__
Das einzige was in der Zeile aufgerufen wird ist `bytes`, und laut Fehlermeldung ist das ein Modul. Also wo bindest Du den Namen an ein Modul?
Die einbuchstabigen Namen sind sehr unschön und auch völlig unnötig. Du kannst die Werte nach dem `split()` auch gleich den richtigen Namen zuweisen. Dann aber bitte lokalen Namen und keinen globalen. Das ist nicht nur unschön, sondern kann Dir bei Webanwendungen auch Fehler verursachen, denn man darf nicht davon ausgehen das es nur einen Thread gibt, der da gleichzeitig läuft. Im Zusammenhang damit sieht der `write_data()`-Aufruf so völlig Argumente suspekt aus. Was soll der denn schreiben wenn er nichts übergeben bekommt? Alles was eine Funktion ausser Konstanten benötigt, sollte die Funktion als Argument(e) übergeben bekommen.
Re: Flask Request.data
Verfasst: Sonntag 16. September 2018, 18:53
von Hypec
Ich hab das ganze als Globale Variabeln gespeichert um sie hier in write_data() weiter verwenden zu können.
Code: Alles auswählen
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
global luftfeuchtigkeitdrin
global temperaturdrin
global luftfeuchtigkeitausen
global temperaturausen
global erdfeuchtigkeit
global lux
if request.method == 'POST':
data = request.data
bdata = bytes(data)
bdata.split(',')
a,b,c,d,e,f = bdata.split(',')
luftfeuchtigkeitdrin = a
temperaturdrin = b
luftfeuchtigkeitausen = c
temperaturausen = d
erdfeuchtigkeit = e
lux = f
write_data()
return data
return render_template('getdata.html')
@app.route('/writedata')
def write_data():
my_date = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
fmt = '%Y-%m-%d'
tmt = '%H:%M'
with open('data/data.csv', 'a', newline='') as csvfile:
spamwriter = csv.writer(csvfile, delimiter=' ')
spamwriter.writerow([my_date.strftime(fmt), my_date.strftime(tmt), luftfeuchtigkeitdrin, temperaturdrin, luftfeuchtigkeitausen, temperaturausen, erdfeuchtigkeit, lux])
Re: Flask Request.data
Verfasst: Sonntag 16. September 2018, 19:14
von Hypec
Also ich habe das ganze jetzt so umgeschrieben, allerdings wird damit mein problem das split nur bytes will und ich es nicht hinbekomme den str richtig in bytes zu formatieren leider immer noch nicht gelöst.
Code: Alles auswählen
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
if request.method == 'POST':
data = request.data
bdata = bytes(data)
bdata.split(',')
luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux = bdata.split(',')
write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux)
return data
return render_template('getdata.html')
@app.route('/writedata')
def write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux):
my_date = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
fmt = '%Y-%m-%d'
tmt = '%H:%M'
with open('data/data.csv', 'a', newline='') as csvfile:
spamwriter = csv.writer(csvfile, delimiter=' ')
spamwriter.writerow([my_date.strftime(fmt), my_date.strftime(tmt), luftfeuchtigkeitdrin, temperaturdrin, luftfeuchtigkeitausen, temperaturausen, erdfeuchtigkeit, lux])
Code: Alles auswählen
2018-09-16T18:13:25.771042+00:00 app[web.1]: File "/app/app.py", line 42, in getdata
2018-09-16T18:13:25.771044+00:00 app[web.1]: bdata.split(',')
2018-09-16T18:13:25.771056+00:00 app[web.1]: TypeError: a bytes-like object is required, not 'str'
Re: Flask Request.data
Verfasst: Sonntag 16. September 2018, 22:23
von __blackjack__
@Hypec: Was hat denn `data` für einen Typ? Entweder das ist schon `str`, dann verstehe ich nicht warum Du es in Bytes umwandelst. Oder es ist schon `bytes`, dann macht der `bytes()`-Aufruf so gar keinen Sinn, denn dann hätte er ja keinen Effekt. Das Problem *jetzt* ist jedenfalls das `bdate` vom Typ `bytes` ist und Du versuchst das an einem Zeichenkettenkomma zu trennen. Das geht nicht, denn `bytes` und `str` passen so nicht zusammen. Entweder ruft man `split()` auf einem `bytes`-Objekt mit einem Argument auf das auch vom Typ `bytes` ist, oder man ruft `split()` auf einer Zeichenkette mit einer Zeichenkette als Argument auf. Mischen geht nicht.
Da es sich bei den Daten um Text handelt und nicht um Binärdaten, wäre es sinnvoll das ganze als Zeichenketten zu verarbeiten. Spätestens der Writer für die CSV-Datei will Zeichenketten haben und keine Bytes.
Re: Flask Request.data
Verfasst: Montag 17. September 2018, 06:00
von Hypec
Also data ist ein string allerdings wenn ich es als string lasse kommt die Fehlermeldung (genau kann ich es erst wieder heute nachmittag sagen schreibe gerade vom Handy): bytes-like Objekt erwartet, str bekommen. So vom Inhalt her kommt dann die Fehlermeldung was ich nicht verstehe da ich ein test Script habe, wo ich die d
Daten zwar nicht empfange sie aber trotzdem im gleichen Format als variabel habe und das funktioniert problemlos.
Re: Flask Request.data
Verfasst: Montag 17. September 2018, 08:19
von Sirius3
@Hypec: warum ist `write_data` eine Route? Das macht doch keinen Sinn. `/getdata` zum Schreiben von Daten zu benutzen ist auch verwirrend.
Mal liefert `/getdata` ein HTML-Dokument, mal die Daten, die man per Post sowieso geschickt hat. Zweiteres ist so oder so unsinnig.
Datum und Uhrzeit sollten nicht in zwei getrennten Spalten stehen. Später muß man sie dann wieder mühsam in eine zusammenfassen.
Wo bekommst Du denn einen Fehler, wenn Du data als String beläßt?
Re: Flask Request.data
Verfasst: Montag 17. September 2018, 14:17
von Hypec
Oke habe ich jetzt geändert /getdata gibt die Daten zurück an den Sender, einfach nur damit ich weiß ob es geklappt hat, und das HTML Dokument da die Url ja auch im Browser existiert und dammit, falls sie jemand aufrufen sollte, nichts dummes rauskommt wird das HTML Dokument ausgeliefert. /getdata schreibt ja keine Daten es empfängt sie nur splitet sie und gibt sie dann an write_data weiter das sie dort in die csv Datei geschrieben werden.
Datum und Uhrzeit hab ich getrennt da ich später über ein input date zusammen mit einem input time, die Start und End Zeit abfragen will und damit ich diese nicht zusammen fügen muss habe ich es getrennt. Allerdings habe ich es noch nicht hinbekommen 2 Zeiten abzufragen und alles was dazwischen in der csv datei steht in eine list zu schreiben um es dann in einem Plot anzuzeigen.
Ich hab jetzt diesen code hier und der Server an den die Daten gesendet werden gibt mir in der Konsole diese Fehlermeldung zurück.
Code: Alles auswählen
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
if request.method == 'POST':
data = request.data
data.split(',')
luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux = data.split(',')
write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux)
return data
return render_template('getdata.html')
def write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux):
my_date = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
fmt = '%Y-%m-%d'
tmt = '%H:%M'
with open('data/data.csv', 'a', newline='') as csvfile:
spamwriter = csv.writer(csvfile, delimiter=' ')
spamwriter.writerow([my_date.strftime(fmt), my_date.strftime(tmt), luftfeuchtigkeitdrin, temperaturdrin, luftfeuchtigkeitausen, temperaturausen, erdfeuchtigkeit, lux])
Code: Alles auswählen
2018-09-17T13:26:46.606494+00:00 app[web.1]: [2018-09-17 13:26:46,604] ERROR in app: Exception on /getdata [POST]
2018-09-17T13:26:46.606517+00:00 app[web.1]: Traceback (most recent call last):
2018-09-17T13:26:46.606519+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
2018-09-17T13:26:46.606520+00:00 app[web.1]: response = self.full_dispatch_request()
2018-09-17T13:26:46.606522+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
2018-09-17T13:26:46.606523+00:00 app[web.1]: rv = self.handle_user_exception(e)
2018-09-17T13:26:46.606525+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
2018-09-17T13:26:46.606526+00:00 app[web.1]: reraise(exc_type, exc_value, tb)
2018-09-17T13:26:46.606527+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
2018-09-17T13:26:46.606529+00:00 app[web.1]: raise value
2018-09-17T13:26:46.606530+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
2018-09-17T13:26:46.606532+00:00 app[web.1]: rv = self.dispatch_request()
2018-09-17T13:26:46.606533+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
2018-09-17T13:26:46.606535+00:00 app[web.1]: return self.view_functions[rule.endpoint](**req.view_args)
2018-09-17T13:26:46.606536+00:00 app[web.1]: File "/app/app.py", line 41, in getdata
2018-09-17T13:26:46.606538+00:00 app[web.1]: data.split(',')
2018-09-17T13:26:46.606547+00:00 app[web.1]: TypeError: a bytes-like object is required, not 'str'
2018-09-17T13:26:46.608183+00:00 app[web.1]: 10.124.6.113 - - [17/Sep/2018:13:26:46 +0000] "POST /getdata HTTP/1.1" 500 291 "-" "SIMCOM_MODULE"
2018-09-17T13:26:46.609117+00:00 heroku[router]: at=info method=POST path="/getdata" host=pythonv1.herokuapp.com request_id=e3d0190c-cf26-4b89-b356-244614ed416a fwd="109.42.0.104" dyno=web.1 connect=0ms service=25ms status=500 bytes=456 protocol=http
Re: Flask Request.data
Verfasst: Montag 17. September 2018, 15:48
von __blackjack__
@Hypec: Ich denke wir haben schon verstanden was `getdata()` macht, und genau deswegen ist die URL ja so verwirrend. Aus Sicht des Aufrufers ist das falsch, denn wenn man etwas mit `get*` aufruft, erwartet jeder das der Aufrufer damit auf etwas zugreifen kann, nicht das er damit Daten senden kann.
Die Erklärung mit der Zeit ist auch komisch. Datum und Zeitangabe zusammen beschreiben den Zeitpunkt. Wenn Du am Ende filtern oder suchen möchtest, musst Du die dann ja doch immer zusammenfügen. Und auch die Eingabe, denn letztlich wird man da ja `datetime`-Objekte für die Vergleiche nehmen, und das nicht per Hand in Einzelteilen vergleichen wollen.
Die Problembeschreibung für die Ausnahme bleibt die gleiche: bei ``a.split(b)`` müssen entweder `a` und `b` beide `str` oder beide `bytes` sein. Mischen geht nicht.
Code: Alles auswählen
In [17]: 'a,b'.split(',')
Out[17]: ['a', 'b']
In [18]: b'a,b'.split(b',')
Out[18]: [b'a', b'b']
In [19]: b'a,b'.split(',')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-19-484fae72ad9e> in <module>()
----> 1 b'a,b'.split(',')
TypeError: a bytes-like object is required, not 'str'
An der Stelle frage ich mich gerade ob `request.data` immer `bytes` sind, oder ob da der Sender einfach nicht sagt das es sich um Plaintext handelt was er da sendet.
Re: Flask Request.data
Verfasst: Montag 17. September 2018, 19:06
von Sirius3
Wie postest Du Daten an getdata? Was ist der Content-Type?
Re: Flask Request.data
Verfasst: Dienstag 18. September 2018, 17:12
von Hypec
Also den Contenten Type den hab ich bisher gar nicht definiert habe aber jetzt die letzten 2 Stunden mal rumprobiert hab aber ihn nicht so definiert bekommen das es als str gesendet wird.
Ich habe jetzt die Zeit zusammen gefasst und das mit dem als byte spliten gemacht hier in dem Code bekomme jetzt aber sowas hier zurück.
Code: Alles auswählen
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
if request.method == 'POST':
data = request.data
#data.split(b',')
luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux = data.split(b',')
write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux)
return data
return render_template('getdata.html')
def write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux):
my_date = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
fmt = '%Y-%m-%d %H:%M'
with open('data/data.csv', 'a', newline='') as csvfile:
spamwriter = csv.writer(csvfile, delimiter=' ')
spamwriter.writerow([my_date.strftime(fmt), ',',luftfeuchtigkeitdrin, ',',temperaturdrin, ',',luftfeuchtigkeitausen, ',',temperaturausen, ',',erdfeuchtigkeit, ',',lux])
Bekomme ich:
Code: Alles auswählen
"2018-09-18 18:04" , b'71.60' , b'24.60' , b'69.80' , b'28.40' , b'978' , b'2456.96\n'
Gewünscht:
Re: Flask Request.data
Verfasst: Dienstag 18. September 2018, 18:37
von __blackjack__
@Hypec: Na dann musst Du halt die Daten die ankommen selbst in eine Zeichenkette umwandeln. Am besten vor dem `split()`, dann muss das nicht für jedes Element gemacht werden.
Bei dem `csv`-Writer das Leerzeichen als Trenner anzugeben und dann in die Daten manuell ein Komma zwischen jedes Element zu setzen ist, äh, eher nicht sinnvoll.
Re: Flask Request.data
Verfasst: Donnerstag 20. September 2018, 16:36
von Hypec
Danke das hab ich jetzt geschafft aber ich hab das problem das bei dem split ein "\n" eingebaut wird welches ich nicht mit replace weg bekomme, ich weiß das es bei dem Split mit eingebaut wird da es nicht nur in der Csv datei drin steht sondern auch bei dem return an den Absender mit dabei ist. Kann mir da jemand weiterhelfen?
Code: Alles auswählen
app = Flask(__name__)
@app.route('/getdata', methods=['GET', 'POST'])
def getdata():
if request.method == 'POST':
data = request.data
data = str(data)
data = data.replace("b'", "")
data = data.replace("'", "")
data = data.replace("\n", "")
luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux = data.split(',')
write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux)
return data
return render_template('getdata.html')
def write_data(luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux):
my_date = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
fmt = '%Y-%m-%d %H:%M'
with open('data/data.csv', 'a') as csvfile:
spamwriter = csv.writer(csvfile, delimiter=',')
spamwriter.writerow([my_date.strftime(fmt),luftfeuchtigkeitdrin,temperaturdrin,luftfeuchtigkeitausen,temperaturausen,erdfeuchtigkeit,lux])
Re: Flask Request.data
Verfasst: Donnerstag 20. September 2018, 16:49
von __blackjack__
@Hypec: Argh, das ist eklig und kaputt. Bitte nicht auf der Zeichenkettenrepräsentation eines `bytes`-Objekt rumwerkeln, sondern die Bytes ordentlich in eine Zeichenkette dekodieren. Dann musst Du da auch nichts entfernen was eigentlich gar nicht dazu gehört. Aus Bytes die Text enthalten eine Zeichenkette zu machen, nennt sich auch dekodieren und da gibt es eine Methode für.
Das '\\n' (also die *zwei* Zeichen (Backslash und kleines n), denn '\n' ist nur *ein* Zeichen (Zeilenendezeichen)) kommen auch nicht durch das `split()` sondern durch die falsche `str()`-Umwandlung.
Re: Flask Request.data
Verfasst: Donnerstag 20. September 2018, 17:01
von Hypec
Oke wie muss ich den str dann richtig umwandeln und kann auch den Rest sauberer lösen?
Re: Flask Request.data
Verfasst: Donnerstag 20. September 2018, 21:12
von Sirius3
@Hypec: ich verstehe nicht, warum Du nicht die offensichtlichsten Fehler korrigieren kannst. ›/getdata‹ ist nicht zum Hochladen von Daten da.
__blackjack__ hat Dir schon geschrieben, wie es gemacht werden muß (decode).
Re: Flask Request.data
Verfasst: Freitag 21. September 2018, 13:36
von Hypec
Kann ich machen aber da außer mir niemand an dem Server arbeitet oder Daten hin senden soll, habe ich es für mich halt aus serversicht geschrieben aber ich ändere es auch gerne in senddata.