Skip to content

Commit b4813a2

Browse files
authored
Performance: Move to 3.11 and tidy up for Balena (hzeller#2)
* zooom zoom * bleep * tweak; remove zlib, but libjpeg is required at runtime * rm emu * tbh * rewrite for merge to 0.5.0
1 parent 44f9e46 commit b4813a2

7 files changed

+31
-40
lines changed

CHANGELOG.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
77
# v0.5.0
88
## (2023-06-29)
99

10+
* Upgrade: Switch Python version and base OS: Python 3.11 on Alpine
1011
* New feature: `showDepartureNumbers` option - Adds 1st / 2nd / 3rd prefix as per UK train departures
1112
* New feature: `firstDepartureBold` option - toggle bold of first departure line as this is regional
1213
* New feature: `targetFPS` option - configurable FPS regulator (zero to disable)
1314
* Development UX: `fpsTime` option - Adjusts how frequently the Effecive FPS is displayed
14-
* Development UX: `emulator` option - Emulator mode via pygame
1515
* Development UX: `headless` option - Run using emulated serial port (Useful for optimisation checks)
16-
* Development UX: Skip NRE attribution sleep in any dev mode (headless/emulator)
16+
* Development UX: Skip NRE attribution sleep in emulation mode
17+
* Development UX: Simplify Dockerfile slightly in an attempt to be Balena-y
1718
* Performance: Seconds now render every 0.1 second, rather than a hotspot (reduce CPU)
1819
* Performance: All "in-loop" TTF font rendering is now cached (reduce CPU)
1920
* Fix: screen1Platform/screen2Platform being required incorrectly on the env

Dockerfile

+19-20
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
1-
FROM balenalib/raspberry-pi-debian-python:3.7-buster-run AS builder
1+
FROM balenalib/raspberry-pi-alpine-python:3.11.2-3.15-build as builder
22

33
WORKDIR /usr/src/app
44

5-
RUN mkdir -p /usr/src/debian-rootfs
6-
7-
RUN install_packages apt-rdepends
8-
9-
RUN apt-get update && \
10-
apt-get download \
11-
$(apt-rdepends tzdata python3 libopenjp2-7 libfreetype6-dev libjpeg-dev libtiff5 libxcb1 | grep -v "^ " | sed 's/debconf-2.0/debconf/g' | sed 's/^libc-dev$/libc6-dev/g' | sed 's/^libz-dev$/zlib1g-dev/g')
12-
13-
RUN for pkg in *.deb; \
14-
do dpkg-deb -x $pkg /usr/src/debian-rootfs; \
15-
done
5+
# Shared libraries
6+
RUN apk add freetype-dev libjpeg-turbo-dev
167

8+
# Install the required python packages, and save the compiled result to an output folder
9+
# This requires gcc/etc which is why we do it in the build image and save the result for the run image
1710
COPY ./requirements.txt .
18-
RUN pip install -t /usr/src/python-packages -r requirements.txt --no-cache-dir --extra-index-url=https://www.piwheels.org/simple
19-
11+
RUN pip install --target=/usr/src/python-packages -r requirements.txt --no-cache-dir --config-settings="pillow=--disable-zlib"
2012

21-
FROM busybox:stable
13+
# Grab the "run" image for the device, which is much lighter weight
14+
FROM balenalib/raspberry-pi-alpine-python:3.11.2-3.15-run
2215

23-
24-
COPY --from=builder /usr/src/debian-rootfs ./
16+
# Copy in the compiled packages
2517
COPY --from=builder /usr/src/python-packages/ /usr/src/python-packages/
2618

27-
COPY VERSION ./
19+
# Shared libraries
20+
RUN apk add freetype-dev libjpeg-turbo-dev
2821

22+
# And the app
23+
WORKDIR /usr/src/app
2924
COPY src ./src
30-
ENV PYTHONPATH=/usr/src/python-packages/
25+
COPY VERSION .
26+
27+
# Tell python where to find these mysterious precompiled packages
28+
ENV PYTHONPATH=/usr/src/python-packages
3129

32-
CMD ["python3", "src/main.py"]
30+
# And off we go
31+
CMD ["python3", "src/main.py"]

balena.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,6 @@ data:
7272
- showDepartureNumbers: False
7373
- firstDepartureBold: True
7474
- targetFPS: 70
75-
version: 0.4.0
75+
- fpsTime: 10
76+
version: 0.5.0
7677

docs/04-configuration.md

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ These environment variables are specified using the [balenaCloud dashboard](http
2424
| `screen2Platform` | `2` (sets the platform you want to have displayed on the second display)
2525
| `individualStationDepartureTime` | `False` (Displays the estimated or scheduled time of the service at each leg of a journey)
2626
| `fpsTime` | `4` (adjusts how often the effective FPS is displayed)
27-
| `emulator` | `True` (outputs to pygame emulator rather than serial; useful for running on a development machine)
2827
| `headless` | `True` (outputs to noop serial device rather than serial port; useful for running on a development machine)
2928
| `showDepartureNumbers` | `True` (adds 1st / 2nd / 3rd as per UK train departures)
3029
| `firstDepartureBold` | `False` (makes the first departure use either the bold or normal font)

requirements.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
luma.oled
2-
luma.emulator
32
timeloop
43
requests
5-
xmltodict
4+
xmltodict

src/config.py

-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ def loadConfig():
1616
data["headless"] = False
1717
if os.getenv("headless") == "True":
1818
data["headless"] = True
19-
data["emulator"] = False
20-
if os.getenv("emulator") == "True":
21-
data["emulator"] = True
2219
data["dualScreen"] = False
2320
if os.getenv("dualScreen") == "True":
2421
data["dualScreen"] = True

src/main.py

+6-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from luma.core.interface.serial import spi, noop
1414
from luma.core.render import canvas
1515
from luma.oled.device import ssd1322
16-
from luma.emulator.device import pygame
1716
from luma.core.virtual import viewport, snapshot
1817
from luma.core.sprite_system import framerate_regulator
1918

@@ -392,16 +391,12 @@ def drawSignage(device, width, height, data):
392391

393392
print('Starting Train Departure Display v' + version_file.read())
394393
config = loadConfig()
395-
if config['emulator']:
396-
print('Emulating using pygame; frames will be locked to 60fps')
397-
device = pygame(256, 64)
394+
if config['headless']:
395+
print('Headless mode, running main loop without serial comms')
396+
serial = noop()
398397
else:
399-
if config['headless']:
400-
print('Headless mode, running main loop without serial comms')
401-
serial = noop()
402-
else:
403-
serial = spi(port=0)
404-
device = ssd1322(serial, mode="1", rotate=config['screenRotation'])
398+
serial = spi(port=0)
399+
device = ssd1322(serial, mode="1", rotate=config['screenRotation'])
405400

406401
if config['dualScreen']:
407402
serial1 = spi(port=1, gpio_DC=5, gpio_RST=6)
@@ -426,7 +421,7 @@ def drawSignage(device, width, height, data):
426421
if config['dualScreen']:
427422
virtual = drawStartup(device1, width=widgetWidth, height=widgetHeight)
428423
virtual.refresh()
429-
if config['emulator'] is not True and config['headless'] is not True:
424+
if config['headless'] is not True:
430425
time.sleep(5)
431426

432427
timeAtStart = time.time() - config["refreshTime"]

0 commit comments

Comments
 (0)