Guten Abend,
mittlerweile bin ich ein Stück weiter und habe mich für ein Client-Server Modell entschieden, sprich die einzelnen RaspberryPis sprechen nur mit einem Script auf dem Server.
Der Server spricht dann wieder mit den UI's auf Desktop, Tablet & Co.
Außerdem holt sich das Client-Script seine Einstellungen beim Server ab und auch die angeschlossenen Sensoren werden dynamisch erzeugt. Zumindest das habe ich schon einmal alles geschafft.
Sehr wahrscheinlich habe ich es nicht gut gelöst, aber immerhin.
Erstmal der Code:
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 my_tinkerforge import *
# logging
LOG_CONSOLE = True
LOG_FILE = False
LOG_FILE_PATH = "/var/log/raspi.log"
DEVICE_IP = "192.168.127.30"
WS_SERVER = "192.168.127.30:5500"
consumers = [] # queue for sending commands
sensors = []
bricklets = {}
settings = {"id": 0, "tf_callback": 0}
@asyncio.coroutine
def send_data_loop(websocket):
# create sending-queue
loop = asyncio.get_event_loop()
sending_queue = Queue()
logger.debug('websockets .... Queue startet')
def changed(tmp):
loop.call_soon_threadsafe(sending_queue.put_nowait, tmp)
logger.debug('websockets .... call_soon_threadsafe')
try:
consumers.append(changed)
logger.debug('websockets .... consumers.append')
# step 1 get settings
yield from websocket.send(json.dumps(["get_settings", DEVICE_IP, "", "", ""]))
while True:
tmp_data = yield from sending_queue.get()
yield from websocket.send(tmp_data)
logger.debug('websockets .... yield from websocket.send : %s' % tmp_data)
finally:
consumers.remove(changed)
logger.debug('websockets .... consumers.remove')
@asyncio.coroutine
def client_handler():
# connect to server
websocket = yield from websockets.connect('ws://' + WS_SERVER + '/')
# 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)
message_handler(message_rec)
# close sending-queue if client discconect
task.cancel()
logger.debug('websockets .... task.cancel')
def message_handler(tmp):
global settings
global sensors
# decode JSON String
tmp_json = json.loads(tmp)
if tmp_json[0] == "send_settings":
settings = tmp_json[4]
logger.info('websockets .... get Settings -> id = %s , title = %s , tf_callback = %s' % (
settings["id"], settings["title"], settings["tf_callback"]))
for consumer in consumers:
consumer(json.dumps(["get_sensors", settings["id"], "", "", ""]))
elif tmp_json[0] == "send_sensors":
sensors = tmp_json[4]
for x in sensors:
set_tinkerforge_bricklet(x[0], x[1], x[2], tinkerforge_connection)
logger.info('websockets .... get Sensors -> id = %s , title = %s , type = %s' % (
x[0], x[1], x[2]))
tinkerforge_connection.connect("localhost", 4223)
for x in sensors:
bricklets[x[1]].set_callback(settings["tf_callback"])
logger.info('Tinkerforge ... System online')
def set_tinkerforge_bricklet(uid, title, tf_type, tf_connection):
if tf_type == "temperature":
bricklets[title] = BrickletTemperature(uid, tf_connection, logger, consumers)
# connect to Masterbrick
logger.info('Tinkerforge ... Bricklet %s online' % title)
def set_logging():
# 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)
logger.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)
logger.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.info('System startet')
#
# set up Tinkerforge
#
tinkerforge_connection = IPConnection()
#
# set up Websocket-Server
#
asyncio.get_event_loop().run_until_complete(client_handler())
Code: Alles auswählen
import json
from tinkerforge.bricklet_temperature import Temperature
from tinkerforge.bricklet_barometer import Barometer
from tinkerforge.bricklet_ambient_light import AmbientLight
from tinkerforge.bricklet_humidity import Humidity
class BrickletTemperature:
value = 0.0
trigger_difference = 0.1
value_digits = 1
def __init__(self, uid, tmp_connection, tmp_logging, tmp_queue):
self.bricklet = Temperature(uid, tmp_connection)
self.__uid = uid
self.__logging = tmp_logging
self.__queue = tmp_queue
self.__logging.debug('Tinkerforge ... Temperatur-Bricklet "%s" initialisiert' % uid)
def set_callback(self, timeframe=5000):
self.bricklet.set_temperature_callback_period(timeframe)
self.bricklet.register_callback(self.bricklet.CALLBACK_TEMPERATURE, self.__changed)
self.__logging.debug('Tinkerforge ... Temperatur-Bricklet "%s" Callback gesetzt' % self.__uid)
def read(self):
return self.bricklet.get_temperature() / 100.0
def __changed(self, tmp_value):
# get new temperature
tmp_value = (tmp_value / 100.0)
# only if difference is higher or equial to 0.1
if abs(self.value - tmp_value) >= self.trigger_difference:
# old temperature set to new temperature
self.value = tmp_value
self.__logging.debug('Tinkerforge ... Temperaturänderung bei "%s" -> %f' % (self.__uid, self.value))
# create json-string ( sensor-id <> sensor-type <> sensor-name <> sensor-value )
tmp_json = json.dumps(["send_data", self.__uid, "sensor", "temperature", round(self.value, self.value_digits)])
# send new temperature to all clients
for consumer in self.__queue:
consumer(tmp_json)
self.__logging.debug('websockets .... Temperaturänderung bei "%s" -> Warteschlange ' % self.__uid)
Ich versuche jetzt das Script das hier erarbeitet wurde entsprechend anzupassen.
Im Prinzip funktioniert das auch ohne Fehler.
Nur, wenn ich das richtig sehe ist es doch unnötig eine Liste der
consumers anzulegen, da das Client-Skript ausschließlich mit dem Server Skript spricht, sprich es gibt immer nur einen
consumer. Hab ich das soweit richtig verstanden?
Ich versuche nun schon eine ganze Weile zu verstehen wie ich die Liste entfernen kann und trotzdem meine Callback-Änderungen durchgegeben bekomme - leider bekomme ich es nicht hin.