Aus einem Script mit einem Webserver kommunizieren ...
Anmerkung am Rande: Statt da irgendwie selber Formate zu erfinden und zu parsen würde ich die Daten die da hin und her geschickt werden als JSON kodieren.
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
wow, vielen Dank erst einmal.
Ich werde mich jetzt damit beschäftigen und versuche das Ganze zu verstehen, danach werde ich dann versuchen die Daten in JSON-Container zu packen.
Danke, das hilft mir echt weiter
Ich werde mich jetzt damit beschäftigen und versuche das Ganze zu verstehen, danach werde ich dann versuchen die Daten in JSON-Container zu packen.
Danke, das hilft mir echt weiter

-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
so, habe deine Verbesserungen jetzt eingebaut und nebenbei noch 2-3 kleinere Fehler in meinem javascript/python-Code beseitigt.
Jetzt läuft es schon mal zum Teil.
Die Links vom html-Client lösen weiterhin die richtigen Kommandos auf der python-Console aus.
Allerdings werden die Werte bei Temperaturänderung nicht übertragen, mir scheint die werden in ne Warteliste gepackt und dann mitgeschickt wenn ich auf einen Link zum senden von Kommandos klicke.
Beispiel:
- ich starte beide Skripte, der html-Client verbindet sich mit dem python-Script
- jetzt findet eine Temperaturänderung (Nr1) statt, wird auch auf der python-Console ausgegeben, aber NICHT auf der clienseitigen javascript-Console
- 4-5 sec. nichts
- jetzt findet die nächste Temperaturänderung (Nr2) statt, wird auch wieder auf der python-Console ausgegeben, und wieder NICHT auf der clienseitigen javascript-Console
- so, jetzt klicke ich im html-Cleint den Link "TV schalten" an -> auf der python-Console erscheint das richtige Kommando UND in der javascript-Console erscheinen auf einmal die Einträge für Temperaturänderung Nr1 und Nr2
- wieder ne Weile nichts
- jetzt findet die nächste Temperaturänderung (Nr3) statt -> diese wird solange nicht gesendet bis ich im html-Client ein Kommando sende.
Ich hoffe man versteht was ich meine.
Jetzt läuft es schon mal zum Teil.
Die Links vom html-Client lösen weiterhin die richtigen Kommandos auf der python-Console aus.
Allerdings werden die Werte bei Temperaturänderung nicht übertragen, mir scheint die werden in ne Warteliste gepackt und dann mitgeschickt wenn ich auf einen Link zum senden von Kommandos klicke.
Beispiel:
- ich starte beide Skripte, der html-Client verbindet sich mit dem python-Script
- jetzt findet eine Temperaturänderung (Nr1) statt, wird auch auf der python-Console ausgegeben, aber NICHT auf der clienseitigen javascript-Console
- 4-5 sec. nichts
- jetzt findet die nächste Temperaturänderung (Nr2) statt, wird auch wieder auf der python-Console ausgegeben, und wieder NICHT auf der clienseitigen javascript-Console
- so, jetzt klicke ich im html-Cleint den Link "TV schalten" an -> auf der python-Console erscheint das richtige Kommando UND in der javascript-Console erscheinen auf einmal die Einträge für Temperaturänderung Nr1 und Nr2
- wieder ne Weile nichts
- jetzt findet die nächste Temperaturänderung (Nr3) statt -> diese wird solange nicht gesendet bis ich im html-Client ein Kommando sende.
Ich hoffe man versteht was ich meine.
@der_Mausbiber: das hängt damit zusammen, dass Dein tinkerforge nichts von asyncio weiß.
Macht die ganze Sache etwas komplizierter:
Macht die ganze Sache etwas komplizierter:
Code: Alles auswählen
def change_temperature(temp):
# changed temperature in temp
new_temperature = temp / 100.0
print(new_temperature)
for consumer in temperature_consumers:
consumer(new_temperature)
@asyncio.coroutine
def temperature_loop(websocket):
loop = asyncio.get_event_loop()
temperature_changed = Queue()
def changed(temp):
loop.call_soon_threadsafe(temperature_changed.put_nowait, temp)
try:
temperature_consumers.append(changed)
while True:
temp = yield from temperature_changed.get()
yield from websocket.send('Temperatur: %f' % temp)
finally:
temperature_consumers.remove(temperature_changed)
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
juhu
Jetzt klappt es mit dem senden und aktualisieren der Werte.
Einzige Problem ist jetzt, das das Script abstürzt wenn ich den Browser schliesse (und damit die Verbindung).

