User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 1:48 pm

Hi everyone,

I am pretty much a beginner and although I've been using the Raspberry Pi for a few years I've never written my own Python scripts.

Here is my problem; I am building a temperature monitoring system with 4 DS18B20 waterproof sensors. I have the sensors working fine and they all output accurate data. I also have a 20x4 LCD on the I2C bus which is configured and working OK. What I don't know how to do is add the 4 temperatures, to 4 separate lines on the LCD.

My code is below and the temperatures need to be in lines 84 to 87. I am also having problems working out how to pull the IP address and hostname of the device.

Code: Select all

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20   # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT  = 0x08  # On
#LCD_BACKLIGHT = 0x00  # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  time.sleep(E_DELAY)
  bus.write_byte(I2C_ADDR, (bits | ENABLE))
  time.sleep(E_PULSE)
  bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)

def main():
  # Main program block

  # Initialise display
  lcd_init()

  while True:

    # Send some test
    lcd_string("Out Temp:" ,LCD_LINE_1)
    lcd_string("In  Temp:      ",LCD_LINE_2)
    lcd_string("RX  Temp:      ",LCD_LINE_3)
    lcd_string("VRS Temp:      ",LCD_LINE_4)

    time.sleep(3)
  
    # Send some more text
    lcd_string("Time: %s" %time.strftime("%H:%M"),LCD_LINE_1)
    lcd_string("Date: %s" %time.strftime("%d/%m/%Y"),LCD_LINE_2)
    lcd_string("  IP:" ,LCD_LINE_3)
    lcd_string("Host:",LCD_LINE_4)

    time.sleep(3)

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x01, LCD_CMD)
Thanks in advance, I appreciate any help.

Bret

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 3:32 pm

Sorry, I wasn't clear in my last sentence - I have no issues pulling the IP address in a separate Python file but I have not been able to get it to work in this file. Everything I have tried just results in the LCD being blank.

PhatFil
Posts: 391
Joined: Thu Apr 13, 2017 3:55 pm

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 4:20 pm

hi, Ive not used a lcd with a pi or python, but have used a lot of them with arduino and esp projects.

one thing that stands out from your post tho is reference to lines 83 and 84 in a 20x4 lcd ??

20x4 reads to me as 20 characters and 4 lines??

but the blank lines your seeing is probably due to the backlight and contrast so you need only adjust the pots you wired into these circuits as per this walktrough google spat out.. https://www.raspberrypi-spy.co.uk/2012/ ... ng-python/

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 4:50 pm

Hi Phil,

Thanks for your reply. The 20x4 is 4 lines with 20 characters on each. I have the LCD working perfectly as per attached images, but I don't have the experience with Python to bring in the live data. I can do it in individual scripts but have been very unsuccessful in trying to combine the different functions in the same file.
WhatsApp Image 2018-08-18 at 17.43.19.jpeg
WhatsApp Image 2018-08-18 at 17.43.19.jpeg (155.82 KiB) Viewed 460 times
WhatsApp Image 2018-08-18 at 17.43.12.jpeg
WhatsApp Image 2018-08-18 at 17.43.12.jpeg (154.18 KiB) Viewed 460 times
Many thanks,
Bret

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 5:09 pm

I take it you have another python program that reads your DS18B20 temp sensors that works, if you post that as well I will try and combine the 2 python programs for you or at least give you some thing to start with.

I have done some thing similar my self for a project but I used RPLCD to drive the 20x4 LCD which uses a different set of commands to drive the LCD from within the python program.
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 5:44 pm

Hi Bob,

I'm not entirely sure how I got my sensors working as I've spent around 2 weeks messing around trying different things, but basically I now have 4 files, each of which takes data from a different sensor. All I do to manually checked is run each file individually.

Code: Select all

#! /bin/bash
 
# Read Temperature
tempread=`cat /sys/bus/w1/devices/28-011562bc68ff/w1_slave`
# Format
temp=`echo "scale=2; "\`echo ${tempread##*=}\`" / 1000" | bc`
 
# Output
echo "The current indoor temperature is " $temp "°C"
I also have out-temp, rx-temp and vrs-temp with the only difference being the sensor serial number. As I understand I am just reading the raw data from the sensor. It's the $temp and °C values I need to add in.

Obviously I will need this data to update too, and I'm not certain how I do this without restarting the service. Is there a loop I can do to refresh the data every few seconds, or maybe every 5 minutes?

Many thanks,
Bret

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 6:31 pm

Ok so first off I am flying blind here as I don't have an I2C LCD so I cant test the code so expect indent errors or other errors in the code.

