Skip to content

Commit

Permalink
Merge pull request #96 from CalamityJames/new-features
Browse files Browse the repository at this point in the history
Large performance improvements and a couple of nice to have new features
  • Loading branch information
chrisys authored Jul 4, 2023
2 parents d185a94 + b4813a2 commit 5a19296
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 138 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
._DS_Store
src/__pycache__
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).

# v0.5.0
## (2023-06-29)

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

# v0.4.0
## (2023-02-18)

Expand Down
39 changes: 19 additions & 20 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
FROM balenalib/raspberry-pi-debian-python:3.7-buster-run AS builder
FROM balenalib/raspberry-pi-alpine-python:3.11.2-3.15-build as builder

WORKDIR /usr/src/app

RUN mkdir -p /usr/src/debian-rootfs

RUN install_packages apt-rdepends

RUN apt-get update && \
apt-get download \
$(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')

RUN for pkg in *.deb; \
do dpkg-deb -x $pkg /usr/src/debian-rootfs; \
done
# Shared libraries
RUN apk add freetype-dev libjpeg-turbo-dev

# Install the required python packages, and save the compiled result to an output folder
# This requires gcc/etc which is why we do it in the build image and save the result for the run image
COPY ./requirements.txt .
RUN pip install -t /usr/src/python-packages -r requirements.txt --no-cache-dir --extra-index-url=https://www.piwheels.org/simple

RUN pip install --target=/usr/src/python-packages -r requirements.txt --no-cache-dir --config-settings="pillow=--disable-zlib"

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


COPY --from=builder /usr/src/debian-rootfs ./
# Copy in the compiled packages
COPY --from=builder /usr/src/python-packages/ /usr/src/python-packages/

COPY VERSION ./
# Shared libraries
RUN apk add freetype-dev libjpeg-turbo-dev

# And the app
WORKDIR /usr/src/app
COPY src ./src
ENV PYTHONPATH=/usr/src/python-packages/
COPY VERSION .

# Tell python where to find these mysterious precompiled packages
ENV PYTHONPATH=/usr/src/python-packages

CMD ["python3", "src/main.py"]
# And off we go
CMD ["python3", "src/main.py"]
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.0
0.5.0
6 changes: 5 additions & 1 deletion balena.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,9 @@ data:
- screen1Platform:
- screen2Platform:
- individualStationDepartureTime: False
version: 0.4.0
- showDepartureNumbers: False
- firstDepartureBold: True
- targetFPS: 70
- fpsTime: 10
version: 0.5.0

6 changes: 5 additions & 1 deletion docs/04-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ These environment variables are specified using the [balenaCloud dashboard](http
| `screen1Platform` | `1` (sets the platform you want to have displayed on the first or single-screen display)
| `screen2Platform` | `2` (sets the platform you want to have displayed on the second display)
| `individualStationDepartureTime` | `False` (Displays the estimated or scheduled time of the service at each leg of a journey)

| `fpsTime` | `4` (adjusts how often the effective FPS is displayed)
| `headless` | `True` (outputs to noop serial device rather than serial port; useful for running on a development machine)
| `showDepartureNumbers` | `True` (adds 1st / 2nd / 3rd as per UK train departures)
| `firstDepartureBold` | `False` (makes the first departure use either the bold or normal font)
| `targetFPS` | `20` (Frame rate regulator FPS target; 0 disables the regulator, which will increase FPS on constrained CPU, but will run the CPU hot at 100%.)

If using two screens the following line needs to be added into /boot/config.txt which is achieved by using the 'Define DT overlays' option within the Device configuration screen on balenaCloud: `spi1-3cs`

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
luma.oled
timeloop
requests
xmltodict
xmltodict
24 changes: 18 additions & 6 deletions src/config.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import os
import re


def loadConfig():
data = {
"journey": {},
"api": {}
}

data["targetFPS"] = int(os.getenv("targetFPS") or 70)
data["refreshTime"] = int(os.getenv("refreshTime") or 180)
data["fpsTime"] = int(os.getenv("fpsTime") or 180)
data["screenRotation"] = int(os.getenv("screenRotation") or 2)
data["screenBlankHours"] = os.getenv("screenBlankHours") or ""
data["headless"] = False
if os.getenv("headless") == "True":
data["headless"] = True
data["dualScreen"] = False
if os.getenv("dualScreen") == "True":
data["dualScreen"] = True
data["firstDepartureBold"] = True
if os.getenv("firstDepartureBold") == "False":
data["firstDepartureBold"] = False
data["hoursPattern"] = re.compile("^((2[0-3]|[0-1]?[0-9])-(2[0-3]|[0-1]?[0-9]))$")

data["journey"]["departureStation"] = os.getenv("departureStation") or "PAD"
Expand All @@ -26,19 +35,22 @@ def loadConfig():
data["journey"]["individualStationDepartureTime"] = True

data["journey"]["outOfHoursName"] = os.getenv("outOfHoursName") or "London Paddington"
data["journey"]["stationAbbr"] = { "International": "Intl." }
data["journey"]["stationAbbr"] = {"International": "Intl."}
data["journey"]['timeOffset'] = os.getenv("timeOffset") or "0"
data["journey"]["screen1Platform"] = os.getenv("screen1Platform")
data["journey"]["screen2Platform"] = os.getenv("screen2Platform")
data["journey"]["screen1Platform"] = os.getenv("screen1Platform") or ""
data["journey"]["screen2Platform"] = os.getenv("screen2Platform") or ""

if data["journey"]["screen1Platform"].isnumeric() != True:
if data["journey"]["screen1Platform"].isnumeric() is not True:
data["journey"]["screen1Platform"] = ""

if data["journey"]["screen2Platform"].isnumeric() != True:
if data["journey"]["screen2Platform"].isnumeric() is not True:
data["journey"]["screen2Platform"] = ""

data["api"]["apiKey"] = os.getenv("apiKey") or None
data["api"]["operatingHours"] = os.getenv("operatingHours") or ""

data["showDepartureNumbers"] = False
if os.getenv("showDepartureNumbers") == "True":
data["showDepartureNumbers"] = True

return data

Loading

0 comments on commit 5a19296

Please sign in to comment.