PH wert auf LCD Display anzeigen lassen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Max87
User
Beiträge: 3
Registriert: Samstag 24. März 2018, 18:07

Hallo,

Ich bin ein totaler Anfänger was programmieren angeht und versuche durch viel lesen, copy and paste und try and error mich so durchzuwurschteln :).

Ich habe es nach längerem ausprobieren geschafft mir auf einem LCD Display die Temperatur (1-Wire) anzeigen zu lassen und schalte auch eine USB Steckdosenleiste bei einem bestimmten Wert An und Aus.

Code: Alles auswählen

 
import  RPi.GPIO as GPIO
import os
import I2C_LCD_driver
import time
import sys
import i2c
import temperatur

mylcd = I2C_LCD_driver.lcd()


def Socket_1an():
    command = os.system ("sudo sispmctl -o 1")

def Socket_2an():
    command = os.system ("sudo sispmctl -o 2")

def Socket_3an():
    command = os.system ("sudo sispmctl -o 3")

def Socket_4an():
    command = os.system ("sudo sispmctl -o 4")

def Socket_1aus():
    command = os.system ("sudo sispmctl -f 1")    
    
def Socket_2aus():
    command = os.system ("sudo sispmctl -f 2")

def Socket_3aus():
    command = os.system ("sudo sispmctl -f 3")    
    
def Socket_4aus():
    command = os.system ("sudo sispmctl -f 4")
while 1:

    tempfile = open('/sys/bus/w1/devices/28-041471ce7aff/w1_slave')
    thetext = tempfile.read()
    tempfile.close()

    tempdata = thetext.split("\n")[1].split(" ")[9]
    temperature = float(tempdata[2:])
    temperature = temperature / 1000

    if temperature < 25:
        Socket_1an()

    else:
        Socket_1aus()

    mylcd.lcd_display_string("Temp: " + temperatur.temp() + " C")
 #   mylcd.lcd_display_string("PH: " + i2c()  + " PH")
    time.sleep(2)

    mylcd.lcd_clear()

#    time.sleep(2)

    mylcd.lcd_display_string("Time: %s" %time.strftime("%H:%M"), 1)
    mylcd.lcd_display_string("Date: %s" %time.strftime("%m/%d/%Y"), 2)

    time.sleep(2) 



Jetzt stehe ich allerdings vor einer für mich allein unlösbaren Aufgabe.
Ich habe ein PH Modul über i2c angeschlossen und es macht auch was es soll mit dem sample code vom Hersteller.
Allerdings würde ich mir den gemessenen PH Wert gerne auch auf das LCD Display anzeigen lassen.
Ich hoffe es hat jemand lust mir ein wenig zu helfen den sample code zu verstehen. :D

Code: Alles auswählen

import io  # used to create file streams
import fcntl  # used to access I2C parameters like addresses
import time  # used for sleep delay and timestamps
import string  # helps parse strings

class atlas_i2c:
    long_timeout = 5  # the timeout needed to query readings and calibrations
    short_timeout = 5  # timeout for regular commands
    default_bus = 1  # the default bus for I2C on the newer Raspberry Pis,
                     #certain older boards use bus 0
    default_address = 99  # the default address for the pH sensor

    def __init__(self, address=default_address, bus=default_bus):
        # open two file streams, one for reading and one for writing
        # the specific I2C channel is selected with bus
        # it is usually 1, except for older revisions where its 0
        # wb and rb indicate binary read and write
        self.file_read = io.open("/dev/i2c-" + str(bus), "rb", buffering=0)
        self.file_write = io.open("/dev/i2c-" + str(bus), "wb", buffering=0)

        # initializes I2C to either a user specified or default address
        self.set_i2c_address(address)

    def set_i2c_address(self, addr):
        # set the I2C communications to the slave specified by the address
        # The commands for I2C dev using the ioctl functions are specified in
        # the i2c-dev.h file from i2c-tools
        I2C_SLAVE = 0x703
        fcntl.ioctl(self.file_read, I2C_SLAVE, addr)
        fcntl.ioctl(self.file_write, I2C_SLAVE, addr)

    def write(self, string):
        # appends the null character and sends the string over I2C
        string += "\00"
        self.file_write.write(string)

    def read(self, num_of_bytes=31):
        # reads a specified number of bytes from I2C,
        #then parses and displays the result
        res = self.file_read.read(num_of_bytes)  # read from the board
        response = filter(lambda x: x != '\x00', res)
        # remove the null characters to get the response
        if(ord(response[0]) == 1):  # if the response isnt an error
            char_list = map(lambda x: chr(ord(x) & ~0x80), list(response[1:]))
            # change MSB to 0 for all received characters except the first
            #and get a list of characters
            # NOTE: having to change the MSB to 0 is a glitch in the raspberry
            #pi, and you shouldn't have to do this!
            return "Command succeeded " + ''.join(char_list)
            # convert the char list to a string and returns it
        else:
            return "Error " + str(ord(response[0]))

    def query(self, string):
        # write a command to the board, wait the correct timeout,
        #and read the response
        self.write(string)

        # the read and calibration commands require a longer timeout
        if((string.upper().startswith("R")) or
           (string.upper().startswith("CAL"))):
            time.sleep(self.long_timeout)
        elif((string.upper().startswith("SLEEP"))):
            return "sleep mode"
        else:
            time.sleep(self.short_timeout)

        return self.read()

    def close(self):
        self.file_read.close()
        self.file_write.close()