second you need to edit the sensorids line and put your sensor numbers in there in the correct order, 1,2,3,4 is the order they need to be in to match the display order.

So this how it should work all being well............ ;)

So in main loop there is a new loop which reads the 4 sensors in order of their display and adds the result to the text for each line these results are then saved as line 1 - 4 which are what is used in the following lines when the information is written to the LCD.

the code for reading the sensors is tried and tested so should work without error unless the indentation does not match what you are using,
( I use standard 4 space indentation )

Code: Select all

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20   # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT  = 0x08  # On
#LCD_BACKLIGHT = 0x00  # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  time.sleep(E_DELAY)
  bus.write_byte(I2C_ADDR, (bits | ENABLE))
  time.sleep(E_PULSE)
  bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)
    
# read sensors 
sensorids = ["28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff"] # this line needs editing to add your actual device numbers in the correct order
sensorname = ["Out Temp:", "In  Temp:", "RX  Temp:", "VRS Temp:"]
line0 = "error"  
line1 = "error" 
line2 = "error" 
line3 = "error" 

def read_temp_raw():
    f = open(device_file, "r")
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != "YES":
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find("t=")
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        
        return temp_c
        

    

def main():
  # Main program block

  # Initialise display
  lcd_init()

  while True:
  
    #get sensor name and reading and save result with text for each line loop 
    data =""
    for sensor in range(len(sensorids)):
        device_file = "/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave"
        temperature = (read_temp())
        dtemp = "%.1f" % temperature
        result = sensorname[sensor] + (str(dtemp)) + "°C "
        line[sensor] = result
        
       
         

    # Send some test
    lcd_string(line0,LCD_LINE_1)
    lcd_string(line1,LCD_LINE_2)
    lcd_string(line2,LCD_LINE_3)
    lcd_string(line3,LCD_LINE_4)

    time.sleep(3)
  
    # Send some more text
    lcd_string("Time: %s" %time.strftime("%H:%M"),LCD_LINE_1)
    lcd_string("Date: %s" %time.strftime("%d/%m/%Y"),LCD_LINE_2)
    lcd_string("  IP:" ,LCD_LINE_3)
    lcd_string("Host:",LCD_LINE_4)

    time.sleep(3)

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x01, LCD_CMD)
if you get errors apart from indentation errors post the error message and i will try and help sort the problem. indentation errors should be self evident.
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 7:12 pm

You might get a syntaxerror: Non-ASCII character '\xc2' in file version1.py on line 118, but no encoding declared,
if you do add this line as the first line in your program after the python shebang if you have one.

Code: Select all

# -*- coding: utf-8
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 10:02 pm

Sorry for the delay, had a bit of TV and Wife time but she's asleep now! :D

I'm now getting the following errors:

Code: Select all

Traceback (most recent call last):
  File "templcd.py", line 145, in <module>
    main()
  File "templcd.py", line 118, in main
    temperature = (read_temp())
  File "templcd.py", line 92, in read_temp
    lines = read_temp_raw()
  File "templcd.py", line 86, in read_temp_raw
    f = open(device_file, "r")
NameError: global name 'device_file' is not defined
I'm only taking a guess that there should possible be a def device_file entry in there somewhere?

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 10:24 pm

Its because you while true loop is in another function I think that's what's causing the problem, the orignal version of this part of the code had the while true loop as part of the main program.

so added a global variable for this and told each def function to use it were needed. also removed an unwanted data = "" line.

Code: Select all

# -*- coding: utf-8

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20   # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT  = 0x08  # On
#LCD_BACKLIGHT = 0x00  # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  time.sleep(E_DELAY)
  bus.write_byte(I2C_ADDR, (bits | ENABLE))
  time.sleep(E_PULSE)
  bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)
    
# read sensors 
sensorids = ["28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff"] # this line needs editing to add your actual device numbers in the correct order
sensorname = ["Out Temp:", "In  Temp:", "RX  Temp:", "VRS Temp:"]
line0 = "error"  
line1 = "error" 
line2 = "error" 
line3 = "error" 
device_file = ""

def read_temp_raw():
    global device_file
    f = open(device_file, "r")
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != "YES":
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find("t=")
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        
        return temp_c
        

    

