HTTP request senden an Homematic CCU3

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

Hallo Zusammen
Bin bei Python ein Anfänger und hätte deshalb mal eine, vermutlich triviale, Frage.

Von einem ESP8266 an dem mehrere Sensoren hängen übertrage ich die Daten in einen Raspberry 3 nodejs Server und anschließend in eine mysql Datenbank.
(dieser Weg, weil ich nirgendwo gefunden habe wie das mit Python3 geht :/ )

Andere Sensoren werden über bluetooth ausgelesen und mit einem Python Skript aufbereitet und in dieselbe Datenbank geschrieben. Aus diesem Skript möchte ich gerne einige Werte in einen Homematic Server übertragen. Das funktionert manuell vom Browser aus mit dem Aufruf:

Code: Alles auswählen

http://192.168.xx.xx:8181/egal.exe?x=dom.GetObject(Variablenname).State(wert)
Mit fehlt jetzt der Syntax wie ich das von Python aus mache.

Der Weg über

Code: Alles auswählen

try:
        import httplib2
        wert = 123,45
        
        conn = http.lib.HTTPConnection("http://192.168.xx.xx:8181")
        conn.request("/egal.exe?x=dom.GetObject(Variablenname).State(%s) )" ,(wert,))
        res = conn.getresponse()
        print("Gesendet")
  
except:
       print("Fehler beim Senden")
funktioniert leider nicht.
Hat jemand eine Idee wie das geht.
Danke im Voraus.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eagleflight: Der Code ist ja offensichtlich nicht der den Du tatsächlich ausführst. Und wenn diese unsinnige ”Fehlerbehandlung” nicht wäre, könntest Du auch selbst schon mal sehen was Dir da für eine Ausnahme um die Ohren fliegt und in welcher Zeile die ausgelöst wird.

Der Code sieht nach echt wüst zusammengeraten aus.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

Ja, halt ein erster Versuch, bis ich jetzt auf die Request Funktionen gestossen bin. Wie man das als Anfänger eben macht.
Dieser Code funktioniert jetzt, ist aber immer noch holprig :/

Code: Alles auswählen

import MySQLdb
import RPi.GPIO as GPIO
import Python_DHT
import lcddriver
import time
from miflora_poller import MiFloraPoller, MI_CONDUCTIVITY, MI_MOISTURE, MI_LIGHT, MI_TEMPERATURE, MI_BATTERY
from btlewrap.gatttool import GatttoolBackend
import requests

#GPIO Modus (BOARD / BCM)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
 
#GPIO Pins zuweisen
GPIO_Rel_1 = 19
GPIO_Rel_2 = 20
GPIO_Rel_3 = 21
GPIO_Rel_4 = 26
GPIO_LED   = 17
GPIO_pin   = 27

# GPIO einstellen 
#Richtung der GPIO-Pins festlegen (IN / OUT)
GPIO.setup(GPIO_LED, GPIO.OUT)
GPIO.setup(GPIO_Rel_1,GPIO.OUT)
GPIO.setup(GPIO_Rel_2,GPIO.OUT)
GPIO.setup(GPIO_Rel_3,GPIO.OUT)
GPIO.setup(GPIO_Rel_4,GPIO.OUT)
# und ausschalten
GPIO.output(GPIO_LED, GPIO.LOW)
GPIO.output(GPIO_Rel_1, GPIO.HIGH)
GPIO.output(GPIO_Rel_2, GPIO.HIGH)
GPIO.output(GPIO_Rel_3, GPIO.HIGH)
GPIO.output(GPIO_Rel_4, GPIO.HIGH)

# Http String : http://192.168.xx.xx:8181/egal.exe?x=dom.GetObject("Systemvariable").State(Wert)
url = "http://192.168.xx.xx:8181"
urlbegin ="/egal.exe?x=dom.GetObject("
# hier den Variablen Namen
urlmiddle = ").State("
# hier den Übergabe wert
urlend = ")"
            
