LED Shim as a thermometer

I have a BMP680 setup as a weather clock. I show the day, date, time, temp, humidity, pressure and the UV index in a continuously scrolling message on an RGB 8 x 8 LED matrix (sense hat). The color of the message elements change based on the measurements. The temp message is displayed in blue if the temp is Zero c or lower for example.
I want to add a quick glance secondary display for temperature using the LED shim. It will be mounted vertically like a thermometer.
I want the current temp to be in the center / middle. A white marker. Then have the other LEDs color based on the temperature above or below the marker. So if the temp was say 0c, below the marker would be all blue, and above yellow up to 12c. Above 12c I want it green. And above 26c I want red. 14 degrees each side of the marker are displayed. Actually it will be more like 13 and 15 or 15 and 13, as the marker can’t be in the exact center.

Just looking for a place to start, what example code to start with? The function list isn’t up yet or I’d start there. I’d class my python skills as average or a little above average. I’m no expert but I’m not exacly a noob either, if that makes sense.

Oooh- you’re right. I’ve been pretty lax on publishing and updating the documentation- this is mostly because the toolchain for building it is a huge hassle to work with and despite being auto-generated it’s not quite as automated as it could be.

The temperature false colour stuff I found for the thermal camera might come in handy for you here, it basically uses a list of colours, picks the appropriate one out using the current temperature, and then blends it with the next colour depending on where the temperature lies between those points.

If you use colours in order of hue then you can use hsv_to_rgb and just scale your temperature to an appropriate hue value. That would limit you to green->yellow->orange->red but it makes it easy to pull off.

Going to try and play around with it latter on today. First run was basically to test all the LEDs to make sure it all works. That’s was A OK. =) So now I can take my time tinkering with it. I’ll have a look at the stuff you mentioned, thanks.
Playing around with my rover project at the moment. Just taking a little break to make a cup of coffee and check my e-mail. I’m Installing the Pololu track set and wiring up my motors. Still a little work to do before I run it for the first time.

This the same chip used in the Scroll pHat HD right? If yes looking at its function reference may help?
How big is the buffer? Maybe I could load my color scale into it, then scroll to a point in the buffer that reflects the current temp? A sliding scale only showing 28 points?

It doesn’t have the magic buffer that Scroll pHAT HD does, but there’s nothing stopping you from pre-computing a colour spectrum into a regular list and pulling values from that. It shouldn’t be necessary though, as any function you produce that provides a value for a colour (for producing a colour scale) could be called on the fly. Unless you hand code the whole thing of course!

The C-code I used for blending a list of colours into a heatmap is as follows:

	// Heatmap code borrowed from: http://www.andrewnoske.com/wiki/Code_-_heatmaps_and_color_gradients
	const int NUM_COLORS = 7;
	static float color[NUM_COLORS][3] = { {0,0,0}, {0,0,1}, {0,1,0}, {1,1,0}, {1,0,0}, {1,0,1}, {1,1,1} };
	int idx1, idx2;
	float fractBetween = 0;
	float vmin = 5.0;
	float vmax = 50.0;
	float vrange = vmax-vmin;
	v -= vmin;
	v /= vrange;
	if(v <= 0) {idx1=idx2=0;}
	else if(v >= 1) {idx1=idx2=NUM_COLORS-1;}
	else
	{
		v *= (NUM_COLORS-1);
		idx1 = floor(v);
		idx2 = idx1+1;
		fractBetween = v - float(idx1);
	}

	int ir, ig, ib;


	ir = (int)((((color[idx2][0] - color[idx1][0]) * fractBetween) + color[idx1][0]) * 255.0);
	ig = (int)((((color[idx2][1] - color[idx1][1]) * fractBetween) + color[idx1][1]) * 255.0);
	ib = (int)((((color[idx2][2] - color[idx1][2]) * fractBetween) + color[idx1][2]) * 255.0);