def main():
    global device_file
  # Main program block

  # Initialise display
  lcd_init()

  while True:
  
    #get sensor name and reading and save result with text for each line loop 
    
    for sensor in range(len(sensorids)):
        device_file = "/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave"
        temperature = (read_temp())
        dtemp = "%.1f" % temperature
        result = sensorname[sensor] + (str(dtemp)) + "°C "
        line[sensor] = result
        
       
         

    # Send some test
    lcd_string(line0,LCD_LINE_1)
    lcd_string(line1,LCD_LINE_2)
    lcd_string(line2,LCD_LINE_3)
    lcd_string(line3,LCD_LINE_4)

    time.sleep(3)
  
    # Send some more text
    lcd_string("Time: %s" %time.strftime("%H:%M"),LCD_LINE_1)
    lcd_string("Date: %s" %time.strftime("%d/%m/%Y"),LCD_LINE_2)
    lcd_string("  IP:" ,LCD_LINE_3)
    lcd_string("Host:",LCD_LINE_4)

    time.sleep(3)

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x01, LCD_CMD)
let the debugging commence............................... :lol:
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 10:31 pm

Debugging indeed. Almost there! :lol:

Code: Select all

 File "templcd2.py", line 113
    lcd_init()
             ^
IndentationError: unindent does not match any outer indentation level
While this is only an indentation error, it hasn't changed from the original file so unsure what's wrong. I have tried to increase the indent equally from line 113 to the end but I get different indentation errors every time. Can't seem to work out where it needs to go.

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 11:13 pm

Look at the line above that starts global.

Looks to be indented to much may be just one space, change indenting so it's all the same in the Def function.

Probably due to different editors being used.
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sat Aug 18, 2018 11:19 pm

OK, so I think I've resolved the indentation but we now seem to have another name not defined issue. I have tried to define "line" in various ways but just cause myself more errors.

Code: Select all

Traceback (most recent call last):
  File "templcd2.py", line 132, in <module>
    line[sensor] = result
NameError: name 'line' is not defined

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 8:57 am

Odd that it should get past the first 2 line statements and fail on the 3rd.

you did add all 4 sensor identification numbers to the line as I said you needed to.

try this code, if it works it will print the lines on the screen as it creates them before putting them on the LCD, I also added brackets that I think should be on the lcd_string lines that I missed out.

Code: Select all

# -*- coding: utf-8

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20   # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT  = 0x08  # On
#LCD_BACKLIGHT = 0x00  # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  time.sleep(E_DELAY)
  bus.write_byte(I2C_ADDR, (bits | ENABLE))
  time.sleep(E_PULSE)
  bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)
    
# read sensors 
sensorids = ["28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff"] # this line needs editing to add your actual device numbers in the correct order
sensorname = ["Out Temp:", "In  Temp:", "RX  Temp:", "VRS Temp:"]
line0 = "error"  
line1 = "error" 
line2 = "error" 
line3 = "error" 
device_file = ""

def read_temp_raw():
    global device_file
    f = open(device_file, "r")
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != "YES":
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find("t=")
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        
        return temp_c
        

    

def main():
  global device_file
  # Main program block

  # Initialise display
  lcd_init()

  while True:
  
    #get sensor name and reading and save result with text for each line loop 
    
    for sensor in range(len(sensorids)):
        device_file = "/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave"
        temperature = (read_temp())
        dtemp = "%.1f" % temperature
        result = sensorname[sensor] + (str(dtemp)) + "°C "
        line[sensor] = result
        print line[sensor]
       
         

    # Send some test
    lcd_string(line[0],LCD_LINE_1)
    lcd_string(line[1],LCD_LINE_2)
    lcd_string(line[2],LCD_LINE_3)
    lcd_string(line[3],LCD_LINE_4)

    time.sleep(3)
  
    # Send some more text
    lcd_string("Time: %s" %time.strftime("%H:%M"),LCD_LINE_1)
    lcd_string("Date: %s" %time.strftime("%d/%m/%Y"),LCD_LINE_2)
    lcd_string("  IP:" ,LCD_LINE_3)
    lcd_string("Host:",LCD_LINE_4)

    time.sleep(3)

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x01, LCD_CMD)
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 9:05 am

Morning Bob,

Same error I'm afraid using the updated script:

Code: Select all

Traceback (most recent call last):
  File "templcd3.py", line 148, in <module>
    main()
  File "templcd3.py", line 124, in main
    line[sensor] = result
NameError: global name 'line' is not defined
My sensors line is as follows:

Code: Select all

sensorids = ["28-0215629f5fff", "28-011562bc68ff", "28-0115629bb3ff", "28-000003eb"]
I tried quite a lot of changes last night but then reverted back to your last update as a failsafe.

Thanks,
Bret

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 11:53 am

I think the problem stems from the fact that you are calling you main loop form a def function.

so lets try making the main loop just par of the program and not a function now it might break your part of the program that drives the LCD but nothing ventured noting gained. we can always go back one step.

Code: Select all

