Forum: PC-Programmierung [Python] Kommunikation zwischen zwei Scripten


von Rene K. (xdraconix)


Lesenswert?

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é

von Jack V. (jackv)


Lesenswert?

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
von Einer (Gast)


Lesenswert?

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.

von Rene K. (xdraconix)


Lesenswert?

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)

von Rolf M. (rmagnus)


Lesenswert?

Rene K. schrieb:
> Ich habe es jetzt mit UDP Sockets gemacht.

Hinsichtlich des von dir genannten Problems unterscheiden sich UDP und 
TCP eigentlich nicht.

von Rene K. (xdraconix)


Lesenswert?

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.

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

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
von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

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

von Sascha W. (sascha-w)


Lesenswert?

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

von imonbln (Gast)


Lesenswert?

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.

von Nur_ein_Typ (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Rene K. (xdraconix)


Lesenswert?

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
von Rolf M. (rmagnus)


Lesenswert?

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

von Nur_ein_Typ (Gast)


Lesenswert?

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! ;-)

von Rene K. (xdraconix)


Lesenswert?

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.

von Nur_ein_Typ (Gast)


Lesenswert?

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?

von Rene K. (xdraconix)


Angehängte Dateien:

Lesenswert?

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)

von Nur_ein_typ (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.