hmvar1 = "'MiaFlora_Temp'"
hmvar2 = "'MiaFlora_Humidity'"
hmvar3 = "'MiaFlora_Conductivity'"
hmvar4 = "'MiaFlora_Brightness'"
hmvar5 = "'MiaFlora_Battery'"

# Daten aus der Bluetooth Schnittstelle abholen
poller = MiFloraPoller('C4:7C:8D:6A:5A:57', GatttoolBackend)
        MI_Temp       = poller.parameter_value(MI_TEMPERATURE)
        MI_Moist       = poller.parameter_value(MI_MOISTURE)
        MI_Bright      = poller.parameter_value(MI_LIGHT)
        MI_Conduct  = poller.parameter_value(MI_CONDUCTIVITY)
        MI_Batt         = poller.parameter_value(MI_BATTERY)
      

try:
           # an MSQL schicken
           
           curs.execute ("INSERT INTO BlueTooth_1(datum, temp, humidity, conductivity, brightness, battery, sender_id) Values (NOW(), %s, %s,%s ,%s, %s, %s)" ,(MI_Temp, MI_Moist, MI_Conduct, MI_Bright, MI_Batt,"BT1",))
            db.commit()
            print("DB geschrieben")
           
           # an homematic senden
                    
            # http string 5x zusammenbauen
            sysvar1 = url + urlbegin + hmvar1 + urlmiddle + str(MI_Temp) + urlend
            sysvar2 = url + urlbegin + hmvar2 + urlmiddle + str(MI_Moist) + urlend
            sysvar3 = url + urlbegin + hmvar3 + urlmiddle + str(MI_Conduct) + urlend
            sysvar4 = url + urlbegin + hmvar4 + urlmiddle + str(MI_Bright) + urlend
            sysvar5 = url + urlbegin + hmvar5 + urlmiddle + str(MI_Batt) + urlend
            
            #http request absenden         
            r1 = requests.get(sysvar1)
            r2 = requests.get(sysvar2)
            r3 = requests.get(sysvar3)
            r4 = requests.get(sysvar4)
            r5 = requests.get(sysvar5)
            
            # und schaun ob es geklappt hat
            print (r1, r2, r3, r4, r5)
            print("http gesendet", "200 = OK")
            
except:
           print("Schiefgegangen")
           
           # usw Relais schalten

Diese String Zusammenbastelei müsste noch einfacher gehen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eagleflight: Erster Versuch ist keine Erklärung, jedenfalls nicht wenn es ums Programmieren geht, denn das war sicher kein erster Versuch das zu programmieren sondern einfach nur wildes Raten, und so funktioniert das nicht.

Der jetzt gezeigte Code kommt nicht am Compiler vorbei weil der mindestens zwei Syntaxfehler enthält. Einrückung hat in Python eine Bedeutung und muss korrekt sein. Zudem wird mit vier Leerzeichen pro Einrückebene gearbeitet. Keine Tabs.

Wenn man das behebt wird grundsätzlich 'Schiefgegangen' ausgegeben weil der ``try``-Block Fehler enthält. Wenn Du nicht schon wieder diese völlig unsinnige ”Fehlerbehandlung” machen würdest, wüsstest Du bereits mehr. Wenn Du Ausnahmen nicht sinnvoll behandeln kannst, dann mach es *gar nicht* statt die ganzen Informationen über Art und Ort *jeder* Ausnahme einfach durch ein nichtssagendes 'Schiefgegangen' platt zu bügeln. Hinter ``except`` sollte immer eine oder mehrere tatsächlich erwartete Ausnahme stehen, und in dem ``except``-Block muss die dann auch *sinnvoll* behandeln werden. Ausnahme wäre es wenn man die Ausnahme mit einem ``raise`` wieder auslöst, nachdem man etwas für sämtliche Ausnahmen sinnvolles gemacht hat. Das ist sehr sehr selten. Ich glaube ich habe das noch nie gemacht. Mindestens `Exception` hatte ich hinter ``except`` stehen und das auch an einen Namen gebunden, zum Beispiel um es per `logging` zu protokollieren.