Thanks Phil. I’ve been really struggling with this. All the examples work fine, until I edit them to try and make it do what I want. Then I get errors, something something not defined import ledshim or something similar. Likely to do with the code I take out. I’ll take a screen shot of the actual error or write it down next time I get one. And post the code I meddling with. I’m lost most times trying to figure out what the python file is actually doing before I edit it. I’m not a python noob, but no expert either. I’ll keep plugging away at it. Not knowing what I’m doing hasn’t stopped me before.
I have zero C skills. =(

One of the files I was playing with was the cpu_temp.py file. I was trying to have it get the temp from my BMP180 instead of calling it up from the CPU. Baby steps etc. I’ll have another go latter today and not any errors I get.

I’m making a little headway, I have it (all the LED’s) changing color based on temperature. What I need to know now, is how to change just a set group of LED’s to all one color. Or just 1 LED to a set color. I’m looking through the examples but it’s not jumping out at me.

#!/usr/bin/python
#!/usr/bin/env python
import time
import ledshim

import Adafruit_BMP.BMP085 as BMP085

sensor = BMP085.BMP085()


ledshim.set_clear_on_exit()



while True:

    t= sensor.read_temperature()
    t= round(t)
          
    if t <= 0:
        ledshim.set_all(0, 0, 255)
        
    if t > 0 and t < 13:
        ledshim.set_all(255, 255, 0)

    if t >=13 and t <= 27:
        ledshim.set_all(0, 255, 0)

    if t > 27:
        ledshim.set_all(255, 0, 0)

    ledshim.show()
    time.sleep(0.5)

.

Ok, looks like I need to use ledshim.set_pixel(x, r, g, b), so I need the arguments etc for that?
And can I do a ledshim.set_pixel(x, r, g, b to x, r, g, b) set a groupe from say LED 1 to LED 13.
Does it start at 0 or 1 for the first LED?

An example of what I want to is, if the temperature is 0c,the first 14 LEDs are all Yellow, and the last 14 Blue.
If its above 0c the first 16 are Green and the last 12 Yellow.
Below 0c all are Blue. Those will be my scales, on which I’ll put a white marker showing the exact temp. I’ll work about the marker later though. Maybe I have to use “col”?

You would have to create a method to set multiple pixels yourself, it would be based around set_pixel() and might perhaps look something like this:

def set_multiple_pixels(indexes, r, g, b):
    for index in indexes:
        ledshim.set_pixel(index, r, g, b)

Which you could then run with:

set_multiple_pixels(range(0,14), 255, 0, 0)

To set pixels 0 to 13 to red.

You can now use all of the smarts of range() to address different combinations of the available LEDs (0-27), eg every other pixel:

>>> range(0,27,2)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26]

Or just the other side of the display:

>>> range(27,13,-1)
[27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14]

Or every third pixel:

>>> range(0,27,3)
[0, 3, 6, 9, 12, 15, 18, 21, 24]

The set_multiple_pixels function will step through each number in the range, list or tuple supplied and treat it as a pixel index to set.

Going from one set of r, g, b values to another is somewhat more complicated since you need to calculate exactly how you’ll blend them.

You could then expand this function to do colour sweeps like so:

import time
import signal
import ledshim

def set_multiple_pixels(indexes, from_colour, to_colour=None):
    """Set multiple pixels to a range of colours sweeping from from_colour to to_colour

    :param from_colour: A tuple with 3 values representing the red, green and blue of the first colour
    :param to_colour: A tuple with 3 values representing the red, green and blue of the second colour

    """

    if to_colour is None:
        to_colour = from_colour

    length = float(len(indexes))
    step = 0
    from_r, from_g, from_b = from_colour
    to_r, to_g, to_b = to_colour
    step_r, step_g, step_b = to_r - from_r, to_g - from_g, to_b - from_b
    step_r /= length
    step_g /= length
    step_b /= length

    for index in indexes:
        ledshim.set_pixel(index, from_r + (step_r * step), from_g + (step_g * step), from_b + (step_b * step))
        step += 1

# Just green
set_multiple_pixels(range(0,28), (0,255,0))
ledshim.show()
time.sleep(1)

# Sweep from yellow to blue, whee!
set_multiple_pixels(range(0,28), from_colour=(255,255,0), to_colour=(0,0,255))
ledshim.show()
time.sleep(1)

# Half and half
set_multiple_pixels(range(0,14), from_colour=(0,0,255), to_colour=(128,128,255))
set_multiple_pixels(range(14,28), from_colour=(255,0,0), to_colour=(255,255,0))
ledshim.show()

signal.pause()

Heck I should build these functions into ledshim!

That looks to be the info I was looking for, thanks a bunch. This should keep me busy for a while, lol.

That really fixed me up, making good progress now. I have my scales or background colors, or what ever you want to call them the way I want now. Just have to set my marker for the current temp. That’s going to require some math I think. Might do that another day. Its blistering hot today and my neck and back are getting sore. time to take a break I think. any way, another big thanks for the code / info. =)
I’ll post my code when I get it done.

