Micro Dot pHAT to display clock and BME280 sensor data

This the code I use with my BME680

import os
import time, datetime
import bme680
import SI1145.SI1145 as SI1145
import RPi.GPIO as GPIO
from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED
   
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)  
GPIO.setup(16,GPIO.OUT, initial=1) #Red
GPIO.setup(19,GPIO.OUT, initial=1) #Yellow
GPIO.setup(20,GPIO.OUT, initial=1) #Green
GPIO.setup(21,GPIO.OUT, initial=1) #Blue


s=(0.1) # scroll speed
w=(0) # color all white toggle
o=(165)
L=(1) #LED's on or off
x=(2) #shutdown variable
m=(0)

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

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

    global w
    global o
    global L
    global m

    if vis < 270 and m == (0):
        sense.low_light = True
        w = (0)
        o = (165)
        L = (1)
    elif vis >= 270 and vis < 500 and m == (0):
        sense.low_light = False
        w = (0)
        o = (165)
        L = (0)
    elif vis >= 500 and m == (0):
        sense.low_light = False
        w = (255)
        o = (255)
        L = (0)
    
# is really stick down
def pushed_up(event):
    global L
    global m
    if event.action == ACTION_PRESSED:
       sense.low_light = True
       L = (1)
       m = (1)
        
# is really stick up
def pushed_down(event):
    global L
    global m
    if event.action == ACTION_PRESSED:
       sense.low_light = False
       L = (0)
       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
        GPIO.output(16, 1) # Red
        GPIO.output(19, 1) # Yellow
        GPIO.output(20, 1) # Green
        GPIO.output(21, L) # Blue <
    elif t > 0 and t < 13:
        tc = [255, 255, w] # Yellow
        GPIO.output(16, 1) # Red
        GPIO.output(19, L) # Yellow <
        GPIO.output(20, 1) # Green
        GPIO.output(21, 1) # Blue
    elif t >= 13 and t <= 25:
        tc = [w, 255, w]   # Green
        GPIO.output(16, 1) # Red
        GPIO.output(19, 1) # Yellow
        GPIO.output(20, L) # Green <
        GPIO.output(21, 1) # Blue
    else:
        tc = [255, w, w]   # Red
        GPIO.output(16, L) # Red <
        GPIO.output(19, 1) # Yellow
        GPIO.output(20, 1) # Green
        GPIO.output(21, 1) # Blue
        
    msg = "and %sc" % (t)
    sense.show_message(msg, scroll_speed=s, text_colour=tc)


    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
        msg = "with %s%% Humidity" % (h)
        sense.show_message(msg, scroll_speed=s, text_colour=hc)
    elif h >= 30 and h <= 60:
        hc = [w, 255, w]  # Green
        msg = "with %s%% Humidity" % (h)
        sense.show_message(msg, scroll_speed=s, text_colour=hc)
    elif h > 60 and h < 80:
        hc = [255, 255, w]  # Yellow
        msg = "with %s%% Humidity" % (h)
        sense.show_message(msg, scroll_speed=s, text_colour=hc)
    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 < 985:
        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 >= 985 and p < 1005:
        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 >= 1005 and p < 1025:
        pc = [w, 255, w]  # Green
        msg = "- Barometer is Mid Range @ %smb" % (p)
        sense.show_message(msg, scroll_speed=s, text_colour=pc)
    elif p >= 1025 and p < 1050:
        pc = [w, w, 255]  # Blue
        msg = "- Barometer is High @ %smb" % (p)
        sense.show_message(msg, scroll_speed=s, text_colour=pc)
    elif p >= 1050:
        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)

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

    if u > 0 and u < 3 and L == 0:
        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 and L == 0:
        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 and L == 0:
        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 and L == 0:
        msg = "- UV Index is Very High @ %s" % (u)
        sense.show_message(msg, scroll_speed=s, text_colour=(255, w ,w)) # Red
    elif u >= 11 and L == 0:
        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()
        os.system("sudo shutdown now -P")
        time.sleep(30)
    elif x == 1:
        sense.clear()
        raise SystemExit
        time.sleep(30)

# Last edited on May 10thth 2018
# run sudo crontab -e
# add
# @reboot python3 /home/pi/THPUVBME.py &

1 Like

Thanks. The issue I have is displaying the clock - the readings are all being passed through fine, so I’m happy with how that part works, but I cannot seem to get the clock displaying correctly.