Jetzt klappt es mit dem senden und aktualisieren der Werte.
Einzige Problem ist jetzt, das das Script abstürzt wenn ich den Browser schliesse (und damit die Verbindung).
Code: Alles auswählen
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\tasks.py", line 317, in _step
result = coro.throw(exc)
File "D:/GoogleDrive/workspace/masm/testing/raspi-server-testD.py", line 34, in temperature_loop
temperature_consumers.remove(temperature_changed)
ValueError: list.remove(x): x not in list
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
wenn ich den Code um "if websocket.open" erweitere
dann bekomme ich beim schließen des Browserfensters nur noch eine Fehlermeldung (anstatt wie vorher 2-3)
Code: Alles auswählen
@asyncio.coroutine
def temperature_loop(websocket):
loop = asyncio.get_event_loop()
temperature_changed = Queue()
def changed(temp):
loop.call_soon_threadsafe(temperature_changed.put_nowait, temp)
try:
temperature_consumers.append(changed)
while True:
temp = yield from temperature_changed.get()
yield from websocket.send('Temperature: %f' % temp)
finally:
if websocket.open:
temperature_consumers.remove(temperature_changed)
dann bekomme ich beim schließen des Browserfensters nur noch eine Fehlermeldung (anstatt wie vorher 2-3)
Code: Alles auswählen
Fatal write error on socket transport
protocol: <websockets.server.WebSocketServerProtocol object at 0x02D87A90>
transport: <asyncio.selector_events._SelectorSocketTransport object at 0x02D87E30>
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\selector_events.py", line 502, in write
n = self._sock.send(data)
ConnectionAbortedError: [WinError 10053] Eine bestehende Verbindung wurde softwaregesteuert
durch den Hostcomputer abgebrochen
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
Auf der Suche nach dem Fehler habe ich mal intensives logging betrieben und so gut wie jede Zeile auf der Console ausgegeben.
Vielleicht kann mir jemand mit diesen Angaben weiterhelfen:
Zum Ablauf:
- zuerst habe ich den Server gestartet
- dann mehrere Temperaturänderungen abgewartet
- danach habe ich mich mit dem Client verbunden
- eine Temperaturänderung abgewartet -> Anzeige auf dem Client ok
- danach den Browser geschlossen
- wieder ein paar Temperaturänderungen abgewartet
- danach habe ich den Browser wieder geöffnet und mich neuverbunden
- nächste Temperaturänderung abgewartet -> Anzeige im Client wieder ok
Ich hatte gehofft dem Fehler so selbst auf die Spur zu kommen, doch ehrlich gesagt verstehe ich fast nur Bahnhof.
Vielleicht kann mir jemand mit diesen Angaben weiterhelfen:
Code: Alles auswählen
2014-12-10 00:41:01 : System startet
2014-12-10 00:41:01 : Tinkerforge ... Bricklets installiert
2014-12-10 00:41:01 : Tinkerforge ... Verbindung hergestellt
2014-12-10 00:41:01 : Tinkerforge ... Callbacks konfiguriert
2014-12-10 00:41:01 : Tinkerforge ... Callbacks gestartet
2014-12-10 00:41:01 : Tinkerforge ... System online
2014-12-10 00:41:01 : websockets ... set up websockets-server
2014-12-10 00:41:01 : websockets ... System online
2014-12-10 00:41:01 : Tinkerforge ... Temperaturänderung -> 22.930000
2014-12-10 00:41:07 : Tinkerforge ... Temperaturänderung -> 22.870000
2014-12-10 00:41:12 : Tinkerforge ... Temperaturänderung -> 22.930000
2014-12-10 00:41:20 : Tinkerforge ... Temperaturänderung -> 22.870000
2014-12-10 00:41:23 : websockets ... asyncio.async
2014-12-10 00:41:23 : websockets ... asyncio.get_event_loop
2014-12-10 00:41:23 : websockets ... Queue
2014-12-10 00:41:23 : websockets ... temperature_consumers.append
2014-12-10 00:41:25 : Tinkerforge ... Temperaturänderung -> 22.930000
2014-12-10 00:41:25 : websockets ... call_soon_threadsafe
2014-12-10 00:41:25 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:41:25 : websockets ... yield from temperature_changed.get
2014-12-10 00:41:25 : websockets ... yield from websocket.send
Fatal write error on socket transport
protocol: <websockets.server.WebSocketServerProtocol object at 0x02E17AF0>
transport: <asyncio.selector_events._SelectorSocketTransport object at 0x022B6350>
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\selector_events.py", line 502, in write
n = self._sock.send(data)
ConnectionAbortedError: [WinError 10053] Eine bestehende Verbindung wurde softwaregesteuert
durch den Hostcomputer abgebrochen
2014-12-10 00:41:38 : websockets ... task.cancel
Future/Task exception was never retrieved
future: Task(<temperature_loop>)<exception=ValueError('list.remove(x): x not in list',)>
Traceback (most recent call last):
File "D:/GoogleDrive/workspace/masm/testing/raspi-server-testA.py", line 44, in temperature_loop
temp = yield from temperature_changed.get()
File "C:\Python34\lib\asyncio\queues.py", line 186, in get
return (yield from waiter)
File "C:\Python34\lib\asyncio\futures.py", line 348, in __iter__
yield self # This tells Task to wait for completion.
File "C:\Python34\lib\asyncio\tasks.py", line 370, in _wakeup
value = future.result()
File "C:\Python34\lib\asyncio\futures.py", line 235, in result
raise CancelledError
concurrent.futures._base.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:/GoogleDrive/workspace/masm/testing/raspi-server-testA.py", line 49, in temperature_loop
logger.error('websockets ... Unexpected error: %f' % sys.exc_info()[0])
TypeError: a float is required
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\tasks.py", line 317, in _step
result = coro.throw(exc)
File "D:/GoogleDrive/workspace/masm/testing/raspi-server-testA.py", line 51, in temperature_loop
temperature_consumers.remove(temperature_changed)
ValueError: list.remove(x): x not in list
2014-12-10 00:41:59 : Tinkerforge ... Temperaturänderung -> 23.000000
2014-12-10 00:41:59 : websockets ... call_soon_threadsafe
2014-12-10 00:41:59 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:08 : Tinkerforge ... Temperaturänderung -> 23.060000
2014-12-10 00:42:08 : websockets ... call_soon_threadsafe
2014-12-10 00:42:08 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:16 : Tinkerforge ... Temperaturänderung -> 23.000000
2014-12-10 00:42:16 : websockets ... call_soon_threadsafe
2014-12-10 00:42:16 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:21 : Tinkerforge ... Temperaturänderung -> 23.120000
2014-12-10 00:42:21 : websockets ... call_soon_threadsafe
2014-12-10 00:42:21 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:26 : Tinkerforge ... Temperaturänderung -> 23.060000
2014-12-10 00:42:26 : websockets ... call_soon_threadsafe
2014-12-10 00:42:26 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:29 : websockets ... asyncio.async
2014-12-10 00:42:29 : websockets ... asyncio.get_event_loop
2014-12-10 00:42:29 : websockets ... Queue
2014-12-10 00:42:29 : websockets ... temperature_consumers.append
2014-12-10 00:42:51 : Tinkerforge ... Temperaturänderung -> 23.120000
2014-12-10 00:42:51 : websockets ... call_soon_threadsafe
2014-12-10 00:42:51 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:51 : websockets ... yield from temperature_changed.get
2014-12-10 00:42:51 : websockets ... call_soon_threadsafe
2014-12-10 00:42:51 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 00:42:51 : websockets ... yield from websocket.send
- zuerst habe ich den Server gestartet
- dann mehrere Temperaturänderungen abgewartet
- danach habe ich mich mit dem Client verbunden
- eine Temperaturänderung abgewartet -> Anzeige auf dem Client ok
- danach den Browser geschlossen
- wieder ein paar Temperaturänderungen abgewartet
- danach habe ich den Browser wieder geöffnet und mich neuverbunden
- nächste Temperaturänderung abgewartet -> Anzeige im Client wieder ok
Ich hatte gehofft dem Fehler so selbst auf die Spur zu kommen, doch ehrlich gesagt verstehe ich fast nur Bahnhof.
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
ein kleineren Fehler habe ich gefunden.
Leider bekomme ich die Fehlermeldung immernoch, jetzt nur etwas kürzer:
Leider bekomme ich die Fehlermeldung immernoch, jetzt nur etwas kürzer:
Code: Alles auswählen
2014-12-10 23:32:37 : System startet
2014-12-10 23:32:37 : Tinkerforge ... Bricklets installiert
2014-12-10 23:32:37 : Tinkerforge ... Verbindung hergestellt
2014-12-10 23:32:37 : Tinkerforge ... Callbacks konfiguriert
2014-12-10 23:32:37 : Tinkerforge ... Callbacks gestartet
2014-12-10 23:32:37 : Tinkerforge ... System online
2014-12-10 23:32:37 : websockets ... set up websockets-server
2014-12-10 23:32:37 : websockets ... System online
2014-12-10 23:32:48 : Tinkerforge ... Temperaturänderung -> 20.750000
2014-12-10 23:32:53 : Tinkerforge ... Temperaturänderung -> 20.680000
2014-12-10 23:32:58 : Tinkerforge ... Temperaturänderung -> 20.620000
2014-12-10 23:32:59 : websockets ... asyncio.async
2014-12-10 23:32:59 : websockets ... asyncio.get_event_loop
2014-12-10 23:32:59 : websockets ... Queue
2014-12-10 23:32:59 : websockets ... temperature_consumers.append
2014-12-10 23:33:11 : Tinkerforge ... Temperaturänderung -> 20.750000
2014-12-10 23:33:11 : websockets ... call_soon_threadsafe
2014-12-10 23:33:11 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:11 : websockets ... yield from temperature_changed.get
2014-12-10 23:33:11 : websockets ... yield from websocket.send
2014-12-10 23:33:16 : Tinkerforge ... Temperaturänderung -> 20.680000
2014-12-10 23:33:16 : websockets ... call_soon_threadsafe
2014-12-10 23:33:16 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:16 : websockets ... yield from temperature_changed.get
2014-12-10 23:33:16 : websockets ... yield from websocket.send
2014-12-10 23:33:26 : Tinkerforge ... Temperaturänderung -> 20.620000
2014-12-10 23:33:26 : websockets ... call_soon_threadsafe
2014-12-10 23:33:26 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:26 : websockets ... yield from temperature_changed.get
2014-12-10 23:33:26 : websockets ... yield from websocket.send
2014-12-10 23:33:31 : Tinkerforge ... Temperaturänderung -> 20.680000
2014-12-10 23:33:31 : websockets ... call_soon_threadsafe
2014-12-10 23:33:31 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:31 : websockets ... yield from temperature_changed.get
2014-12-10 23:33:31 : websockets ... yield from websocket.send
Fatal write error on socket transport
protocol: <websockets.server.WebSocketServerProtocol object at 0x02DF7AF0>
transport: <asyncio.selector_events._SelectorSocketTransport object at 0x021A6350>
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\selector_events.py", line 502, in write
n = self._sock.send(data)
ConnectionAbortedError: [WinError 10053] Eine bestehende Verbindung wurde softwaregesteuert
durch den Hostcomputer abgebrochen
2014-12-10 23:33:31 : websockets ... task.cancel
2014-12-10 23:33:31 : websockets ... Unexpected error: <class 'concurrent.futures._base.CancelledError'>
Future/Task exception was never retrieved
future: Task(<temperature_loop>)<exception=ValueError('list.remove(x): x not in list',)>
Traceback (most recent call last):
File "D:/GoogleDrive/workspace/masm/testing/raspi-server-testA.py", line 44, in temperature_loop
temp = yield from temperature_changed.get()
File "C:\Python34\lib\asyncio\queues.py", line 186, in get
return (yield from waiter)
File "C:\Python34\lib\asyncio\futures.py", line 348, in __iter__
yield self # This tells Task to wait for completion.
File "C:\Python34\lib\asyncio\tasks.py", line 370, in _wakeup
value = future.result()
File "C:\Python34\lib\asyncio\futures.py", line 235, in result
raise CancelledError
concurrent.futures._base.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\tasks.py", line 317, in _step
result = coro.throw(exc)
File "D:/GoogleDrive/workspace/masm/testing/raspi-server-testA.py", line 51, in temperature_loop
temperature_consumers.remove(temperature_changed)
ValueError: list.remove(x): x not in list
2014-12-10 23:33:36 : Tinkerforge ... Temperaturänderung -> 20.750000
2014-12-10 23:33:36 : websockets ... call_soon_threadsafe
2014-12-10 23:33:36 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:51 : Tinkerforge ... Temperaturänderung -> 20.870000
2014-12-10 23:33:51 : websockets ... call_soon_threadsafe
2014-12-10 23:33:51 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:55 : websockets ... asyncio.async
2014-12-10 23:33:55 : websockets ... asyncio.get_event_loop
2014-12-10 23:33:55 : websockets ... Queue
2014-12-10 23:33:55 : websockets ... temperature_consumers.append
2014-12-10 23:33:56 : Tinkerforge ... Temperaturänderung -> 20.810000
2014-12-10 23:33:56 : websockets ... call_soon_threadsafe
2014-12-10 23:33:56 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:56 : websockets ... call_soon_threadsafe
2014-12-10 23:33:56 : websockets ... Temperaturänderung -> Warteschlange
2014-12-10 23:33:56 : websockets ... yield from temperature_changed.get
2014-12-10 23:33:56 : websockets ... yield from websocket.send
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
Code: Alles auswählen
#!/usr/bin/env python3
import asyncio
from asyncio.queues import Queue
import logging
import websockets
from tinkerforge.ip_connection import IPConnection
from tinkerforge.bricklet_temperature import Temperature
import pymysql
import sys
from constants import *
temperature_consumers = []
def change_temperature(temp):
# changed temperature in temp
new_temperature = temp / 100.0
logger.info('Tinkerforge ... Temperaturänderung -> %f' % new_temperature)
for consumer in temperature_consumers:
consumer(new_temperature)
logger.debug('websockets ... Temperaturänderung -> Warteschlange')
@asyncio.coroutine
def temperature_loop(websocket):
loop = asyncio.get_event_loop()
logger.debug('websockets ... asyncio.get_event_loop')
temperature_changed = Queue()
logger.debug('websockets ... Queue')
def changed(temp):
loop.call_soon_threadsafe(temperature_changed.put_nowait, temp)
logger.debug('websockets ... call_soon_threadsafe')
try:
temperature_consumers.append(changed)
logger.debug('websockets ... temperature_consumers.append')
while True:
temp = yield from temperature_changed.get()
logger.debug('websockets ... yield from temperature_changed.get')
yield from websocket.send('Temperature: %f' % temp)
logger.debug('websockets ... yield from websocket.send')
except:
logger.error('websockets ... Unexpected error: %r' % sys.exc_info()[0])
finally:
temperature_consumers.remove(temperature_changed)
logger.debug('websockets ... temperature_consumers.remove')
@asyncio.coroutine
def socket_handler(websocket, path):
task = asyncio.async(temperature_loop(websocket))
logger.debug('websockets ... asyncio.async')
while True:
# get message from client
message_rec = yield from websocket.recv()
# leave if client is disconnect
if message_rec is None:
break
# switch to different tasks
logger.debug('websockets ... yield from websocket.recv -> %f' % message_rec)
if message_rec == "set_light":
logger.info('websockets ... Licht schalten')
elif message_rec == "set_tv":
logger.info('websockets ... TV schalten')
else:
logger.warning('websockets ... Unbekannter Befehl -> %f' % message_rec)
task.cancel()
logger.debug('websockets ... task.cancel')
def set_logging(logging_daemon):
# Logging auf Console
if LOG_CONSOLE:
console_handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s : %(message)s', '%Y-%m-%d %H:%M:%S')
console_handler.setFormatter(formatter)
logging_daemon.addHandler(console_handler)
# Logging in Datei
if LOG_FILE:
file_handler = logging.FileHandler(LOG_FILE_PATH, mode='w', encoding=None, delay=False)
formatter = logging.Formatter('%(asctime)s : %(message)s', '%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(formatter)
logging_daemon.addHandler(file_handler)
if __name__ == "__main__":
# set up Logging Deamon
logger = logging.getLogger('raspi_server')
# set up Logging-Level
logger.setLevel(logging.DEBUG)
# start Logging
set_logging(logger)
logger.info('System startet')
# MySQL Verbindung herstellen
if DATABASE:
mysql_connection = pymysql.connect(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, passwd=MYSQL_PW,
db=MYSQL_DB, autocommit=True)
mysql_cursor = mysql_connection.cursor()
logger.info('mySQL ... Verbindung online')
# get connection to Tinkerforge-MasterBrick - Step 1
ipcon = IPConnection()
# set up Temperature-Bricklet
bricklet_temperatur = Temperature(TF_TEMP_UID, ipcon)
logger.debug('Tinkerforge ... Bricklets installiert')
# connect with MasterBrick
ipcon.connect(TF_HOST, TF_PORT)
logger.debug('Tinkerforge ... Verbindung hergestellt')
# set up Temperature-Bricklet callback-Time
bricklet_temperatur.set_temperature_callback_period(5000)
logger.debug('Tinkerforge ... Callbacks konfiguriert')
# set up Temperature-Bricklet callback
bricklet_temperatur.register_callback(bricklet_temperatur.CALLBACK_TEMPERATURE, change_temperature)
logger.debug('Tinkerforge ... Callbacks gestartet')
logger.info('Tinkerforge ... System online')
# set up Websocket-Server
start_server = websockets.serve(socket_handler, WS_IP, WS_PORT)
logger.debug('websockets ... set up websockets-server')
# run Websocket-Server
asyncio.get_event_loop().run_until_complete(start_server)
logger.info('websockets ... System online')
asyncio.get_event_loop().run_forever()
# Verbindung zum Master-Brick trennen
ipcon.disconnect()
if DATABASE:
mysql_cursor.close()
mysql_connection.close()
@der_Mausbiber: der Fehler ist in Zeile 51. Es sollte doch das gleiche aus der Liste entfernt werden wie in Zeile 41 hinzugefügt wird
Das except in Zeile 48 ist nicht so toll, da das Abbrechen des Task auch über Exceptions gelöst ist.

-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
Danke
Das hat mir schon einmal weiter geholfen.
Der entsprechende Code-Abschnitt sieht jetzt so aus:
Allerdings bekomme ich immer noch einen Fehler in den Logs:
Diesen Fehler würde ich gerne noch wegbekommen.

Das hat mir schon einmal weiter geholfen.
Der entsprechende Code-Abschnitt sieht jetzt so aus:
Code: Alles auswählen
@asyncio.coroutine
def temperature_loop(websocket):
loop = asyncio.get_event_loop()
logger.debug('websockets ... asyncio.get_event_loop')
temperature_changed = Queue()
logger.debug('websockets ... Queue')
def changed(temp):
loop.call_soon_threadsafe(temperature_changed.put_nowait, temp)
logger.debug('websockets ... call_soon_threadsafe')
try:
temperature_consumers.append(changed)
logger.debug('websockets ... temperature_consumers.append')
while True:
temp = yield from temperature_changed.get()
logger.debug('websockets ... yield from temperature_changed.get')
yield from websocket.send('Temperature: %f' % temp)
logger.debug('websockets ... yield from websocket.send')
finally:
temperature_consumers.remove(changed)
logger.debug('websockets ... temperature_consumers.remove')
Code: Alles auswählen
2014-12-13 19:06:21 : System startet
2014-12-13 19:06:21 : Tinkerforge ... Bricklets installiert
2014-12-13 19:06:21 : Tinkerforge ... Verbindung hergestellt
2014-12-13 19:06:21 : Tinkerforge ... Callbacks konfiguriert
2014-12-13 19:06:21 : Tinkerforge ... Callbacks gestartet
2014-12-13 19:06:21 : Tinkerforge ... System online
2014-12-13 19:06:21 : websockets ... set up websockets-server
2014-12-13 19:06:21 : websockets ... System online
2014-12-13 19:06:25 : websockets ... asyncio.async
2014-12-13 19:06:25 : websockets ... asyncio.get_event_loop
2014-12-13 19:06:25 : websockets ... Queue
2014-12-13 19:06:25 : websockets ... temperature_consumers.append
2014-12-13 19:06:29 : Tinkerforge ... Temperaturänderung -> 22.180000
2014-12-13 19:06:29 : websockets ... call_soon_threadsafe
2014-12-13 19:06:29 : websockets ... Temperaturänderung -> Warteschlange
2014-12-13 19:06:29 : websockets ... yield from temperature_changed.get
2014-12-13 19:06:29 : websockets ... yield from websocket.send
Fatal write error on socket transport
protocol: <websockets.server.WebSocketServerProtocol object at 0x02C77AF0>
transport: <asyncio.selector_events._SelectorSocketTransport object at 0x022A6350>
Traceback (most recent call last):
File "C:\Python34\lib\asyncio\selector_events.py", line 502, in write
n = self._sock.send(data)
ConnectionAbortedError: [WinError 10053] Eine bestehende Verbindung wurde softwaregesteuert
durch den Hostcomputer abgebrochen
2014-12-13 19:06:40 : websockets ... task.cancel
2014-12-13 19:06:40 : websockets ... temperature_consumers.remove
2014-12-13 19:06:48 : Tinkerforge ... Temperaturänderung -> 22.250000
2014-12-13 19:06:58 : Tinkerforge ... Temperaturänderung -> 22.310000
2014-12-13 19:07:03 : Tinkerforge ... Temperaturänderung -> 22.250000
@der_Mausbiber: der Fehler ist wahrscheinlich ein Protokoll-Fehler. Wenn eine Verbindung geschlossen wird, wird ein Close-Frame Frame(fin=True, opcode=8, data=b'\x03\xe9') vom Browser zum Server geschickt, der Antwortet auch mit einem Close-Frame Frame(fin=True, opcode=8, data=b'\x03\xe9'). Schließt der Browser den Socket aber zu schnell, kann dieser Close-Frame nicht mehr geschrieben werden. Mit Chrome unter Mac tritt dieser Fehler nicht auf, aber wer weiß welchen Browser Du da unter Windows verwendest.
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
Chromeaber wer weiß welchen Browser Du da unter Windows verwendest.

- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Also ich würde vermutlich das anders angehen: zwei unabhängige Dienste.
Ein periodisch aufgefufenes Skript welches die aktuelle Temperatur mit Zeitstempel in eine Datenbank schreibt. Ein webserver-app die auf die selbe datenenbank zugreift.
Ein periodisch aufgefufenes Skript welches die aktuelle Temperatur mit Zeitstempel in eine Datenbank schreibt. Ein webserver-app die auf die selbe datenenbank zugreift.
@jens: und eine webserver-app, die periodisch die Datenbank abfragt? Wenn alte Temperaturen nicht mehr gebraucht werden, ist doch eine Datenbank völlig unnötig.
@der_Mausbiber: dann scheinen sich die Windows-Sockets irgendwo zu verschlucken. Im Grunde kann der Fehler ignoriert werden, dazu müßtest Du die entsprechende Stelle im websockets-Modul ändern.
@der_Mausbiber: dann scheinen sich die Windows-Sockets irgendwo zu verschlucken. Im Grunde kann der Fehler ignoriert werden, dazu müßtest Du die entsprechende Stelle im websockets-Modul ändern.
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
@jens
Die Daten speichere ich schon zu statistischen Zwecken zusätzlich in einer Datenbank.
Allerdings möchte ich den Netzwerkverkehr aufs nötigste beschränken und so wird nur dann ein Wert übertragen wenn sich dieser auch geändert hat.
Außerdem möchte ich noch andere Sensoren darüber ansteuern, bei welchem die Datenabfrage über eine Datenbank nicht mehr so perfekt passen würde.
@sirius3
Danke, dann werde ich diesen Fehler nicht weiter beachten.
Ich versuche das Skript jetzt zu verstehen und frage dann hier nochmal kurz nach ob ich auch alle srichtig verstanden habe wenn es in Ordnung ist.
Die Daten speichere ich schon zu statistischen Zwecken zusätzlich in einer Datenbank.
Allerdings möchte ich den Netzwerkverkehr aufs nötigste beschränken und so wird nur dann ein Wert übertragen wenn sich dieser auch geändert hat.
Außerdem möchte ich noch andere Sensoren darüber ansteuern, bei welchem die Datenabfrage über eine Datenbank nicht mehr so perfekt passen würde.
@sirius3
Danke, dann werde ich diesen Fehler nicht weiter beachten.
Ich versuche das Skript jetzt zu verstehen und frage dann hier nochmal kurz nach ob ich auch alle srichtig verstanden habe wenn es in Ordnung ist.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Das dachte ich mir. So ein Temperatur-Verlauf ist ja naheliegend... Also brauchst du so oder so alle Daten in einer Datenbank...der_Mausbiber hat geschrieben:Die Daten speichere ich schon zu statistischen Zwecken zusätzlich in einer Datenbank.
Client sendet seinen Zeitstempel oder den letzten Temperatur-Wert und dann weiß der Server ob sich die Temperatur geändert hat oder nicht...der_Mausbiber hat geschrieben:Allerdings möchte ich den Netzwerkverkehr aufs nötigste beschränken und so wird nur dann ein Wert übertragen wenn sich dieser auch geändert hat.
Warum eigentlich "Netzwerkverkehr aufs nötigste beschränken" ? Was ist das Ziel? Handy? Dann wäre eine App das passendere mit Push-Benachrichtigung...
Warum nicht?der_Mausbiber hat geschrieben:Außerdem möchte ich noch andere Sensoren darüber ansteuern, bei welchem die Datenabfrage über eine Datenbank nicht mehr so perfekt passen würde.
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
So, hat ein wenig länger gedauert da ich anderweitig beschäftigt war.
Die Anzeige in der WebApp (will es mal so nennen) soll mir aber die aktuelle Temperatur anzeigen, also auch wenn sich diese innerhalb von 3 Minuten mehrmals ändert.
Deswegen schicke ich diese Daten über websockets.
Warum websockets? Da ich von der WebApp auch Schaltvorgänge bedienen will brauche ich sowieso ein Verbindung zum Script.
Z.Bsp. habe ich auf der Website auch Schalter zum schalten von Steckdosen.
Diesen Befehl empfängt das Script und leitet dann den Schaltvorgang ein.
Abgesehen davon verstehe ich nicht wie ich das gleiche Verhalten mit einer Datenbank nachbauen soll.
Klar, sowie die Temperatur sich ändert kann ich diese mit einem Timestamp in der Datenbank speichern. Aber woher weiß der Client wenn sich der Wert geändert hat? Dazu müsste die Datenbank eine Art Callback auslösen und ich weiß nicht wie das gehen soll.
Die Hardware-Seite besteht dabei aus mehreren raspberry pis mit diversen Sensoren, einem Linux-Server der die Seite hostet und von außerhalb ist die Steuerung nur über VPN zu erreichen.
Ja und nein, für statische Zwecke nehme ich alle 3 Minuten die Temperatur und speicher sie in einer Datenbank, somit kann ich dann leicht Durchschnitt, Höchstwerte, etc... ausgeben.Das dachte ich mir. So ein Temperatur-Verlauf ist ja naheliegend... Also brauchst du so oder so alle Daten in einer Datenbank...
Die Anzeige in der WebApp (will es mal so nennen) soll mir aber die aktuelle Temperatur anzeigen, also auch wenn sich diese innerhalb von 3 Minuten mehrmals ändert.
Deswegen schicke ich diese Daten über websockets.
Warum websockets? Da ich von der WebApp auch Schaltvorgänge bedienen will brauche ich sowieso ein Verbindung zum Script.
Z.Bsp. habe ich auf der Website auch Schalter zum schalten von Steckdosen.
Diesen Befehl empfängt das Script und leitet dann den Schaltvorgang ein.
Abgesehen davon verstehe ich nicht wie ich das gleiche Verhalten mit einer Datenbank nachbauen soll.
Klar, sowie die Temperatur sich ändert kann ich diese mit einem Timestamp in der Datenbank speichern. Aber woher weiß der Client wenn sich der Wert geändert hat? Dazu müsste die Datenbank eine Art Callback auslösen und ich weiß nicht wie das gehen soll.
Ziel ist alles weitestgehend zu automatisieren und dazu eine ansprechende Steuerung über Handy, Tablet und Desktop-PC zu realisieren.Was ist das Ziel? Handy? Dann wäre eine App das passendere mit Push-Benachrichtigung...
Die Hardware-Seite besteht dabei aus mehreren raspberry pis mit diversen Sensoren, einem Linux-Server der die Seite hostet und von außerhalb ist die Steuerung nur über VPN zu erreichen.
Wie oben geschrieben sende ich Schaltbefehl vom Client zum Script, dafür brauche ich eine direkte Verbindung. Bzw. würde ich eine Lösung über die Datenbank sehr umständlich finden.Warum nicht?
-
- User
- Beiträge: 72
- Registriert: Donnerstag 2. Oktober 2014, 09:51
so, jetzt habe ich das Script fast verstanden, nur die Funktion
verstehe ich noch nicht komplett.
Trotzdem konnte ich das Ganze jetzt so umbauen das die Schalterzustände an andere Clients weiter und die Daten per json übergeben werden.
Ich habe das Gefühl das das Script ziemlich genau macht was ich will und will mich nochmal herzlich bei euch für die Hilfe bedanken.
Ansonsten wünsche ich dann ein frohes neues Jahr ....
Anbei nochmal das Script wie es jetzt aussieht, samt mysql-Anbindung.
Code: Alles auswählen
def temperature_loop(websocket):
Trotzdem konnte ich das Ganze jetzt so umbauen das die Schalterzustände an andere Clients weiter und die Daten per json übergeben werden.
Ich habe das Gefühl das das Script ziemlich genau macht was ich will und will mich nochmal herzlich bei euch für die Hilfe bedanken.



Ansonsten wünsche ich dann ein frohes neues Jahr ....
Anbei nochmal das Script wie es jetzt aussieht, samt mysql-Anbindung.
Code: Alles auswählen
#!/usr/bin/env python3
import asyncio
from asyncio.queues import Queue
import logging
import threading
import time
import json
import websockets
from tinkerforge.ip_connection import IPConnection
from tinkerforge.bricklet_remote_switch import RemoteSwitch
import pymysql
from tinkerforge.bricklet_temperature import Temperature
from constants import *
consumers = [] # queue for sending commands
switches = [] # list of all switches and corresponding settings
@asyncio.coroutine
def send_data_loop(websocket):
# create sending-queue
loop = asyncio.get_event_loop()
send_data_changed = Queue()
logger.debug('websockets .... Queue startet')
def changed(tmp):
loop.call_soon_threadsafe(send_data_changed.put_nowait, tmp)
logger.debug('websockets .... call_soon_threadsafe')
try:
consumers.append(changed)
logger.debug('websockets .... consumers.append')
# create json-string & send FIRST temperature to all clients if some new client is connecting
tmp_json = json.dumps([raspberry_device[1], "sensor", "temperature", round(main_temperature, 1)])
yield from websocket.send(tmp_json)
logger.debug('websockets .... Erste Daten -> Client ')
while True:
temp = yield from send_data_changed.get()
yield from websocket.send(temp)
logger.debug('websockets .... yield from websocket.send : %s' % temp)
finally:
consumers.remove(changed)
logger.debug('websockets .... consumers.remove')
@asyncio.coroutine
def socket_handler(websocket, path):
# set up sending-queue
task = asyncio.async(send_data_loop(websocket))
logger.debug('websockets .... asyncio.async')
while True:
# get message from client
message_rec = yield from websocket.recv()
# leave if client is disconnect
if message_rec is None:
break
# switch to different tasks
logger.debug('websockets .... yield from websocket.recv -> %s' % message_rec)
search_command(message_rec)
# close sending-queue if client discconect
task.cancel()
logger.debug('websockets .... task.cancel')
def set_logging(logging_daemon):
# Logging auf Console
if LOG_CONSOLE:
console_handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s : %(message)s', '%Y-%m-%d %H:%M:%S')
console_handler.setFormatter(formatter)
logging_daemon.addHandler(console_handler)
# Logging in Datei
if LOG_FILE:
file_handler = logging.FileHandler(LOG_FILE_PATH, mode='w', encoding=None, delay=False)
formatter = logging.Formatter('%(asctime)s : %(message)s', '%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(formatter)
logging_daemon.addHandler(file_handler)
def search_command(tmp):
# decode JSON String
tmp_json = json.loads(tmp)
# extract variables from json
send_location = tmp_json[0]
send_type = tmp_json[1]
send_string = tmp_json[2]
send_command = tmp_json[3]
logger.info('Tinkerforge ... Schalteränderung -> %s = %s' % (send_string, send_command))
# if a switch is sending
if send_type == "switch":
# search all switches to find the right one
for item in switches:
# extract Variables
switch_id = item[0]
switch_string = item[6]
switch_typ = item[7]
switch_send_a = item[8]
switch_send_b = item[9]
# switch found
if switch_string == send_string:
# which kind of switch
if switch_typ == "C":
# switch
bricklet_remote.switch_socket_c(switch_send_a, int(switch_send_b), int(send_command))
# get Time & Date and update Database
uhrzeit = time.strftime('%Y-%m-%d %H:%M:%S')
mysql_cursor.execute("UPDATE switches SET timestamp = %s, state = %s WHERE id = %s",
(uhrzeit, send_command, switch_id))
# put switch change into all clients-queues
for consumer in consumers:
consumer(tmp)
logger.debug('websockets .... Schalteränderung -> Warteschlange')
break
def read_temperature():
return bricklet_temperatur.get_temperature() / 100.0
def callback_temperature(te):
global main_temperature
# get new temperature
te = (te / 100.0)
# only if difference is higher or equial to 0.1
if abs(main_temperature - te) >= 0.1:
# old temperature set to new temperature
main_temperature = te
logger.info('Tinkerforge ... Temperaturänderung -> %f' % main_temperature)
# create json-string
tmp_json = json.dumps([raspberry_device[1], "sensor", "temperature", round(main_temperature, 1)])
# send new temperature to all clients
for consumer in consumers:
consumer(tmp_json)
logger.debug('websockets .... Temperaturänderung -> Warteschlange ')
def db_timer_tasks():
global __timer
# get Time & Date
uhrzeit = time.strftime('%Y-%m-%d %H:%M:%S')
# Task 1 - take a temperature sample
mysql_cursor.execute("INSERT INTO sensor_data_temperature (timestamp , data , sensors_id) VALUES (%s , %s , %s)",
(uhrzeit, main_temperature, raspberry_device[0]))
logger.debug('Tinkerforge ... Temperaturwert %f in Datenbank aufgenommen' % main_temperature)
# start Timer again
if __timer_is_running:
__timer = threading.Timer(__timer_intervall, db_timer_tasks).start()
def get_db_settings():
global switches
# get ID
mysql_cursor.execute("SELECT * FROM raspi_devices WHERE ip = %s LIMIT 1", WS_IP)
__tmp_data = mysql_cursor.fetchone()
raspberry_pi_id = __tmp_data[0]
raspberry_pi_name = __tmp_data[2]
# get switches for this ID
mysql_cursor.execute("SELECT * FROM switches WHERE raspi_devices_id = %s", raspberry_pi_id)
switches = mysql_cursor.fetchall()
logger.info('mySQL ......... Einstellungen eingelesen, id = %s', raspberry_pi_id)
# return ID for use in other functions
return raspberry_pi_id, raspberry_pi_name
if __name__ == "__main__":
#
# set up Logging Deamon
#
logger = logging.getLogger('raspi_server')
# set up Logging-Level
logger.setLevel(logging.DEBUG)
# start Logging
set_logging(logger)
logger.info('System startet')
#
# set up MySQL Connection
#
mysql_connection = pymysql.connect(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, passwd=MYSQL_PW,
db=MYSQL_DB, autocommit=True)
mysql_cursor = mysql_connection.cursor()
# get some settings from db
raspberry_device = get_db_settings()
logger.info('mySQL ......... Verbindung online')
#
# set up Tinkerforge
#
tinkerforge_connection = IPConnection()
# set up Bricklets
bricklet_temperatur = Temperature(TF_TEMP_UID, tinkerforge_connection)
bricklet_remote = RemoteSwitch(TF_REMOTE_UID, tinkerforge_connection)
# connect to Masterbrick
tinkerforge_connection.connect(TF_HOST, TF_PORT)
# set up Callbacks
bricklet_temperatur.set_temperature_callback_period(5000)
bricklet_temperatur.register_callback(bricklet_temperatur.CALLBACK_TEMPERATURE, callback_temperature)
# first data
main_temperature = read_temperature()
# finish
logger.info('Tinkerforge ... System online')
#
# set up Database Timer
#
if DATABASE_TIMER > 0:
__timer_is_running = True
__timer_intervall = DATABASE_TIMER
__timer = threading.Timer(DATABASE_TIMER, db_timer_tasks).start()
#
# set up Websocket-Server
#
start_server = websockets.serve(socket_handler, WS_IP, WS_PORT)
logger.debug('websockets .... set up websockets-server')
# run Websocket-Server
asyncio.get_event_loop().run_until_complete(start_server)
logger.info('websockets .... System online')
asyncio.get_event_loop().run_forever()
#
#
#
tinkerforge_connection.disconnect()
mysql_cursor.close()
mysql_connection.close()