nice to see your making headway sounds like a cool[pun intended ] project …
.
it’s hot ,dam hot ,i was trimming a really thick hedge at work but gave up ,lol
going to turn on the air conditioner and tidy my Pi storage shelf’s

Have to tidy it up and refine it a bit before I post my code. set_multiple_pixels(range was what I went with. Way too hot to play with it now. I’ll likely have another go in the morning after I walk Ginger. The back side of the house is in the shade in the morning and that’s where my gazebo is. On my back deck. We usually finish our walk around 7:30 so that will give me a few hours to play around until the sun comes over the house. If its not raining? If it is I’ll have to setup in the house. The gazebo has a canvas roof and isn’t 100% waterproof. There are a few small holes from the wind tugging it etc. I use it more for shade anyway.

Here is my test code. Keep in mind that my LED shim is vertical with LED 0 at the top and 27 at the bottom. And my marker goes up as temp increases. It made for some interesting math to get it to track in the right direction.
For testing I set my temp at -30 and had it increment by 1 every second and a half.
Below -27 there is no marker, just all blue LED’s. once it hits -27 it appears at the bottom and moves up until you hit 0c, the top most LED. Then the scale shifts and it counts up from 1c to 28c. If it goes over 28c it turns orange and counts up from 28. I may change the last scale to be 25c at the bottom. It all works with no exception errors so I’m happy for now.

#!/usr/bin/python
#!/usr/bin/env python
import time
import ledshim

import Adafruit_BMP.BMP085 as BMP085

sensor = BMP085.BMP085()

def set_multiple_pixels(indexes, r, g, b):
    for index in indexes:
        ledshim.set_pixel(index, r, g, b)

ledshim.set_clear_on_exit()
t = -30


while True:

    #t= sensor.read_temperature()
    #t= round(t)
    #print(t)
        

    if t <= 0 and t >= -27:
        ledshim.set_all(0, 0, 255) #Blue
        M = (t * (-1))
        ledshim.set_pixel(M, 255, 255, 255)
        # B B B B B B B B B B B B B B B B B B B B B B B B B B B B
    elif t > 0 and t <= 28: # Main
        set_multiple_pixels(range(0,3), 255, 0, 0) #Red
        set_multiple_pixels(range(3,16), 0, 255, 0) #Green
        set_multiple_pixels(range(16,28), 255, 255, 0) #Yellow
        M = (28 - t)
        ledshim.set_pixel(M, 255, 255, 255)
        # R R R G G G G G G G G G G G G G Y Y Y Y Y Y Y Y Y Y Y Y
    elif t > 28: # Realy Hot 
        set_multiple_pixels(range(0,27), 255, 165, 0) #Orange
        set_multiple_pixels(range(27,28), 255, 0, 0) #Red
        M = (t - 56) * (-1)
        ledshim.set_pixel(M, 255, 255, 255)
        # O O O O O O O O O O O O O O O O O O O O O O O O O O O R
    else:
        set_multiple_pixels(range(0,3), 255, 255, 255) #Blue
        set_multiple_pixels(range(3,28), 0, 255, 255) #Aqua
        M = (56 + t)
        ledshim.set_pixel(M, 255, 255, 255)
        # B B B A A A A A A A A A A A A A A A A A A A A A A A A A        

    ledshim.show()
    time.sleep(1.5)
    t = t + 1

Got it all up and running, very happy with how it turned out. Made a few minor fixes to my code. I’ll edit what I posted above to what I’m currently using.
@gadgetoid Phil, what is the command to clear it? I used set all (0, 0, 0) and then an ledshim show, just wondering if there is a oneline command to do it.
Also wondering how to adjust the brightness, other than changing (255, 255, 255) to (128, 128, 128) etc? I thought I saw it in one of the examples but can’t find it now?

1 Like

Got the brightness setting ledshim.set_brightness(0.5) I’m assuming 1.0 is full bright and 0.5 is half brightness?

It looks like ledshim.clear() is the clear command. I still had to run ledshim.show() after it to make it clear. For my sense hat all I have to run is sense.clear() and it blanks. No big deal, now that I know. I had a few places I left out the ledshim.show and was scratching my head, lol.

Here is my full python file. Keep in mind there is a Sense Hat, BME680, Si1145, DS3231 RTC and the LEDShim.
I use the Si1145 to measure the ambient light level and auto adjust the LED Shim and Sense Hat LED matrix brightness. In dark conditions they are both dimmed to half brightness. In sunlight they both go to full bright. In very bright sunlight the text on the Sense Hat LED matrix goes to all white text. Normally its colored based on conditions. Below zero c temps turn the temperature message blue for example. I find the Red and Blue text hard to see in very bright sunlight. I can also override the auto function with the Sense Hat joystick. The Sense Hat shows a repeating scrolling message or day, date, time, temp, humidity, pressure and UV index. It runs headless on a powerboost and lipo battery.

import time, datetime
import bme680
import SI1145.SI1145 as SI1145
import ledshim
import RPi.GPIO as GPIO
from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED

ledshim.set_clear_on_exit()
   
sense = SenseHat()
sense.set_rotation(180)
sense.set_imu_config(False, False, False)
sense.low_light = False

uvs = SI1145.SI1145()
sensor = bme680.BME680()

sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)

