Skip to content

🦀 Hackable information display fully built in Rust

License

Notifications You must be signed in to change notification settings

eliabieri/wg_display

Repository files navigation




🦀 Hackable information display fully built in Rust and extensible through WebAssembly Components 🦀

Extensible, open-source and connected to the local community


GitHub Workflow Status GitHub Workflow Status

GitHub release (latest SemVer) GitHub commits since latest release (by SemVer)

⭐️ What WG Display can show you

  • 🚂 The next public transport connections between two stations
  • 🏊🏻 The current temperature of the Aare River and whether it is a good idea to take a dip
  • ⏰ The current date and time
  • 🧖🏽‍♀️ The current occupancy in the "Sauna Lorrainebad" in Bern, CH
  • 🕺🏾 The next event at the Cafete Club
  • .. what ever idea you might have? Simply write your own widget

✨ Features

  • 🦀 Fully built in Rust
  • 🔧 Extensible through WebAssembly. Write your own widget in Rust or any other language that compiles to WebAssembly
  • 🚀 Easy deployment. Compiles to single binary
  • 🤑 Only needs a Raspberry Pi (64-bit capable) and a 15$ display
  • ⚙️ Widgets can be configured by the user via a web interface

📚 Table of contents

WG Display image front


Configuration dashboard The web interface allows the users to configure system aspects like the background color used on the display or various configuration options of the different widgets.

🚀 Getting started

  1. Flash the latest Raspberry Pi OS Lite (64-bit) image to an SD card.
    You can use the Raspberry Pi Imager. It allows you to configure the Wi-Fi credentials and enable SSH (you'll need it in the next step).
  2. SSH into the Raspberry Pi and run the installation script
    # SSH into the Raspberry Pi
    ssh [email protected]
    # Run the installation script (after you've logged in over SSH)
    curl -sL https://raw.githubusercontent.com/eliabieri/wg_display/main/install_on_raspberry.py | python3

The configuration dashboard should be available at wgdisplay.local

🛠️ Assembling the hardware

WG Display is best deployed on a Raspberry Pi and a cheap display hat.

💡 Even a Raspberry PI Zero 2 W is sufficient! 
The application is very ressource efficient and generally only utilizes around 3% CPU on a Raspberry PI 3B.

Some displays that are tested to be good

  • 5" MIPI DIS Display
    • ✨ Requires no driver
    • ✨ Includes stand
    • 📐 Large enough to display ~ 6 widgets
    • 💲💲💲
  • 3.5" HAT Display
    • ✨ Includes enclosure for wall mounting
    • ⚠️ Requires a driver
    • 📐 Large enough to display ~ 3 widgets
    • 💲
  • 3.5" HAT HDMI Display
    • ✨ Requires no driver
    • 📐 Large enough to display ~ 3 widgets
    • 💲💲
  • Any other display you might find
    • WG Display uses the terminal for rendering, so there are no special display requirements

🔨Building from source

Prerequisites

First, install rustup then

# Install WebAssembly target
rustup target add wasm32-wasip2
# Install trunk for building the frontend
cargo install --locked trunk
# Install NPM dependencies
cd frontend && npm install

Prerequisites for cross-compilation

First, install docker, then

cargo install cross --git https://github.com/cross-rs/cross

Building the project

# Native build
make
# Cross compilation (Raspberry Pi 3/4/Zero 2 W with 64-bit OS)
make app_aarch64

Then simply copy over the generated binary to the target and run it.

💡 To run it at boot, simply add the path to the binary to the end of the ~/.bashrc file.

👏 Writing your own widget

Want your WG Display to show you

  • 🥳 the upcoming events in your favorite nightclub
  • 🚮 the trash calendar in your municipality
  • 🍺 beers on sale in your local supermarket?

You've got two options

  • Write your own widget. It's easy using the provided guide and reference implementations
  • In case you don't feel capable of writing it yourself, open a feature request and tag it using the widget request label

📖 Documentation (rustdocs)

The rustdocs can be built using

make docs

This generates three separate documentations, one for each crate

app: app/target/doc/app/index.html
common: common/target/doc/common/index.html
frontend: frontend/target/doc/frontend/index.html

🧪 Testing

Widgets should provide unit tests for their functionality where adequate.
Asynchronous functions can be tested using the tokio_test::block_on function.

🔮 What comes next

  • Add installation script
  • Dynamically load widgets
  • Template repository for widgets written in Rust
  • Smoothen up web interface (e.g. add loading indicator, allow updating of widgets)
  • Template repository for widgets written in JS
  • Allow user to configure Wi-Fi credentials via web interface
  • Starting the binary through systemd
  • Implement an update mechanism
  • Implement authentication for the web interface

🔒 Safety

This project uses #[forbid(unsafe_code)] in all crates to ensure that no unsafe Rust is ever added to the project

♻️ Updating the dependencies

# To update the dependencies in all crates, simply run
scripts/update_dependencies.sh

🦾 Developing on target

When developing, an occasional run on a target may be required.
You can the following script as a template to copy over the binary to the target and restart it

#!/bin/sh
set -e

# Note:
# - Set hostname of target to wgdisplay
# - Add public key to authorized_keys on target
# - Enable root ssh login: https://raspberrypi.stackexchange.com/questions/48056/how-to-login-as-root-remotely

make app_arm
ssh [email protected] "sudo /usr/bin/pkill -9 app || true"
scp /Users/eliabieri/git/wg_display/app/target/arm-unknown-linux-gnueabihf/release/app [email protected]:/home/pi
ssh [email protected] "sudo reboot"