Initial backup of LTP-305G matrix clock setup on matrixpi
Captures everything needed to redeploy the two-display clock (hour on I2C 0x61, minute on I2C 0x63) on a fresh Pi: - Both systemd units (matrix0x61.service, matrix0x63.service) - Deployed Pimoroni script tree, including the local %I (12-hour) clock customization - Vendored upstream sources (ltp305-python, breakout-garden) so restore is fully offline-capable - Boot config snippet enabling I2C - install.sh that wires it all back up idempotently - Inventory doc cross-referencing every live-system path Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6
vendor/breakout-garden/examples/README.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Breakout Garden examples
|
||||
|
||||
These example programs demonstrate the sort of thing that's possible by combining
|
||||
two or more Pimoroni breakouts on Breakout Garden.
|
||||
|
||||
Each example folder has its own README that you should check before running the example.
|
||||
26
vendor/breakout-garden/examples/colour-control/README.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# Colour control example
|
||||
|
||||
Use the trackball and switch to control the hue and brightness of the trackball's RGBW LEDs
|
||||
and the 5x5 RGB matrix's LEDs.
|
||||
|
||||
|
||||
Scroll up to increase brightness and left/right to change hue. Click to turn on/off.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [Trackball Breakout](https://shop.pimoroni.com/products/trackball-breakout)
|
||||
- A Pimoroni [5x5 RGB Matrix Breakout](https://shop.pimoroni.com/products/5x5-rgb-matrix-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./colour-control.py` in the terminal.
|
||||
|
||||
80
vendor/breakout-garden/examples/colour-control/colour-control.py
vendored
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
import colorsys
|
||||
import atexit
|
||||
|
||||
from trackball import TrackBall
|
||||
from rgbmatrix5x5 import RGBMatrix5x5
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires an
|
||||
Trackball Breakout and a 5x5 RGB Matrix Breakout.
|
||||
|
||||
Use the trackball and switch to control the hue and
|
||||
brightness of the trackball's RGBW LEDs.
|
||||
|
||||
Scroll up to increase brightness and left/right
|
||||
to change hue. Click to turn on/off.
|
||||
|
||||
Press Ctrl+C to exit.
|
||||
""")
|
||||
|
||||
# Set up the trackball
|
||||
trackball = TrackBall(interrupt_pin=4)
|
||||
|
||||
@atexit.register
|
||||
def clear_trackball():
|
||||
trackball.set_rgbw(0, 0, 0, 0)
|
||||
|
||||
# Set up the 5x5 RGB matrix
|
||||
rgbmatrix5x5 = RGBMatrix5x5()
|
||||
rgbmatrix5x5.set_clear_on_exit()
|
||||
rgbmatrix5x5.set_brightness(0.8)
|
||||
|
||||
x = 0
|
||||
y = 50.0
|
||||
|
||||
toggled = False
|
||||
|
||||
while True:
|
||||
up, down, left, right, switch, state = trackball.read()
|
||||
|
||||
# Update x and y vals based on movement
|
||||
y += up
|
||||
y -= down
|
||||
x += right / 10.0
|
||||
x -= left / 10.0
|
||||
|
||||
# Clamp to min of 0 and max of 100
|
||||
x %= 100
|
||||
y = max(0, min(y, 100))
|
||||
|
||||
# Calculate hue and brightness
|
||||
h = x / 100.0
|
||||
v = y / 100.0
|
||||
|
||||
# Prevents button from retriggering
|
||||
debounce = 0.5
|
||||
|
||||
# Change toggled state if switch is pressed
|
||||
if state and not toggled:
|
||||
toggled = True
|
||||
time.sleep(debounce)
|
||||
elif state and toggled:
|
||||
toggled = False
|
||||
time.sleep(debounce)
|
||||
|
||||
# Set brightness to zero if switch toggled
|
||||
if toggled:
|
||||
v = 0
|
||||
|
||||
# Calculate RGB vals
|
||||
w = 0
|
||||
r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(h, 1.0, v)]
|
||||
|
||||
# Set LEDs
|
||||
trackball.set_rgbw(r, g, b, w)
|
||||
rgbmatrix5x5.set_all(r, g, b)
|
||||
rgbmatrix5x5.show()
|
||||
|
||||
time.sleep(0.01)
|
||||
44
vendor/breakout-garden/examples/distance/README.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Distance example
|
||||
|
||||
This example, the Park-O-Matic 6000, is a mockup of a car reversing
|
||||
indicator.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [VL53L1X Time of Flight Sensor Breakout](https://shop.pimoroni.com/products/vl53l1x-breakout)
|
||||
- A Pimoroni [1.12" OLED Breakout (SPI)](https://shop.pimoroni.com/products/1-12-oled-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
For this example you'll need to make sure some additional software is installed:
|
||||
|
||||
```
|
||||
sudo apt install python3-pil
|
||||
```
|
||||
|
||||
You'll need to clone and install the library for the 1.12" OLED Breakout (SPI)
|
||||
as follows:
|
||||
|
||||
```
|
||||
git clone https://github.com/pimoroni/sh1106-python
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
This example assumes that you have the OLED plugged into the front slot on the
|
||||
Breakout Garden HAT, which should also work with the Breakout Garden Mini HAT.
|
||||
To change it to the back slot, change `device=1` to `device=0` on the line
|
||||
where the OLED is set up.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./distance.py` in the terminal.
|
||||
|
||||
You can change the `threshold` value (in cm) to change the threshold at which the warning
|
||||
indicator starts flashing.
|
||||
72
vendor/breakout-garden/examples/distance/distance.py
vendored
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageFont
|
||||
from PIL import ImageDraw
|
||||
|
||||
import VL53L1X
|
||||
|
||||
from luma.core.interface.serial import spi
|
||||
from luma.core.render import canvas
|
||||
from luma.oled.device import sh1106
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires an
|
||||
VL53L1X Time of Flight Sensor Breakout and a 1.12" OLED Breakout (SPI).
|
||||
|
||||
The Park-O-Matic 6000 is a car reversing indicator mockup!
|
||||
|
||||
Press Ctrl+C a couple times to exit.
|
||||
""")
|
||||
|
||||
# Set up OLED
|
||||
|
||||
oled = sh1106(spi(port=0, device=1, gpio_DC=9), rotate=2, height=128, width=128)
|
||||
|
||||
# Set up VL53L1X Time of Flight sensor
|
||||
|
||||
tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
|
||||
tof.open() # Initialise the I2C bus and configure the sensor
|
||||
tof.start_ranging(3) # Start ranging, 1 = Short Range, 2 = Medium Range, 3 = Long Range
|
||||
|
||||
|
||||
# Load fonts
|
||||
|
||||
rr_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts', 'Roboto-Regular.ttf'))
|
||||
rb_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts', 'Roboto-Black.ttf'))
|
||||
rr_24 = ImageFont.truetype(rr_path, 24)
|
||||
rb_20 = ImageFont.truetype(rb_path, 20)
|
||||
rr_12 = ImageFont.truetype(rr_path, 12)
|
||||
|
||||
|
||||
i = 0
|
||||
threshold = 20 # Threshold at which the warning indicator flashes, in cm
|
||||
|
||||
# Main loop
|
||||
|
||||
while True:
|
||||
i += 1
|
||||
|
||||
background = Image.open("images/distance.png").convert(oled.mode) # Load the artwork
|
||||
|
||||
draw = ImageDraw.ImageDraw(background)
|
||||
|
||||
# Measure the distance and write to the right place on the display
|
||||
|
||||
cm = tof.get_distance() // 10
|
||||
cm += 1
|
||||
pos = 80 - (rb_20.getsize(str(cm))[0] / 2)
|
||||
draw.text((pos, 30), "{}".format(cm), fill="white", font=rb_20)
|
||||
|
||||
# Flash the warning indicator if the distance is below the threshold
|
||||
|
||||
if cm > threshold or i % cm == 1:
|
||||
draw.rectangle([(76, 66), (115, 110)], fill="black")
|
||||
|
||||
# Display on the OLED
|
||||
|
||||
oled.display(background)
|
||||
|
||||
time.sleep(0.05)
|
||||
BIN
vendor/breakout-garden/examples/distance/fonts/Roboto-Black.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/distance/fonts/Roboto-Regular.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/distance/images/distance.png
vendored
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
22
vendor/breakout-garden/examples/haptic-trackball/README.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Haptic trackball example
|
||||
|
||||
This example demonstrates how to generate haptic feedback
|
||||
as the trackball is scrolled/pressed.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [DRV2605L Haptic Breakout](https://shop.pimoroni.com/products/drv2605l-linear-actuator-haptic-breakout)
|
||||
- A Pimoroni [Trackball Breakout](https://shop.pimoroni.com/products/trackball-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./haptic-trackball.py` in the terminal.
|
||||
77
vendor/breakout-garden/examples/haptic-trackball/haptic-trackball.py
vendored
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
from trackball import TrackBall
|
||||
from drv2605 import DRV2605
|
||||
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires a
|
||||
DRV2605L Haptic Breakout and a Trackball Breakout.
|
||||
|
||||
This example demonstrates how to generate haptic feedback
|
||||
as the trackball is scrolled/pressed.
|
||||
|
||||
Press Ctrl+C to exit.
|
||||
""")
|
||||
|
||||
|
||||
# Set up Trackball Breakout.
|
||||
trackball = TrackBall(interrupt_pin=4)
|
||||
drv2605 = DRV2605()
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
|
||||
delta_x = 0
|
||||
delta_y = 0
|
||||
last_state = 0
|
||||
|
||||
# Set up Haptic Breakout.
|
||||
drv2605.reset()
|
||||
drv2605.set_realtime_data_format('Unsigned')
|
||||
drv2605.set_feedback_mode('LRA')
|
||||
drv2605.set_mode('Real-time Playback')
|
||||
drv2605.go()
|
||||
|
||||
try:
|
||||
while True:
|
||||
# Get positional values from trackball.
|
||||
up, down, left, right, switch, state = trackball.read()
|
||||
y += up
|
||||
y -= down
|
||||
x += right
|
||||
x -= left
|
||||
|
||||
delta_x += right
|
||||
delta_x -= left
|
||||
|
||||
delta_y += up
|
||||
delta_y -= down
|
||||
|
||||
x = max(0, min(x, 255))
|
||||
y = max(0, min(y, 255))
|
||||
|
||||
# Generate a longer click when trackball is pressed.
|
||||
if state != last_state:
|
||||
drv2605.set_realtime_input(255)
|
||||
time.sleep(0.01)
|
||||
drv2605.set_realtime_input(0)
|
||||
last_state = state
|
||||
|
||||
# Generate shorter clicks when trackball is scrolled.
|
||||
if abs(delta_x) > 2:
|
||||
drv2605.set_realtime_input(255)
|
||||
time.sleep(0.005)
|
||||
drv2605.set_realtime_input(0)
|
||||
delta_x = 0
|
||||
|
||||
elif abs(delta_y) > 2:
|
||||
drv2605.set_realtime_input(255)
|
||||
time.sleep(0.005)
|
||||
drv2605.set_realtime_input(0)
|
||||
delta_y = 0
|
||||
|
||||
time.sleep(0.001)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
57
vendor/breakout-garden/examples/heartbeat/README.md
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# Heartbeat example
|
||||
|
||||
This example, the Pulse-O-Matic 6000, is a heartbeat plotter and BPM display.
|
||||
|
||||
## Important!
|
||||
|
||||
**This code should not be used for medical diagnosis, as the basis for a real smoke
|
||||
or fire detector, or in life-critical situations. It's for fun/novelty use only,
|
||||
so bear that in mind while using it.**
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden HAT](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [MAX30105 Breakout - Heart Rate, Oximeter, Smoke Sensor](https://shop.pimoroni.com/products/max30105-breakout-heart-rate-oximeter-smoke-sensor)
|
||||
- A Pimoroni [1.12" OLED Breakout (SPI)](https://shop.pimoroni.com/products/1-12-oled-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
For this example you'll need to make sure some additional software is installed:
|
||||
|
||||
```
|
||||
sudo apt install python3-pil
|
||||
```
|
||||
|
||||
You'll need to clone and install the library for the 1.12" OLED Breakout (SPI)
|
||||
as follows:
|
||||
|
||||
```
|
||||
git clone https://github.com/pimoroni/sh1106-python
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
This example assumes that you have the OLED plugged into the front slot on the
|
||||
Breakout Garden HAT, which should also work with the Breakout Garden Mini HAT.
|
||||
To change it to the back slot, change `device=1` to `device=0` on the line
|
||||
where the OLED is set up.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./heartbeat.py` in the terminal.
|
||||
|
||||
It's best to hold the sensor against your fingertip (the fleshy side)
|
||||
using a piece of wire or a rubber band looped through the mounting
|
||||
holes on the breakout, as the sensor is very sensitive to small
|
||||
movements and it's hard to hold your finger against the sensor with
|
||||
even pressure.
|
||||
|
||||
If you're using your MAX30105 Breakout with Breakout Garden, then
|
||||
we'd recommend using one of our
|
||||
[Breakout Garden Extender Kits](https://shop.pimoroni.com/products/breakout-garden-extender-kit)
|
||||
with some [female to female jumper jerky](https://shop.pimoroni.com/products/jumper-jerky?variant=348491271).
|
||||
BIN
vendor/breakout-garden/examples/heartbeat/fonts/LiberationSans-Bold.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/heartbeat/fonts/LiberationSans-BoldItalic.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/heartbeat/fonts/LiberationSans-Italic.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/heartbeat/fonts/LiberationSans-Regular.ttf
vendored
Normal file
46
vendor/breakout-garden/examples/heartbeat/fonts/SIL Open Font License.txt
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
Digitized data copyright (c) 2010 Google Corporation
|
||||
with Reserved Font Arimo, Tinos and Cousine.
|
||||
Copyright (c) 2012 Red Hat, Inc.
|
||||
with Reserved Font Name Liberation.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
133
vendor/breakout-garden/examples/heartbeat/heartbeat.py
vendored
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# NOTE! This code should not be used for medical diagnosis. It's
|
||||
# for fun/novelty use only, so bear that in mind while using it.
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageFont
|
||||
from PIL import ImageDraw
|
||||
|
||||
from threading import Thread
|
||||
from luma.core.interface.serial import spi
|
||||
from luma.oled.device import sh1106
|
||||
|
||||
from max30105 import MAX30105, HeartRate
|
||||
|
||||
print("""
|
||||
NOTE! This code should not be used for medical diagnosis. It's
|
||||
for fun/novelty use only, so bear that in mind while using it.
|
||||
|
||||
This Pimoroni Breakout Garden example requires a
|
||||
MAX30105 Breakout and a 1.12" OLED Breakout (SPI).
|
||||
|
||||
The Pulse-O-Matic 6000 is a heartbeat plotter and BPM display.
|
||||
|
||||
Press Ctrl+C a couple times to exit.
|
||||
""")
|
||||
|
||||
# Set up OLED
|
||||
oled = sh1106(spi(port=0, device=1, gpio_DC=9), rotate=2, height=128, width=128)
|
||||
|
||||
# Load fonts
|
||||
lsb_18 = ImageFont.truetype("fonts/LiberationSans-Bold.ttf", 18)
|
||||
lsr_12 = ImageFont.truetype("fonts/LiberationSans-Regular.ttf", 12)
|
||||
|
||||
# Set up MAX30105 Breakout
|
||||
max30105 = MAX30105()
|
||||
max30105.setup(leds_enable=2)
|
||||
|
||||
max30105.set_led_pulse_amplitude(1, 0.2)
|
||||
max30105.set_led_pulse_amplitude(2, 12.5)
|
||||
max30105.set_led_pulse_amplitude(3, 0)
|
||||
|
||||
max30105.set_slot_mode(1, 'red')
|
||||
max30105.set_slot_mode(2, 'ir')
|
||||
max30105.set_slot_mode(3, 'off')
|
||||
max30105.set_slot_mode(4, 'off')
|
||||
|
||||
hr = HeartRate(max30105)
|
||||
data = []
|
||||
running = True
|
||||
|
||||
bpm = 0
|
||||
bpm_avg = 0
|
||||
beat_detected = False
|
||||
beat_status = False
|
||||
|
||||
|
||||
def sample():
|
||||
"""Function to thread heartbeat values separately to
|
||||
OLED drawing"""
|
||||
global bpm, bpm_avg, beat_detected, beat_status
|
||||
|
||||
average_over = 5
|
||||
bpm_vals = [0 for x in range(average_over)]
|
||||
last_beat = time.time()
|
||||
|
||||
while running:
|
||||
t = time.time()
|
||||
samples = max30105.get_samples()
|
||||
if samples is not None:
|
||||
for i in range(0, len(samples), 2):
|
||||
ir = samples[i + 1]
|
||||
beat_detected = hr.check_for_beat(ir)
|
||||
if beat_detected:
|
||||
beat_status = True
|
||||
delta = t - last_beat
|
||||
last_beat = t
|
||||
bpm = 60 / delta
|
||||
bpm_vals = bpm_vals[1:] + [bpm]
|
||||
bpm_avg = sum(bpm_vals) / average_over
|
||||
d = hr.low_pass_fir(ir & 0xff)
|
||||
data.append(d)
|
||||
if len(data) > 128:
|
||||
data.pop(0)
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
|
||||
# The thread to measure acclerometer values
|
||||
t = Thread(target=sample)
|
||||
t.start()
|
||||
|
||||
# The main loop that draws values to the OLED
|
||||
while True:
|
||||
try:
|
||||
img = Image.open("images/heartbeat.png").convert(oled.mode)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Draw the heartbeat trace
|
||||
vals = data
|
||||
new_vals = [x / float((max(vals) - min(vals))) * 32 for x in vals]
|
||||
|
||||
for i in range(1, len(new_vals)):
|
||||
draw.line([(i - 1, 80 - new_vals[i - 1]), (i, 80 - new_vals[i])],
|
||||
fill="white")
|
||||
|
||||
# Draw the Pulse-O-Matic "branding"
|
||||
draw.rectangle([(0, 0), (128, 20)], fill="black")
|
||||
if bpm_avg > 40:
|
||||
draw.text((0, 1), "BPM: {:.2f}".format(bpm_avg), fill="white",
|
||||
font=lsb_18)
|
||||
else:
|
||||
draw.text((0, 1), "BPM: --.--", fill="white", font=lsb_18)
|
||||
if beat_status:
|
||||
draw.text((115, 1), u"\u2665", fill="white", font=lsb_18)
|
||||
beat_status = False
|
||||
draw.line([(0, 20), (128, 20)], fill="white")
|
||||
|
||||
draw.rectangle([(0, 108), (128, 128)], fill="black")
|
||||
draw.text((0, 110), "Pulse-O-Matic 6000", fill="white", font=lsr_12)
|
||||
draw.line([(0, 108), (128, 108)], fill="white")
|
||||
|
||||
# Display on the OLED
|
||||
oled.display(img)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
running = False
|
||||
sys.exit(0)
|
||||
BIN
vendor/breakout-garden/examples/heartbeat/images/heartbeat.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
34
vendor/breakout-garden/examples/nightlight/README.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Nightlight example
|
||||
|
||||
A simple little example of how to make a nightlight with the LTR-559 and 5x5
|
||||
RGB matrix breakouts. It can be toggled on or off by tapping the sensor, or
|
||||
triggered automatically when it gets dark.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [LTR-559 Light & Proximity Sensor Breakout](https://shop.pimoroni.com/products/ltr-559-light-proximity-sensor-breakout)
|
||||
- A Pimoroni [5x5 RGB Matrix Breakout](https://shop.pimoroni.com/products/5x5-rgb-matrix-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install all of the required libraries.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./nightlight.py` in the terminal.
|
||||
|
||||
You can change the RGB values of the `colour` variable to change the colour
|
||||
of the light to whatever you wish. If you want the light and proximity
|
||||
thresholds to be more or less sensitive, then you can change the values of
|
||||
the `light_threshold` and `prox_threshold` variables.
|
||||
|
||||
## Notes
|
||||
|
||||
It's probably best to have the sensor and matrix breakouts on either side
|
||||
of your Breakout Garden HAT, so that they're spaced apart and the LTR-559
|
||||
won't be affected by the light from the matrix.
|
||||
103
vendor/breakout-garden/examples/nightlight/nightlight.py
vendored
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
|
||||
from ltr559 import LTR559
|
||||
from rgbmatrix5x5 import RGBMatrix5x5
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires an
|
||||
LTR-559 Light and Proximity Breakout and a 5x5 RGB Matrix Breakout.
|
||||
This example creates a little nightlight that can be toggled on or
|
||||
off by tapping the proximity sensor with your finger, or triggered
|
||||
automatically when it's dark.
|
||||
|
||||
Press Ctrl+C to exit.
|
||||
""")
|
||||
|
||||
# Set up the LTR-559 sensor
|
||||
|
||||
ltr559 = LTR559()
|
||||
|
||||
# Set up the 5x5 RGB matrix
|
||||
rgbmatrix5x5 = RGBMatrix5x5()
|
||||
rgbmatrix5x5.set_clear_on_exit()
|
||||
rgbmatrix5x5.set_brightness(0.8)
|
||||
|
||||
# Initial variables to keep track of state of light
|
||||
state = False
|
||||
last_state = False
|
||||
toggled = False
|
||||
|
||||
light_threshold = 100 # Low-light trigger level
|
||||
prox_threshold = 1000 # Proximity trigger level
|
||||
colour = (255, 165, 0) # Orange-ish
|
||||
|
||||
|
||||
# Function to toggle the RGB matrix on or off depending on state
|
||||
def toggle_matrix():
|
||||
global state, last_state
|
||||
|
||||
if state is True and last_state is False:
|
||||
rgbmatrix5x5.set_all(*colour)
|
||||
rgbmatrix5x5.show()
|
||||
elif state is False and last_state is True:
|
||||
rgbmatrix5x5.clear()
|
||||
rgbmatrix5x5.show()
|
||||
|
||||
last_state = state
|
||||
|
||||
|
||||
# Read the sensor once, as the first values are always squiffy
|
||||
ltr559.update_sensor()
|
||||
lux = ltr559.get_lux()
|
||||
prox =ltr559. get_proximity()
|
||||
time.sleep(1)
|
||||
|
||||
try:
|
||||
while True:
|
||||
# Read the light and proximity sensor
|
||||
ltr559.update_sensor()
|
||||
lux = ltr559.get_lux()
|
||||
prox = ltr559.get_proximity()
|
||||
|
||||
# If it's dark and the light isn't toggled on, turn on
|
||||
if lux < light_threshold and not toggled:
|
||||
state = True
|
||||
if state != last_state:
|
||||
print("It's dark! Turning light ON")
|
||||
toggle_matrix()
|
||||
|
||||
# If it's light and the light isn't on, turn off
|
||||
elif lux >= light_threshold and not toggled:
|
||||
state = False
|
||||
if state != last_state:
|
||||
print("It's light! Turning light OFF")
|
||||
toggle_matrix()
|
||||
|
||||
# If there's a tap on the sensor
|
||||
if prox > prox_threshold:
|
||||
# Toggle it off if it's currently on
|
||||
if toggled:
|
||||
state = False
|
||||
toggled = False
|
||||
if state != last_state:
|
||||
print("Toggling light OFF")
|
||||
toggle_matrix()
|
||||
# Toggle it on if it's currently off
|
||||
else:
|
||||
state = True
|
||||
toggled = True
|
||||
if state != last_state:
|
||||
print("Toggling light ON")
|
||||
toggle_matrix()
|
||||
# Wait a short while to prevent the on/off switch
|
||||
# from immediately re-triggering
|
||||
time.sleep(0.5)
|
||||
|
||||
elif prox < prox_threshold and lux >= light_threshold:
|
||||
state = False
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
28
vendor/breakout-garden/examples/rainbow-compass/README.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# Rainbow compass example
|
||||
|
||||
Calculates and displays compass heading as an
|
||||
RGB colour around the hue wheel, with North being red, South cyan,
|
||||
East green, and West purple, approximately.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [LSM303D Motion Sensor Breakout](https://shop.pimoroni.com/products/lsm303d-6dof-motion-sensor-breakout)
|
||||
- A Pimoroni [5x5 RGB Matrix Breakout](https://shop.pimoroni.com/products/5x5-rgb-matrix-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install all of the required libraries.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./rainbow-compass.py` in the terminal, and then
|
||||
walk through the calibration steps.
|
||||
|
||||
Depending on the orientation of you LSM303D breakout, you can change the
|
||||
line that says `Y = 2` in the `raw_heading` function to e.g. `Y = 1` if
|
||||
you have the breakout flat rather than vertical.
|
||||
100
vendor/breakout-garden/examples/rainbow-compass/rainbow-compass.py
vendored
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
import math
|
||||
import colorsys
|
||||
from lsm303d import LSM303D
|
||||
from rgbmatrix5x5 import RGBMatrix5x5
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires an LSM303D
|
||||
Motion Sensor Breakout and a 5x5 RGB Matrix Breakout.
|
||||
|
||||
The Rainbow Compass calculates and displays compass heading as an
|
||||
RGB colour around the hue wheel, with North being red, South cyan,
|
||||
East green, and West purple, appromximately.
|
||||
|
||||
Press Cyrl-+C to exit.
|
||||
""")
|
||||
|
||||
|
||||
def raw_heading(minimums, maximums, zero=0):
|
||||
"""Return a raw compass heading calculated from the magnetometer data."""
|
||||
|
||||
X = 0
|
||||
Y = 2 # Change to 1 if you have the breakout flat
|
||||
|
||||
# The range over which values will be calculated, i.e. -1 to +1
|
||||
mag_range = 2
|
||||
|
||||
# Get the magnetometer's values
|
||||
mag = list(lsm.magnetometer())
|
||||
|
||||
# Scale and shift values
|
||||
for i in range(len(mag)):
|
||||
mag[i] = ((mag_range / (maximums[i] - minimums[i])) * mag[i]) - \
|
||||
(mag_range / 2.0)
|
||||
|
||||
# Calculate the heading from the vector
|
||||
heading = math.atan2(mag[Y], mag[X])
|
||||
|
||||
if heading < 0:
|
||||
heading += (2 * math.pi)
|
||||
|
||||
# Convert radian value to degrees
|
||||
heading_degrees = (round(math.degrees(heading), 2) - zero) % 360
|
||||
|
||||
return heading_degrees
|
||||
|
||||
|
||||
lsm = LSM303D(0x1d) # Change to 0x1e if you have soldered the address jumper
|
||||
|
||||
# Set up the 5x5 RGB matrix
|
||||
rgbmatrix5x5 = RGBMatrix5x5()
|
||||
rgbmatrix5x5.set_clear_on_exit()
|
||||
rgbmatrix5x5.set_brightness(0.8)
|
||||
|
||||
# Python 2/3 compatibility
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
input("Lay your LSM303D in Breakout Garden flat (LSM303D vertical), \n\
|
||||
press a key to start, then rotate it 360 degrees, keeping it flat...\n")
|
||||
|
||||
# Variables to govern calibration time
|
||||
t_start = time.time()
|
||||
t_elapsed = 0
|
||||
calibration_time = 30
|
||||
|
||||
# Initial values for mins and maxs
|
||||
minimums = list(lsm.magnetometer())
|
||||
maximums = list(lsm.magnetometer())
|
||||
|
||||
# Run calibration until time limit is reached
|
||||
while t_elapsed < calibration_time:
|
||||
mag = lsm.magnetometer()
|
||||
for i in range(len(mag)):
|
||||
if mag[i] < minimums[i]: # Set new min
|
||||
minimums[i] = mag[i]
|
||||
if mag[i] > maximums[i]: # Set new max
|
||||
maximums[i] = mag[i]
|
||||
t_elapsed = time.time() - t_start
|
||||
|
||||
input("Calibration complete!\n\nIf you want to set a zero (North) point, \n\
|
||||
then turn your breakout to that point and press a key...\n")
|
||||
|
||||
# Zero point for the compass
|
||||
zero = raw_heading(minimums, maximums)
|
||||
|
||||
input("Press a key to begin readings!\n")
|
||||
|
||||
# Begin compass readings and display on RGB matrix
|
||||
while True:
|
||||
rh = raw_heading(minimums, maximums, zero=zero)
|
||||
hue = rh / 360.0 # Hue is based on compass heading
|
||||
r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(hue, 1.0, 1.0)]
|
||||
rgbmatrix5x5.set_all(r, g, b) # Set whole matrix to calculated RGB
|
||||
rgbmatrix5x5.show()
|
||||
print("compass heading: {:0.0f} degrees".format(rh))
|
||||
time.sleep(0.1)
|
||||
49
vendor/breakout-garden/examples/seismograph/README.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# Seismograph example
|
||||
|
||||
The Dino-Detect v1.2 beta is a dino stomp detector. It's a
|
||||
UNIX system, I know this.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [LSM303D 6DoF Sensor Breakout](https://shop.pimoroni.com/products/lsm303d-6dof-motion-sensor-breakout)
|
||||
- A Pimoroni [1.12" OLED Breakout (SPI)](https://shop.pimoroni.com/products/1-12-oled-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
For this example you'll need to make sure some additional software is installed:
|
||||
|
||||
```
|
||||
sudo apt install python3-pil
|
||||
```
|
||||
|
||||
You'll need to clone and install the library for the 1.12" OLED Breakout (SPI)
|
||||
as follows:
|
||||
|
||||
```
|
||||
git clone https://github.com/pimoroni/sh1106-python
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
This example assumes that you have the OLED plugged into the front slot on the
|
||||
Breakout Garden HAT, which should also work with the Breakout Garden Mini HAT.
|
||||
To change it to the back slot, change `device=1` to `device=0` on the line
|
||||
where the OLED is set up.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./seismograph.py` in the terminal.
|
||||
|
||||
Note that it takes a baseline reading initially to zero out the axes,
|
||||
and then calculates subsequent readings against the baseline, so make
|
||||
sure that your Breakout Garden is sitting still when you start the
|
||||
program.
|
||||
|
||||
The `sensitivity` variable can be changed to make the seismograph more or
|
||||
less sensitive to dino stomps.
|
||||
BIN
vendor/breakout-garden/examples/seismograph/fonts/Roboto-Black.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/seismograph/fonts/Roboto-Regular.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/seismograph/images/seismograph.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
122
vendor/breakout-garden/examples/seismograph/seismograph.py
vendored
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
from PIL import ImageFont
|
||||
from PIL import ImageDraw
|
||||
except ImportError:
|
||||
print("""This example requires PIL.
|
||||
Install with: sudo apt install python{v}-pil
|
||||
""".format(v="" if sys.version_info.major == 2 else sys.version_info.major))
|
||||
sys.exit(1)
|
||||
|
||||
from lsm303d import LSM303D
|
||||
from threading import Thread
|
||||
from luma.core.interface.serial import spi
|
||||
from luma.core.render import canvas
|
||||
from luma.oled.device import sh1106
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires an
|
||||
LSM303D 6DoF Breakout and a 1.12" OLED Breakout (SPI).
|
||||
|
||||
The Dino-Detect v1.2 beta is a dino stomp detector. It's a
|
||||
UNIX system, I know this.
|
||||
|
||||
Press Ctrl+C to exit.
|
||||
""")
|
||||
|
||||
# Set up OLED
|
||||
|
||||
oled = sh1106(spi(port=0, device=1, gpio_DC=9), rotate=2, height=128, width=128)
|
||||
|
||||
# Load fonts
|
||||
|
||||
rr_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts', 'Roboto-Regular.ttf'))
|
||||
print(rr_path)
|
||||
rb_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts', 'Roboto-Black.ttf'))
|
||||
rr_24 = ImageFont.truetype(rr_path, 24)
|
||||
rb_20 = ImageFont.truetype(rb_path, 20)
|
||||
rr_12 = ImageFont.truetype(rr_path, 12)
|
||||
|
||||
# Set up LSM303D motion sensor
|
||||
|
||||
lsm = LSM303D(0x1d)
|
||||
|
||||
samples = []
|
||||
points = []
|
||||
|
||||
sx, sy, sz = lsm.accelerometer() # Starting values to zero out accelerometer
|
||||
|
||||
sensitivity = 5 # Value from 1 to 10. Determines twitchiness of needle
|
||||
|
||||
# Function to thread accelerometer values separately to OLED drawing
|
||||
|
||||
def sample():
|
||||
while True:
|
||||
x, y, z = lsm.accelerometer()
|
||||
|
||||
x -= sx
|
||||
y -= sy
|
||||
z -= sz
|
||||
|
||||
v = y # Change this axis depending on orientation of breakout
|
||||
|
||||
# Scale up or down depending on sensitivity required
|
||||
|
||||
if v < 0:
|
||||
v *= (100 * sensitivity)
|
||||
else:
|
||||
v *= (40 * sensitivity)
|
||||
|
||||
|
||||
# Only keep 96 most recent values in list
|
||||
|
||||
points.append(v)
|
||||
if len(points) > 96:
|
||||
points.pop(0)
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
# The thread to measure acclerometer values
|
||||
|
||||
t = Thread(target=sample)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
# Wait for at least one data oint
|
||||
|
||||
while len(points) == 0:
|
||||
pass
|
||||
|
||||
# The main loop that draws values to the OLED
|
||||
|
||||
while True:
|
||||
background = Image.open("images/seismograph.png").convert(oled.mode)
|
||||
draw = ImageDraw.ImageDraw(background)
|
||||
|
||||
draw.line([(128, 64), (96, 64 + points[-1])], fill="white")
|
||||
draw.line([(128, 63), (96, 64 + points[-1])], fill="white")
|
||||
draw.line([(128, 65), (96, 64 + points[-1])], fill="white")
|
||||
|
||||
# Draw the seismograph trace
|
||||
|
||||
for i in range(1, len(points)):
|
||||
draw.line([(i - 1, 64 + points[i - 1]), (i, 64 + points[i])], fill="white")
|
||||
|
||||
# Draw the Dino-Detect "branding"
|
||||
|
||||
draw.rectangle([(0, 0), (128, 20)], fill="black")
|
||||
draw.text((0, 1), "AUS (A UNIX System)", fill="white", font=rr_12)
|
||||
draw.line([(0, 20), (128, 20)], fill="white")
|
||||
|
||||
draw.rectangle([(0, 108), (128, 128)], fill="black")
|
||||
draw.text((0, 110), "Dino-Detect v1.2 BETA", fill="white", font=rr_12)
|
||||
draw.line([(0, 108), (128, 108)], fill="white")
|
||||
|
||||
# Display on the OLED
|
||||
|
||||
oled.display(background)
|
||||
46
vendor/breakout-garden/examples/spirit-level/README.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Spirit level example
|
||||
|
||||
This examples emulates a circular spirit level, using the LCD to draw
|
||||
the spirit level and the 3DoF motion sensor to detect orientation.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [MSA301 3DoF Motion Sensor Breakout](https://shop.pimoroni.com/products/msa301-3dof-motion-sensor-breakout)
|
||||
- A Pimoroni [1.3" LCD Breakout](https://shop.pimoroni.com/products/1-3-spi-colour-lcd-240x240-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
For this example you'll need to make sure some additional software is installed:
|
||||
|
||||
```
|
||||
sudo apt install python3-pil
|
||||
```
|
||||
|
||||
You'll need to clone and install the library for the 1.3" LCD Breakout
|
||||
as follows:
|
||||
|
||||
```
|
||||
git clone https://github.com/pimoroni/st7789-python
|
||||
cd library
|
||||
sudo python3 setup.py install
|
||||
```
|
||||
|
||||
This example assumes that you have the LCD plugged into the front slot on the
|
||||
Breakout Garden HAT, which should also work with the Breakout Garden Mini HAT.
|
||||
To change it to the back slot, change `cs=ST7789.BG_SPI_CS_FRONT` to
|
||||
`cs=ST7789.BG_SPI_CS_BACK` and `backlight=19` to backlight=18` on the line
|
||||
where the LCD is set up.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./spirit-level.py` in the terminal.
|
||||
|
||||
It's assumed that you have the MSA301 breakout and LCD breakout lying flat, so
|
||||
your Raspberry Pi or Raspberry Pi Zero will be perpendicular to your flat surface.
|
||||
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-bubble.png
vendored
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-crosshair-black.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-crosshair-red.png
vendored
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
107
vendor/breakout-garden/examples/spirit-level/spirit-level.py
vendored
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||
import math
|
||||
import msa301
|
||||
import ST7789 as ST7789
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires an
|
||||
MSA301 3DoF Motion Sensor Breakout and a 1.3" LCD Breakout.
|
||||
|
||||
This examples emulates a circular spirit level, using the
|
||||
LCD to draw the spirit level and the accelerometer to
|
||||
detect orientation.
|
||||
|
||||
Press Ctrl+C to exit.
|
||||
""")
|
||||
|
||||
# Set up LCD
|
||||
disp = ST7789.ST7789(
|
||||
port=0,
|
||||
cs=ST7789.BG_SPI_CS_FRONT,
|
||||
dc=9,
|
||||
backlight=19,
|
||||
spi_speed_hz=80 * 1000 * 1000
|
||||
)
|
||||
|
||||
WIDTH = disp.width
|
||||
HEIGHT = disp.height
|
||||
|
||||
disp.begin()
|
||||
|
||||
# Load the image assets
|
||||
level = Image.open("images/spirit-level.png").convert("RGBA")
|
||||
bubble = Image.open("images/spirit-level-bubble.png").convert("RGBA")
|
||||
crosshair_black = Image.open("images/spirit-level-crosshair-black.png").convert("RGBA")
|
||||
crosshair_red = Image.open("images/spirit-level-crosshair-red.png").convert("RGBA")
|
||||
|
||||
# Sizes/coordinates of things
|
||||
bubble_dia = 64
|
||||
bubble_rad = bubble_dia / 2
|
||||
circle_dia = 190
|
||||
circle_rad = circle_dia / 2
|
||||
border = (WIDTH - circle_dia) / 2
|
||||
|
||||
centre_x = WIDTH / 2
|
||||
centre_y = HEIGHT / 2
|
||||
|
||||
# Set up MSA301
|
||||
accel = msa301.MSA301()
|
||||
accel.set_power_mode('normal')
|
||||
|
||||
x_vals = []
|
||||
y_vals = []
|
||||
|
||||
smooth = 3
|
||||
|
||||
while True:
|
||||
# Read MSA301 values
|
||||
x, y, z = accel.get_measurements()
|
||||
|
||||
# z = x-axis, y = y-axis
|
||||
bubble_centre_x = (2 - (z + 1)) * (circle_dia / 2) + border
|
||||
bubble_centre_y = (y + 1) * (circle_dia / 2) + border
|
||||
|
||||
# Work out vector length to check if outside circle
|
||||
delta_x = bubble_centre_x - centre_x
|
||||
delta_y = bubble_centre_y - centre_y
|
||||
|
||||
vector_length = math.sqrt(delta_x ** 2 + delta_y ** 2)
|
||||
|
||||
# If outside circle, scale position back down relatively
|
||||
if vector_length > circle_rad - bubble_rad:
|
||||
scale = (circle_rad - bubble_rad) / vector_length
|
||||
bubble_centre_x = centre_x + delta_x * scale
|
||||
bubble_centre_y = centre_y + delta_y * scale
|
||||
|
||||
|
||||
# Average x and y values to smooth jitter
|
||||
x_vals.append(bubble_centre_x)
|
||||
|
||||
if len(x_vals) > smooth:
|
||||
x_vals = x_vals[1:]
|
||||
|
||||
bubble_centre_x = int(sum(x_vals) / len(x_vals))
|
||||
|
||||
y_vals.append(bubble_centre_y)
|
||||
|
||||
if len(y_vals) > smooth:
|
||||
y_vals = y_vals[1:]
|
||||
|
||||
bubble_centre_y = int(sum(y_vals) / len(y_vals))
|
||||
|
||||
|
||||
# Use red crosshair if bubble is close to centre
|
||||
if (-0.05 < z < 0.05) and (-0.05 < y < 0.05):
|
||||
crosshair = crosshair_red
|
||||
else:
|
||||
crosshair = crosshair_black
|
||||
|
||||
# Construct image
|
||||
image = Image.new('RGBA', (WIDTH, HEIGHT), color=(0, 0, 0, 0))
|
||||
image.paste(level, (0, 0))
|
||||
image.paste(bubble, (int(bubble_centre_x - (bubble_dia / 2)), int(bubble_centre_y - (bubble_dia / 2))), mask=bubble)
|
||||
image.paste(crosshair, (0, 0), mask=crosshair)
|
||||
|
||||
# Display on LCD
|
||||
disp.display(image)
|
||||
49
vendor/breakout-garden/examples/uv-warning/README.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# UV warning example
|
||||
|
||||
This example uses a VEML6075 UVA/B sensor, a 5x5 RGB matrix, and a 1.2" OLED breakout
|
||||
to display average UV index as a traffic light warning on the RGB matrix, with green
|
||||
being a low UV index, yellow/orange being moderate, and red high or extreme. The numerical
|
||||
values and a descriptive warning are displayed on the OLED.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [VEML6075 UVA/B Sensor Breakout Breakout](https://shop.pimoroni.com/products/veml6075-uva-b-sensor-breakout)
|
||||
- A Pimoroni [5x5 RGB Matrix Breakout](https://shop.pimoroni.com/products/5x5-rgb-matrix-breakout)
|
||||
- A Pimoroni [1.12" OLED Breakout (SPI)](https://shop.pimoroni.com/products/1-12-oled-breakout)
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
For this example you'll need to make sure some additional software is installed:
|
||||
|
||||
```
|
||||
sudo apt install python3-pil
|
||||
```
|
||||
|
||||
You'll need to clone and install the library for the 1.12" OLED Breakout (SPI)
|
||||
as follows:
|
||||
|
||||
```
|
||||
git clone https://github.com/pimoroni/sh1106-python
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
This example assumes that you have the OLED plugged into the front slot on the
|
||||
Breakout Garden HAT, which should also work with the Breakout Garden Mini HAT.
|
||||
To change it to the back slot, change `device=1` to `device=0` on the line
|
||||
where the OLED is set up.
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./uv-warning.py` in the terminal
|
||||
|
||||
## Notes
|
||||
|
||||
You might want rotate your Pi and Breakout Garden so that the UV sensor is facing
|
||||
upwards at a better angle to detect UV light.
|
||||
BIN
vendor/breakout-garden/examples/uv-warning/fonts/Roboto-Black.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/uv-warning/fonts/Roboto-Regular.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/uv-warning/images/uv-warning.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
99
vendor/breakout-garden/examples/uv-warning/uv-warning.py
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import veml6075
|
||||
import smbus
|
||||
import colorsys
|
||||
from PIL import Image
|
||||
from PIL import ImageFont
|
||||
from PIL import ImageDraw
|
||||
from luma.core.interface.serial import spi
|
||||
from luma.core.render import canvas
|
||||
from luma.oled.device import sh1106
|
||||
from rgbmatrix5x5 import RGBMatrix5x5
|
||||
|
||||
print("""
|
||||
This Pimoroni Breakout Garden example requires a VEML6075 UV
|
||||
Breakout, a 5x5 RGB Matrix Breakout, and a 1.12" OLED Breakout (SPI).
|
||||
|
||||
The UV-O-Meter 3000 displays UV levels visually and in text.
|
||||
|
||||
Press Ctrl+C a couple times to exit.
|
||||
""")
|
||||
|
||||
# Map UV index to a descriptive level
|
||||
|
||||
def uv_to_description(avg_uv_index):
|
||||
if avg_uv_index < 3:
|
||||
return "LOW"
|
||||
elif 3 <= avg_uv_index < 6:
|
||||
return "MEDIUM"
|
||||
elif 6 <= avg_uv_index < 8:
|
||||
return "HIGH"
|
||||
elif 8 <= avg_uv_index < 11:
|
||||
return "V. HIGH"
|
||||
elif avg_uv_index > 11:
|
||||
return "EXTREME"
|
||||
else:
|
||||
return ""
|
||||
|
||||
bus = smbus.SMBus(1)
|
||||
|
||||
# Set up UV sensor
|
||||
uv_sensor = veml6075.VEML6075(i2c_dev=bus)
|
||||
uv_sensor.set_shutdown(False)
|
||||
uv_sensor.set_high_dynamic_range(False)
|
||||
uv_sensor.set_integration_time('100ms')
|
||||
|
||||
# Set up RGB matrix
|
||||
rgbmatrix5x5 = RGBMatrix5x5()
|
||||
rgbmatrix5x5.set_clear_on_exit()
|
||||
rgbmatrix5x5.set_brightness(1.0)
|
||||
|
||||
# Set up OLED
|
||||
oled = sh1106(spi(port=0, device=1, gpio_DC=9), rotate=2, height=128, width=128)
|
||||
|
||||
# Load fonts
|
||||
rr_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts', 'Roboto-Regular.ttf'))
|
||||
rb_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts', 'Roboto-Black.ttf'))
|
||||
rb_15 = ImageFont.truetype(rb_path, 15)
|
||||
rr_15 = ImageFont.truetype(rr_path, 15)
|
||||
|
||||
while True:
|
||||
try:
|
||||
img = Image.open("images/uv-warning.png").convert(oled.mode)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
draw.rectangle([(0, 0), (128, 128)], fill="black")
|
||||
|
||||
# Get UV data and calculate indices
|
||||
uva, uvb = uv_sensor.get_measurements()
|
||||
uv_comp1, uv_comp2 = uv_sensor.get_comparitor_readings()
|
||||
uv_indices = uv_sensor.convert_to_index(uva, uvb, uv_comp1, uv_comp2)
|
||||
uva_index, uvb_index, avg_uv_index = uv_indices
|
||||
|
||||
# Draw UV data to OLED
|
||||
draw.text((0, 0), "UV-O-Meter 3000", fill="white", font=rb_15)
|
||||
draw.text((0, 30), "UVA index: {:05.02f}".format(uva_index), fill="white", font=rr_15)
|
||||
draw.text((0, 48), "UVB index: {:05.02f}".format(uvb_index), fill="white", font=rr_15)
|
||||
draw.text((0, 66), "Avg. index: {:05.02f}".format(avg_uv_index), fill="white", font=rr_15)
|
||||
draw.text((0, 100), "Level: {}".format(uv_to_description(avg_uv_index)), fill="white", font=rb_15)
|
||||
|
||||
# Map avg. UV index to colour, from green to red
|
||||
hue = (10.001 - min(10, avg_uv_index)) / 30
|
||||
sat = 1.0
|
||||
val = 1.0
|
||||
r, g, b = [int(255 * c) for c in colorsys.hsv_to_rgb(hue, sat, val)]
|
||||
|
||||
# Light RGB matrix with calculated colour
|
||||
rgbmatrix5x5.set_all(r, g, b)
|
||||
rgbmatrix5x5.show()
|
||||
oled.display(img)
|
||||
|
||||
# Also print current UV index
|
||||
print ('Avg. UV index: {}'.format(avg_uv_index))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
53
vendor/breakout-garden/examples/weather/README.md
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# Weather example
|
||||
|
||||
This example turns your Breakout Garden into a mini weather display
|
||||
combining indoor temperature and pressure data with a weather icon
|
||||
indicating the current local weather conditions.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This example requires:
|
||||
|
||||
- A Pimoroni [Breakout Garden](https://shop.pimoroni.com/products/breakout-garden-hat-i2c-spi)
|
||||
- A Pimoroni [BME680 Breakout](https://shop.pimoroni.com/products/bme680-breakout)
|
||||
- A Pimoroni [1.12" OLED Breakout (SPI)](https://shop.pimoroni.com/products/1-12-oled-breakout)
|
||||
|
||||
You'll need the requests (`sudo pip install requests`), geocoder (`sudo pip install geocoder`),
|
||||
and BeautifulSoup4 (`sudo pip install beautifulsoup4`) libraries to query the Dark Sky weather page.
|
||||
|
||||
## Installation
|
||||
|
||||
Pop the breakouts into your Breakout Garden, and then run the `install.sh`
|
||||
script in the root of this repository with `sudo ./install.sh` to automagically
|
||||
install the libraries to run the I2C breakouts.
|
||||
|
||||
For this example you'll need to make sure some additional software is installed:
|
||||
|
||||
```
|
||||
sudo apt install python3-lxml python3-pil
|
||||
sudo pip3 install requests geocoder beautifulsoup4
|
||||
```
|
||||
|
||||
You'll need to clone and install the library for the 1.12" OLED Breakout (SPI)
|
||||
as follows:
|
||||
|
||||
```
|
||||
git clone https://github.com/pimoroni/sh1106-python
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
This example assumes that you have the OLED plugged into the front slot on the
|
||||
Breakout Garden HAT, which should also work with the Breakout Garden Mini HAT.
|
||||
To change it to the back slot, change `device=1` to `device=0` on the line
|
||||
where the OLED is set up.
|
||||
|
||||
|
||||
## Running this example
|
||||
|
||||
To run this example, type `./weather.py` in the terminal
|
||||
|
||||
## Notes
|
||||
|
||||
This example uses Sheffield as the default location, so you'll need to specify your city and
|
||||
country code at the top of the file, changing the variables called `CITY` and `COUNTRYCODE`
|
||||
to your current location.
|
||||
BIN
vendor/breakout-garden/examples/weather/fonts/Roboto-Black.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/weather/fonts/Roboto-Regular.ttf
vendored
Normal file
BIN
vendor/breakout-garden/examples/weather/icons/cloud.png
vendored
Executable file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
vendor/breakout-garden/examples/weather/icons/rain.png
vendored
Executable file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
vendor/breakout-garden/examples/weather/icons/snow.png
vendored
Executable file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
vendor/breakout-garden/examples/weather/icons/storm.png
vendored
Executable file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
vendor/breakout-garden/examples/weather/icons/sun.png
vendored
Executable file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
vendor/breakout-garden/examples/weather/icons/wind.png
vendored
Executable file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
vendor/breakout-garden/examples/weather/images/weather.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
218
vendor/breakout-garden/examples/weather/weather.py
vendored
Executable file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import time
|
||||
import datetime
|
||||
import glob
|
||||
import logging
|
||||
import sys
|
||||
|
||||
try:
|
||||
import requests
|
||||
import geocoder
|
||||
import lxml
|
||||
from bs4 import BeautifulSoup
|
||||
from PIL import Image
|
||||
from PIL import ImageFont
|
||||
from PIL import ImageDraw
|
||||
except ImportError:
|
||||
print("""
|
||||
This script requires several modules to run correctly.
|
||||
Install with:
|
||||
sudo pip install requests geocoder beautifulsoup4
|
||||
sudo apt install python{v}-lxml python{v}-pil
|
||||
""".format(v="" if sys.version_info.major == 2 else sys.version_info.major))
|
||||
sys.exit(1)
|
||||
|
||||
import bme680
|
||||
from luma.core.interface.serial import spi
|
||||
from luma.core.error import DeviceNotFoundError
|
||||
from luma.oled.device import sh1106
|
||||
|
||||
|
||||
|
||||
|
||||
TEMPERATURE_UPDATE_INTERVAL = 0.1 # in seconds
|
||||
|
||||
# Default to Sheffield-on-Sea for location
|
||||
CITY = "Sheffield"
|
||||
COUNTRYCODE = "GB"
|
||||
|
||||
# Used to calibrate the sensor
|
||||
TEMP_OFFSET = 0.0
|
||||
|
||||
|
||||
logging.basicConfig(level=os.environ.get("LOGLEVEL", "WARNING"))
|
||||
|
||||
|
||||
print("""This Pimoroni Breakout Garden example requires a
|
||||
BME680 Environmental Sensor Breakout and a 1.12" OLED Breakout.
|
||||
|
||||
This example turns your Breakout Garden into a mini weather display
|
||||
combining indoor temperature and pressure data with a weather icon
|
||||
indicating the current local weather conditions.
|
||||
|
||||
Press Ctrl+C a couple times to exit.
|
||||
""")
|
||||
|
||||
|
||||
# Convert a city name and country code to latitude and longitude
|
||||
def get_coords(address):
|
||||
g = geocoder.arcgis(address)
|
||||
coords = g.latlng
|
||||
logging.info("Location coordinates: %s", coords)
|
||||
return coords
|
||||
|
||||
|
||||
# Query Dark Sky (https://darksky.net/) to scrape current weather data
|
||||
def get_weather(coords):
|
||||
weather = {}
|
||||
try:
|
||||
res = requests.get("https://darksky.net/forecast/{}/uk212/en".format(","
|
||||
.join([str(c) for c in coords])))
|
||||
if res.status_code == 200:
|
||||
soup = BeautifulSoup(res.content, "lxml")
|
||||
curr = soup.find("span", "currently")
|
||||
if curr:
|
||||
img_name = curr.img["alt"].split()[0]
|
||||
logging.info("Weather summary: %s", img_name)
|
||||
weather["summary"] = img_name
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.error("Could not get weather data from DarkSky: {}".format(e))
|
||||
pass
|
||||
|
||||
return weather
|
||||
|
||||
|
||||
# This maps the weather summary from Dark Sky
|
||||
# to the appropriate weather icons
|
||||
icon_map = {
|
||||
"snow": ["snow", "sleet"],
|
||||
"rain": ["rain"],
|
||||
"cloud": ["fog", "cloudy", "partly-cloudy-day", "partly-cloudy-night"],
|
||||
"sun": ["clear-day", "clear-night"],
|
||||
"storm": [],
|
||||
"wind": ["wind"]
|
||||
}
|
||||
|
||||
# Pre-load icons into a dictionary with PIL
|
||||
icons = {}
|
||||
|
||||
for icon in glob.glob("icons/*.png"):
|
||||
icon_name = icon.split("/")[1].replace(".png", "")
|
||||
icon_image = Image.open(icon)
|
||||
icons[icon_name] = icon_image
|
||||
|
||||
|
||||
location_string = "{city}, {countrycode}".format(city=CITY,
|
||||
countrycode=COUNTRYCODE)
|
||||
coords = get_coords(location_string)
|
||||
|
||||
|
||||
def get_weather_icon(weather):
|
||||
if weather:
|
||||
summary = weather["summary"]
|
||||
|
||||
for icon in icon_map:
|
||||
if summary in icon_map[icon]:
|
||||
logging.info("Weather icon: %s", icon)
|
||||
return icons[icon]
|
||||
logging.error("Could not determine icon for weather")
|
||||
return None
|
||||
else:
|
||||
logging.error("No weather information provided to get icon")
|
||||
return None
|
||||
|
||||
|
||||
# Get initial weather data for the given location
|
||||
weather_icon = get_weather_icon(get_weather(coords))
|
||||
|
||||
# Set up OLED
|
||||
oled = sh1106(spi(port=0, device=1, gpio_DC=9), rotate=2, height=128, width=128)
|
||||
|
||||
# Set up BME680 sensor
|
||||
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_temp_offset(TEMP_OFFSET)
|
||||
|
||||
# Load fonts
|
||||
rr_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts',
|
||||
'Roboto-Regular.ttf'))
|
||||
rb_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fonts',
|
||||
'Roboto-Black.ttf'))
|
||||
rr_24 = ImageFont.truetype(rr_path, 24)
|
||||
rb_20 = ImageFont.truetype(rb_path, 20)
|
||||
rr_12 = ImageFont.truetype(rr_path, 12)
|
||||
|
||||
# Fetch sensor dating first so that device settings take effect
|
||||
sensor.get_sensor_data()
|
||||
# Initial values
|
||||
low_temp = sensor.data.temperature
|
||||
high_temp = sensor.data.temperature
|
||||
curr_date = datetime.date.today().day
|
||||
|
||||
last_checked = time.time()
|
||||
|
||||
# Main loop
|
||||
while True:
|
||||
# Limit calls to Dark Sky to 1 per minute
|
||||
if time.time() - last_checked > 60:
|
||||
weather_icon = get_weather_icon(get_weather(coords))
|
||||
last_checked = time.time()
|
||||
|
||||
# Load in the background image
|
||||
background = Image.open("images/weather.png").convert(oled.mode)
|
||||
|
||||
# Place the weather icon and draw the background
|
||||
if weather_icon:
|
||||
background.paste(weather_icon, (10, 46))
|
||||
draw = ImageDraw.ImageDraw(background)
|
||||
|
||||
# Gets temp. and press. and keeps track of daily min and max temp
|
||||
if sensor.get_sensor_data():
|
||||
temp = sensor.data.temperature
|
||||
press = sensor.data.pressure
|
||||
if datetime.datetime.today().day == curr_date:
|
||||
if temp < low_temp:
|
||||
low_temp = temp
|
||||
elif temp > high_temp:
|
||||
high_temp = temp
|
||||
else:
|
||||
curr_date = datetime.datetime.today().day
|
||||
low_temp = temp
|
||||
high_temp = temp
|
||||
|
||||
# Write temp. and press. to image
|
||||
draw.text((8, 22), "{0:4.0f}".format(press),
|
||||
fill="white", font=rb_20)
|
||||
draw.text((86, 12), u"{0:2.0f}°".format(temp),
|
||||
fill="white", font=rb_20)
|
||||
|
||||
# Write min and max temp. to image
|
||||
draw.text((80, 0), u"max: {0:2.0f}°".format(high_temp),
|
||||
fill="white", font=rr_12)
|
||||
draw.text((80, 110), u"min: {0:2.0f}°".format(low_temp),
|
||||
fill="white", font=rr_12)
|
||||
|
||||
# Write the 24h time and blink the separator every second
|
||||
if int(time.time()) % 2 == 0:
|
||||
draw.text((4, 98), datetime.datetime.now().strftime("%H:%M"),
|
||||
fill="white", font=rr_24)
|
||||
else:
|
||||
draw.text((4, 98), datetime.datetime.now().strftime("%H %M"),
|
||||
fill="white", font=rr_24)
|
||||
|
||||
# These lines display the temp. on the thermometer image
|
||||
draw.rectangle([(97, 43), (100, 86)], fill="black")
|
||||
temp_offset = 86 - ((86 - 43) * ((temp - 20) / (32 - 20)))
|
||||
draw.rectangle([(97, temp_offset), (100, 86)], fill="white")
|
||||
|
||||
# Display the completed image on the OLED
|
||||
oled.display(background)
|
||||
|
||||
time.sleep(TEMPERATURE_UPDATE_INTERVAL)
|
||||