Some python coding help


#1

Hello,

So, i’m teaching myself Python and getting there bit by bit. I have a Rainbow Hat and want to create a Python program to display the temperature ONLY only when I press key A and Pressure when I press key B. If I don’t press a key the hat should do nothing.

So, somehow I need to combine the following script sections to run an a continuous loop but I’m struggling so would really appreciate it if somebody could point me in the right direction.

#displays the temperature on the LCD segments

while True:
    t = rh.weather.temperature()
    rh.display.clear()
    rh.display.print_float(t)
    rh.display.show()
    time.sleep(0.5)

#displays the pressure on the LCD segments

    p = rh.weather.pressure()
    rh.display.clear()
    rh.display.print_float(p)
    rh.display.show()
    time.sleep(0.5)

#key touch scripts, I want to use A for temperature and B for pressure
@rh.touch.A.press()
def touch_a(channel):
    rh.lights.rgb(1, 0, 0)

@rh.touch.A.release()
def release_a(channel):
    rh.lights.rgb(0, 0, 0)

@rh.touch.B.press()
def touch_b(channel):      
    rh.lights.rgb(0, 1, 0)

@rh.touch.B.release()
def release_b(channel):    
    rh.lights.rgb(0, 0, 0)

Any help will truly be appreciated

Thanks

Scott


#2

I’ve tried to format your code using backticks so we can see what’s going on, for future reference you can post code examples using the following markup:

```
your code here
```

Indenting by 4 spaces also works.

I couldn’t figure out if you’ve put your decorated functions @rh.touch.A.release() inside or underneath the while loop.

The Python decorators you’re using don’t need to be called more than once. They’re basically a way of describing to Python that “when X happens, run this function.”

In your case, you’re saying:

when I touch A
turn on the left LED

So the first thing you should be doing in your script is laying out these instructions, just as you described them in this forum:

when I touch A
display the pressure on the LCD segments

when I touch B
display the temperature on the LCD segments

Finally decorators have a weird side-effect - you can set up as many decorators as you like, but unless you add something at the bottom of your program for Python to keep itself busy with, it will simply ignore them and exit your script immediately. This could be a while True or signal.pause() depending on what you want to do there.


#3
import time
import rainbowhat as rh
a = 0
b = 1
c = 2
t = rh.weather.temperature()
p = rh.weather.pressure()
inputs = [False, False, False]

@rh.touch.press()
def touch_press(channel):
    global inputs
    inputs[channel] = True

@rh.touch.release()
def touch_release(channel):
    global inputs
    inputs[channel] = False

while True:
    if inputs[a]:
		rh.lights.rgb(1,0,0)
		rh.display.clear()
		rh.display.print_float(t)
		rh.display.show()
		time.sleep(0.1)

    if inputs[b]:
		rh.lights.rgb(0,1,0)
		rh.display.clear()
		rh.display.print_float(p/100)
		rh.display.show()
		time.sleep(0.1)

    if inputs[c]:
		rh.rainbow.clear()

#4

not sure why my indents are coming across but thats the code i ended up using, looks messy to me but it works!

thanks


#5

actually the C button doesn’t clear the screen, no idea why? also, I’m sure I could have achieved the same result with less code ? any ideas…


#6

Looks like you haven’t cleared the display for the C button, just the rainbow.

There’s definitely some code repetition, but until it’s repeated more than twice you would just be impacting readability by moving it into a function.

You also need to update the temperature/pressure variables periodically- at the moment your code will only show the temperature/pressure from the time it was first run.


#7

I tried another method

#3 button weather station
# Press A for temperature
# Press B for pressure
# Press C to stop

import signal
import rainbowhat as rh
import time

t = rh.weather.temperature()
p = rh.weather.pressure()

@rh.touch.A.press()
def touch_a(channel):
    print("Temperature in Degrees c")
    rh.lights.rgb(1,0,0)
    rh.display.clear()
    rh.display.print_float(t)
    rh.display.show()
    time.sleep(0.1)
    
@rh.touch.B.press()
def touch_b(channel):
    print("Pressure in Millibars")
    rh.lights.rgb(0,1,0)
    rh.display.clear()
    rh.display.print_float(p/100)
    rh.display.show()
    time.sleep(0.1)

@rh.touch.C.press()
def touch_c(channel):
    print("Display cleared")
    rh.lights.rgb(0,0,1)
    rh.display.clear()
    rh.display.show()
    