Der `GPIO.setwarnings()`-Aufruf sollte nicht sein. Statt Warnungen zu unterdrücken, sollte man deren Ursachen abstellen, dazu sind die Warnungen ja da. In der Regel ist das hier einfach nur das man mit ``try``/``finally`` sicherstellt, das am Programmende auch `GPIO.cleanup()` aufgerufen wird.

Die Module `time`, `lcddriver`, `MySQLdb`, und `Python_DHT` werden importiert aber nirgends verwendet.

Das ``as`` beim `GPIO`-Import macht keinen Sinn, weil das zum umbenennen gedacht ist, hier aber das Modul unter genau dem Namen importiert werden soll, den es tatsächlich hat.

Namen werden in Python klein_mit_unterstrichen geschrieben, ausgenommen Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Wenn man Namen durchnummeriert will man in der Regel bessere Namen verwenden oder eine Datenstruktur statt einzelner Werte. In der Regel eine Liste. Schau Dir für die Relativen-Pins beispielsweise mal an was man `setup()` und `output()` so an Argumenten übergeben kann. Ach und falls das keine Relativen-Pins sind, sondern das `Rel` im Namen für Relais stehen soll: Man erspart Lesern ratespiele wenn man keine Abkürzungen in Namen verwendet.

Die Nummer im Tabellennamen `BlueTooth_1` riecht auch komisch. Auch da nummeriert man nicht. Das wäre dann eher eine zusätzliche Spalte in der Tabelle.

Das die `sender_id` in der Datenbank eine Zeichenkette ist, halte ich für ein bisschen ungewöhnlich, denn normalerweise sind solche Spalten Zahlen die als Fremdschlüssel in eine andere Tabelle dienen.

Bei den nummerierten `hmvar1`-Namen möchte man auch eine Liste verwenden, am besten eine von Tupeln mit Variablennamen und Konstanten für die `parameter_value()`-Methode, denn dann kann man einfach eine Schleife schreiben um die Werte in eine Liste zu stecken und später dann an den Webserver zu übertragen.

Zeichenketten lassen sich in der Tat einfacher mit Werten zusammenbringen, da solltest Du vielleicht mal das Tutorial in der Python-Dokumentation durcharbeiten.

Auf Modulebene sollte nur Code stehen, der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

@blackjack

Herzlichen Dank für den umfangreichen Kommentar. Werde das mal so anpassen und dann in den nächsten Tagen wieder posten. DAnn als ganzes Skript, beim letzten war es nur ein Ausschnitt. Würde mich freuen, wenn Du bei den weiteren Code-Posting auch Deine Kommentare abgibst. Das beschleunigt das Lernen von Python ungemein.

Das sind tatsächlich meine ersten Schritte in Python und Linux. Ich habe vorher nur in Codesys Steuerungen unter Windows programmiert und das ist auch schon ein paar Jährchen her.

Ich habe am Samstag den Raspberry, Sensoren, Relaisboard und NodeMCUs bekommen installiert, die NodeMCU's geflasht und in Betrieb genommen, Breadboards zusammengebastelt usw. Der Einfachheit zunächst mal mit Tutorials aus dem Netz in Betrieb genommen und geschaut ob es geht. Im Netz gibt es viele Codeschnipsel, die zwar so irgendwie funktionieren, aber kaum zusammen passen. Daher kommen auch die unterschiedlichen Schreibweisen und Namen , die ich einfach so übernommen und zusammen kopiert habe. Eben learning by doing :) ohne die Basics wirklich durchzuarbeiten :/ Also mehr oder weniger eine erste Spielerei um zu sehen was geht.

