GPIO lesen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

Guten Tag allerseits, ich versuche den Zustand der GPIO's zu lesen:

Code: Alles auswählen

import os
status = os.system("gpio read 26")
print(type(status))
if(status == 1):
    print("LED ein")
else:
    print("LED aus")
erzeugt die Ausgabe:

Code: Alles auswählen

0
<class 'int'>
LED aus
bei ausgeschalteter LED und

Code: Alles auswählen

1
<class 'int'>
LED aus
bei eingschalteter LED. Irgendwie gelingt es nicht auf die 1 zuzugreifen. Wo liegt der Fehler?

Danke für jede Hilfe -
Stefan
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Autsch. Verzeih, aber das ist wirklich nicht schoen, was du da treibst.

Das Ursprungsproblem besteht darin, dass du den schon lange nicht mehr empfohlenen os.system call benutzt. Und der hat einen andere Semantik, als du das glaubst: nur weil ein Programm 0 oder 1 ausgibt, heisst das nicht, das die Ausgabe dann auch magisch als Rueckgabewert von os.system auftaucht. Das ist der sogenannte Returncode, also die Art wie Linux kommuniziert, dass der Prozess ok beendet wurde. Und der ist immer 0 wenn alles glatt ging.

Aber selbst wenn du das umgehen wuerdest (mit subprocess.run zb) - das ist wirklich ganz extrem von hinten durch die Brust ins Auge. Es gibt einen ganzen Zoo von Bibliotheken, mitttels derer man auf dem PI Pins einliest, und das schneller, zuverlaessiger und eleganter als mit einem solchen Prozessaufruf.

Mein Tipp: installier dir erstmal gpiozero, und benutz das.
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

Mh, das Problem eines Unverständigen ist das er das Ganze nicht überblick und trotzdem versucht einzusteigen.

Code: Alles auswählen

import subprocess
import shlex

cmd = "gpio read 26"
args = shlex.split(cmd)

process = subprocess.run(args, stdout=subprocess.PIPE)
output = process.stdout
print(type(output))
print(output[0])
zst = output[0]
if (zst == 48):
    print("aus")
else:
    print("an")
ist die jetzige Lösung, vermutlich trotzdem noch nicht elegant :-)
gpiozero ist installiert, aber mangels fundierter englischkentnisse schwierig einzusteigen:
https://gpiozero.readthedocs.io/en/stable/faq.html
ich will mich hier nicht als Kloppie outen, sondern nur eine Lösung für das Problem suchen die ich verstehe..

Danke
Stefan
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Knollo: Das `shlex`-Modul ist nicht wirklich nötig. Warum schreibst Du da die Liste nicht einfach selbst hin?

Das was Du `process` nennst ist kein Prozess, das ist das Ergebnis eines Prozesses der bereits beendet ist.

Der Bytewert 48 ist mehr als undurchsichtig, den muss man entweder erklären, oder das nicht mit magischen Zahlen schreiben. Und was zum Henker bedeutet `zst`?

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import subprocess


def main():
    gpio_result = subprocess.run(
        ["gpio", "read", "26"], stdout=subprocess.PIPE
    )
    if int(gpio_result.stdout):
        print("an")
    else:
        print("aus")


if __name__ == "__main__":
    main()
Aber das ist wie gesagt der falsche Weg das so zu machen. Selbst ein Modul das die generische GPIO-Schnittstelle des Kernels verwendet, wäre besser als *das*.

Insbesondere bei der gezeigten Funktionalität hat das keinen Vorteil gegenüber eines einfachen Shell-Skripts (ungetestet):

Code: Alles auswählen

#!/bin/sh
if gpio read 26 > /dev/null; then
    echo 'an'
else
    echo 'aus'
fi
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

Code: Alles auswählen

from gpiozero import LED
led=LED(12)
while True:
	led.on()
	print(led.is_active)
	#'True'
	time.sleep(1)
	led.off()
	print(led.is_active)
	#'False'
	time.sleep(1)
Danke, sieht jetzt so hoffentlich besser aus:-)?
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Knollo: Grundsätzlich ja. Wobei das ja jetzt etwas anderes macht als das Programm im ersten Beitrag. Und da ist hoffentlich eine LED angeschlossen, sonst ist es natürlich irreführend die `LED`-Klasse zu verwenden und das Objekt `led` zu nennen.