@rh.touch.release()
def release(channel):
    print("Button release!")
    rh.lights.rgb(0,0,0)

while True:
    for pixel in range(7):
        rh.rainbow.clear()
        rh.rainbow.set_pixel(pixel, 255, 0, 0)
        rh.rainbow.show()
        time.sleep(0.1)

signal.pause()

Any better? I’m not sure how the loop works…


#8

That’ll work, too.

You can drop the time.sleep() from the touch_a and touch_b handlers since it will do little else than prevent you tapping the button more than 10 times a second.

You can also drop signal.pause() since the while True loop will run indefinitely and anything beneath and outside of it will never be reached.

You still need to update your t and p variables. That could happen within the while True loop, or in the touch handlers.

Perhaps:

while True:
    global t, p

    t = rh.weather.temperature()
    p = rh.weather.pressure()

    for pixel in range(7)
        rh.rainbow.clear()
        rh.rainbow.set_pixel(pixel, 255, 0, 0)
        rh.rainbow.show()
        time.sleep(0.1)

Which would update the temperature and pressure approximately once every 0.1 seconds. But the temperature/pressure displayed upon the screen would not change without pressing the corresponding button again.

That’s where your earlier solution had its merits.


#9

I might use something like this:

import time
import rainbowhat as rh

A = 0
B = 1
C = 2

mode = C

@rh.touch.press()
def touch_press(channel):
    global mode
    mode = channel

while True:
    rh.display.clear()

    if mode == A:
        rh.lights.rgb(1,0,0)
        temperature = rh.weather.temperature()
        rh.display.print_float(temperature)

    if mode == B:
        rh.lights.rgb(0,1,0)
        pressure = rh.weather.pressure() / 100
        rh.display.print_float(pressure)

    if mode == C:
        rh.lights.rgb(0,0,1)

    rh.display.show()

    time.sleep(0.1)

#10

thanks Gadgetoid , that code looks sweet. I get it now! cheers


#11

Hi Gadgetoid,

I tried running your code but keep getting an error stating that…

NameError: global name ‘mode’ is not defined

I tried all sorts with the code to get it working but I’m failing badly. I thought figuring it out would help me to learn what the code is doing but I think I’ve managed to confuse myself even more.

Any idea what’s going wrong as from what I can see mode has been defined as channel?

Sorry to be a pain

Scott


#12

Whoops. See my edited example above. I forgot to declare mode before trying to use it.


#13

Brilliant, thanks, so what’s the significance of mode = 2 ?

Once again, thank you very much.

Scott


#14

Let’s use mode = C to be less cryptic.

By adding mode = C to the top, we’re declaring our intent to use the variable mode and explicitly creating it at the same time. Now that it exists global mode can find what it’s looking for without exploding.

Attempting to use a variable that hasn’t been declared will invariably result in a NameError.

I suppose mode = None may be more valid, and then adding an additional line to the code:

if mode is None:
    rh.lights.rgb(0,0,0)

Then if you should choose to clear the display with a timeout or something later, or another input, you can just set mode to None and the loop will take care of it.


#15

Ah, I see, thank you. Will play with variations until it finally sinks in!

Cheers

scott


#16

none, other than assigning a default value/channel to the mode variable when creating it, I believe.


#17

Hi all I was looking for this myself thanks for the great code.

Additionally does anyone know how to write an if statement into this for pressure changes to light up the little LEDs (Stormy, rain, dry, fair etc) and continually update when changes in pressure occur? I’ve been wanting to do this but not sure how.

Thanks


#18

Hi Mystical,

That’s such a coincidence, that’s EXACTLY what I’m trying to achieve at the moment. Problem is I only started to learn to code a month ago so it’s a steep learning curve.

Here’s the code so far, I think you will get the idea.Its a mess and doesnt work but ill figure it out eventually!

I need t figure the ranges our properly because you have 6 weather states but 7 leds! So at the moment my ranges are off which results in all the LEDs lighting except the far left one. With 1000mb only the 3 centre LEDs should light.

Have a look and let me know what you think, feel free to put me right as I’m new to it all!

import time
import rainbowhat as rh
A = 0
B = 1
C = 2
mode = C
pressure = rh.weather.pressure() / 100

@rh.touch.press()
def touch_press(channel):
	global mode
	mode = channel