Das eigentliche Ziel des Projektes ist es, einen Langzeitversuch über Pflanzenwachstum bei verschiedenen Düngertypen zu dokumentieren.
Dazu 10 der Bluetooth Sensoren (sender_id ist im übrigen die MAC Adresse) und 8 NodeMCU's auslesen und die erhaltenen Werte entsprechend speichern und die so erhaltenen Werte für die Relais zur Bewässerung und Beleuchtung auszuwerten.

Nachdem ich letzte Woche über Bluetooth Pflanzen Sensoren für Temperatur, Feuchtigkeit, Licht und Leitfähigkeit gestolpert bin, habe ich nun vor, etliche dieser Dinger im Raspi auszulesen, dazu noch ein paar andere Sensoren für Gase über Wifi/Esp anzukoppeln und daraus eine automatische Bewässerung, Temperierung, Beleuchtung und Langzeit Protokollierung abzuleiten. Deshalb auch die noch nicht eingebundenen Relais.

Nächster Schritt ist es jetzt den Code auf Vordermann zu bekommen, Also Main() einzubauen und die einzelnen Programmteile in Funktionen mit passender Variablenübergabe unterzubringen. Dann noch die SQL Datenbank auf eine Synology zu verlegen um die SD Karte im RASPI zu entlasten und schließlich die empfangenen Werte entsprechend zu verarbeiten und die Relais zu schalten. Am Ende erfolgt dann noch eine Visualisierung der Werte.

Neben den "Unschönheiten" die Du angeführt hast hakt es im Moment an zwei Dingen:

1. Wie generiere ich einen Webserver im Python Programm, der an Port 8000 lauscht und die Sendungen der NodeMCU's,, die in einem Zeitfenster von 10 min erfolgt, aufnimmt und mit den anderen Sensoren zusammen in die Datenbank schreibt. Aus dem Netz habe ich eine Lösung über nodejs, aber das ist Murks mit zwei verschiedenen Servern und zwei Skripten zu arbeiten :/

2. Wie generiere ich einen Timer, der zu bestimmten Zeitpunkten die verschiedenen Sensoren abfragt und in die Datenbank schreibt. Eine Abfrage auf if time.strftime("%S") = x sekunden -> schreibe in die Datenbank erscheint mir umständlich.

Gruß und nochmals Danke
Heinz
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eagleflight: Hier mal Dein Programmausschnitt überarbeitet (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import requests
from btlewrap.gatttool import GatttoolBackend
from miflora_poller import (
    MiFloraPoller, MI_CONDUCTIVITY, MI_MOISTURE, MI_LIGHT, MI_TEMPERATURE,
    MI_BATTERY,
)
from RPi import GPIO

MIFLORA_MAC_ADDRESS = 'C4:7C:8D:6A:5A:57'
RELAIS_PINS = [19, 20, 21, 26]
GPIO_LED = 17
HOMEMATIC_URL_TEMPLATE = (
    'http://192.168.xx.xx:8181/egal.exe?x=dom.GetObject("{}").State({})'
)


def main():
    GPIO.setmode(GPIO.BCM)
    try:
        GPIO.setup(GPIO_LED, GPIO.OUT)
        GPIO.setup(RELAIS_PINS, GPIO.OUT)
        
        GPIO.output(GPIO_LED, GPIO.LOW)
        GPIO.output(RELAIS_PINS, GPIO.HIGH)

        sensors = [
            (MI_TEMPERATURE, 'MiaFlora_Temp'),
            (MI_MOISTURE, 'MiaFlora_Humidity'),
            (MI_CONDUCTIVITY, 'MiaFlora_Conductivity'),
            (MI_LIGHT, 'MiaFlora_Brightness'),
            (MI_BATTERY, 'MiaFlora_Battery'),
        ]
        poller = MiFloraPoller(MIFLORA_MAC_ADDRESS, GatttoolBackend)
        values = [poller.parameter_value(parameter) for parameter, _ in sensors]
        
        cursor.execute(
            'INSERT INTO BlueTooth_1(datum, temp, humidity, conductivity,'
            ' brightness, battery, sender_id)'
            ' Values (NOW(), %s, %s, %s, %s, %s, %s)',
            values + ['BT1'],
        )
        connection.commit()
        print('DB geschrieben')

        responses = [
            requests.get(HOMEMATIC_URL_TEMPLATE.format(homematic_name, value))
            for (_, homematic_name), value in zip(sensors, values)
        ]
        print(responses)
        print('http gesendet 200 = OK')
    finally:
        GPIO.cleanup()


if __name__ == '__main__':
    main()
Ad 1.: Webserver geht in Python am einfachsten mit einem der Mikrorahmenwerke. Also beispielsweise Bottle oder Flask.

Ad 2.: Man könnte sich mit dem `sched`-Modul aus der Standardbibliothek etwas basteln, oder etwas fertiges wie APScheduler verwenden, oder aber man macht das gar nicht in Python sondern schreibt sich beispielsweise eine systemd-Timer-Unit. Notfalls auch einen Cronjob.

Was man eher nicht machen sollte ist Datums- und Zeitangaben in Zeichenketten umzuwandeln um sie dann zu vergleichen. Es gibt in der Standardbibliothek das `datetime`-Modul mit Datentypen die man vergleichen kann.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

Hey.
Ich habe noch nicht mal angefangen zu denken und Du schickst mir schon fast fertigen Code. Danke Vielmals. :)