Das läuft so aber nicht ohne `time` auch zu importieren. Und eine She-Bang-Zeile könnte man dem bei der Gelegenheit auch verpassen, damit man das als Programm ausführen kann.

Die Kommentare sind ein bisschen irreführend, denn in Python beziehen sich Kommentare die alleine stehen auf die nachfolgenden Code-Zeilen. Da der Kommentar jeweils kurz ist und damit die Zeilenlänge nicht ausufert, würde ich die beiden hinter den jeweiligen `print()`-Aufruf schreiben.

Eingerückt wird mit vier Leerzeichen pro Ebene. Keine Tabulatorzeichen. Die machen nur Probleme.

Dann noch das ganze in eine Hauptfunktion die nur aufgerufen wird wenn man das als Programm aufruft, und es ist vollständig. 🙂

Code: Alles auswählen

#!/usr/bin/env python3
import time

from gpiozero import LED


def main():
    led = LED(12)
    while True:
        led.on()
        print(led.is_active)  # → True
        time.sleep(1)
        led.off()
        print(led.is_active)  # → False
        time.sleep(1)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

Aha, danke - im Gesamtprojekt handelt es sich um eine Gartenbewässerung mit 6 Kreisläufen.
Auf dem Raspi-Server liegt ein php Seite mit 6 Textinput, 6 Button - "Ein" und 6 Butto -"Aus". In den Textinputform erfolgt die Eingaber der maximalen Bewässerungsdauer. Per PHP wird das Pythonsript mit Parameterübergabe($_POST) aufgerufen.
An irgendeiner Stelle soll der Zustand aller 6 Ventile geprüft werden und falls offen, dann geschlossen werden. Am Ende steht alles in einer Funktion in Form einer Schleife . Diese durchläuft ein Array mit den angeschlossenen Pins und prüft den Zustand.Bis zu dem Punkt läuft jetzt alles perfekt.

Als nächsten Schritt soll in die Webseite noch ein Timer per Javascript eingebaut werden. Das gilt es noch zu basteln.

Danke für die konstruktive Hilfe
Stefan
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Ich würde den Sprachenbruch ja direkt vermeiden und die Webanwendung in Python schreiben.
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

Hallo, Problem ist das die PHP-Seite erst nach Ablauf des php-Scriptes neu aufgerufen wird. Also, wenn der sleep() 30 Minuten läuft erfolgt anschließend die neue Webseite und der clientseitige Einbau des Timers ist somit nicht mehr sinnvoll.
Oder???
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Daher ist es ja nicht sinnvoll, mit PHP zu arbeiten, und statt dessen alles in Python zu lösen. Dann kann auch im Hintergrund etwas abgefragt werden und unabhängig davon Webseiten ausgeliefert werden.
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

??? wie kann per Javascript ein Pythonsript aufgerufen und die Variablen übergeben werden, hab ich wiedermal was verpasst???
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein, aber das kannst du auch mit PHP nicht. Was du kannst ist einen Webserver von JavaScript aus ansprechen, und den kannst du auch in Python schreiben, und damit gleichzeitig deine Bewaesserung steuern.
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

__deets__ hat geschrieben: Donnerstag 11. Juni 2020, 15:43 Nein, aber das kannst du auch mit PHP nicht. Was du kannst ist einen Webserver von JavaScript aus ansprechen
...ist Ajax das Stichwort?

und bzgl. php > Python:

Code: Alles auswählen

    <?php
    var_dump($_POST);
    if ($_POST["GPIO"] == "GPIO") {
        echo "GPIO schalten";
        shell_exec("python3 gpio.py");
    }
    ?>
...läuft so wie es soll, wobei die Möglichkeit alles in Python zu schreiben mir wirklich lieber wäre. Nun da gibt es wieder was zu tun : 8)
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mit der Wasserpumpenzange die Felgenmuttern lösen läuft auch “wie es soll”. Ist trotzdem nicht optimal. AJAX ist ein Stichwort. Aber heutzutage sind eher websockets angesagt.
Knollo
User
Beiträge: 28
Registriert: Mittwoch 10. Juni 2020, 14:44

Antworten