Bottom Page

Thread Rating:
  • 2 Vote(s) - 3.5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
 Check presence of a file
#1
Hi All,
I have concocted a piece of coding to read and log temperatures from DS18B20 sensors.

def read_ds18b20(sensorid):     #Functon reads DS15B20 sensor
        tfile = open("/sys/bus/w1/devices/"+ sensorid +"/w1_slave")
        text = tfile.read()
        # Close file after reading it.
        tfile.close()
        # Select 21st word starting from 0.
        sensor_data =text.split(" ")[20] 
        # Remove 't=' and make floating.
        temp_raw = float(sensor_data[2:])
        #print (temp_raw)
        temp = temp_raw / 1000
        digitemp = '%.1f' % temp    #round to 1 decimal
        #print ("digitemp = " + digitemp)
        return digitemp
The ID's (like 28-000009adc801) of the sensors appear as files in /sys/bus/w1/devices/ .


I use the following to read the multiple sensors:
# Execute DS18B20 function for sensor ID's below.
    temp1 = float(read_ds18b20('28-000009aeba12'))      #Motor 1 temp.
    temp2 = float(read_ds18b20('28-000009aeba12'))      #Motor 2 temp.
    temp3 = float(read_ds18b20('28-000009adc801'))      #outside temp.
If there is a change of motor and thus another sensor id, the program halts with "file not found" because the new ID has no file in /sys/bus/w1/devices/.

How can i make the program continue without intervention?

Any comments on the construction of the function are also welcomed.
Rgds Steffen
Quote
#2
There are 2 ways you can do this:
1) Check if the file exist and then open it (typical from other languages like C)
2) try to open it and capture the the error ("ask forgiveness not permission", normal in languages with exceptions like python)
The 2nd one has also big advantages when you add security concerns...
In this case your code can be rewritten as:
def read_ds18b20(sensorid):
    """
    Functon reads DS15B20 sensor
    """
    device = f"/sys/bus/w1/devices/{sensorid}/w1_slave"
    try:
        # No need to close, the with block does it for us...
        with open(device, 'rt') as tfile:
            text = tfile.read()
    except FileNotFoundError:
        # Things to do when the sensor id is invalid...
        # I just going to return None.
        return None
    except PermissionError:
        # The file exists, but the user is not in the right group
        print(f"You must be in the right group to access:\n{device}")
        # Just continue with the error...
        raise
    # Ok, everything was correct, let's continue
    # Select 21st word starting from 0.
    sensor_data =text.split(" ")[20] 
    # Remove 't=' and make floating.
    temp = float(sensor_data[2:]) / 1000
    #return rounded to 1 decimal
    return round(temp, 1)
I am using 2 features that are from recent versions of python, the string interpolation f"bla bla {variable} bla bla" that you can change it to "bla bla {} bla bla".format(variable) and the new exceptions FileNotFoundError and PermissionError... if your python is too old and returns other exception, just experiment from the terminal and use the proper ones...
ThiefOfTime and buran like this post
Quote
#3
Hi killerrex,

Tks for your quick reply.
Tried your solution but i run into an syntax error on

device = f"/sys/bus/w1/devices/{sensorid}/w1_slave"
^

i could not find any typos so somthing else must be wrong.
I run python 3.5.3 and faithfully updated/upgraded so i think i'm ok there.

Any thoughts?

Steffen
buran wrote May-21-2018, 09:40 AM:
Please, use proper tags when post code, traceback, output, etc.
See BBcode help for more info.

Also please, always post the entire traceback that you get. We need to see the whole thing. Do not just give us the last line.
Take a time to read What to include in a post
Quote
#4
(May-20-2018, 05:58 PM)killerrex Wrote: I am using 2 features that are from recent versions of python, the string interpolation f"bla bla {variable} bla bla" that you can change it to "bla bla {} bla bla".format(variable) and the new exceptions FileNotFoundError and PermissionError... if your python is too old and returns other exception, just experiment from the terminal and use the proper ones...
f-strings are 3.6+ feature, so with 3.5 you are not OK to use them
Quote
#5
Thanks everybody and my apologies for the confusion caused by my unfamiliarity with the BB.

I got the problem solved with thanks to killirrex for putting me on the right track.


The whole scripot now looks like:

#!/usr/bin/env python

      #Versie 2.3; 21mei2018
      #Dit programma leest elke sensor apart uit en slaat aan het einde
      #de resultaten op in een csv file.
      #Importeer benodigde libraries.
      #21/05File not found opgelost.

