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:
46
vendor/breakout-garden/examples/spirit-level/README.md
vendored
Normal file
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
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-bubble.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-crosshair-black.png
vendored
Normal file
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-crosshair-black.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-crosshair-red.png
vendored
Normal file
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level-crosshair-red.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level.png
vendored
Normal file
BIN
vendor/breakout-garden/examples/spirit-level/images/spirit-level.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
107
vendor/breakout-garden/examples/spirit-level/spirit-level.py
vendored
Executable file
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)
|
||||
Reference in New Issue
Block a user