sensor.set_gas_status(bme680.DISABLE_GAS_MEAS)
#sensor.set_gas_heater_temperature(320)
#sensor.set_gas_heater_duration(150)
#sensor.select_gas_heater_profile(0)

GPIO.setmode(GPIO.BCM)  
GPIO.setwarnings(False)
GPIO.setup(5, GPIO.IN, pull_up_down = GPIO.PUD_OFF)  

s=(0.1) # scroll speed
w=(0) # color all white toggle
o=(165)
x=(2) #shutdown variable
m=(0)

def set_multiple_pixels(indexes, r, g, b):
    for index in indexes:
        ledshim.set_pixel(index, r, g, b)

def Shutdown(channel):  
    global x
    x = (0)

def readvis():
    vis = uvs.readVisible()
    vis = (round(vis))

    global w
    global o
    global m

    if vis < 270 and m == (0):
        sense.low_light = True
        ledshim.set_brightness(0.5)
        ledshim.show()
        w = (0)
        o = (165)
    elif vis >= 270 and vis < 600 and m == (0):
        sense.low_light = False
        ledshim.set_brightness(1.0)
        ledshim.show()
        w = (0)
        o = (165)
    elif vis >= 600 and m == (0):
        sense.low_light = False
        ledshim.set_brightness(1.0)
        ledshim.show()
        w = (255)
        o = (255)

    
# is really stick down
def pushed_up(event):
    global m
    if event.action == ACTION_PRESSED:
       sense.low_light = True
       ledshim.set_brightness(0.5)
       ledshim.show()
       m = (1)
        
# is really stick up
def pushed_down(event):
    global m
    if event.action == ACTION_PRESSED:
       sense.low_light = False
       ledshim.set_brightness(1.0)
       ledshim.show() 
       m = (1)

#is really stick right
def pushed_left(event):
    global w
    global o
    global m
    if event.action == ACTION_PRESSED:
        w = (255)
        o = (255)
        m = (1)
        
# is really stick left
def pushed_right(event):
    global w
    global o
    global m
    if event.action == ACTION_PRESSED:
        w = (0)
        o = (165)
        m = (1)

def pushed_middle(event):
    global m
    if event.action == ACTION_PRESSED:
        m = (0)

sense.stick.direction_up = pushed_up
sense.stick.direction_down = pushed_down
sense.stick.direction_left = pushed_left
sense.stick.direction_right = pushed_right
sense.stick.direction_middle = pushed_middle