import sys
import time
import csv
import os
import spidev
import RPi.GPIO as GPIO

spi = spidev.SpiDev()
spi.open(0,0)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(22,GPIO.IN)
GPIO.setup(27,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)

def read_MCP(sensorid):         #Function reads MCP3008.
        adc = spi.xfer2([1,(8+sensorid)<<4,0],20000)
        adcread = ((adc[1]&3) << 8) + adc[2]
        return adcread

def read_ds18b20(sensorid):     #Function reads DS18B20 sensor.
        device="/sys/bus/w1/devices/"+ sensorid +"/w1_slave"
        try:
            with open (device) as tfile:
                text=tfile.read()
        except FileNotFoundError:
            GPIO.output(25,True)
            notemp = 9999
            return notemp
        sensor_data =text.split(" ")[20]    #Select 21st word start with zero.
        # Haal 't=' weg en maak floating
        temp_raw = float(sensor_data[2:])   #Remove 'T="and make floating.    
        #print (temp_raw)
        temp = temp_raw
        digitemp = '%.1f' % temp            #Round to one decimal.
        return digitemp
    
datum = (time.strftime('%d/%m/%Y'))     # Define date/time variables.
tijd = (time.strftime('%H:%M:%S'))

GPIO.output(25,False)                   #reset FileNotFound LED

while True:

    while True:

        time.sleep(1)
        if GPIO.input(22):          #Contact key is ON
            GPIO.output(27,True)    #Turn on LED indicator.
            break
        else:                       #Contact key is dus OFF
            GPIO.output(27,False)   #LED indicator OFF
            print ('Schakelaar is UIT')

# Checked water level BB with key OFF
                #Check watersensor SB, channel0 of ADC.    
            level = read_MCP(0)
            level_SB = round(level,1)
            print (level_SB)
            
# Turn on the SB pump if value > 510.
            if (level_SB) > 510:
                GPIO.output(23,GPIO.HIGH)    #LED/pomprelais SB ON.
            else:
                GPIO.output(23,GPIO.LOW)     #LED/pomprelais SB OFF.

               #Check watersensor BB, channel1 of ADC.
            level =read_MCP(1)
            level_BB= round(level,1)
            print (level_BB)
            
# Turn on the BB pump if value > 510
            if (level) > 510:
                GPIO.output(24,GPIO.HIGH)    #LED/pomprelais BB ON.
            else:
                GPIO.output(24,GPIO.LOW)     #LED/pomprelais BB OFF.            

# Exec DS18B20 function for sensorID's below.
    temp1 = float(read_ds18b20('28-000009aeba12'))      #Motor 1
    temp2 = float(read_ds18b20('28-000009aeba12'))      #Motor 2
    temp3 = float(read_ds18b20('28-000009adc801'))      #Buitentemperatuur

# Define 'lijst'.   
    lijst = [0,0,0,0,0,0,0,0]

# Exec function 'read_temp36' for each ADC channel.
    for offset in range(0,8):
        adcread = read_MCP(offset)
        print (adcread)
        result = (adcread*330)/float(1024)
        lijst[offset] = adcread
        offset +=1              #Decrease offset by 1
       
    data = [datum,tijd,temp1,temp2,temp3,round(lijst[0],1),round(lijst[1],1),round((((lijst[2]*3.3/1024)-0.52)/0.08),1),round((((lijst[3]*3.3/1024)-0.52)/0.08),1)]

# lijst 0 is watersensor SB, lijst 1 is idem BB, lijst 3 is stroom SB, lijst 4 is stroom BB

# Turn on the SB pump if value > 510.    if (lijst[0]) > 510:
        GPIO.output(23,GPIO.HIGH)       #LED/pomprelais SB ON
    else:
        GPIO.output(23,GPIO.LOW)        #LED/pomprelais SB ON

# Turn on the BB pump if value > 510.
    if (lijst[1]) > 510:
        GPIO.output(24,GPIO.HIGH)       #LED/pomprelais BB ON
    else:
        GPIO.output(24,GPIO.LOW)        #LED/pomprelais BB ON

    print (data)

        #Output naar csv file
    #csvfile = "/home/pi/programs/testdata.csv"
    #with open (csvfile,'a') as output:
    #    writer = csv.writer(output, delimiter = ',' ,lineterminator = '\n')
    #    writer.writerow(data)
        
    time.sleep(0.5)
