The goal of this project was to avoid waiting at the tram-stop in sub-zero temperatures, which would be achieved by having a constantly-updating display showing the next departure time from our local tram-stop.
If there is a tram due in a couple of minutes we could leave the house in safety, if there was a wait of 10+ minutes we'd stay indoors.
The hardware for this project is simple:
- 1 x WeMos Mini D1
- Approximately cost €2.50.
- 1 x Push-Button
- Approximate cost €0.05.
- 1 x I2C LCD Display
- Approximate cost €1.50.
- We've previously documented using an I2C LCD with an Arduino.
- In my project the display was initially 2x16, but the code allows for different dimensions.
- I soon upgraded it to a 4x20 display instead, as pictured below.
Wiring merely consists of connecting the display to the Mini D1 board, which is in turn powered by a simple USB-PSU, then adding in the push-button as an optional extra. The display-wiring is as follows:
- Vcc -> Vcc (3.3v)
- Ground -> Ground
- SCL -> WeMos D1 D1
- SDA -> WeMos D1 D2
The push-button is connected between D0 & D8, and is entirely optional
The initial wireup.
Adding a button between D0 & D8..
Fitting things into the box I had 3d-printed.
The boxed result.
The software for this project is logically divided into a few distinct parts:
- Handling connections to the local WiFi network.
- You need an IP so you can connect to the internet to fetch the timing details.
- Fetching the current date & time, via NTP.
- Drawing that date & time.
- Fetching the tram-time for the local tram-stop.
- I had to introduce a simple tram-API to cut down on the processing on the device itself.
- Drawing that data.
- Allowing over the air updates, directly from the arduino IDE.
- Handling button-input, if this is added.
For dealing with the date & time, including retrieving the current time via NTP, I used the standard time library, which has excellent support for such things. The web GUI allows changing the time-zone, which is necessary if you're outside GMT.
Retriving the departure-times for a given tram-stop is pretty straight-forward, but unfortunately I implemented my project at a time when the Helsinki transport system switched their public API away from being a simple HTTP-fetch of JSON data, now it is a little more verbose.
To simplify the complexity of dealing with that new API, which in fact is pretty flexible and straight-forward, I setup a simple proxy to return the appropriate departure-details as CSV via the numerical stop-ID:
Parsing CSV is much simpler for the hardware, which is barely able to make HTTPS calls, but I will say the Helsinki documentation was excellent. I managed to make this transition in only a couple of hours.
If you've previously configured WiFi details the device will connect automatically, and begin showing the current date & time, along with the upcoming departure times.
If you've never configured the device it will instead notice that, and begin to operate as a WiFi access-point - you can use your mobile phone, or other WiFi-connected device to connect to this access-point and choose the local WiFi network it should join.
This project doesn't require any recompilation to change the networking details, the tram-stop, or the timezone.
Once configured the system will:
- Update the date/time display once a second.
- Resync the time, via NTP, every five minutes to avoid drift.
- Serve a simple GUI via HTTP
- This mirrors the output, shown on the screen, as well as allowing changes to be made.
- Control the backlight.
- Change the tram-stop being monitored.
- Change the TimeZone offset (i.e. This project is for Helsinki, so we're at
GMT + 2.)
The button, if present, allows two things :
- A short-press
- Toggles the state of the backlight.
- A long-press
- Triggers an immediate resync of the date & time, as well as the tram-data..
The main code looks like this:
Several libraries are used, and these are bundled together in a git repository, you can access all the source by cloning the repo involved, and then looking at the project:
The project has become much more user-friendly thanks to the addition of the access-point functionality. You no longer need to recompile the code to configure your WiFi details, change the tram-stop, or adjust the timezone offset.
Previously the display was hard-wired for 2x16 LCDs, now this is flexible via
#definestatements - I used this facility to update the display from 2 rows of 16-characters (2x16) to 4 rows of 20 characters (4x20):#define NUM_ROWS 4 #define NUM_COLS 20
The code has also recently been updated to support over-the-air updates, directly from the arduino IDE.
Finally the built-in HTTP-server shows the tram-data, along with explicit links for controlling the backlight, changing the tram-stop, and changing the timezone.