def main():
    device = atlas_i2c()  # creates the I2C port object, specify the address
                          # or bus if necessary
    print ">> Atlas Scientific sample code"
    print ">> Any commands entered are passed to the board via I2C except:"
    print (">> Address,xx changes the I2C address the Raspberry Pi "
    "communicates with.")
    print (">> Poll,xx.x command continuously polls the board every "
    "xx.x seconds")
    print (" where xx.x is longer than the %0.2f second "
    "timeout." % atlas_i2c.long_timeout)
    print " Pressing ctrl-c will stop the polling"

    # main loop
    while True:
        myinput = raw_input("Enter command: ")

        # address command lets you change which address
        # the Raspberry Pi will poll
        if(myinput.upper().startswith("ADDRESS")):
            addr = int(string.split(myinput, ',')[1])
            device.set_i2c_address(addr)
            print ("I2C address set to " + str(addr))

        # contiuous polling command automatically polls the board
        elif(myinput.upper().startswith("POLL")):
            delaytime = float(string.split(myinput, ',')[1])

            # check for polling time being too short,
            # change it to the minimum timeout if too short
            if(delaytime < atlas_i2c.long_timeout):
                print ("Polling time is shorter than timeout, setting "
                "polling time to %0.2f" % atlas_i2c.long_timeout)
                delaytime = atlas_i2c.long_timeout

            # get the information of the board you're polling
            info = string.split(device.query("I"), ",")[1]
            print ("Polling %s sensor every %0.2f seconds, press ctrl-c "
            "to stop polling" % (info, delaytime))

            try:
                while True:
                    print device.query("R")
                    time.sleep(delaytime - atlas_i2c.long_timeout)
            except KeyboardInterrupt:  # catches the ctrl-c command,
                                       # which breaks the loop above
                print "Continuous polling stopped"

        # if not a special keyword, pass commands straight to board
        else:
            try:
                print device.query(myinput)
            except IOError:
                print "Query failed"


if __name__ == '__main__':
    main()

Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Statt acht Funktionen mit leichten Abwandlungen, schreibt man eine Funktion mit Parametern. Die Ausgabe der aktuellen Zeit ist falsch, Da Du sie zweimal abfragst und es so zu Inkonsistenzen kommen kann.

Code: Alles auswählen

import I2C_LCD_driver
import subprocess
from datetime import datetime as DateTime

def switch_socket(num, switch_on):
    subprocess.call(["sudo", "sispmctl", "-o" if switch_on else "-f", str(num)])

def get_temperature():
    with open('/sys/bus/w1/devices/28-041471ce7aff/w1_slave') as data:
        _, temperature = data.read().rsplit('=', 1)
    return 0.001 * float(temperature)

def main():
    mylcd = I2C_LCD_driver.lcd()
    while True:
        temperature = get_temperature()
        switch_socket(1, switch_on=temperature < 25)
        mylcd.lcd_display_string("Temp: {:.2f}C".format(temperatur), 1)
        # mylcd.lcd_display_string("PH: {} PH".format(??), 2)
        time.sleep(2)

        mylcd.lcd_clear()
        now = DateTime.now()
        mylcd.lcd_display_string("Time: {:%H:%M}".format(now), 1)
        mylcd.lcd_display_string("Date: {:%m/%d/%Y}".format(now), 2)
        time.sleep(2)

if __name__ == "__main__":
    main()

Die Klasse `atlas_i2c` hat ein paar komische Eigenheiten. Warum werden zwei File-Objekte erzeugt? Defaults sowohl als Klassenvariablen (sollten wohl eher Konstanten sein) als auch als Defaultwerte von __init__-Parametern zu benutzen, ist verwirrend, weil nur zweiteres benutzt wird. `read` sollte bei einem Fehler eine Exception werfen und nicht irgendwie codierte Strings als Ergebnis. Die `if`-Abfragen haben viel zu viele Klammern. Ansonsten müßte man doch um Werte abzufragen nur »device.query("R")« aufrufen:

