The following components are required (all through hole):
Qty. | Item | Value | Label | Footprint | Price |
---|---|---|---|---|---|
1 | ESP8266 NodeMCU v3 board (4MB flash) | - | - | US$ 2.05 | |
3 | MAX7219 8×8 SPI LED matrix | - | - | US$ 3.14 | |
1 | DC Female Power Socket | 5.5 × 2.1mm | J1 |
PTH | US$ 0.07 |
1 | Trimmer potentiometer | 3mm, 1kΩ | R1 |
DIP-3 PTH | US$ 0.04 |
1 | LED | green, 3mm | LED1 |
THT | US$ 0.02 |
1 | LED | yellow, 3mm | LED2 |
THT | US$ 0.02 |
1 | Resistor (axial) | 4.7kΩ, ¼W, ±5% | R2 |
THT | US$ 0.01 |
2 | Resistor (axial) | 100Ω, ¼W, ±5% | R3 , R4 |
THT | US$ 0.01 |
I used RobotDyn yellow/amber colored modules. A lot of other modules will also work, but they need to be 5-pin SPI chainable modules. Be aware of the pinout!
For the ESP8266 board, I used a KeyeStudio NodeMCU but any other NodeMCU V2 or V3 board also works.
The knockoff V3 boards are better because they use a CH340 USB controller chip and have the A0
pin reference
voltage set at 3.3V
instead of 1.0V
, meaning no voltage divider circuit is needed.
The circuit board is very simple and just holds the ESP8266 and the 3 LED matrices as well as the power jack and a trimpot to adjust the LED brightness.
I had 10 boards (1.6mm FR4 ENIG, RoHS, black solder mask) manufactured by JLPCB for US$ 44.00 including shipping in April 2021. The black solder mask makes it easy to prevent reflections inside the case (and it looks gorgeous).
The Fritzing file as well as the exported Gerber files can be found in the hardware folder.
The robotdyn-max7219-LED-matrix.fzpz
Fritzing part was made
by @vanepp
on the Fritzing forums.
[TBD]
$ pip3 install --user esptool
$ pip3 install --user adafruit-ampy
Download the latest MicroPython firmware for ESP8266 and flash it to the NodeMCU.
esp8266-20220117-v1.18.bin
and flash it to the ESP8266.
Note: Since July 2024, when using the OpenWeatherMap API, you need to use a custom build of MicroPython with a larger TLS buffer. See the section below for more details.
Note: The USB serial device (/dev/tty.usbserial-1430
) will be different, depending on your operating
system, USB controller and port you use.
$ esptool.py --port /dev/tty.usbserial-1430 erase_flash
$ esptool.py --port /dev/tty.usbserial-1430 --baud 460800 write_flash --flash_size=detect -fm dio 0x00 firmware/ESP8266_GENERIC-20240602-v1.24.0.bin
OpenWeatherMap switched to a new SSL certificate in July 2024 which is too large for the default buffer size in the ESP8266's MicroPython TLS implementation with axTLS. This causes the ESP8266 to crash when trying to fetch weather data. To address this, the buffer size needs to be increased by recompiling the firmware with appropriate settings. More details can be found in this GitHub issue.
I have provided a precompiled firmware image with the necessary changes in the firmware folder. The firmware
is based on MicroPython 1.24.0
and has a larger TLS buffer size of 8192 bytes. Simply use the ESP8266_GENERIC-20240602-v1.24.0-tls-buffer-8192.bin
file instead of ESP8266_GENERIC-20240602-v1.24.0.bin
.
You can also compile the firmware for ESP8266 yourself with the following steps:
gh repo clone micropython/micropython
cd micropython
git checkout v1.24.0
make -C ports/esp8266 submodules
docker run --rm -v $HOME:$HOME -u $UID -w $PWD -e GIT_DISABLE_UNTRACKED_CACHE=1 larsks/esp-open-sdk make -j8 -C mpy-cross
cd ports/esp8266
docker run --rm -v $HOME:$HOME -u $UID -w $PWD -e GIT_DISABLE_UNTRACKED_CACHE=1 larsks/esp-open-sdk make -j8 AXTLS_DEFS_EXTRA="-Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=8192" BOARD="ESP8266_GENERIC"
The firmware can then be found at build-ESP8266_GENERIC/firmware.bin
.
Edit secrets.py
and configure the values for your WiFi network (WIFI_SSID
and WIFI_PASSWORD
).
Next, sign up for a free account on OpenWeather, generate
an API key and set it in the OW_API_KEY
constant in secrets.py
.
Find the location you want to display weather data for on OpenWeather and set the
GEO_NAME
, GEO_LAT
and GEO_LON
constants in secrets.py
. GEO_NAME
is not really used at the
moment, so it's only a reminder for you so you know what place you're looking at.
DISPLAY_OFF_START
and DISPLAY_OFF_END
are used to control when the display is turned off, e.g. at night. The value
is the hour in 24-hour format, in UTC. Adjust accordingly. If you're in New York City and you want the display to turn
off from 11pm to 7am, you might want to set DISPLAY_OFF_START
to 3
and DISPLAY_OFF_END
to 11
. Set both values
to 0
if you never want to turn off the display.
Use Adafruit's ampy
tool to upload the software to the ESP8266. Adjust the
port according to your operating system and USB controller.
$ ampy --port /dev/tty.usbserial-1430 --baud 115200 put src/boot.py
$ ampy --port /dev/tty.usbserial-1430 --baud 115200 put src/max7219.py
$ ampy --port /dev/tty.usbserial-1430 --baud 115200 put src/symbols.py
$ ampy --port /dev/tty.usbserial-1430 --baud 115200 put src/secrets.py
$ ampy --port /dev/tty.usbserial-1430 --baud 115200 put src/main.py
The trimmer potentiometer at R1
is used to adjust the brightness of the display. The brightness is always
forced to be at the lowest value when the power jack is unplugged. Whe DISPLAY_OFF_START
and DISPLAY_OFF_END
are set to any other value than 0
, the display will be turned off during the specified time period and the
potentiometer value is ignored.
LED 1
is used to indicate network activity, while connecting to WiFi or fetching weather data.
LED 2
is used for debugging purposes. It blinks every 2 seconds (or whatever you set in BLINK_DELAY
). If it
does not blink, it means that the display is not updating and the ESP8266 has locked up.
The weather icons were custom designed using this excellent LED Matrix Editor.