I don’t know if my clock function is not right:

# Function for the clock
def clock():
    while True:
        clockEndTime = time.time() + showClock
        while time.time() < clockEndTime:
            clear()
            t = datetime.datetime.now()
            if t.second % 2 == 0:
                set_decimal(2, 1)
                set_decimal(4, 1)
            else:
                set_decimal(2, 0)
                set_decimal(4, 0)
            write_string(t.strftime('%H%M%S'), kerning=False)
            show()
            time.sleep(0.05)

Or whether the implementation of it is correct:

def microdot():
    clear()
    write_string( "%.1f" % temperature + "C", kerning=False)
    show()
    time.sleep(5)
    # Uncomment to display pressure if needed
    #clear()
    #write_string( "%.0f" % pressure + "hPa", kerning=False)
    #show()
    #time.sleep(5)
    clear()
    write_string( "%.0f" % humidity + "% RH", kerning=False)
    show()
    time.sleep(5)
    clock()

Or finally if the main part that runs everything is not calling it correctly - I suspect it is likely this part personally:

while True:
        temperature,pressure,humidity = bme280.readBME280All()
        if temperature >= 26:
            pushover()
        else:
            continue
        microdot()

Hope that clarifies what I’m struggling with.

I don’t have a microdot, so I think you’ll have to wait for @gadgetoid etc to chime in. I’d have to look at the examples and likely guess at what might be wrong. :(

Ok, thanks. Appreciate your help so far anyway - your project sounds great, the BME680 Breakout Board is really cool. I’ve got one at home too.

What does the “set decimal” do? and why the set decimal (2, 1) then right after (4, 1)?

You know, I’m not really sure. It was in the examples for the Micro Dot pHAT Python library, so I just included it. I suspect it’s not needed. I found a few other minor issues like that too, but I cannot remember off the top of my head.

I suspect the examples were created using earlier versions of the library that are no longer required.

Yeah, looking at that now, I can’t make any sense out of it though?

Looking at your original code above. I see where defined functions, but I don’t see where you called those functions?
There should be a clock() statement to call the def clock():
I could have easily just missed it though?

def microdot():
    clear()
    write_string( "%.1f" % temperature + "C", kerning=False)
    show()
    time.sleep(5)
    # Uncomment to display pressure if needed
    #clear()
    #write_string( "%.0f" % pressure + "hPa", kerning=False)
    #show()
    #time.sleep(5)
    clear()
    write_string( "%.0f" % humidity + "% RH", kerning=False)
    show()
    time.sleep(5)
    clock()

It’s the last function called.

I don’t think that’s the right place to put it though? I think you have too many while true loops?

Ok, I will look to add the whole def clock(): code in the def microdot(): section instead, to see if that works.

I’d make each def separate, if you can?
def time:
def temp:
def humidity:
def pressure:
def microdot:
Have to take a break, back in a hour of so.

Yeah, that may be it. Thanks.

I’ll try and test it when I get home. I suspect you might be onto something as I’m not sure if you can call a function inside another function…

EDIT: I just tried something really basic in IDLE:

def type1():
    print ("One")

def type2():
    print ("Two")

def all():
    type1()
    type2()

all()

And when I ran it, the print out was:

One
Two
>>>

Which looks like it works as I had hoped.

I’ve been learning python as I go. No formal training, just numerous web searches and trial and error. Mostly syntax error, lol.

Same here! Now if only somebody with expertise from the Pimoroni crew could help out… :D

Isn’t today the day they do the Bilge Tank Video? Phil must be busy or he would have replied by now.

I only use def, if I have too. Like if I’m doing something multiple times in my code. Then I can call it with just one line of code instead of repeating my same code over and over.
If that bit of code only runs the once in while true loop, I just do the full code the once.
Following some of those examples can have you head scratching though. There was a bunch of stuff in the BME680 examples I just striped out. string formatting etc.

Ok, so I’ve been tweaking things in my code. I’ve now managed to get the loop fixed so that if the temperature is too high, a Pushover notification is sent and the loop continues. However, I’ve concluded that the def clock(): function is what is causing the issue.

Here’s my latest code. If anybody could help get the clock part working I’d be very grateful!

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import bme280
import time
import datetime
import sys
import threading
import httplib, urllib
from microdotphat import write_string, set_decimal, clear, show
from beebotte import *

### Replace CHANNEL_TOKEN with that of your Beebotte channel
### and YOUR_CHANNEL_NAME_HERE with the channel you create
bbt = BBT(token = 'CHANNEL_TOKEN')
chanName = "YOUR_CHANNEL_NAME_HERE"

### Change Beebotte channel name as suits you - in this instance, it is called BME280.
temp_resource   = Resource(bbt, chanName, 'temperature')
pressure_resource  = Resource(bbt, chanName, 'pressure')
humidity_resource = Resource(bbt, chanName, 'humidity')

# Sends data to your Beebotte channel
def beebotte():
    while True:
        temp_resource.write(round(temperature,1))
        pressure_resource.write(round(pressure,0))
        humidity_resource.write(round(humidity,0))
        time.sleep(900)    # 15 mins to prevent maxing API limit

# Experimental! Clock - may not work yet!
# Display time on Micro Dot pHAT for set time
showClock = 5 # Seconds

# Function for the clock
def clock():
    while True:
        clockEndTime = time.time() + showClock
        while time.time() < clockEndTime:
            clear()
            t = datetime.datetime.now()
            if t.second % 2 == 0:
                set_decimal(2, 1)
                set_decimal(4, 1)
            else:
                set_decimal(2, 0)
                set_decimal(4, 0)
            write_string(t.strftime('%H%M%S'), kerning=False)
            show()
            time.sleep(0.05)

# Experimental! Pushover notifications - should work
# Replace APP_TOKEN and USER_TOKEN where applicable
def pushover():
    conn = httplib.HTTPSConnection("api.pushover.net:443")
    conn.request("POST", "/1/messages.json",
      urllib.urlencode({
        "token": "APP_TOKEN",
        "user": "USER_TOKEN",
        "html": "1",
        "title": "High temperature!",
        "message": "It is "+str(temperature)+ "°C in the nursery!",
        "url": "https://beebotte.com/dash/RANDOM_ID_HERE",
        "url_title": "View Beebotte dashboard",
        "sound": "siren",
      }), { "Content-type": "application/x-www-form-urlencoded" })
    conn.getresponse()

# Display stats on the Micro Dot pHAT
def microdot():
    clear()
    write_string( "%.1f" % temperature + "C", kerning=False)
    show()
    time.sleep(5)
    # Uncomment to display pressure if needed
    #clear()
    #write_string( "%.0f" % pressure + "hPa", kerning=False)
    #show()
    #time.sleep(5)
    clear()
    write_string( "%.0f" % humidity + "% RH", kerning=False)
    show()
    time.sleep(5)
    #clock() # Not working right now

try:
    # Get the first reading from the BME280 sensor
    temperature,pressure,humidity = bme280.readBME280All()
    # Start the Beebotte function as a thread so it works in the background
    beebotte_thread = threading.Thread(target=beebotte)
    beebotte_thread.daemon = True
    beebotte_thread.start()
    # Run a loop to collect data and display it on the Micro Dot pHAT
    # and send notifications via Pushover if it is too hot
    while True:
        temperature,pressure,humidity = bme280.readBME280All()
        if temperature >= 26:
            pushover()
            microdot()
            pass
        else:
            pass
        microdot()

except (KeyboardInterrupt, SystemExit):
    sys.exit()
    pass

Thanks!

As a test I’d run just the clock.py from here, https://github.com/pimoroni/microdot-phat/blob/master/examples/clock.py and see if it works. If it does leave it as it is and add to it to show the temperature after the time. Without doing all the def’s. Get that working and then just add humidity and pressure. Just one big while true loop something like this. That’s just sample made up on the fly code.
bme.readTemperature()
write_string (Temperature, “C”)
show()
time.sleep(5)

bme.readHumidity()
write_string(Humidity “%”)
show()
time.sleep(5)

bme.readPressure()
write_string(Pressure “Pa”)
show()
time.sleep(5)

Do you have a link to the python library etc, you are using for the BME280? I had to hunt one up for my BMP180. With that I could separate the temp and pressure into two separate readings. I only used the Temp reading. t = bmp.read_temperature()
It was the same deal with my BME680, I read them each separately in my code.
if sensor.get_sensor_data():
t = (sensor.data.temperature)
h = (sensor.data.humidity)
p = (sensor.data.pressure)