Now i will try to get a 4 x 20 LCD screen incorporated to display various values.
Should i do that in the same script or write a new one and somehow point it??

Tks Steffen
Quote
#6
It is better always to keep the code in a single point (don't repeat yourself) in python you can always use the import machinery to do this.
The only problem is that when you "import" the scripts is executed, so it is common to guard the run part with the __main__ trick.
In your case, there is some mix between proper functions and data, but if you modify the read_MCP to request the spi from the arguments you can store the 2 functions in a separate file:
#!/usr/bin/env python

# This shall be in a file at the same folder as all your programs
# I used low_level.py, but you can have more imagination than me...

import RPi.GPIO as GPIO


def read_MCP(spi, sensorid):         #Function reads MCP3008.
        adc = spi.xfer2([1,(8+sensorid)<<4,0],20000)
        adcread = ((adc[1]&3) << 8) + adc[2]
        return adcread
 

def read_ds18b20(sensorid):     #Function reads DS18B20 sensor.
        device="/sys/bus/w1/devices/"+ sensorid +"/w1_slave"
        try:
            with open (device) as tfile:
                text=tfile.read()
        except FileNotFoundError:
            GPIO.output(25,True)
            notemp = 9999
            return notemp
        sensor_data =text.split(" ")[20]    #Select 21st word start with zero.
        # Haal 't=' weg en maak floating
        temp_raw = float(sensor_data[2:])   #Remove 'T="and make floating.    
        #print (temp_raw)
        temp = temp_raw
        digitemp = '%.1f' % temp            #Round to one decimal.
        return digitemp

def _test():
    # Define here if you want some simple tests to check your functions
    # You can run it as python low_level.py
    pass

if __name__ == '__main__':
    # This part runs only when this script is the main script, not when imported from other
    _test()
Then in your other scripts can import from this other -imagine you call it low_level.py) with from low_level import read_MCP, read_ds18b20
Now your main script will be:
#!/usr/bin/env python
 
      #Versie 2.3; 21mei2018
      #Dit programma leest elke sensor apart uit en slaat aan het einde
      #de resultaten op in een csv file.
      #Importeer benodigde libraries.
      #21/05File not found opgelost.
 
import sys
import time
import csv
import os
import spidev
import RPi.GPIO as GPIO

from low_level import read_MCP, read_ds18b20

spi = spidev.SpiDev()
spi.open(0,0)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(22,GPIO.IN)
GPIO.setup(27,GPIO.OUT)
GPIO.setup(23,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)
     
datum = (time.strftime('%d/%m/%Y'))     # Define date/time variables.
tijd = (time.strftime('%H:%M:%S'))
 
GPIO.output(25,False)                   #reset FileNotFound LED
 
while True:
 
    while True:
 
        time.sleep(1)
        if GPIO.input(22):          #Contact key is ON
            GPIO.output(27,True)    #Turn on LED indicator.
            break
        else:                       #Contact key is dus OFF
            GPIO.output(27,False)   #LED indicator OFF
            print ('Schakelaar is UIT')
 
# Checked water level BB with key OFF
                #Check watersensor SB, channel0 of ADC.    
            level = read_MCP(spi, 0)
            level_SB = round(level,1)
            print (level_SB)
             
# Turn on the SB pump if value > 510.
            if (level_SB) > 510:
                GPIO.output(23,GPIO.HIGH)    #LED/pomprelais SB ON.
            else:
                GPIO.output(23,GPIO.LOW)     #LED/pomprelais SB OFF.
 
               #Check watersensor BB, channel1 of ADC.
            level =read_MCP(1)
            level_BB= round(level,1)
            print (level_BB)
             
# Turn on the BB pump if value > 510
            if (level) > 510:
                GPIO.output(24,GPIO.HIGH)    #LED/pomprelais BB ON.
            else:
                GPIO.output(24,GPIO.LOW)     #LED/pomprelais BB OFF.            
 
# Exec DS18B20 function for sensorID's below.
    temp1 = float(read_ds18b20('28-000009aeba12'))      #Motor 1
    temp2 = float(read_ds18b20('28-000009aeba12'))      #Motor 2
    temp3 = float(read_ds18b20('28-000009adc801'))      #Buitentemperatuur
 
# Define 'lijst'.   
    lijst = [0,0,0,0,0,0,0,0]
 