while True:
	rh.display.clear()

	if mode == A:
		rh.lights.rgb(1,0,0)
		temperature = rh.weather.temperature()
		rh.display.print_float(temperature)
				
	if mode == B:
		rh.lights.rgb(0,1,0)
		pressure = rh.weather.pressure() / 100
		rh.display.print_float(pressure)
				
	if mode == C:
		rh.lights.rgb(0,0,1)
		
# Detect and Display LED 0 for DRY which is 1030 or above
		
	if pressure >= float(1029):
		pass
		rh.rainbow.set_pixel(0, 255, 0, 0)
		rh.rainbow.show()
		
# Detect and Display LED 1 for FAIR which is 1020 or above
		
	if pressure >= float(1020) <= float(1028):
		pass
		rh.rainbow.set_pixel(1, 255, 0, 0)
		rh.rainbow.show()
		
# Detect and Display LED 2,3,4 for CHANGE which is > 991 but <= 1019
		
	if pressure >= float(991) <= float(1019):
		pass
		rh.rainbow.set_pixel(2, 255, 0, 0)
		rh.rainbow.set_pixel(3, 255, 0, 0)
		rh.rainbow.set_pixel(4, 255, 0, 0)
		rh.rainbow.show()
		
# Detect and Display LED 5 for RAIN which is < 990 but 

	if pressure >= float(980) <= float(990):
		pass
		rh.rainbow.set_pixel(5, 255, 0, 0)
		
#Detect and Display LED 6 for STORMY which is 970 or below
	
	if pressure <= float(970):
		pass
		rh.rainbow.set_pixel(6, 255, 0, 0)
		
	rh.display.show()
				
	time.sleep(0.01)

cheers

Scott


#19

Hey Scott,

Glad we are on the same page so we can work this out together lol. That was very helpful thank you for the code. See my attached code below. I believe it is working, disregard my colour changes to the lights was just mucking around. If that works ok and I have not made any mistakes the temp needs to be fixed as mine is overheating from the Pi and not displaying the correct temp. There is a solution which is corrected temp. = measured temp. - (CPU temp. - measured temp.) / 2. but I need to figure out how to program that in. Let me know how you go. Dean.

import colorsys
import time
import rainbowhat as rh

A = 0
B = 1
C = 2

mode = C
pressure = rh.weather.pressure() / 100

@rh.touch.press()
def touch_press(channel):
global mode
mode = channel

while True:
rh.display.clear()

if mode == A:
    rh.lights.rgb(1,0,0)
    temperature = rh.weather.temperature()
    rh.display.print_float(temperature)
if mode == B:
    rh.lights.rgb(0,1,0)
    pressure = rh.weather.pressure() / 100
    rh.display.print_float(pressure)
if mode == C:
    rh.lights.rgb(0,0,1)
if pressure >= float(1030):
    pass
    rh.rainbow.set_pixel(0, 255, 128, 0)
    rh.rainbow.show()
elif pressure >= float(1020) <= float(1029):
    pass
    rh.rainbow.set_pixel(1, 255, 255, 0)
    rh.rainbow.show()
elif pressure >= float(1010) <= float(1019):
    pass
    rh.rainbow.set_pixel(2, 204, 204, 0)
    rh.rainbow.show()
elif pressure >= float(1000) <= float(1009):
    pass
    rh.rainbow.set_pixel(3, 0, 255, 0)
    rh.rainbow.show()
elif pressure >= float(990) <= float(999):
    pass
    rh.rainbow.set_pixel(4, 0, 128, 255)
    rh.rainbow.show()
elif pressure >= float(980) <= float(989):
    pass
    rh.rainbow.set_pixel(5, 0, 0, 255)
    rh.rainbow.show()
elif pressure <= float(970):
    pass
    rh.rainbow.set_pixel(6, 127, 0, 255)
rh.display.show()
time.sleep(0.1)

#20

That looks great Dean, will have play tonight and let you know how I get on. Think you might be missing an rh.display.show() on the bottom elif? and the bottom float should be 979 otherwise you lose the range between 970 and 980.

I’d like to have each weather state a different colour but started out with red so I could be sure of the code.

I bought a mini black hat to solve the temp problem so my rainbow hat is off the pi but I’m sure we can figure out the code between ourselves.

Speak later

Cheers

PS. Done some work on colors

Scott