Ein paar Fragen treten auf:
Macht es wegen der Übersichtlichkeit nicht Sinn die Einzelfunktionen, wie GPIO setzen, Sensoren auslesen, Datenbank schreiben, HTTP senden, Relais schalten in einzelne Funktionen mit "Erfolg" als Rückmeldung zu verlegen und diese nur aus der main() aufzurufen ? Damit könnte man bei mehreren Sensoren nur über die MAC Adresse als Übergabe einfach die Funktion z.B. sensoren_auslesen(MAC) mehrfach aufrufen und die Returns entsprechend verarbeiten.

Beim Schreibvorgang in die MySQl Datenbank war nach dem try: insert.. und db.commit() ein except und dann db.rollback() . Macht das nicht Sinn dafür ?

Cronjob hatte ich mir auch schon überlegt, zumal die ESP's ja in ganz unterschiedlichen Zeiten senden. Aber das wäre ja ein zweites Programm oder kann man aus main() einen anderen Task abfragen ? Wie bekommt man da die Werte in das Hauptprogramm ?

Scheduler schau ich mir mal an.

Gruß
Heinz
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

@blackjack

Habe Deinen Skriptvorschlag mal ausprobiert:
Datenbank war nicht bezeichnet:
db = MySQLdb.connect("localhost", "weather", "weather", "weather_station")
curs=db.cursor()

syntax geändert: cursor.execute() = curs.execute()
connection.committ() = db.commit()
danach war der Absatz SQL schreiben ok.

Der HTTP request läuft ebenfalls.

Nochmals Danke für die Hilfe.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@eagleflight: Funktionen sind sinnvoll. Ein `rollback` im except kann schon Sinn machen, aber dann solltest Du auch ein raise im except-Block haben, damit der Fehler trotzdem weitergereicht wird.
Den Web-Server würdest Du ja nicht über cron steuern, sondern als Service, da der Webserver ständig laufen sollte.
Warum kürzt Du `cursor` als `curs` ab?
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

Guten Abend.
Gut, dann werde ich das morgen mal machen und alles in Funktionen aufteilen damit es übersichtlicher ausschaut. Habe schon damit angefangen aber noch nicht fertig.

Zeitkritisch ist auch die Sensorabfrage. Da dieser wegen Stromverbrauch ständig schlafen geht, kann die Abfrage bis zu 30 sek dauern.

Zum Webserver die Frage. Der nodejs server empfängt ja die Daten problemlos und schreibt sie auch in die Datenbank, aber wie bekomme ich die Werte in das Python Skript damit ich damit arbeiten kann ?