# -*- coding: utf-8

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20   # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT  = 0x08  # On
#LCD_BACKLIGHT = 0x00  # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  time.sleep(E_DELAY)
  bus.write_byte(I2C_ADDR, (bits | ENABLE))
  time.sleep(E_PULSE)
  bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)
    
# read sensors 
sensorids = ["28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff"] # this line needs editing to add your actual device numbers in the correct order
sensorname = ["Out Temp:", "In  Temp:", "RX  Temp:", "VRS Temp:"]
line[0] = "error"  
line[1] = "error" 
line[2] = "error" 
line[3] = "error" 
device_file = ""

def read_temp_raw():
    
    f = open(device_file, "r")
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != "YES":
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find("t=")
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        
        return temp_c
        

    


try:
  # Main program block

  # Initialise display
  lcd_init()

  while True:
  
    #get sensor name and reading and save result with text for each line loop 
    
    for sensor in range(len(sensorids)):
        device_file = "/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave"
        temperature = (read_temp())
        dtemp = "%.1f" % temperature
        result = sensorname[sensor] + (str(dtemp)) + "°C "
        line[sensor] = result
        print line[sensor]
       
         

    # Send some test
    lcd_string(line[0],LCD_LINE_1)
    lcd_string(line[1],LCD_LINE_2)
    lcd_string(line[2],LCD_LINE_3)
    lcd_string(line[3],LCD_LINE_4)

    time.sleep(3)
  
    # Send some more text
    lcd_string("Time: %s" %time.strftime("%H:%M"),LCD_LINE_1)
    lcd_string("Date: %s" %time.strftime("%d/%m/%Y"),LCD_LINE_2)
    lcd_string("  IP:" ,LCD_LINE_3)
    lcd_string("Host:",LCD_LINE_4)

    time.sleep(3)





  except KeyboardInterrupt:
    pass
  finally:
    lcd_byte(0x01, LCD_CMD)
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 12:07 pm

OK, so when I try that the only error I get is:

Code: Select all

File "templcd4.py", line 149
    except KeyboardInterrupt:
         ^
A brief search shows this as being an indentation problem as it should be the same indent as "try:" so I have changed the indentation. I am now getting the old error back again:

Code: Select all

Traceback (most recent call last):
  File "templcd4.py", line 80, in <module>
    line[0] = "error"
NameError: name 'line' is not defined

User avatar
DougieLawson
Posts: 33620
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 1:08 pm

Rather than using an array of sensorids why not use glob to find them.

Code: Select all

#!/usr/bin/python3
import glob

sysDir = '/sys/bus/w1/devices/'
w1Devices = glob.glob(sysDir + '28*')
for w1Dev in w1Devices:
  w1Slave = w1Dev + '/w1_slave'
  print (w1Slave)
Microprocessor, Raspberry Pi & Arduino Hacker
Mainframe database troubleshooter
MQTT Evangelist
Twitter: @DougieLawson

2012-18: 1B*5, 2B*2, B+, A+, Z, ZW, 3Bs*3, 3B+

Any DMs sent on Twitter will be answered next month.

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 1:18 pm

You've got me there Dougie, you're talking to a complete beginner in Python. I had long term plans to have bootup and shutdown messages with this LCD too but I can't even display my temperatures. :roll:

I'm not certain but looking at the code you've suggested, would that pull the sensors in any kind of order? I have 4 lines and 4 temperature sensors, so the current script calls them in order and displays in the same order, or not as the case may be at the moment.

User avatar
DougieLawson
Posts: 33620
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 1:29 pm

Just try my small snippet of code - see what it gives you.
Microprocessor, Raspberry Pi & Arduino Hacker
Mainframe database troubleshooter
MQTT Evangelist
Twitter: @DougieLawson

2012-18: 1B*5, 2B*2, B+, A+, Z, ZW, 3Bs*3, 3B+

Any DMs sent on Twitter will be answered next month.

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 1:41 pm

Ah yes OK, so it returns the list of sensors which makes sense.

User avatar
DougieLawson
Posts: 33620
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 1:56 pm

So you can use that to avoid hard-coding sensor names in your programs. Which is a "Good thing®" as it means you don't have to muck about when you add a new sensor or replace a broken one.
Microprocessor, Raspberry Pi & Arduino Hacker
Mainframe database troubleshooter
MQTT Evangelist
Twitter: @DougieLawson

2012-18: 1B*5, 2B*2, B+, A+, Z, ZW, 3Bs*3, 3B+

Any DMs sent on Twitter will be answered next month.

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 2:22 pm

