Ich habe mir ein kleines Programm geschrieben in Python, welches als Service auf einem Raspberry läuft. Das funktioniert auch wunderbar. Dieses Programm schaltet die Port-Pins an/aus und überwacht diese sowie schreibt dessen Status in ein Datenbank. Das funktioniert tadellos. Nun möchte ich aus einem anderem Python Script, welches durch einen Browser (Apache2, PHP) gestartet wurde die Pins über das als Service laufende Script schalten bzw dessen Status übermitteln lassen. Wie stelle ich das am besten an? Ein TCP/IP Listener habe probiert, dies funktioniert natürlich nicht, da ja der Port auf der IP bereits durch das "Server-Script" geblockt wird. Habt ihr eine Idee wie man dies umsetzen könnte? Liebe Grüße René
dbus (Einstieg z.B. unter https://wiki.python.org/moin/DbusExamples) wäre mein Ansatz. Rene K. schrieb: > Ein TCP/IP Listener habe probiert, dies > funktioniert natürlich nicht, da ja der Port auf der IP bereits durch > das "Server-Script" geblockt wird. Und einer der anderen 65534 Ports war auch keine Option?
:
Bearbeitet durch User
Rene K. schrieb: > Ich habe mir ein kleines Programm geschrieben in Python, welches als > Service auf einem Raspberry läuft. [...] > Ein TCP/IP Listener habe probiert, dies > funktioniert natürlich nicht, da ja der Port auf der IP bereits durch > das "Server-Script" geblockt wird. D.h. Dein erstes Script (Server-Script?) öffnet schon einen Port und wartet dort auf Anfragen? Beschreibe mal genauer, was Du schon hast, und was Du willst, so dass man ein genaues Bild hat.
Ich habe es jetzt mit UDP Sockets gemacht. Geht ganz gut und ist eigentlich genau das was ich suche.: Server:
1 | import socket |
2 | |
3 | # UDP Verbindung |
4 | SocketIP = "127.0.0.1" |
5 | SocketPort = 20001 |
6 | SocketBuffer = 1024 |
7 | |
8 | SocketCon = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) |
9 | SocketCon.bind((SocketIP, SocketPort)) |
10 | |
11 | # Dauerschleife |
12 | while(True): |
13 | |
14 | # Empfange Daten |
15 | SocketRecByte = SocketCon.recvfrom(SocketBuffer) |
16 | SocketMessage = SocketRecByte[0] |
17 | SocketClientAddress = SocketRecByte[1] |
18 | |
19 | print(SocketMessage) |
Client:
1 | import socket |
2 | |
3 | msgFromClient = "Ping Ping" |
4 | bytesToSend = str.encode(msgFromClient) |
5 | serverAddressPort = ("127.0.0.1", 20001) |
6 | bufferSize = 1024 |
7 | |
8 | # Create a UDP socket at client side |
9 | UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) |
10 | |
11 | # Send to server using created UDP socket |
12 | UDPClientSocket.sendto(bytesToSend, serverAddressPort) |
Rene K. schrieb: > Ich habe es jetzt mit UDP Sockets gemacht. Hinsichtlich des von dir genannten Problems unterscheiden sich UDP und TCP eigentlich nicht.
Rolf M. schrieb: > Hinsichtlich des von dir genannten Problems unterscheiden sich UDP und > TCP eigentlich nicht. Über den gleichen Weg hat mir mein Journal aber ausgeworfen das der TCP Port bereits verwendet wird. Hat den Service des Servers geschlossen und das wars.
Es gibt da noch massig andere Möglichkeiten, wenn BEIDE Prozesse da rankommen: - gemeinsamer Speicherplatz ("Systemvariable") - gemeinsame Datei - Messaging per System-Prozessmanager - gemeinsame Datenbank (-Tabelle) - eigener Dienst ("Reflektor", Webserver) - direkte Kommunikation per IPC (inter process communication, Socket) Einige von denen bieten auch den Vorteil, einer gewissen zeitlichen Entkopplung.
:
Bearbeitet durch User
Hallo Rene. Rene K. schrieb: > > Wie stelle ich das am besten an? Ein TCP/IP Listener habe probiert, dies > funktioniert natürlich nicht, da ja der Port auf der IP bereits durch > das "Server-Script" geblockt wird. > > Habt ihr eine Idee wie man dies umsetzen könnte? Primitiv Lösung: Per Clibboard. Pythonm kann sehr einfach Strings in das Betriebssystemeigene Clibboard schieben bzw. auslesen. Das könntest Du theoretisch auch für die Kommunikation von Skripts untereinander missbrauchen. Ist aber langsam und Situationsabhängig unsicher: Wenn ein anderes Programm auf das Clibboard zugreift, sind Stolperer vorprogrammiert. Habe ich vor 15 oder so Jahren mal experimentell gemacht. Mit freundlichem Gruß: Bernd Wiebus alias dl1eic http://www.l02.de
Rene K. schrieb: > Rolf M. schrieb: >> Hinsichtlich des von dir genannten Problems unterscheiden sich UDP und >> TCP eigentlich nicht. > > Über den gleichen Weg hat mir mein Journal aber ausgeworfen das der TCP > Port bereits verwendet wird. Hat den Service des Servers geschlossen und > das wars. Dann müsste ja ein anderes Programm den Port nutzen - mal mit netstat schauen. Hast du die Empfangsroutine in einen eigenen Thread gesteckt, da die ja blockiert bis mal was kommt? Wenn ja ergibt sich das Problem das beim beenden des Programms der Thread nicht oder nicht sofort beendet wird und damit der Port dann bein nächsten Programmstart noch belegt ist. Sascha
Rene K. schrieb: > Nun möchte ich aus einem anderem Python Script, welches durch einen > Browser (Apache2, PHP) gestartet wurde die Pins über das als Service > laufende Script schalten bzw dessen Status übermitteln lassen. Hast du vor die Python scripte als CGI nur schnell zu starten. Vielleicht wäre hier sowas wie Flask oder Django angebracht, welches hinter den Apache die Kommunikation übernimmt, das macht die Architektur ggf etwas schmaler weil es auch Python ist. Rene K. schrieb: > Wie stelle ich das am besten an? Ein TCP/IP Listener habe probiert, dies > funktioniert natürlich nicht, da ja der Port auf der IP bereits durch > das "Server-Script" geblockt wird. Verstehe ich nicht, der Apache benutzt entweder Port 80 oder Port 443, oder beide. Beides Ports sind Well Knwon Ports. Dein Script zum Schalten sollte einen Port größer 1024 verwenden, außerdem sollte dein Script nur auf localhost lauschen. Ich denke hier liegt irgendwo ein Problem. die Architektur sollte ungefähr so aussehen: Internet <-- Extern; Port 80, 443 --> Apache2 <-- Localhost; Random Port X > 1024 --> Backend; [PHP | Flask | Django] <-- Localhost; Random Port Y > 1024 --> Dein Script. Wobei dein Schaltscript ein Server ist und das Backend eine art Proxy ist, denn für dein Schaltscript ist es Client für denn Apache ist es ein Server. Welche IPC (Interprozess Kommunikation) du verwendest, ist erstmal egal, denn da gibt es viele Wege. Meine Skizze nimmt TCP/IP, möglich wären auch UnixSockets, Named Pipes, Shared Memory, message queue und viele weitere. Persönlich spiele ich gerade mit MQTT und so ein publischer/subscriber Modell ist auch nicht schlecht. Dein Script könnte zum Beispiel die geänderten IOs an einen MQTT Broker annoncieren und einen Topic zum ändern der IOs abonnieren. Dann könnte jeder auf dem System mithilfe des MQTT Protokoll, die Ports bearbeiten. Ist zwar ein Overhead, aber je nachdem Was du sonst noch so mit dem PI machen willst, könnte der Overhead gerechtfertigt sein. Rene K. schrieb: > Dieses Programm schaltet die Port-Pins an/aus und überwacht diese sowie > schreibt dessen Status in ein Datenbank. Das funktioniert tadellos. Was genau macht diese Datenbank denn noch so und vor allen wer ließt die Datenbank? Wie schon von anderen gesagt die Datenbank könnte eine Tabelle als IPC verwenden. Oder wenn das nicht gewünscht ist, frage ich mich ob es vielleicht sinnvoll ist, nach dem Motto: divide et impera, das IO Script zu zerschlagen. Dann hättest du einen kleinen Monitor der die IOs überwacht und Änderungen per IPC Propagiert und einen "Buchhalter" der die Änderungen in der Datenbank vermerkt. Je nach Komplexität des Gesamtsystem könnte das zu einen Clean Design beitragen und die Datenbank und dein Backend würden die gleiche IPC nutzen.
Rene K. schrieb: > Ich habe mir ein kleines Programm geschrieben in Python, welches als > Service auf einem Raspberry läuft. Das funktioniert auch wunderbar. > > Dieses Programm schaltet die Port-Pins an/aus und überwacht diese sowie > schreibt dessen Status in ein Datenbank. Das funktioniert tadellos. > > Nun möchte ich aus einem anderem Python Script, welches durch einen > Browser (Apache2, PHP) gestartet wurde die Pins über das als Service > laufende Script schalten bzw dessen Status übermitteln lassen. > > Wie stelle ich das am besten an? Ein TCP/IP Listener habe probiert, dies > funktioniert natürlich nicht, da ja der Port auf der IP bereits durch > das "Server-Script" geblockt wird. > > Habt ihr eine Idee wie man dies umsetzen könnte? Auch nach mehrmaligem Lesen erscheint mir Dein Ansatz etwas gewöhnungsbedürftig. Aus welchem Grund sollten das zwei Skripte machen? Eines reicht doch völlig aus, und im Anhang findest Du ein einfaches Beispiel von mir, das ich mit Flask realisiert habe und in dem ein eigener Thread zur Erfassung und Speicherung der Daten läuft (im Moment erzeugt dieser Thread die Daten per random.uniform(), aber diesen Teil hast Du ja bereits implementiert und mußt ihn nur "umziehen" oder importieren). Auch die Beispieldaten für die Visualisierung werden zufällig erzeugt, in einer realistischen Anwendung werden die natürlich aus der Datenbank gelesen (und müssen auch nicht wie im Beispiel mit Matplotlib, sondern können auch mit wesentlich leistungsfähigeren Frameworks wie Bokeh, Altair, flot, jqplot oder ähnlichen realisiert werden). Aber selbst wenn Du zwei Skripte benutzt, muß das "Portpin-Programm" ja nicht direkt in die Datenbank schreiben, sondern kann die erfaßten Daten einfach über HTTP an Dein "Webfrontend-Program" übergeben. Dieses zweite Programm hat ja bereits alles, was es braucht: einen HTTP-Listener zur Datenübermittlung sowie eine Verbindung zur Datenbank zur Persistierung der Daten. Zuletzt ein kleiner Tipp: die Daten, die Du speicherst, gehören eigentlich in ein Append-Only-Log wie eine Zeitserien-Datenbank. Dafür ist eine relationale Datenbank weder nötig noch sinnvoll, denn die Garanrien einer solchen wie transaktionale und referentielle Integrität werden hier nicht benötigt. Aber genau diese Garantien machen eine relationale Datenbank ziemlich teuer, und daher performen solche Datenbanken mit derartigen Daten vergleichsweise schlecht. Schlimmer noch: aufgrund dieser Garantien muß eine relationale Datenbank ein Write-Ahead-Log führen, und das heißt: für jeden noch so kleinen Write in die Datenbank sind mindestens drei Schreibzugriffe auf das Persistierungsmedium notwendig, und das ist der Langlebigkeit einer SD-Karte in einem Raspberry Pi nicht eben zuträglich. Für die extrem leistungsfähige relationale Datenbank PostgreSQL gibt es immerhin die Erweiterung TimescaleDB, die für Zeitseriendaten eine wesentlich bessere Performance bietet als eine klassische relationale Datenbank. Außerdem erweitert TimescaleDB die Datenbank um verschiedene Funktionen zur Auswertung Deiner Daten... aber das Problem mit den Schreibzugriffen bleibt dabei leider dennoch bestehen.
Ich bedanke mich erstmal für den wahnsinnig vielen Input :-D Hintergrund war / ist das ich eine Zeitschaltuhr für ein Relais realisieren möchte, auf welche ich extern zugriff habe. Da ich bereits einen Server zu Hause stehen habe, war / ist die Idee die Datenbank sowie die Webseite eben auf diesen zu hosten. Mir war vorher, und man möchte mir das bitte verzeihen, nicht bekannt das Python auch Multithreading beherrscht - das sind aktuell meine ersten Schritte in Python und mein erstes Python Script überhaupt. :-) Da Python ja nun Multithreading beherrscht, erübrigt sich natürlich die Frage "Wie zwischen zwei Scripten kommunizieren" vollends. Dennoch benötige ich natürlich die UDP Verbindung. Und diese funktioniert tadellos, ich habe das Script mal angefügt. Einzigster Wehrmutstropfen: Wenn ich den UDP Server auf "localhost" lauschen lasse, bekomme ich natürlich keine externen Pakete mehr hinein. Wenn ich eine IP vergebe, muss ich sicherstellen das sie bei der nächsten DHCP Verhandlung wieder die selbe bekommt. Das läßt sich natürlich sehr leicht lössen indem man eine feste vergibt. Gibt es dennoch eine Möglichkeit in Python die aktuelle IP eines Adapters herrauszufinden?
1 | #!/usr/bin/python3
|
2 | |
3 | import datetime |
4 | import sys |
5 | import socket |
6 | import mysql.connector |
7 | import threading |
8 | import RPi.GPIO as GPIO |
9 | import time |
10 | |
11 | # MySQL Verbindung
|
12 | DBcon = mysql.connector.connect( |
13 | host="192.168.178.5", |
14 | user="*****", |
15 | password="*****", |
16 | database="Aquarium" |
17 | )
|
18 | |
19 | # Relais aus der Datenbank abrufen
|
20 | DBcur = DBcon.cursor() |
21 | sql = "SELECT * FROM Relais" |
22 | DBcur.execute(sql) |
23 | DBrelais = DBcur.fetchall() |
24 | |
25 | # UDP Verbindung
|
26 | SocketIP = "192.168.178.119" |
27 | SocketPort = 20001 |
28 | SocketBuffer = 1024 |
29 | SocketCon = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) |
30 | SocketCon.bind((SocketIP, SocketPort)) |
31 | |
32 | # Init Relays
|
33 | GPIO.setmode(GPIO.BCM) |
34 | GPIO.setwarnings(False) |
35 | |
36 | for x in DBrelais: |
37 | GPIO.setup(x[2], GPIO.OUT, initial=x[4]) |
38 | print("ID: ", x[0], " Pin: ", x[2], " Init: ", x[4], " Name: ", x[1]) |
39 | time.sleep(0.3) |
40 | |
41 | # UDP Server
|
42 | def UDP_Server(): |
43 | while(True): |
44 | |
45 | # Empfange Daten
|
46 | SocketRecByte = SocketCon.recvfrom(SocketBuffer) |
47 | SocketMessage = SocketRecByte[0].decode("utf-8") |
48 | SocketClientAddress = SocketRecByte[1] |
49 | |
50 | # Daten konvertieren
|
51 | varRelais = int(SocketMessage[0]) - 1 |
52 | varStat = int(SocketMessage[1]) |
53 | |
54 | if varStat == 3: |
55 | sql = "UPDATE Relais SET Override = 0 WHERE id = " + SocketMessage[0] |
56 | DBcur.execute(sql) |
57 | DBcon.commit() |
58 | else: |
59 | GPIO.output(DBrelais[varRelais][2], varStat) |
60 | sql = "UPDATE Relais SET Status = " + SocketMessage[1] + ", Override = 1 WHERE id = " + SocketMessage[0] |
61 | DBcur.execute(sql) |
62 | DBcon.commit() |
63 | |
64 | # Debug Messages
|
65 | local_time = time.ctime(time.time()) |
66 | print(" -> ", local_time, SocketMessage, SocketClientAddress) |
67 | |
68 | def DataBase_Client(): |
69 | while(True): |
70 | i=0 |
71 | |
72 | sql = "SELECT * FROM Schaltpunkte" |
73 | DBcur.execute(sql) |
74 | DBtimes = DBcur.fetchall() |
75 | |
76 | sql = "SELECT * FROM Relais" |
77 | DBcur.execute(sql) |
78 | DBrelais = DBcur.fetchall() |
79 | |
80 | now = datetime.datetime.now() |
81 | |
82 | for x in DBtimes: |
83 | start = now.replace(hour=x[9], minute=x[10], second=0) |
84 | if DBrelais[x[1]-1][5] == 0: |
85 | if start < now: |
86 | stop = now.replace(hour=x[11], minute=x[12], second=0) |
87 | if stop > now: |
88 | GPIO.output(DBrelais[x[1]-1][2], 0) |
89 | else: |
90 | GPIO.output(DBrelais[x[1]-1][2], 1) |
91 | else: |
92 | GPIO.output(DBrelais[x[1]-1][2], 1) |
93 | |
94 | for x in DBrelais: |
95 | i = i + 1 |
96 | state = GPIO.input(x[2]) |
97 | |
98 | sql = "UPDATE Relais SET Status = " + str(state) + " WHERE id = " + str(i) |
99 | DBcur.execute(sql) |
100 | DBcon.commit() |
101 | time.sleep(60) |
102 | |
103 | # Multithreading and Startpoint
|
104 | |
105 | t1 = threading.Thread(target=UDP_Server) |
106 | t2 = threading.Thread(target=DataBase_Client) |
107 | |
108 | t1.start() |
109 | t2.start() |
:
Bearbeitet durch User
Rene K. schrieb: > Wenn ich den UDP Server auf "localhost" lauschen lasse, bekomme ich > natürlich keine externen Pakete mehr hinein. Wenn ich eine IP vergebe, > muss ich sicherstellen das sie bei der nächsten DHCP Verhandlung wieder > die selbe bekommt. Das läßt sich natürlich sehr leicht lössen indem man > eine feste vergibt. Alternativ kannst du auch einfach auf allen Interfaces lauschen. Rene K. schrieb: > Gibt es dennoch eine Möglichkeit in Python die aktuelle IP eines > Adapters herrauszufinden? https://psutil.readthedocs.io/en/latest/#psutil.net_if_addrs
Rene K. schrieb: > Ich bedanke mich erstmal für den wahnsinnig vielen Input :-D Sehr gerne und nichts zu danken, dafür ist so ein Forum ja da! ;-) Ich habe gerade noch bezaubernden Besuch, denke aber nochmal über die Aufgabenstellung nach und schreibe heute Abend oder morgen noch etwas dazu... ;-) Könntest Du mir vielleicht noch einen Hinweis darauf geben, welche Rolle denn Deine Datenbank bei der ganzen Sache spielen soll? Dient die nur der Konfiguration der An- und Aus-Zeiten oder wird dort auch etwas (mehr oder weniger dauerhaft) aufgezeichnet bzw. gespreichert? Möchtest Du die Schaltzeiten in Deiner Datenbank lieber datums- oder wochentagsabhängig konfigurieren oder reichen Uhrzeiten aus, weil jeden Tag um dieselben Zeiten geschaltet werden soll? Übrigens: Python kann nahezu alles, natürlich auch Multithreading, Multiprocessing, asynchrones Zeugs und concurrent Futures... und das schon ganz allein nur mit seinen Standardbibliotheken. Trotzdem leidet es unter dem "Global Interpreter Lock" beim parallelen Zugriff von Threads auf gemeinsame Datenstrukturen -- aber das und die Lösungsstrategien dafür sind eher etwas für Fortgeschrittene. Insofern: herzlich willkommen und viel Vergnügen in der wunderbaren Welt von Python! ;-)
Angedacht sind die Wochentage natürlich auch. Das dann aber sekundär im Nachgang. Des weiteren beinhaltet die Tabelle noch die Temperatur-, Co2 sowie die TDS Werte für 7 Tage rückläufig. Das ich das in eine externe Datenbank (anderer Server) packe, hat den Hintergrund das dafür eine performante Lösung bereits parat steht und dort auch die Ausfallsicherheit gegeben ist. Was ich auf einer SD-Card nicht als so ganz zuverlässig erachte.
Rene K. schrieb: > Angedacht sind die Wochentage natürlich auch. Das dann aber sekundär im > Nachgang. Hm, okay, das sollten wir vielleicht gleich berücksichtigen. Ich würde das dann so machen, daß Wiederholungs- und Wochentagseinträge mit bestimmten Datumsangaben angelegt werden, etwa 1970-01-01 für Wiederholungs- und 1970-01-02 für Wochentage... > Des weiteren beinhaltet die Tabelle noch die Temperatur-, Co2 sowie die > TDS Werte für 7 Tage rückläufig. Das ich das in eine externe Datenbank > (anderer Server) packe, hat den Hintergrund das dafür eine performante > Lösung bereits parat steht und dort auch die Ausfallsicherheit gegeben > ist. Was ich auf einer SD-Card nicht als so ganz zuverlässig erachte. Sollen die Meßdaten auch benutzt werden, um automatisch etwas zu schalten? Sollen ggf. mehrere Pins geschaltet werden können?
Nur_ein_Typ schrieb: > Hm, okay, das sollten wir vielleicht gleich berücksichtigen. Ich würde > das dann so machen, daß Wiederholungs- und Wochentagseinträge mit > bestimmten Datumsangaben angelegt werden, etwa 1970-01-01 für > Wiederholungs- und 1970-01-02 für Wochentage... Ich hätte dies mit einer Matrize gemacht, wäre mir so vorgeschwebt sprich: 1 - Montag 2 - Dienstag 3 - Mittwoch 4 - Donnerstag 5 - Freitag 6 - Samstag 7 - Sonntag 8 - immer Und hätte dies dann in einem Case ausgefiltert. Die Zeitunterscheidung funktioniert schon tadellos. Die Tage fehlen halt noch. Nur_ein_Typ schrieb: > Sollen die Meßdaten auch benutzt werden, um automatisch etwas zu > schalten? Sollen ggf. mehrere Pins geschaltet werden können? Richtig, der Ph Sensor schaltet ein Magnetventil und der TDS Sensor schaltet eine extra Flächenpumpe. Diese laufen beide über 230V und können direkt über die Relais angesteuert werden. Auf meiner Platine, welche gerade bei JLCPCB schon in Bestückung ist, habe ich auch separat noch ein PWM Ausgang sowie zwei weitere freie Pins herrausgeführt - falls noch andere Ideen dazu kommen (Fütterungsautomat eventuell, Lüfter für Flächenbewegung etc... aber das ist alles noch nicht geplant)
Rene K. schrieb: > Ich hätte dies mit einer Matrize gemacht, wäre mir so vorgeschwebt > sprich: > > 1 - Montag > 2 - Dienstag > > Und hätte dies dann in einem Case ausgefiltert. Schade, es gibt kein switch/case in Python, bisher haben wir Pythonistas sowas entweder mit if/elif/else oder mit einem Dictionary (dict) gemacht -- wobei der Ansatz mit dem Dictionary deswegen so gut funktioniert hat, weil Funktionen und Klassen und Instanzen in Python erstklassige Objekte sind, die sich problemlos in einer Variablen speichern lassen. Seit dem ziemlich neuen Python 3.10 gibt es allerdings eine Möglichkeit namens "Structural Pattern Matching" -- und das ist sowas wie switch/case aus anderen Programmiersprachen, aber auf Steroiden -- und in ein paar Wochen hab vielleicht sogar ich es verstanden. ;-) > Die Zeitunterscheidung > funktioniert schon tadellos. Die Tage fehlen halt noch. Najaaa... zu den schönen Eigenschaften der Python-Standardbibliothek und vieler externer Libraries gehört es, daß die Klassen / Datentypen schon von Hause aus meistens die Operationen zulassen, mit denen der Anwender rechnet. Zum Beispiel liefern Datenbankbibliotheken, die der Standardisierung durch PEP 249 [1] folgen, für Datums- und Zeitspalten etwas zurück, das einer der Klassen im Standardmodul datetime folgt -- und ja, damit kann man vergleichen und sogar rechnen. (Wer mehr wünscht, dem sei das externe Modul dateutil [2] empfohlen.) Nun könnte man Deine Datums- und Zeitangaben auf viele Weisen in einer Datenbank speichern -- und über noch viel mehr Möglichkeiten mit Python ansprechen. Aber am Ende sind die Fragen ja a) wie bilde ich das datenbank-technisch ab, und b), wie schaffe ich es, daß mein Python-Programm erkennt, welcher Zustand gewünscht ist, natürlich jeweils anhand von Datum und Zeit. Ich ganz persönlich würde in so einem Fall einen objektrelationalen Mapper (ORM) benutzen, zum Beispiel SQLObject oder SQL-Alchemy. Andererseits weiß ich nicht, wie tief Du in die Materie einsteigen willst, ob Du eine Unabhängigkeit von Plattform und Datenbank brauchst, und insgesamt... genau. Aber selbst ohne die Feinheiten von OR-Mapping ist die Frage: möchtest Du Deine Operationen lieber in der Datenbank oder lieber im Python-Code abbilden. Eine moderne relationale Datenbank kann da ja eine Menge machen und im Wesentlichen vermutlich sogar Dein Ergebnis kalkulieren, bei PostgreSQL bin ich sicher. Deswegen frage ich mich ein bisschen, worum es Dir geht -- und was Du vielleicht bereits kannst. Und auch, wie schnell Du lernen willst. Python kann sehr einfach, aber auch enorm komplex sein. Es gibt Gründe, warum Python einerseits an einigen Schulen LOGO etc. als Einsteigersprache ablöst und es andererseits extrem beliebt ist in Bereichen wie Machine Learning und Data Science... ;-) [1] https://www.python.org/dev/peps/pep-0249/ [2] https://dateutil.readthedocs.io/en/stable/ > Nur_ein_Typ schrieb: >> Sollen die Meßdaten auch benutzt werden, um automatisch etwas zu >> schalten? Sollen ggf. mehrere Pins geschaltet werden können? > > Richtig, der Ph Sensor schaltet ein Magnetventil und der TDS Sensor > schaltet eine extra Flächenpumpe. Diese laufen beide über 230V und > können direkt über die Relais angesteuert werden. Oh, okay... Dann müssen wir darüber nachdenken, wie wo was warum geschaltet werden soll. Wenn Du eine genauere Beschreibung hast, bitte ich sehr darum. Warum die genauere Beschreibung? Nun, mein "Cron"-Thread läuft in meinem Programm immer in definierten Zeitabständen. Womöglich möchtest Du aber bestimmte Peripherie manuell schalten, also: den in der Datenbank definierten festgelegten Zeitplan überschreiben. Aber dann möchtest Du vielleicht auch nicht, daß Deine Flächenpumpe ewig läuft, wenn Du sie manuell eingeschaltet hast... aber wie lange soll sie...? > Auf meiner Platine, welche gerade bei JLCPCB schon in Bestückung ist, > habe ich auch separat noch ein PWM Ausgang sowie zwei weitere freie Pins > herrausgeführt - falls noch andere Ideen dazu kommen (Fütterungsautomat > eventuell, Lüfter für Flächenbewegung etc... aber das ist alles noch > nicht geplant) Dein Bild zeigt, wenn ich das richtig verstehe, einen "Hat", also einen Aufsatz für einen Raspberry Pi oder einen ähnlichen SBC. Vermute ich korrekt? ;-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.