Code: Alles auswählen

import fcntl
import time

class AtlasI2C:
    def __init__(self, address=99, bus=1):
        """
        the specific I2C channel is selected with bus
        it is usually 1, except for older revisions where its 0
        """
        self.bus = open("/dev/i2c-{}".format(bus), "rwb")
        self.set_i2c_address(address)

    def set_i2c_address(self, addr):
        """
        set the I2C communications to the slave specified by the address
        """
        I2C_SLAVE = 0x703
        fcntl.ioctl(self.bus, I2C_SLAVE, addr)

    def write(self, string):
        """sends the string over I2C"""
        self.bus.write(string + b"\0")
        self.bus.flush()

    def read(self, num_of_bytes=31):
        """reads a specified number of bytes from I2C"""
        res = self.bus.read(num_of_bytes)  # read from the board
        if ord(res[0]) != 1:
            raise IOError("Lesefehler")
        return res[1:].rstrip(b'\0')

    def query(self, string, wait_time=5):
        """write a command to the board, wait the correct timeout,
        and read the response"""
        self.write(string)
        time.sleep(wait_time)
        return self.read()

    def close(self):
        self.bus.close()


def main():
    device = AtlasI2C(address=99)
    print(device.query(b"I"))
    print(device.query(b"R"))

if __name__ == '__main__':
    main()
Max87
User
Beiträge: 3
Registriert: Samstag 24. März 2018, 18:07

Vielen Dank für die guten Hinweise. Die Funktion mit Parametern sieht natürlich viel besser aus. Auch das mit der Ausgabe der Zeit habe ich verstanden. Beim ausführen des codes für I2C bekomme ich allerdings mehrere Fehlermeldungen.

Traceback (most recent call last):
File "test2.py", line 49, in <module>
main()
File "test2.py", line 45, in main
print(device.query(b"I"))
File "test2.py", line 35, in query
self.write(string)
File "test2.py", line 22, in write
self.bus.write(string + b"\0")
IOError: [Errno 9] Bad file descriptor

Der sample Code läuft zwar einwandfrei ich kann verschiedene Behfehle in der Console eingeben und bekomme auch die entsprechende Antwort. Mir ist nur nicht klar wie ich die beiden Scripte mit einander laufen lassen kann und mir alles anstatt in der Console auf dem LCD Display anzeigen lassen kann.
Max87
User
Beiträge: 3
Registriert: Samstag 24. März 2018, 18:07

Hallo,
Nach 2 Tagen verzweifeln hab ich es hinbekommen auch wenn ich sicher bin das es nicht ganz ok ist :D. Was ich nicht hinbekomme ist, dass das Script direkt beim öffnen loslegt sonder ich muss nach dem starten immer z.b Poll,5 eingeben. Vielleicht kann mir auch dazu jemand einen Tipp geben? 8)

Code: Alles auswählen

import I2C_LCD_driver
import io # used to create file streams import fcntl # used to access I2C parameters like addresses import time # used for sleep delay and timestamps 
import string # helps parse strings import subprocess
import time
import subprocess
import fcntl

class atlas_i2c:
    long_timeout = 5  # the timeout needed to query readings and calibrations
    short_timeout = 5  # timeout for regular commands
    default_bus = 1  # the default bus for I2C on the newer Raspberry Pis,
                     #certain older boards use bus 0
    default_address = 99  # the default address for the pH sensor

    def __init__(self, address=default_address, bus=default_bus):
        # open two file streams, one for reading and one for writing
        # the specific I2C channel is selected with bus
        # it is usually 1, except for older revisions where its 0
        # wb and rb indicate binary read and write
        self.file_read = io.open("/dev/i2c-" + str(bus), "rb", buffering=0)
        self.file_write = io.open("/dev/i2c-" + str(bus), "wb", buffering=0)

        # initializes I2C to either a user specified or default address
        self.set_i2c_address(address)

    def set_i2c_address(self, addr):
        # set the I2C communications to the slave specified by the address
        # The commands for I2C dev using the ioctl functions are specified in
        # the i2c-dev.h file from i2c-tools
        I2C_SLAVE = 0x703
        fcntl.ioctl(self.file_read, I2C_SLAVE, addr)
        fcntl.ioctl(self.file_write, I2C_SLAVE, addr)

    def write(self, string):
        # appends the null character and sends the string over I2C
        string += "\00"
        self.file_write.write(string)

    def read(self, num_of_bytes=31):
        # reads a specified number of bytes from I2C,
        #then parses and displays the result
        res = self.file_read.read(num_of_bytes)  # read from the board
        response = filter(lambda x: x != '\x00', res)
        # remove the null characters to get the response
        if(ord(response[0]) == 1):  # if the response isnt an error
            char_list = map(lambda x: chr(ord(x) & ~0x80), list(response[1:]))
            # change MSB to 0 for all received characters except the first
            #and get a list of characters
            # NOTE: having to change the MSB to 0 is a glitch in the raspberry
            #pi, and you shouldn't have to do this!
            return "PH " + ''.join(char_list)
            # convert the char list to a string and returns it
        else:
            return "Error " + str(ord(response[0]))

    def query(self, string):
        # write a command to the board, wait the correct timeout,
        #and read the response
        self.write(string)

        # the read and calibration commands require a longer timeout
        if((string.upper().startswith("R")) or
           (string.upper().startswith("CAL"))):
            time.sleep(self.long_timeout)
        elif((string.upper().startswith("SLEEP"))):
            return "sleep mode"
        else:
            time.sleep(self.short_timeout)

        return self.read()

    def close(self):
        self.file_read.close()
        self.file_write.close()