GPIO.add_event_detect(5, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

while True:

    readvis()

    dateString = "%A %B %-d %-I:%M:%p"
    msg = "It is %s" % (datetime.datetime.now().strftime(dateString))
    sense.show_message(msg, scroll_speed=s, text_colour=(w, 255, 255))


    if sensor.get_sensor_data(): 

       t = (sensor.data.temperature) 
       t = (round(t))
          
    if t <= 0: 
        tc = [w, w, 255]   # Blue
    elif t > 0 and t < 13:
        tc = [255, 255, w] # Yellow
    elif t >= 13 and t <= 25:
        tc = [w, 255, w]   # Green
    else:
        tc = [255, w, w]   # Red
            
    msg = "and %sc" % (t)
    sense.show_message(msg, scroll_speed=s, text_colour=tc)

    if t <= 0 and t >= -27:
        ledshim.set_all(0, 0, 255) #Blue
        M = (t * (-1))
        ledshim.set_pixel(M, 255, 255, 255)
        # B B B B B B B B B B B B B B B B B B B B B B B B B B B B
    elif t > 0 and t <= 28: # Main
        set_multiple_pixels(range(0,3), 255, 0, 0) #Red
        set_multiple_pixels(range(3,16), 0, 255, 0) #Green
        set_multiple_pixels(range(16,28), 255, 255, 0) #Yellow
        M = (28 - t)
        ledshim.set_pixel(M, 255, 255, 255)
        # R R R G G G G G G G G G G G G G Y Y Y Y Y Y Y Y Y Y Y Y
    elif t > 28: # Realy Hot 
        set_multiple_pixels(range(0,27), 255, 140, 0) #Orange
        set_multiple_pixels(range(27,28), 255, 0, 0) #Red
        M = (t - 56) * (-1)
        ledshim.set_pixel(M, 255, 255, 255)
        # O O O O O O O O O O O O O O O O O O O O O O O O O O O R
    else:
        set_multiple_pixels(range(0,3), 255, 255, 255) #Blue
        set_multiple_pixels(range(3,28), 0, 255, 255) #Aqua
        M = (56 + t)
        ledshim.set_pixel(M, 255, 255, 255)
        # B B B A A A A A A A A A A A A A A A A A A A A A A A A A
        

    ledshim.show()


    readvis()

    if sensor.get_sensor_data(): 
       h = (sensor.data.humidity)
       h = (round(h))

    if h < 0:
        h = 0

    if h > 100:
        h = 100

    if h < 30:
        hc = [255, w, w]  # Red
    elif h >= 30 and h <= 60:
        hc = [w, 255, w]  # Green
    elif h > 60 and h < 80:
        hc = [255, 255, w]  # Yellow
    elif h >= 80:
        hc = [255, w, w]  # Red

    msg = "with %s%% Humidity" % (h)
    sense.show_message(msg, scroll_speed=s, text_colour=hc)

    readvis()

    if sensor.get_sensor_data(): 
       p = (sensor.data.pressure) 
       p = round(p)
        
    if p > 0 and p < 982:
        pc = [255, w, w]  # Red
        msg = "- Barometer is Very Low @ %smb - Storm Watch" % (p)
        sense.show_message(msg, scroll_speed=s, text_colour=pc)
    elif p >= 982 and p < 1004:
        pc = [255, 255, w]  # Yellow
        msg = "- Barometer is Low @ %smb - Possible Percipitation" % (p)
        sense.show_message(msg, scroll_speed=s, text_colour=pc)
    elif p >= 1004 and p < 1026:
        pc = [w, 255, w]  # Green
        msg = "- Barometer is Mid Range @ %smb" % (p)
        sense.show_message(msg, scroll_speed=s, text_colour=pc)
    elif p >= 1026 and p < 1048:
        pc = [w, w, 255]  # Blue
        msg = "- Barometer is High @ %smb" % (p)
        sense.show_message(msg, scroll_speed=s, text_colour=pc)
    elif p >= 1048:
        pc = [255, w, w]  # Red
        msg = "- Barometer is Very High @ %smb - Expect Dry Conditions" % (p) 
        sense.show_message(msg, scroll_speed=s, text_colour=pc)

    readvis()

    uv = uvs.readUV()
    u = uv/100
    u = (round(u))

    if u > 0 and u < 3:
        msg = "- UV Index is Low @ %s" % (u)
        sense.show_message(msg, scroll_speed=s, text_colour=(w, 255, w)) # Green        
    elif u >= 3 and u < 6:
        msg = "- UV Index is Moderate @ %s" % (u)
        sense.show_message(msg, scroll_speed=s, text_colour=(255, 255, w)) # Yellow        
    elif u >= 6 and u < 8:
        msg = "- UV Index is High @ %s" % (u)
        sense.show_message(msg, scroll_speed=s, text_colour=(255, o, w)) # Orange       
    elif u >= 8 and u < 11:
        msg = "- UV Index is Very High @ %s" % (u)
        sense.show_message(msg, scroll_speed=s, text_colour=(255, w ,w)) # Red
    elif u >= 11:
        msg = "- UV Index is Extreme @ %s" % (u)
        sense.show_message(msg, scroll_speed=s, text_colour=(255, w, 255)) # Violet
        
    #vis = uvs.readVisible()
    #vis = (round(vis)) 

    #msg = "and the VIS is %s" % (vis)
    #sense.show_message(msg, scroll_speed=s, text_colour=(255, w, 255))

    if x == 0:
        sense.clear()
        ledshim.clear()
        ledshim.show()
        os.system("sudo shutdown now -P")
        time.sleep(30)
    elif x == 1:
        sense.clear()
        ledshim.clear()
        ledshim.show()
        raise SystemExit
        time.sleep(30)

# Last edited on July 20th 2018 LED Shim dim function added.
# run sudo crontab -e
# add
# @reboot python3 /home/pi/BMELED.py &