Ich habe die try Funktion mal ganz rausgenommen.
Wenn ich die Datenbank in die Funktion ausgelagert habe, dann werde ich try wieder verwenden. Ein except führt zu einem db.Rollback und löscht den letzten Datensatz und gibt eine Rückmeldung über return(). Das sollte eigentlich reichen. Dann fehlt eben ein Datensatz. Bei einem Eintrag alle 10 Minuten ist das im Laufe des Jahres ja wohl nicht kritisch.

cursor gab einen syntax Fehler, curs funktioniert :)

Hier mal die zwischenversion, die schon ganz gut läuft. Die Zeitsteuerung gefällt mir noch nicht, habe aber auch keine andere gefunden.
Im Main läuft jetzt die Hauptschleife, die die Abfrage alle 10 Minuten ausführt und schreibt. Das LCD Display schaltet alle 5 sek um und ist beim startup ausgenommen, da dort ja die Hauptvariablen noch nicht definiert sind. Wie gesagt Zwischenversion. Anregungen und Kritiken willkommen.

//Heinz

Code: Alles auswählen

#!/usr/bin/env python3
import MySQLdb
import Python_DHT
import lcddriver
import time
import requests
from btlewrap.gatttool import GatttoolBackend
from miflora_poller import (
    MiFloraPoller, MI_CONDUCTIVITY, MI_MOISTURE, MI_LIGHT, MI_TEMPERATURE,
    MI_BATTERY,
)
from RPi import GPIO
from datetime import datetime, date, time

MIFLORA_MAC_ADDRESS = 'C4:7C:8D:6A:5A:57'
RELAIS_PINS = [19, 20, 21, 26]
GPIO_LED = 17
HOMEMATIC_URL_TEMPLATE = (
    'http://192.168.10.10:8181/egal.exe?x=dom.GetObject("{}").State({})'
)
# lcd display
LCD = lcddriver.lcd()



#Datenbank öffnen
db = MySQLdb.connect("localhost", "weather", "weather", "weather_station")
curs=db.cursor()

def main():
    # startupanzeige beim ersten Start
    startup = True
    print("Start des Programmes, alle 10 Minuten startet die Abfrage ")
    if (startup == True) :
           # startanzeige auf LCD, was soll man schon auf zwei Zeilen schreiben :/
           LCD.lcd_display_string("Bitte warten,   ", 1)
           LCD.lcd_display_string("Programm startet", 2)
    
    # Dauerschleife bis Abbruch durch User Ctrl-C
    while True:
        
                                 
        # jeweils alle 10 Minuten Ablauf starten, Ausführung dauert bis zu 20 sek, Sensor muss aufgeweckt werden
        sekunde = int(datetime.now().strftime("%S"))
        minute  = int(datetime.now().strftime("%M"))
        if (sekunde == 0) and (minute==0 or minute==10 or minute==20 or minute ==30 or minute==40 or minute==50) :
            # startanzeige
            startzeit = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            print("Start der Abfrage  :", startzeit)
            print()
            
            # startup variable auf false
            startup = False
                     
            #GPIO Anschlussart festlegen
            GPIO.setmode(GPIO.BCM)
            # GPIO zuweisen
            GPIO.setup(GPIO_LED, GPIO.OUT)       
            GPIO.setup(RELAIS_PINS, GPIO.OUT)
            # GPIO voreinstellen       
            GPIO.output(GPIO_LED, GPIO.HIGH)     # Funktions LED an
            GPIO.output(RELAIS_PINS, GPIO.HIGH)  # Relais ausschalten bei Programmstart
        
        
            # Bluetooth sensor(en) einlesen  
            sensors = [
                (MI_TEMPERATURE, 'MiaFlora_Temp'),
                (MI_MOISTURE, 'MiaFlora_Humidity'),
                (MI_CONDUCTIVITY, 'MiaFlora_Conductivity'),
                (MI_LIGHT, 'MiaFlora_Brightness'),
                (MI_BATTERY, 'MiaFlora_Battery'),
                 ]
            poller = MiFloraPoller(MIFLORA_MAC_ADDRESS, GatttoolBackend)
            values = [poller.parameter_value(parameter) for parameter, _ in sensors]
        
            #NodeMCU Sensoren via WiFi einlesen
            # Read_NodeMCU()    ->  muss noch gemacht werden
        
            # Werte in MSQL schreiben
            curs.execute(
               'INSERT INTO BlueTooth_1(datum, temp, humidity, conductivity,'
               ' brightness, battery, sender_id)'
               ' Values (NOW(), %s, %s, %s, %s, %s, %s)',
                 values + ['BT1'],
               )
            db.commit()
              
            # HTTP an Homematic senden
            responses = [
              requests.get(HOMEMATIC_URL_TEMPLATE.format(homematic_name, value))
              for (_, homematic_name), value in zip(sensors, values)
              ]
                
            GPIO.output(GPIO_LED, GPIO.LOW)     # Funktions LED an
            GPIO.cleanup()                      # GPIO zurücksetzen
            
            # Werte auf screen ausgeben
            Display_screen(responses,sensors,values)
            
        # Anhand der Werte Relais schalten
        # Switch_relais() ->  muss noch gemacht werden
                  
        #Werte auf LCD ausgeben und dort alle 5 sek die Anzeige wechseln
        # und nur wenn die Abfrage schonmal durchgelaufen
        if (startup == False):
           Display_lcd(responses,sensors,values,LCD)
    