# Exec function 'read_temp36' for each ADC channel.
    for offset in range(0,8):
        adcread = read_MCP(spi, offset)
        print (adcread)
        result = (adcread*330)/float(1024)
        lijst[offset] = adcread
        offset +=1              #Decrease offset by 1
        
    data = [datum,tijd,temp1,temp2,temp3,round(lijst[0],1),round(lijst[1],1),round((((lijst[2]*3.3/1024)-0.52)/0.08),1),round((((lijst[3]*3.3/1024)-0.52)/0.08),1)]
 
# lijst 0 is watersensor SB, lijst 1 is idem BB, lijst 3 is stroom SB, lijst 4 is stroom BB
 
# Turn on the SB pump if value > 510.    if (lijst[0]) > 510:
        GPIO.output(23,GPIO.HIGH)       #LED/pomprelais SB ON
    else:
        GPIO.output(23,GPIO.LOW)        #LED/pomprelais SB ON
 
# Turn on the BB pump if value > 510.
    if (lijst[1]) > 510:
        GPIO.output(24,GPIO.HIGH)       #LED/pomprelais BB ON
    else:
        GPIO.output(24,GPIO.LOW)        #LED/pomprelais BB ON
 
    print (data)
 
        #Output naar csv file
    #csvfile = "/home/pi/programs/testdata.csv"
    #with open (csvfile,'a') as output:
    #    writer = csv.writer(output, delimiter = ',' ,lineterminator = '\n')
    #    writer.writerow(data)
         
    time.sleep(0.5)
You now can re-use that functions from other scripts. In general is always better to keep the things in a single part than abuse from the copy-paste or create a gargantuous script that tries to do everything and each time you try to fix one of the functions you break other three (Keep it simple....)
If you finish having too many small functions and want to organise them properly. you can create easily a package... but that is more advanced python.
Quote
#7
I followed killerex'es suggestion and made base.py

#!/bin/python

# baseprogram; calls the function status from key_check.py

import sys
import os
import time

from key_check import status

while True:
    
    on_or_off=status
    print (on_or_off)
    time.sleep(3)
and key_check.py that containes the function 'status'


#!/bin/python
 
#import RPi.GPIO as GPIO
import time
import os 

#GPIO.setup(22, GPIO.IN)

def status():
    foo = 5     # Lees de status van de GPIO pin uit.
    if (foo) == 4:
      #Schakelaar is AAN.
      key = 'ON'
    else:
      #Schakelaar is UIT.
      key = 'OFF'
    return (key)
      
datum = (time.strftime('%d/%m/%Y'))
#print(datum)
#keystat = status()
#print (keystat)

def _test():

   pass
 
if __name__ == '__main__':
    # This part runs only when this script is the main script, not when imported from other
    _test()

Running key_check on its own is OK.
When i call keycheck.status i get the following response:

Output:
Python 3.6.4 >>> %Run base.py <function status at 0x037E4E40> <function status at 0x037E4E40> KeyboardInterrupt: Forced reset >>>
Any ideas about this?
As you will probably have noticed i am very much a novice, but i'll learn.
is there a site where i can learn about those situation?
Quote
#8
You need to call the functions, remember that in python a function is an object like any other, so when you write:
    on_or_off=status
    print (on_or_off)
Is not different to:
    on_or_off=5
    print (on_or_off)
If you change to:
    # Notice that here I call the function, not just store it in a variable
    on_or_off=status()
    print (on_or_off)
Quote
#9
Tks for the reply. I forgot to put the brackets after the function name.
A step ahead again tks to you. i'l keep plodding on.
Quote

Top Page

Possibly Related Threads...
Thread Author Replies Views Last Post
  Checking the presence of label using pywinauto module Malt 0 156 Jul-26-2019, 09:06 AM
Last Post: Malt
  how to check for file type in a folder SoulsKeeper 4 870 Sep-15-2018, 02:48 PM
Last Post: ichabod801
  [split] Check presence of a file pascale 25 2,299 Jul-08-2018, 12:23 PM
Last Post: pascale
  Check CSV file for value Brian1210 5 1,432 Sep-29-2017, 09:18 PM
Last Post: nilamo
  check if file exists. ian 6 3,096 Jul-15-2017, 09:34 AM
Last Post: wavic
  How to stop inputs on the presence of CR sylas 21 4,917 Apr-20-2017, 04:56 PM
Last Post: Kebap
  Check to see if file is submitted in correct folder DBS 9 3,144 Oct-21-2016, 07:06 PM
Last Post: Larz60+

Forum Jump:


Users browsing this thread: 1 Guest(s)