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>
This commit is contained in:
dissimulo
2026-05-06 01:32:39 -07:00
commit 030172f523
99 changed files with 4445 additions and 0 deletions

View 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View 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)