def switch_socket(num, switch_on):
        subprocess.call(["sudo", "sispmctl", "-o" if switch_on else "-f", str(num)])

def get_temperature():
        with open('/sys/bus/w1/devices/28-041471ce7aff/w1_slave') as data:
            _, temperature = data.read().rsplit('=', 1)
        return 0.001 * float(temperature)

def main():
    mylcd = I2C_LCD_driver.lcd()
    device = atlas_i2c()  # creates the I2C port object, specify the address
                          # or bus if necessary
    print ">> Atlas Scientific sample code"
    print ">> Any commands entered are passed to the board via I2C except:"
    print (">> Address,xx changes the I2C address the Raspberry Pi "
    "communicates with.")
    print (">> Poll,xx.x command continuously polls the board every "
    "xx.x seconds")
    print (" where xx.x is longer than the %0.2f second "
    "timeout." % atlas_i2c.long_timeout)
    print " Pressing ctrl-c will stop the polling"

    # main loop
    while True:
        # mylcd.lcd_clear()
        # address command lets you change which address
        # the Raspberry Pi will pol

        myinput = raw_input("Enter command: ") 
        if(myinput.upper().startswith("ADDRESS")):
            addr = int(string.split(myinput, ',')[1])
            device.set_i2c_address(addr)
            print ("I2C address set to " + str(addr))
           # mylcd.lcd_display_string("I2C " + str(addr))
        # contiuous polling command automatically polls the board
        elif(myinput.upper().startswith("POLL")):
            delaytime = float(string.split(myinput, ',')[1])

            # check for polling time being too short,
            # change it to the minimum timeout if too short
            if(delaytime < atlas_i2c.long_timeout):
                print ("Polling time is shorter than timeout, setting "
                "polling time to %0.2f" % atlas_i2c.long_timeout)
                delaytime = atlas_i2c.long_timeout

            # get the information of the board you're polling
            info = string.split(device.query("I"), ",")[1]
            print ("Polling %s sensor every %0.2f seconds, press ctrl-c "
            "to stop polling" % (info, delaytime))
            # mylcd.lcd_display_string("Polling %s sensor every %0.2f seconds, press ctrl-c "
            # "to stop polling" % (info, delaytime))
            try:
                while True:
                    print device.query("R")
                    temperature = get_temperature()
                    mylcd.lcd_display_string(device.query("R"))
                    mylcd.lcd_display_string("Temp: {:.2f}C".format(temperature), 2)
                    switch_socket(1, switch_on=temperature < 25)
                    time.sleep(delaytime - atlas_i2c.long_timeout)
            except KeyboardInterrupt:  # catches the ctrl-c command,
                                       # which breaks the loop above
                print "Continuous polling stopped"

        # if not a special keyword, pass commands straight to board
        else:
            try:
                print device.query(myinput)
            except IOError:
                print "Query failed"

if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Max87: Du mußt halt all das, was nur im Beispiel-Code sinnvoll war, löschen und durch die direkte Abfrage ersetzen. Im Wesentlichen bleibt nur die innerste while-Schleife übrig.

Code: Alles auswählen

def main():
    mylcd = I2C_LCD_driver.lcd()
    device = atlas_i2c()
    while True:
        temperature = get_temperature()
        mylcd.lcd_display_string(device.query("R"))
        mylcd.lcd_display_string("Temp: {:.2f}C".format(temperature), 2)
        switch_socket(1, switch_on=temperature < 25)
        time.sleep(3)
Antworten