# Ende der while Schleife
#------------------------
        
def Read_NodeMCU():
    return("none")

def Switch_relais():
    return("none")

def Display_screen(responses, sensors, values) :
    # Anzeige der Listenelemente
    einheit ="°C","%","µS/cm","lux","%"
    print("    Sensor                       Wert       HTTP Antwort ")
    print("-----------------------------------------------------------")
    i = 0
    for sensors in sensors:
        #zeile =(sensors[1], values[i], responses[i])
        
        print('{:25}:{:10} {:6} {}'.format(sensors[1], values[i], einheit[i], responses[i]))
        i = i+1
    print("----------------------------------------------------------")
    print()
    endezeit = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print("programmende :", endezeit,"  ")
    print()
    
def Display_lcd(responses, sensors, values,LCD) :
    # Ausgabe auf 2 Zeilen LCD Anzeige alle 5 sekunden wechseln        -> mit timer alle paar sek umschalten ???
    sekunde = int(datetime.now().strftime('%S'))
    #   NodeMCU anzeigen
    #if (sekunde == 5) :
    #   lcd.lcd_display_string("Temp    : C " + str(temperature)+"     ",1)
    #   lcd.lcd_display_string("Feuchte : % " + str(humidity)   +"     ",2)
    
    if (sekunde == 15) :
       LCD.lcd_display_string("MI Temp : C " + str(values[0])  + "   ", 1)
       LCD.lcd_display_string("MI Moist: % " + str(values[1])  + "   ", 2)
        
    if (sekunde == 20) :
       LCD.lcd_display_string("MI Conduct : " + str(values[2])  + "   ", 1)
       LCD.lcd_display_string("MI Bright  : " + str(values[3])  + "   ", 2)
       
    if (sekunde == 30) :
       LCD.lcd_display_string("MI Battery: % " + str(values[4])+"     ",1)
       LCD.lcd_display_string("                                       ",2)
    
    if (sekunde == 40) :
       LCD.lcd_display_string("MI Temp : C " + str(values[0])  + "   ", 1)
       LCD.lcd_display_string("MI Moist: % " + str(values[1])  + "   ", 2)
       
    if (sekunde == 50) :
       LCD.lcd_display_string("MI Conduct: " + str(values[2])  + "   ", 1)
       LCD.lcd_display_string("MI Bright : " + str(values[3])  + "   ", 2)