DougieLawson wrote:
Sun Aug 19, 2018 1:56 pm
So you can use that to avoid hard-coding sensor names in your programs. Which is a "Good thing®" as it means you don't have to muck about when you add a new sensor or replace a broken one.
Dougie.

I agree with what you are saying , the only reason I did it this way was so that the sensors would be read in the order required to match the order in which they would be displayed.
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

pcmanbob
Posts: 4267
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 2:26 pm

Bret

EDIT......

So the code I posted had indent errors , As I now have a spare SD card will install copy of raspbian lite and try setting it up to run your program, don't know how well this will work as I don't have an I2c LCD to attach to the pi, but I can but try.

Will let you know how I get on.

EDIT 2..............
As I suspected got an i2c i/o error but no others !

so try this code

Code: Select all

# -*- coding: utf-8

import smbus
import time

# Define some device parameters
I2C_ADDR  = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20   # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT  = 0x08  # On
#LCD_BACKLIGHT = 0x00  # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
  # Initialise display
  lcd_byte(0x33,LCD_CMD) # 110011 Initialise
  lcd_byte(0x32,LCD_CMD) # 110010 Initialise
  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off 
  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
  lcd_byte(0x01,LCD_CMD) # 000001 Clear display
  time.sleep(E_DELAY)

def lcd_byte(bits, mode):
  # Send byte to data pins
  # bits = the data
  # mode = 1 for data
  #        0 for command

  bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
  bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

  # High bits
  bus.write_byte(I2C_ADDR, bits_high)
  lcd_toggle_enable(bits_high)

  # Low bits
  bus.write_byte(I2C_ADDR, bits_low)
  lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
  # Toggle enable
  time.sleep(E_DELAY)
  bus.write_byte(I2C_ADDR, (bits | ENABLE))
  time.sleep(E_PULSE)
  bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
  time.sleep(E_DELAY)

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")

  lcd_byte(line, LCD_CMD)

  for i in range(LCD_WIDTH):
    lcd_byte(ord(message[i]),LCD_CHR)
    
# read sensors 
sensorids = ["28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff", "28-011562bc68ff"] # this line needs editing to add your actual device numbers in the correct order
sensorname = ["Out Temp:", "In  Temp:", "RX  Temp:", "VRS Temp:"]
line = ""
line0 = "error"  
line1 = "error" 
line2 = "error" 
line3 = "error" 
device_file = ""

def read_temp_raw():
    
    f = open(device_file, "r")
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != "YES":
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find("t=")
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        
        return temp_c
        

    


try:
  # Main program block

  # Initialise display
  lcd_init()

  while True:
  
    #get sensor name and reading and save result with text for each line loop 
    
    for sensor in range(len(sensorids)):
        device_file = "/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave"
        temperature = (read_temp())
        dtemp = "%.1f" % temperature
        result = sensorname[sensor] + (str(dtemp)) + "°C "
        line[sensor] = result
        print line[sensor]
       
         

    # Send some test
    lcd_string(line0,LCD_LINE_1)
    lcd_string(line1,LCD_LINE_2)
    lcd_string(line2,LCD_LINE_3)
    lcd_string(line3,LCD_LINE_4)

    time.sleep(3)
  
    # Send some more text
    lcd_string("Time: %s" %time.strftime("%H:%M"),LCD_LINE_1)
    lcd_string("Date: %s" %time.strftime("%d/%m/%Y"),LCD_LINE_2)
    lcd_string("  IP:" ,LCD_LINE_3)
    lcd_string("Host:",LCD_LINE_4)

    time.sleep(3)





except KeyboardInterrupt:
    pass
finally:
    lcd_byte(0x01, LCD_CMD)
Last edited by pcmanbob on Sun Aug 19, 2018 3:04 pm, edited 1 time in total.
Remember we want information.......................no information no help
The use of crystal balls & mind reading is not supported

User avatar
T-EGWZ34
Posts: 27
Joined: Sat Aug 18, 2018 11:39 am
Location: Bourne, UK

Re: Multiple DS18B20 Sensors on 20x4 LCD

Sun Aug 19, 2018 2:58 pm

Thanks Bob, I appreciate your help. I did get the indentation errors as per:

Code: Select all

 File "templcd5.py", line 151
    pass
       ^
IndentationError: expected an indented block
I corrected the lines it complained about and now I get:

Code: Select all

Traceback (most recent call last):
  File "templcd5.py", line 81, in <module>
    line[0] = "error"
TypeError: 'str' object does not support item assignment
I could be clutching at straws now though.

Return to “Python”

Who is online

Users browsing this forum: Google [Bot] and 16 guests