# -----------------------------------------------
# Programmende
if __name__ == '__main__':
     main()

__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

cursor gibt garantiert keinen Syntaxfehler. Bestenfalls hast du einen NameError bekommen, weil du irgendwo eine Fehlschreibung hattest.

Und die for-Schleife in Display_screen schreibt sich besser

Code: Alles auswählen

for i, sensor in enumerate(sensors):
Damit kannst du dir das ganze i=0, i += 1-Geraffel sparen.
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/pi/python/main_test2.py", line 164, in <module>
    main()
  File "/home/pi/python/main_test2.py", line 80, in main
    cursor.execute(
NameError: name 'cursor' is not defined
Fehlermeldung nach der Rückänderung in cursor. Mit curs funktioniert es, weil curs beim Aufruf der Datenbank in Zeile 28 schon zugewiesen wird

Code: Alles auswählen

curs=db.cursor()
hab das curs jetzt in cursor geändert.

Änderung der Schleife ist wirklich eleganter. Danke für den Hinweis.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Natuerlich musst du einen Namen *ueberall* gleich schreiben. Nur sollte der eben cursor sein, und nicht "curs". Das klingt eher nach einem missglueckten Fluch...
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

:) genau

Code: Alles auswählen

for i, sensor in enumerate(sensors):
funktioniert leider nicht ganz so.
Ich benutze in der folgenden Ausgabezeile ein Format:

Code: Alles auswählen

print('{:25}:{:10} {:6} {}'.format(sensors[1], values[i], einheit[i], responses[i]))
und das findet jetzt das "i" ohne Zähler nicht mehr. :/
eagleflight
User
Beiträge: 28
Registriert: Dienstag 12. Februar 2019, 19:45

So sieht der print aus:

Code: Alles auswählen

Start der Abfrage  : 2019-02-13 21:50:00

    Sensor                       Wert       HTTP Antwort 
-----------------------------------------------------------
MiaFlora_Temp            :      21.1 °C     <Response [200]>
MiaFlora_Humidity        :        50 %      <Response [200]>
MiaFlora_Conductivity    :       605 µS/cm  <Response [200]>
MiaFlora_Brightness      :       146 lux    <Response [200]>
MiaFlora_Battery         :        98 %      <Response [200]>
----------------------------------------------------------

programmende : 2019-02-13 21:50:05
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da kann es so keinen Unterschied geben mit dem i. Da hast du dann noch was anderes verbaselt.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Ein paar Anmerkungen zum Code:

`cursor` sind kurzlebige Objekte für jede Transaktion, und sollten auf keinen Fall gobale Variablen sein.
`sekunde` und `minute` werden fehlerhaft ermittelt. Es darf nur einen now-Aufruf geben. Die Zeit erst in einen String und dann wieder in eine Zahl umzuwandeln ist unsinnig kompliziert, greife direkt auf die Attribute zu. Statt der or-Kette benutze `in`.
Funktionsnamen werden wie Variablen klein_mit_unterstrich geschrieben.
In `Display_lcd` String nicht mit + zusammenstückeln, sondern str.format benutzen.
Die Klammern um die if-Bedingungen gehören weg, elif benutzen oder noch besser, das ganze mit Listen und ohne if lösen.
Direkter Indexzugriff in `Display_screen` ist ein Antipattern, benutze zip.
[pyhon] for sensor, value, einheit, response in zip(sensors, values, einheiten, responses):
print('{:25}:{:10} {:6} {}'.format(sensor, value, einheit, response))[/python]
oder noch besser gar keine parallelen Liste benutzen, sondern nur eine Liste.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eagleflight: Das ist dann eher ein Fall für die `zip()`-Funktion, ganz ohne das `i`. Indexzugriffe sind in Python recht selten nötig und oft ein Zeichen das man etwas „unpythonisches“ macht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten