Making a LED powered METAR map for your wall

While waiting for my airplane kit to arrive I got inspired to make a small crafty project after seeing someone post about it on reddit and showing it to my girlfriend who said we can make one together.

We did a bit more research and because I’ve made some projects with Raspberry Pi before, we decided to go that route. Here’s a picture of the finished project:


Supplies needed

Here’s a list of the things you will need:

Plotting your chart area

Unless you want to make your own frame, the dimensions of your project will be limited by what size shadow box frame you can easily purchase. The simplest size is 16 x 20 inch frames, so I used that as a guide of the area to size out.
This worked out great for the Puget Sound Area to cover the airports from Bellingham in the north to Olympia in the South and Hoquiam and Quillayute on the coast using my old expired sectional chart from my private pilot training.

Plotting out the area and using some wooden meeples to highlight the airports

To light up the airports with the flight category, we’re using the data reported from so we checked the airports we want to highlight via the API to ensure they are reporting data.

After we were satisfied with the area, we created a 16 x 20 inch transparent sheet by cutting up some sheet protectors and taping them together and then overlaying them onto the area and marking down the airports so we could transfer the locations onto the back of foam board for the LEDs to go into.

Transparent sheet with airport locations

Software and Wiring

Since the project is pretty simple, we used a Raspberry Pi Zero W, which has WIFI built in and can run the code to download the weather data using the above mentioned web API to pull the weather for all the airports in one go.

For the code, I’ve started by looking at some of the other projects people have done and the NeoPixel documentation for python.

We wrote an updated and optimized script and published it on Github, along with the instructions to set it up.

We ended up with a total of 22 lit up LEDs, so we wired it directly to the Raspberry as shown here. Before attaching the wires to the Raspberry headers, I soldered the header strip onto the Raspberry so it creates a good connection.

Raspberry Pi LED wiring (image courtesy of adafruit -

Here’s a picture of the wiring while I was testing out the code. I was using a breadboard while doing this since it made it easier to disconnect the wires during testing.

LED wiring in action

To finalize the order of the LEDs you will need to arrange them on the board and make changes to the airport list accordingly.

Another important note is to test the LEDs for all the colors in case there is a bad one, in our case the 5th LED couldn’t show RED light, so we skipped over that one.
The easiest way to test this once you’ve installed the software is to just manually control the colors of the LEDs by opening the python3 console:

sudo python3

Then entering the following to light up 30 LEDs at once (if you are using more, just replace the number below):

import board
import neopixel
pixels = neopixel.NeoPixel(board.D18, 30)

This will light up all LEDs in red, if you see a bad one, mark it with some tape so you don’t use it for an airport.
Repeat the step for green:






Once you’re done you can turn off the lights by typing


and then pressing CTRL+Z to exit the python console.

Board Assembly

Once we figured out the software portion and what airports to light up it was time to drill some holes in the foam board for the LEDs to go into using the template made earlier.

Foam board holes drilled

After we had the holes made we tested it by temporarily affixing the sectional chart onto the board and sticking some of the LEDs into the holes and turning on the project, but we found that the LEDs created a lot of light and the LEDs were sticking out a bit, so we decided to double up the foam board, which made the light more defined and allowed the sectional chart to sit flush on the board, so we glued together the two foam boards.

We did a second quick test and pinned the sectional chart onto the board for the first complete light up test:

First light up test

After that it was time put everything together. we made the final cuts to the chart to fit perfectly onto the board and align with the lights and then glued it to the board using a glue stick.

Then it was time to glue the LEDs onto the board, as you can see from the picture below, some of the LEDs are not lit, one of them because the red light didn’t work and some others because the gap between two airports was too much and it was easier to just skip the light than to cut the lights and having to solder in some wires. at the end we just cut off the remaining LEDs we didn’t need (disconnect the Raspberry power when you do this).

Lit LEDs back of board

Once that was all done and good it was time to assemble it all into the frame – we drilled a hole into the bottom of the frame for the power cable to go through.

Raspberry assembly in frame

And here is the final picture of the completed project:


I hope this was helpful for you.

394 thoughts on “Making a LED powered METAR map for your wall

  1. Erick

    This looks great! Question, what are my options for dimmer lights? Something that glows less. Are they certain specifics I would need to meet? Can you recommend something? Cheers!

    1. Dave

      Change the color to less intence

      COLOR_VFR= (67,0,0) # Green
      COLOR_MVFR= (0,0,67) # Blue
      COLOR_IFR= (0,67,0) # Red
      COLOR_LIFR= (0,34,34) # Magenta
      COLOR_CLEAR= (0,0,0)

      Thats 25% bright
      you could go (2,0,0) etc for really dim


  2. Bob Berlyn

    Looks like a great project and I would like to build. I am an analog electronics guy and pilot but not a programmer. I have discovered that PYTHON is a language but thats really all I know. Does the pi run PYTHON using the operating system (Rasberian) or do I have to get PYTHON software or just load the scrips you wrote into the pi and go.


    1. Philip Rueker Post author

      You just need to load the scripts into the Raspberry file system, “install python” by running the scripts that I’ve documented here and and modify the airports file to have the name of the airports that are relevant to you.

  3. Ulrich Pommer

    Hey Philip,
    First of all, this is a great project. I’m from Germany and would like to take German airports. Is that possible? Do I have to change only the names in the file (airports)? Sorry for my bad english:-(

    greetings Uli

    1. Philip Rueker Post author

      Yes the web service I’m using does also support many international airports, you just need to use the 4 digit ICAO codes like EDDF for Frankfurt and EDDM for Munich.

  4. Rick Sayles

    I saw a MetarMap at SUNnFUN last year and then seeing your project you inspired me to give it a go.

    Thanks for your excellent documentation. Made it work for a non-programmer. It all works now, but it doesn’t update, until you rerun the program, and the pi doesn’t automatically run the program. I have it now where the pi is connected to monitor so I can run the program. I assume you have automated both of those operations?


    1. Philip Rueker Post author


      Yes you can automate this using crontab.
      As I mention on the Github, here’s how you do it:

      If you’d like to have the script refresh in regular intervals, use crontab and set the appropriate interval. For an example you can refer to the crontab file in the GitHub repo (make sure you grant the file execute permissions beforehand). To edit your crontab type: crontab -e, after you are done with the edits, exit out by pressing ctrl+x and confirm the write operation
      The sample crontab will run the script every 5 minutes (the */5) between the hours of 7 to 21, which includes the 21 hour, so it means it will run until 21:55
      Then at 22:05 it will run the script, which will turn all the lights off

  5. Sameer

    This is great! I’m working on this project now as well. I ran into a snag with the level shifter. Everything works great on the breadboard, but when I connect jumper wires to the level shifter directly the LEDs go rainbow colors instead of red or green etc. I just purchased some veroboard to solder the level shifter and create connections without jumper wires.

    How many LEDs are you able to light up directly off the 5v pin without risking the pi? Thx!

    1. Philip Rueker Post author

      I’m running 22 active LEDs directly off the Pi 5v without issues.

  6. Chris

    Using your command sequence for checking all the LED’s:
    import board
    import neopixel
    pixels = neopixel.NeoPixel(board.D18, 30)
    I am presented with Attribute Error ‘neopixel’ has no attribute ‘Neopixel’
    Any solutions for this? I am not a code literate.

    1. Philip Rueker Post author

      Make sure that prior to this you have successfully installed the neopixel library by running the following command as listed in the github instructions:
      sudo pip3 install rpi_ws281x adafruit-circuitpython-neopixel
      After that command, you open python3 by entering:
      sudo python3
      and then enter the commands and it should work:
      Testing pixels screenshot

    1. Bob

      I changed the corntab file by just adding

      */5 7-21 * * * /home/pi/
      05 22 * * * /home/pi/

      I guess I am not understanding root permission. I did run sudo chmod +x corntab

      Thanks for the project just wish I knew more about pi but working on it.

      1. Philip Rueker Post author

        Ah, you need to grant the files that are being executed inside the crontab execute permissions, so you should run the chmod command for the and the file.

        After you have done that you can check that you’ve done it correctly by running "ls -al" and you should see “x” for the files 3 times, similar to this:

        Also just to be clear, you have to edit your system crontab by typing "crontab -e", not by copying my sample file into the folder.

  7. Bob

    looks like it is working, I was doing “sudo nano crontab -e”. Thanks for your help and thanks for the program. I had a thought and it is way above my knowledge with pi. I was thinking could you add a screen somewhere on a chart with 5/10 day forecast or scrolling local weather. Again thanks now I need to start on my frame.

  8. Ron Heberlein

    Thanks for the instructions! I was able to get running manually, but I can’t get it to start on power-up.
    Here’s what the statrup.log shows:

    Thu 07 May 2020 06:46:43 AM PDT
    /home/pi/ 2: /home/pi/ echo
    : not found
    /home/pi/ 4: /home/pi/
    : not found
    /usr/bin/python3: can’t open file ‘/home/pi/
    ‘: [Errno 2] No such file or directory

    And here is my ls -al:
    pi@raspberrypi:~ $ ls -al
    total 132
    drwxr-xr-x 17 pi pi 4096 May 7 06:46 .
    drwxr-xr-x 3 root root 4096 Feb 13 07:55 ..
    -rw-r–r– 1 pi pi 244 May 6 06:50 airports
    -rw——- 1 pi pi 905 May 7 06:46 .bash_history
    -rw-r–r– 1 pi pi 220 Feb 13 07:55 .bash_logout
    -rw-r–r– 1 pi pi 3523 Feb 13 07:55 .bashrc
    drwxr-xr-x 7 pi pi 4096 May 5 22:11 .cache
    drwx—— 11 pi pi 4096 May 6 07:20 .config
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Desktop
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Documents
    drwxr-xr-x 2 pi pi 4096 May 6 20:42 Downloads
    drwx—— 3 pi pi 4096 Feb 13 08:17 .gnupg
    -rwxr-xr-x 1 pi pi 53 Apr 19 14:48
    drwxr-xr-x 3 pi pi 4096 Feb 13 08:03 .local
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:03 MagPi
    drwxr-xr-x 3 pi pi 4096 May 7 06:46 METARMAP
    -rwxr-xr-x 1 pi pi 2568 May 5 22:51
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Music
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Pictures
    -rw-r–r– 1 pi pi 108 Apr 19 14:48
    drwx—— 3 pi pi 4096 May 5 21:41 .pki
    -rw-r–r– 1 pi pi 807 Feb 13 07:55 .profile
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Public
    -rwxr-xr-x 1 pi pi 48 Apr 19 14:48
    -rw-r–r– 1 pi pi 74 May 7 06:44 .selected_editor
    -rw-r–r– 1 root root 264 May 7 06:46 startup.log
    -rwxr-xr-x 1 pi pi 107 Apr 19 14:48
    -rwxr-xr-x 1 pi pi 129 May 6 20:48 startup.sh_test
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Templates
    drwxr-xr-x 2 pi pi 4096 Feb 13 08:17 Videos
    -rw——- 1 pi pi 56 May 7 06:46 .Xauthority
    -rw——- 1 pi pi 2425 May 7 06:47 .xsession-errors
    -rw——- 1 pi pi 2425 May 7 06:35 .xsession-errors.old

    Any thoughts as to what is going on?
    Thanks! Ron

    1. Philip Rueker Post author

      I just updated the instructions on the github and removed the step about setting up rc.local since it seems to cause strange issues with startup.
      I found it easier to just rely on the crontab instead to automatically run the script regularly, so I suggest you just forget the rc.local startup and instead use the crontab.

      1. Ron Heberlein

        That did it. It took a minute to start after a restart, but it came on automatically!
        50 lights setup, now I have to get the sectionals. Thanks for the help!

        1. Spencer Hamons

          Ron…I am going to do this project at Christmas with my son. Did you run into any problems running 50 LEDs off the 5v pin directly on the Pi?

          1. Spencer Hamons

            Just wanted to add for anyone who looks at this project. I have 68 LEDs on my display and it runs great.

  9. Steve Peck

    there is no file in github now… and can you please update the instructions about what you’re saying about cron?

    1. Philip Rueker Post author

      Correct, I removed the file, since for the crontab I just used (which basically does the same).
      The instructions about crontab have been on the Github all this time:

      To have the script start up automatically and refresh in regular intervals, use crontab and set the appropriate interval. For an example you can refer to the crontab file in the GitHub repo (make sure you grant the file execute permissions beforehand to the and file). To edit your crontab type: crontab -e, after you are done with the edits, exit out by pressing ctrl+x and confirm the write operation
      The sample crontab will run the script every 5 minutes (the */5) between the hours of 7 to 21, which includes the 21 hour, so it means it will run until 21:55
      Then at 22:05 it will run the script, which will turn all the lights off

      1. Alex Baumgartner

        Hey just been working on this and I ensured all my LEDs work and the airports are reporting correctly. The only trouble I am having is the crontab portion. I am not a 100% certain its even running… is there a way to verify I have it typed out correctly and that it runs upon booting up?

        Also I found that if an airport identifier has TS in it (such as KHTS) it will assume there is lightning there. I made a slight alteration from ‘TS’ to ‘ TS’ (added a space) I am not sure it’s the most elegant solution in the long run though haha

        Thanks for all the help with setting this all up!

  10. Ron Heberlein


    Have you tried to incorporate blinking lights into the program?
    I’d like to be able to have a light blink if the wind speed (or gust) exceeds a certain value. I’ve been searching on the internet for this and haven’t seen anything that seemed like it would plug into your code. That being said I’m not a programmer…

    1. Philip Rueker Post author

      I felt inspired by your question and since I am a programmer, I expanded the script to support blinking for windy conditions.

      I just uploaded the updated version of the script that now supports animation for wind conditions, if you go to the github, please use the updated, and with the latest version I just uploaded (it makes sure that any currently running scripts will be closed when the next one runs).

      I also added some information to the Readme instructions about the new parameters that I’ve added to the script that you can adjust as needed.

      1. Ron Heberlein

        How awesome!!!
        I found one error in your code. On line 22 and 23, both variables were named “COLOR_IFR_FADE”. I updated line 22 to remove the “_FADE” and everything worked perfectly!

  11. Jordan

    Hi Philip,

    Thanks so much for the tutorial, build a huge map to go in my work area and everyone loves it. Ive seen now the commercial Maps have the ability to flash white when there is lightning reported in the area? Is there any way we could add a line in the script to run this kind of like how you ran the wind one? That would be super cool!

    1. Philip Rueker Post author

      Sure, I just added this functionality in the script, it will flash to white to represent lightning in the vicinity as reported by that airports METAR.
      You can get the latest version with the updated changes from the github.

  12. Kit

    Hi Philip.

    I have an issue where only the first led lights up. I have a strand of 50, the ones you suggested. I can issue “pixels = neopixel.NeoPixel(board.D18, 30)” or use 20, or 10, or 50, I still only get the first led to light up after issuing “pixels.fill()”. Do you think I have a bad strand of leds?

    1. Philip Rueker Post author

      I think there’s two possibilities.
      1) Yes maybe the strand is bad
      2) Did you make sure that you connect the correct ends to the Raspberry? On the LEDs you will find a small arrow on one side like this, this is the side that you have to connect the wires to the Raspberry. direction on LEDs.

      1. Kit

        I did connect the pi to the input end of the led strand. After some testing, the strand is defective. Will give it a try again when the new strand arrives! Thanks for the help.

        1. Colin

          I’m also having issues with the strand. I got about half of them to light up red (not seeming to be talking to the code?), but now none are lighting up. I’ve triple checked the connections. Is it possible the LEDs got fried? I noticed in the link you provided it mentioned that as a possibility I recall reading or seeing any level shifting in your setup.

          “Powering NeoPixels from Raspberry Pi Without Level Shifting”

          1. Colin

            Ok, I was able to get the lights working with the python commands you provided to others. Now I can’t seem to get it to light up to the metars. Maybe its a permissions/executable issue?
            When you enter the “chmod +x” etc. command are you suppose to see some message after? I just enter it and it cycles down to a new line.
            I’ve also noticed that when I run “ls -al” some files are in “root” and some in “pi” like “airports”.

          2. Philip Rueker Post author

            Yes sounds like a permissions issue.
            You can fix to take over the file ownership by running this:
            sudo chown pi:pi FILENAME

            This will make pi the owner and then it should hopefully work.

          3. Jonathan

            How did you finally get them to light up? I have an issue where none of mine light up. I had thought that I needed to order a new strand. Was that you solution?

        2. Jonathan

          Did the new strand work? I am having an issue where none of mine light up either.

      2. Paul

        Great project! I’m sure I’m missing something but both ends of the strand I ordered from your pats list have the white forward arrow..can you show the connector end that is correct? Is it the male or female end?

        1. Philip Rueker Post author

          So if you take the lights, There should be one side on each LED that has the forward arrow and the back side won’t.
          The cables that are on the top side going into the light on the side with the forward arrow is the input end.

          1. Field

            I’ve been struggling for so long and finally read this far down. This fixed it. THANK YOU!!

  13. Chuck

    I just finished making one of these, i love it! thanks for putting together this guide, and the upkeep with the code!

  14. Ron Heberlein

    I wanted to see if anyone else was having issues with the map not refreshing?
    For about the past week, I have to turn the Pi off and then back on to get the map to refresh with the latest weather data. It then will refresh for a while (maybe a few hours), and then gets stuck again.

    Is there a way to plug in a monitor and see how the program is running (other than manually starting the program)?

    1. Philip Rueker Post author

      Maybe your WIFI connection is weak and it fails at some point randomly? I’m not quite sure how the raspberry PI handles that.

      In any case, you could write to a logfile every time the script gets executed.
      If you just want to see if the script get’s started at all you could add something like this to the start of the script:
      echo $(date) - running metar script >> myfile.txt
      This will write the current date/time into a new text file called myfile.txt

      And if you want to just print the entire output of every time the script gets executed automatically, you can modify your crontab to something like this and it will print the entire output that would usually be seen on the console:
      * 7-21 * * * /home/pi/ > /home/pi/outputlog.log 2>&1
      This will print everything that happens in the script into a new file called outputlog.log

  15. Randy

    Great post. I frequently visit Aero Maintenance at Pearson airport and have always liked the METAR chart they have in their office. I was looking for different addressable LED products to make my own METAR chart and, bam!, full build instructions and parts list!

    My plan is to combine this with a previous (insanely over-designed) project of mine: Basically, I’m thinking about building the METAR chart, then cutting out a part of the sectional for the PiTFT screen so it can also display METAR details.

  16. Tony

    Philip, fantastic project. I noticed there is a guy in the US (Metarmaps) selling these so i was curious to see if the code/project existed and found you. A couple of hours work and it was up and running. The VNC charts in Canada are paper only and huge so I discovered the US charts are free and downloadable so I am going to have a poster shop print up the size I want ( 2′ x 3′) and then complete the LED install. Bought you more than a coffee 🙂 Thanks for the project.

    Tony Varga

  17. Scott

    You may not know this for sure but I’m about to start a very large map and I’m up to 81 LEDs so far. Can this project use more than 50? Do you happen to know the limit?

    1. Philip Rueker Post author

      Yes you can, but you will have to wire an external power supply to the LEDs as the internal power coming from the Raspberry Pi won’t be enough to power that many LEDs.

      1. Scott

        Just got my 5050 LEDs and the code works great. The fading confused me a bit because I was expecting a fade but found that it just blinks with a set brightness. I’m using 107 5050 LEDs and the current draw is 0.81A.

  18. Anthony Varga

    Philip, to conserve the lifetime of the LEDs (they are long but really only about 5 years on 24/17) I purchased a micro PIR sensor that I am going to flush mount into my map to trigger the lights on when motion is detected. I am planning to put a 60 minute countdown in Python that when triggered, would start counting and when t=0 the lights would go off. I am not an adept Python programmer but will figure it out but just wondering if you have any thoughts about placement of the timer in the code ?

    1. Philip Rueker Post author

      So the script will just turn on the light and will keep them lit when the script finishes by default.
      So you could just add a sleep timer and then deinit the LEDs which turns them off at the end. So you can just add this to the bottom of the script and it will wait for 3600 seconds and then pixels.deinit() will turn off the LEDs until the next time the script starts and turns them back on.


  19. Anthony Varga

    I think the problem with that is that during the sleep, the metars will not update every five minutes like they do now ?

    1. Philip Rueker Post author

      Yes in that case, what you’ll need to do is make use of a temporary file where you store the time when you started the timer after motion was triggered.
      You can insert the code just after the initialization of the LEDs.
      Here’s a sample that should work, there are 2 new imports in line 9 and 10 and you need to replace the sensor piece of code in line 59 with your reading of your actual motion sensor to return True when motion is detected:

  20. Anthony Varga

    Really appreciate the code insert. I will play this weekend and report back.

  21. Anthony Varga

    Hi Philip, I was looking at and playing with the code you created. I am not a strong Python programmer at all but more an old guy C++ programmer so I can follow it somewhat. When I look at it looks like the code runs every 5 minutes via cron and when it does, the first part of the code captures the web metar data and then at the bottom there is a loop that cycles for the time set to do the flashing lights. So, my understanding is that when the python script runs, it is only testing the PIR input once so it must be triggered to 1 exactly when the script is run by cron. Is my understanding correct ? If that is correct, the chances of it pickup up a motion trigger are slim to none. I know the code allows flexibility to define the duration of the ‘flashing’ loop which is 300 by default so basically the script runs for 5 minutes, exits, reruns via cron immediately, updates the metar data and then loops at the bottom until exit. Python is somewhat new to me so I am playing with a side script that is detecting the PIR and running a 60 minute countdown timer and setting a global variable. would then test that variable and if 1 would operate as it does now but if zero would deinit() and exit. My other thought is to just have running all the time, jumping to the top to do an update every 5 minutes but managing the PIR detector and timing within.

    Sorry, long comment. Basically want to confirm my understanding on how the script is operating and the reason for exiting every five minutes and rerunning immediately to ensure I am not on a wrong track here.

    Thanks !

    PS : I am following your Sling build as well. I own a Commander 112 but contemplating building an RV-10 as a retirement project in a few years.

  22. Scott Moody

    Is there a way to run this without using file PID? The reason I ask, I want to make the file system read-only and this won’t run that way.

    1. Philip Rueker Post author

      You could, but you’d need to make sure that the runtime of the script is less than the trigger time in order to make sure that there are no race-conditions in accessing the LEDs.

      So if you set the script to run for say 270 seconds (4 1/2 minutes) and trigger the script every 5 minutes using the cronjob, then you should be okay (usually the weather fetching and all takes about 5-10 seconds) and you could remove the file PID action.

      It’s basically just a protective layer to make sure only one instance of the script is running at any given time.

  23. Phil Lightstone

    Hi Gang,

    I’m working on a map as well. I was wondering if anyone has sourced a ws2811 string that had more wire in between the LEDs? I believe that most have 3” of wire.

    P …

    1. Philip Rueker Post author

      I have not seen premade strings with longer distances as you said, but you can buy individual LEDs and solder your own custom wire lengths, or use of the premade ones and cut and solder in longer wire where needed.

  24. Phil Lightstone

    Hi Philip,

    I built one for my son’s birthday in October (PS it was a hit), collaborating with Tony. Bought the Alitov on Amazon. Lots of soldering to get the inter LED lengths right. I’ve sent an email out to a few vendors. We’ll see what they come back with.

  25. Nicholas

    Just before I begin, I wanted to make sure I get the airports right. Is there anyway to confirm the airport LED in the code is physically in the correct position on the map? I saw another example and they had some blinking setup tutorial.


    1. Philip Rueker Post author

      When you run the code it will print out the statement saying that it have a message showing which LED is set for which airport, so you can use that to reference to make sure it’s in the right spot.
      LEDs message
      It will count starting from 0 for the first LED and if you have some LEDs that you are skipping and use NULL in the airports file for them it will just skip over them, but the LED count includes them, so like you can see in the image above, I have some gaps for example it goes from LED 0 to LED 2 and skips over the LED 1.

      1. Nicholas

        Got it – I managed to do exactly that and the code appears to be working (just like you said it would). Unfortunately, I incorrectly wired something because I fried the pi and I found the error. I had a spare pi and tried to get it to work and the pi/code works fine but the lights wont turn on. I’m just not sure how to check if the lights are working or if it’s the pi again.

        1. Philip Rueker Post author

          So if you’ve wired them correctly, then you can test just the lights by themselves if you open python and run the following:
          To open python:
          sudo python3
          Then entering the following to light up 30 LEDs at once (if you are using more, just replace the number below):
          import board
          import neopixel
          pixels = neopixel.NeoPixel(board.D18, 30)

          That will fill 30 LEDs with one color.
          If that doesn’t work, then either the Pi is bad, or something is wrong with the wiring.

          1. Nicholas

            I figured it out – thanks for the help!

            I’m getting this error with your new code you made:

            Traceback (most recent call last):
            File “”, line 67, in
            ast = astral.Astral()
            AttributeError: module ‘astral’ has no attribute ‘Astral’

            I’ve attempted it numerous times with no avail. I just set it to false for now.

          2. Philip Rueker Post author

            My apologies, my new code for Astral had an unintended sideeffect in that it only worked for older Raspberries running an older version of the library.
            I just checked in the fix, so please take the newer version of and everything should be working again.

          3. Nicholas

            No need to apologize. Everything is working perfectly now! However, I am just trying to get the code to start up basically as soon as I power the pi. I have done the crontab and I am still running into a bit of a roadblock. All permissions are set properly.

            Thanks for your help with these replies man. You’ve definitely done a great project.

          4. Philip Rueker Post author

            This article helps troubleshoot the crontab
            If you just set it up, then chances are it might just not be running yet, you can restart the crontab with this command:
            sudo /etc/init.d/cron restart

            If it’s running ok, then you should see something like here in the last line saying that it triggered the file:

  26. Chris

    This project just rocks. Got me excited about my crappy programming skills. I have much better woodworking skills. And decent Photoshop skills. Just a couple of suggestions that have worked out for me and some that didn’t.

    You can download a sectional (or area maps) for free from the FAA website:

    Crop and size it as you like and print it at your local Wal-Mart. I suggest matte finish and no frame.

    I used 1/4 inch plywood for better durability. Spray mount is great stuff that is more forgiving than many spray adhesives. I have a dozen art projects still holding 25 years later and still used the same can. Worth the money.

    Use a 5/16 Forstner bit to cut your paper + plywood. This is a very nice bit and cuts a perfect hole in the plywood and also doesn’t tear the chart paper. Make sure to put some wood behind your hold so it doesn’t splinter the plywood when the bit exits.

    My mistakes:
    * Trying to save 10 bucks and solder more length in between bulbs. OMG, it was a not worth it. Just NULL the bulbs and buy another set. I wired some in reverse, which you can’t do, and wasted more of my life. I also tried to find longer lengths as above but to no avail.
    * Make sure your paper and plywood is clean and wiped before adding spray mount. I got too much junk in between and is noticeable in the right light. Presentation is everything.
    * I made my own frames. Well, this wasn’t as hard and turned out real nice, but a pre-made from would be much easier.
    * I’m not good at instructions. Read where each file goes during init and during setup. Make sure you have a K in front of all airports. Mine still doesn’t start at boot, so I have to figure that one out.

  27. Randy

    Almost done with my build:!Ar5QrtP9ZYyWkp05MZCKMqjXnKjiag?e=if99aE

    Totally did what Chris above did. I used the FAA’s TIFF’s to combine the Seattle and KFalls sectionals to cover Astoria, OR down to Roseburg, OR and east to Redmond, OR. Basically my regular range for drilling holes in the sky. I had FedEx Office print them on foam board. Kind of expensive for a 22×28 poster, but looks pretty great.

    Biggest mistake I made was using a wood drill bit to make the holes for the LEDs. It worked, but more or less tore into the lamination and required a lot of cleanup with an Xacto knife.

    Mounting the screen in the poster worked out pretty nicely. Cut it just right so that the screen fits tightly in the foam board and does not need any extra support in the back.

      1. Randy

        Ha! Very cool!

        Forgot to mention the Yellow lights are mine are airports where the wind or gust exceeds 25 knots. Thought about doing blinking lights like you did, but didn’t want to spend the time implementing it.

      2. Anthony Varga

        If anyone is interested, I designed a nice front/flush mounted bezel for the display. You can cut a hole in the map and drop it in. If interested PM me at

        I also did a spinoff from a published light block for these LEDs that enables you to pop the led into the block sideways and a ‘light pipe’ protrudes through a hole in the map. This allows the long LED units to be side mounted and much shallower shadow box.

        These are .STL files that you can slice with Cura or your favourite slicer and 3D print. Whichever colour you want for the display bezel and clear for the light blocks.

  28. Isaac

    Thanks for the very cool project write up! I’ve never used rasberry pi, linux, python, or any of that business before so it has been quite the learning curve.

    I wanted the lights to also light up a little sooner than the 5 minute mark when I first booted the project up, so I did some googling and added

    @rebooth sleep 30 && /pi/home/

    and that seemed to get the job done! Without the sleep 30 seconds it didn’t seem to want to work.. maybe because it was running the script too soon after boot, before it connected to the WiFi?

    I haven’t touch coding since high school (15 years probably!) and that was C++.. I tried a little Python right after that class and it was way over my head. So I’m very happy to be able to learn so much on a project like this now.


    1. Jeff

      Phillip, anyone
      I have read all the data here on how to get the Crontab to work and I’m still having issues with it starting up without me telling it to. Im a noob at programming, so any helpful tips or tricks you might have would be greatly appreciated. thanks

      1. Philip Rueker Post author


        hopefully this article might help with troubleshooting the cron tab

        Usually it’s around permissions, so you can try and make sure that your normal “pi” user account owns the file and that they have read and execute permissions.
        You can check that by typing “ls -al” and seeing that “pi” is listed as the owner and not root.
        To change ownership you can run “sudo chown pi:pi FILENAME” and “sudo chmod +x FILENAME” for execute and “sudo chmod +r FILENAME” for read permissions and that should *usually* help.

        The article I just referenced above has a couple of other tips to troubleshoot it.

  29. Colin

    Troubleshooting tip I encountered when setting up the wifi connection.
    The Raspberry Pi Zero W only supports 2.4 GHz networks, not 5 GHz. In other words, if you are having trouble connecting to wifi with the wpa_supplicant.conf file described, make sure the network you’re trying to connect to is 2.4 GHz.

  30. Anthony Varga

    Phil, the mini display is a great add. What would I do to keep the display static on one airfield ? I would like to mount it by my home field and only report on that field.

    1. Philip Rueker Post author


      In the file, instead of looping through the airports towards the bottom of the file (there’s a comment “Rotate through airports METAR on external display”)
      Remove the indented code under:
      if disp is not None:
      and replace it with this (replace “KPAE” for whatever airport you want to show it for, just make sure that airport is present in the airports file for the LEDs):
      displaymetar.outputMetar(disp, "KPAE", conditionDict.get("KPAE", None))

  31. Phil benyo

    Food for thought out there for people that might be struggling with getting the lights to start automatically- remember to set the timezone for your raspberry pi…keeping in mind time off times set in crontab as well…. pulled my hair out for a few hours this afternoon when I got it working for a brief moment then it wouldn’t work for the life of me… 5 hours later I had the epiphany. Im not smart- just persistent.

    just ordering my map now and will update later!

  32. Adam

    Hi Phillip! Great project – has been a lot of fun so far.
    We got most of the PI/LED/Screen stuff working today – and it has been great.

    Any idea on how to make the Screen show a subset of METARs? I have 45 airports on the map – but only want the screen to show 5-10 of the most important to me.

    1. Philip Rueker Post author

      That’s a neat idea.
      I just updated the script to support this, so you just need to take the updated file and add a new file “displayairports” into the folder with the list of airports you want to show on the LED display.

  33. Andre

    What a wonderful project – thank you Philip for posting! Can you answer what are the maximum number of addressable LED’s the Raspberry Pi can support?

    1. Philip Rueker Post author

      It depends a bit on how bright you set them.
      But using the ones that I’ve used, they are rated to use 0.3W per LED at full power and I have mine set to 50% power, so with using 50% power and assuming that draws 0.15W per LED then you can probably safely power about 40-50 from the direct 5v pin as that would draw about 1.5 amps.
      If you want to control more LEDs than that, then I suggest you use a higher rated external power supply like this one to power the LEDs.
      You can find some details on the wiring for this here:

      1. Andre

        So the limiting factor is the power supply current to the LED’s and not the number of LED addresses available?

        1. Philip Rueker Post author

          Correct, addressing wise there’s no real limit (that I know of) and some people have built maps of the entire US with 200 LEDs.

          So the power supply is the only limit, so for bigger maps you just use a larger separate power supply to provide power to the LEDs.

          1. Philip Rueker Post author

            They are addressed in sequence from the IO pin through the communications wire from the raspberry.

          2. Kit

            I’m running 145 leds off the Raspberry Pi alone. The key is not to exceed 5 volts that the Raspberry Pi provides. I use this formula to figure out the max setting I can use for the LED_BRIGHTNESS variable in

            (5v / # of LEDs) / 0.1v

            This formula assumes a 50 led strand rated for 5v at 100% power, so each LED would pull 0.1v at 100% power (5v / 50 = 0.1v). Using my example of 145 leds, from the formula I get a max led brightness setting of about 0.34, so I would make sure the LED_BRIGHTNESS variable was not set higher than 0.34 so I would not harm the Raspberry Pi circuit board.

            I am actually using 0.15 because I found the leds blinding even at 0.25! They look great during the day and at night. Your milage may vary.

      2. Anthony Varga

        FYI my current map (v2) has 60 LEDs powered directly from the Pi Zero W with no issues and does not get hot.

  34. Spencer Hamons

    I am building this project and would like to put a “Legend” in the lower left of my sectional. Would like to have four LEDs, one each for LIFR, IFR, MVFR, VFR. Is there a way to add-in this details in the file to have it statically display these?

    1. Philip Rueker Post author

      The easiest would be to just add a small bit of code to the file for this right before the “” on line 239:
      pixels[i] = COLOR_VFR
      pixels[i+1] = COLOR_MVFR
      pixels[i+2] = COLOR_IFR
      pixels[i+3] = COLOR_LIFR

      This will illuminate the 4 LEDs after looping through all the airports in the respective colors. If you needed to add a gap from the last airport to where your legend LEDs are then just increment the distance to the “i” variable.

      1. Spencer Hamons

        Forgive my ignorance here, but when I try to add the code listed above, I get an error that says:

        IndentationError: unindent does not match any outer indentation level

        I am hitting “tab” and picking the colors from the declarations, but not sure what is causing the script to error.

        1. Spencer Hamons

          Disregard my comment Philip. I made the change in a plain text editor instead of the Python editor and it worked fine.

          1. Spencer Hamons

            Yeah, that was the problem I was running into with the Python editor in the Pi, all looked indented correctly but the editor would generate an error. I defaulted back to just doing it in a plain text editor and it worked fine. Not really sure what the Python editor was expecting.

            Appreciate your quick response. Building this out with my son now, hopefully will have it built and mounted by the middle of the week. Will post pictures.

  35. Ted


    Amazing project, I learned so much by making this.

    I’m having issues when I change the airport list, I’ve populated the list with 15 ICAO codes and changes the configuration LED_COUNT=15. It worked fine with the airport list provided but with my new list I get this error:

    Setting LED 0 for CYQG to MVFR (0, 0, 255)
    Setting LED 1 for CYCK to MVFR (0, 0, 255)
    Setting LED 2 for CYZR to MVFR (0, 0, 255)
    Setting LED 3 for CYXU to MVFR (0, 0, 255)
    Setting LED 4 for CYKF to MVFR (0, 0, 255)
    Setting LED 5 for CYHM to MVFR (0, 0, 255)
    Setting LED 6 for CYYZ to MVFR (0, 0, 255)
    Setting LED 7 for CYSN to MVFR (0, 0, 255)
    Setting LED 8 for CYOO to MVFR (0, 0, 255)
    Setting LED 9 for CYBN to MVFR (0, 0, 255)
    Setting LED 10 for CYPQ to MVFR (0, 0, 255)
    Setting LED 11 for CYQA to MVFR (0, 0, 255)
    Setting LED 12 for CYTR to VFR (255, 0, 0)
    Setting LED 13 for CYOW to IFR (0, 255, 0)
    Setting LED 14 for CYND to IFR (0, 255, 0)
    Setting LED 15 for CYMX to LIFR (0, 125, 125)
    Traceback (most recent call last):
    File “”, line 235, in
    pixels[i] = color
    File “/usr/local/lib/python3.7/dist-packages/”, line 314, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.7/dist-packages/”, line 280, in _set_item
    raise IndexError

    1. Philip Rueker Post author

      I count 16 in there (note that the first LED is LED 0).

      So if you give it LED_COUNT 15 then you’re one short, hence the error.

  36. Julius

    I think this is so cool. I decided to build one. When I test run it I get these errors and cannot figure out how to correct the error. My manual test of the lights is good. Can you help? Here are the errors:
    File “”, line 226, in
    pixels[i] = color
    File “/usr/local/lib/python3.7/dist-packages/”, line 314, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.7/dist-packages/”, line 280, in _set_item
    raise IndexError

    1. Philip Rueker Post author

      An IndexError usually means that you are trying to address more LEDs than you’ve specified in the LED_COUNT, so make sure you increase the LED_COUNT variable to be at least as big as the amount of LEDs you are using (including NULLS if used).

    2. Julius

      Never mind! It was a problem between the table and the chair. When I checked the airports file I found there were two blank lines after the last airports files. I spent hours years ago with a BASIC program that was failing when it got to a point in the program reading a file. After having another set of eyes look at my data file, he spotted a missing comma right away.

  37. Alex

    Hello. First of all congratulations and thanks to Philip Rueker for putting this together and inspiring the res to us.

    I have and odd issue my ALITOVE WS2811 12mm Diffused Digital RGB LED Pixel Light seems to be
    pixels.fill((0,255,0)) Blue
    pixels.fill((255,0,0)) RED
    pixels.fill((0,0,255)) Green

    Not like on the tutorial, Is this common..?
    So I simply changed the metal file.
    But then found that when tested I get for example my first ten led all do
    All red
    All blue
    All green
    Just fine
    I but when I setup the airports, after an airport that is IFR ( red) the next led will glow purple, regardless of the metal code . I can see the code saying the correct color but it glows differently.

    Is there a test code sequence that runs the pixels thru a color range? Or any ideas on how to test my leds?

    1. Philip Rueker Post author

      That’s very strange. May be a faulty string of lights.

      If you scroll up in the article I explain how you can test all the LEDS for the colors.
      Basically connect to the py, then enter sudo python3 and then you can just initialize the LEDS with one color at a time to test like this:
      import board
      import neopixel
      pixels = neopixel.NeoPixel(board.D18, 30)

      1. Alex

        Hello again, just as an update
        I have an interesting problem. I bought the alitove pixels. (twice)

        I returned the first strip because i thought it had defective pixels. Wrong colors or dim pixels.
        The second one got in, and it is behaving the similarly.

        I found that EVERY time i have a RED pixel , the one before it, turns dim blue. Regardless of the color it is programed to.

        I have tested it now with raspberry pi power only, AND now im testing it with independent power supply .
        Seems the RED command screws things up.
        To add to the oddities. this ones light up differently i had to do this adjustment.
        COLOR_VFR = (0,0,255) # Green
        COLOR_VFR_FADE = (0,0,125) # Green Fade for wind
        COLOR_MVFR = (0,255,0) # Blue
        COLOR_MVFR_FADE = (0,125,0) # Blue Fade for wind
        COLOR_IFR = (255,0,0) # Red
        COLOR_IFR_FADE = (125,0,0) # Red Fade for wind
        COLOR_LIFR = (125,125,0) # Magenta
        COLOR_LIFR_FADE = (75,75,0) # Magenta Fade for wind
        COLOR_CLEAR = (0,0,0) # Clear
        COLOR_LIGHTNING = (255,255,255) # White

        I re flashed the SD card and started over, same thing. Could it be the pi? Any ideas or suggestions are all welcomed.

        1. Philip Rueker Post author

          That’s very strange and I have never heard of that, so yes, maybe indeed something is up with your Pi?
          Maybe the solder connection on the board isn’t solid or something, but it’s hard to say.
          I guess maybe trying another Pi might be the easiest way to troubleshoot it.

          1. Alex

            Hello Philip, just back to thank you. It seems it was the darn ground solder. Cleaned and re did them all.
            Seems to be working.

            im now working on the startup after boot, for some reason it wont.
            you mentioned the file should be owned by user pi
            What would be the command for that? im no linux guru but can type lol

          2. Philip Rueker Post author

            You can change the ownership of the file like this:
            sudo chown pi:pi FILENAME
            And to change the permissions:
            sudo chmod +x FILENAME to give execute permissions (for the .sh files)
            sudo chmod +r FILENAME to give read permissions

            First make sure that you can run the ./ and ./ file from the console and if that works, then you can add them to the crontab.
            If you have trouble with the crontab, here is some tips for troubleshooting it –

  38. Andre

    On your GitHub page, the 1st Software Setup instruction is to download Raspberry Buster Lite. That link takes me to a Raspberry Pi 404 error page. Where can I find Buster Lite?

  39. Andre

    Thanks Philip. After successfully downloading Raspberry Pi OS Lite and unzipping, I tried flashing my SD card with the .img file using Etcher and receive the error message: “Something went wrong. If it is a compressed image, please check that the archive is not corrupted. ENOENT: No such file or directory, open ‘C:\Users\Andre\AppData\Local\Temp\balena-etcher-electron–752-to2cuXRb9arS-.cmd’
    As mentioned, has been unzipped/not compressed. How can I flash this file?

    1. Philip Rueker Post author

      Not sure about etcher.

      I used the Raspberry Pi imager last time, which will let you select the image, it’s available at the same link.

  40. Andre

    I added the wpa_supplicant.conf (with my WiFi’s network & password names included) and ssh files as instructed but my Zero is not connecting to my WiFi – it doesn’t appear in my router/modem’s Device Table list. When I remove the SD card after it’s been in the Pi, it appears the Pi is removing the SSH file when viewed on my Win 10 machine.

    With every step I’ve so far had issues – is this the best way for us to communicate?

    1. Philip Rueker Post author

      Here’s some tips to get the wifi working: or alternatively you could try to use this image called BerryLan that has an app to hook up the wifi, though I have no experience with it.

      Yes I believe the ssh file goes away once it’s been absorbed by the raspberry pi if you put the sd card back into the pc.

      Sharing problems via the comments here is helpful for others who run into issues.

  41. Andre

    Progress! Where do I find /home/pi to store the scripts? Do I have to create it? All I have currently are files in the root and an overlays folder.

    1. Philip Rueker Post author

      /home/pi is the default user directory, so if you SSH into the raspberry using the default pi user, you will land in the /home/pi folder.
      you can also type “cd /home/pi” and you should land in the same folder.

  42. Andre

    How do I copy the 5 script files on my Win 10 computer into the /home/pi directory? Can I do this with the SD card plugged into my Win 10 Computer?

    1. Philip Rueker Post author

      I use a tool called WinSCP to transfer files between my computer and my raspberry.

  43. Andre

    I’ve successfully uploaded all files into the Pi and changed permissions as instructed. When I run, I see the statement messages (Wind animation: False, etc.), the… line, then Done appears and I’m returned to the pi@raspberrypy prompt, but I see no LED’s light up. I’ve verified the LED’s operate correctly with your command to sequence prior to running I’m not sure what the next steps are to troubleshoot and make the system work?

    1. Philip Rueker Post author

      Make sure your airports file is set up. Do you see a list of airports in the line?
      This is how it should look if it’s output

  44. Andre

    Excellent reference – my system is now working!!! What I had wrong – in my airports file, I had included the line number before each airport identifier. Once I removed the numbers, the system began working. I even have the Uctronics display connected and working.
    Awesome coaching, Philip – thank you so much!

  45. Andre

    Observation – the Uctronics display is cycling through my airports list backwards/in reverse order as to how they’re listed in my airports file (from the last airport listed to the first). Can I change/reverse this?

    1. Philip Rueker Post author

      The order for the display is somewhat random and is currently determined by the order that the weather is returned from for simplicity, so there’s no easy way to change the order at the moment.

  46. Andre

    I’ve also noted the program quits running after about 4 minutes. After the “Setting for LED . . .” info, I see Done, the program stops and then displays the prompt. I have installed Crontab and have the refresh cycle set for 1 minute. How can I get it to keep running indefinitely?

    1. Philip Rueker Post author

      The default is 5 minutes via the BLINK_TOTALTIME_SECONDS being 300.
      So the crontab if you set it to run every 5 minutes like in the example crontab on the github should run it indefinitely, but you can change the combination of crontab and the total time as you like.

  47. Andre

    After I edit and run crontab as instructed, the system operates but I no longer see the stream of LED or airport callsigns? I’ve logged in with Putty, WinSCP and have a monitor connected to the Zero with the same results – nothing indicates it’s running like it does when I run the program from the prompt. Also, when using crontab, it takes a few minutes for the program to start after reboot – again, different from when the program is started from the prompt, where it begins to run immediately.

    1. Philip Rueker Post author

      Yes that’s normal. Crontabs operate in the background, so you won’t see anything on the screen when it’s running.
      The program will start automatically via the crontab based on your interval, in my case every 5 minutes, so as you said, it might take a minute or a few to start after you restart the raspberry, which should generally be fine for what the project is doing.

  48. Andre

    After it first cycles and then waits the 5 minutes, the Qctroncis display blanks out then starts jumping back and forth between airports, quickly changing all the data. It doesn’t hold for the 8-10 seconds per airport like it does when it first starts. Is this normal?

    1. Philip Rueker Post author

      If you didn’t change any of the timings from the default and just activated the Display functionality, then the crontab will re-run the script once every 5 minutes to fetch latest weather and the script will run for 300 seconds (aka 5 minutes), changing the screen every 5 seconds.

      Whether you run it from the console directly, or via the crontab makes no difference functionality wise, the crontab just simply triggers the script.

  49. Andre

    I would like the display to stay fixed on my home airport KEIK (I saw your note on what to change in METAR.PY for this change). KEIK updates METARS every minute. Would I change crontab to the following to change the refresh rate: */1 7-21 * * * /home/pi/

    I’m still unclear about the timing relationship between crontab and BLINK_TOTALTIME_SECONDS in If I change crontab to update every minute, do I also need to change the BLINK statement from 300 (5 mins) to 60 (1 min)?

    1. Philip Rueker Post author

      Per the instructions on the github:

      If you want to only show a subset of the airports on the display, create a new file in the folder called displayairports and add the airports that you want to be shown on the display to it

      Yes the general principle is you’d keep them in sync, but if you’re using the script, then it doesn’t really matter if the blink time is longer as the will just cancel the currently running script and then start it anew whenever the crontab gets executed.

    1. Philip Rueker Post author

      No, the only one I worked with is the one I used, so you will have to do your own research using a different one.

  50. Andre

    I am using different addressable LEDs than listed in your Supplies Needed list. As they are individual LEDs and not a pre-wired string, I will need to wire & connect each one by hand. Is there a short routine I could use (similar to what you posted for checking all LED colors) that would step through and light each individual LED in sequence to verify I have them connected in the order matching my airports list?

    1. Philip Rueker Post author

      As long as they are also WS2811, they should work just the same once you wired them correctly. If they are a different type then you’ll have to figure out what library to use to make them work.

  51. Andre

    They are WS2811’s.

    What would be the command line to turn on each LED individually so I can verify the airport being lit on my map is wired in the same sequence as the airports listed in my airports file? (#1 = KCOS, #2 = KDEN, etc.)

  52. Julius Garrett

    Hi Phil,

    This has been a great project. Thank you so much for the work and time put into it. I got my map that I had mounted and installed the lights. The script runs fine. I am using the mini display and a displayairports subset for it. One thing I noticed is it randomly stops scrolling when it reaches no particular airport. Then it starts again. Would I be correct in my thinking that it does this until the next refresh? If so, is there a change I can make for the display to keep rotating?

    I read your reply to another gentleman above. But, I am not sure if it is the same thing. I did not change any of the default times.


    1. Philip Rueker Post author

      Yes the scrolling of the display, along with blinking for weather is controlled by the BLINK_TOTALTIME_SECONDS, so you should set up your crontab to trigger the script again overlapping this.
      I have mine set to 300 seconds (aka 5 minutes) and the crontab to re-trigger every 5 minutes, which basically overlaps, so it appears more or less continuously.

      There will always be a very short pause when the new script triggers at the time where it retrieves the new weather at the beginning, so depending on your internet speed, that might be a few seconds where the scrolling is paused.

      1. Julius Garrett

        Thank you! Letting it run to see the turn off feature and auto start again in the morning.

        Is there a place to drop a dime contribution?

  53. Andre

    Is it possible for an airport to report CLEAR conditions but also have wind speeds above 15 kts? If so, what how will that airport’s LED respond?

  54. Kevin

    Thank you for this. Your instructions are well written and easy to follow.

    I am thinking of attempting this as a gift. How would I get it connected to the recipient’s WiFi?

    1. Philip Rueker Post author

      So you could either give them instructions on how to modify the wifi settings on the sd card like on initial setup, or maybe instead of using the bare Raspberry Pi OS, you could use this Image called BerryLan- with which you can set up the wifi using an app over Bluetooth.

      I haven’t used it myself, but have heard from others that that’s a possible solution that might work for you here.

  55. Andre

    In the file, under NeoPixel LED Configuration, the entry for #38 is COLOR CLEAR = (0,0,0). Doesn’t that turn all LED’s off all? How/when would that setting be used?

  56. Spencer Hamons


    Thanks again for your directions, and continuing to help the community on this with all of our questions. Very generous with your time for something you aren’t getting any renumeration for. Hope you know it is appreciated.

    One more question for you. I found a display that is slightly larger on Amazon and thought I would give it a try on my 2nd project I am doing for my son as a present for just finishing up his Private Pilot Cert. This board came in with a SSH1106 driver requirement instead of the SSH1306 chipset. Would like to see if this looks as good as the .96″ OLED display, even though it is the same resolution, just with a larger size of 1.3″. What would be required to load the driver for the SSH1106 chipset and send the display information to it? If this is overly difficult to do, feel free to disregard. If it is fairly simply, would be interested in trying it. Here is the one I bought. It says it could come with either the SSH1106 or the SSH1306 chipset, but you don’t get to pick which one. I got unlucky I guess.

    1. Philip Rueker Post author

      So if that display requires the SSH1106 driver you will have to install a different library and change the initialization of the display to use that different library inside the file.
      It looks like some people have used this one here successfully with SSH1106
      So to install that library you’d do:
      sudo pip3 install luma.oled
      and then inside the file instead of referencing the adafruit_ssd1306 library you’d reference the luma library and then the initialization of it, you’d have to replace the “disp = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c) line with the appropriate initialization of that library.
      Looks like some samples are here:
      And here’s some more references as the commands to fill the display with an image and turn it on and off are slightly different to the adafruit library:
      So you’d have to replace most of the “disp.XXXX” lines with the appropriate substitution from the api documentation.

      So assuming you can make those few substitutions, it should hopefully be relatively straightforward.

      1. Spencer Hamons

        Thanks Philip. I’m good up to changing the display lines, but can hopefully pull use the links you provided and gather what I need to make the syntax changes. Appreciate your quick response as always.

  57. Matt R

    Philip, thank you for the project. I’ve been wanting to do this for years, but don’t have the acumen myself to program. Your step by step has made it accomplishable.

    I need your help. There is a possibility of a dead LED I need to test, and I’m now in the end-stage of my build. I used your commands to test initially and all pixels worked fine on arrival, but I’ve done some butchery and might have ruined one. I’ve also confirmed the airport is transmitting METARs to

    When I run your suggested commands to fill all LED’s to a single color, it only lasts for a second before the background running code changes the LED’s back to the airport METARs.

    Do you have a suggestion on how to stop the code from refreshing the LED’s? I tried researching into kill commands and stopping python but both are ineffective on my end… Thanks for your help! (new to Pi’s!)

    1. Philip Rueker Post author

      I suggest you just temporarily remove the line from the crontab to trigger the automatic refresh of the LEDS while you do the separate test and then just add it back in the crontab again to re-trigger the METAR script when you are done with your testing.

      You can also always trigger the script that should kill the last run of the metar script (assuming you started it via the script).
      so if you type ./ it will kill the last run of the script.

      1. Matt R

        Thanks Philip, that did it. I greatly appreciate your help and again thanks for making the project possible

  58. Carder Gregory

    Hi Philip,
    Is there a way to be able to assign each LED to a certain airport without the airport list? I plan on doing the entire state of Texas (everything is bigger here) and since I don’t know which LED’s will be skipped or which LED is going to whatever airport, I wanted to see if there was a way to illuminate each LED, one by one and assign its own airport? I saw a video on YouTube by Rhino Offroad who did this but wanted to see if there’s a way to incorporate this into your script? Or if there’s even a backdoor way around this issue? Thanks for everything!

    1. Philip Rueker Post author

      So the way I did it was to first make sure all LEDs were working (with the details on how to test that in my instructions above) and if any of them are not, to just mark that one off (I just taped it with some black tape to mark it so I wouldn’t use it).

      Then to just build out the foam board with all the holes cut ready (using the template on which I wrote down the airport name, so it’s easy to know which hole is which airport) for the LEDs to be glued in and basically building the path from start to end for the LED string and so it becomes self-evident which LEDs are being skipped, so you basically just write down the airports in order following the string of lights into your notepad and put NULL for each LED skipped.

      Since it’s one continuous line of wire for the LEDs it’s pretty easy to just write down the list as you go.

  59. Andre

    How can we check the airports we select actually have METARS available to turn on the LEDs? I created my airports file by looking at the sectional chart and selecting airports that show ATIS/ASOS frequencies but some LEDs never light. I’ve verified all LEDs do light/are wired correctly with your pixels.fill routine.

    1. Philip Rueker Post author

      So at a quick glance, you can use your EFB like ForeFlight, or online on sites like and if that has a color light for an airport, then that airport probably reports online METAR.
      To verify you can type this into your browser and replace the airport code at the end with whatever airport you want to check, so for example:
      If it returns data, then that airport reports METAR information online, if it doesn’t, then it won’t light the LED.

  60. Andre

    I’m having trouble with my system refreshing and staying active. After about 8-9 minutes, all flashing LEDs (indicating wind) turn solid and the system/LEDs no longer update. If I cycle power off/on to the Pi, after the boot cycle completes the LEDs again become active but this cycle repeats, the system seems to freeze and not refresh after 8-9 minutes. After this happens, I am still able to connect with Putty & WinSCP. I’ve edited and enabled crontab per your instructions (including setting it to run every 5 minute as per your example), running sudo /etc/init.d/cron restart after editing crontab, have granted the proper permissions to the 5 files you mentioned on GitHub and have reset BLINK_TOTALTIME_SECONDS to 300. Is there something else I need to change/add to keep my system running continuously?

    1. Philip Rueker Post author

      If you follow my standard guide numbers, then the crontab should be re-running every 5 minutes to re-fetch the latest weather and update the LEDs continuously.
      This guide here – – has a lot of useful tips to troubleshoot the crontab.
      In particular I suggest seeing the syslog to see if it is indeed running correctly.
      If you run tail -n 30 /var/log/syslog you should see a line every 5 minutes indicating that the /home/pi/ script is being triggered like this:
      syslog output

  61. Andre

    If I turn on the Pi, the LEDs never lite. I ran tail -n 30 /var/log/syslog and this is what I see:
    pi@raspberrypi:~ $ tail -n 30 /var/log/syslog
    Feb 4 10:38:28 raspberrypi systemd[450]: Reached target Sockets.
    Feb 4 10:38:28 raspberrypi systemd[450]: Reached target Basic System.
    Feb 4 10:38:28 raspberrypi systemd[1]: Started User Manager for UID 1000.
    Feb 4 10:38:28 raspberrypi systemd[450]: Reached target Default.
    Feb 4 10:38:28 raspberrypi systemd[450]: Startup finished in 632ms.
    Feb 4 10:38:28 raspberrypi systemd[1]: Started Session 1 of user pi.
    Feb 4 10:38:32 raspberrypi dhcpcd[437]: wlan0: no IPv6 Routers available
    Feb 4 10:38:36 raspberrypi systemd[1]: systemd-fsckd.service: Succeeded.
    Feb 4 10:41:34 raspberrypi systemd-timesyncd[198]: Synchronized to time server for the first time (
    Feb 4 10:41:42 raspberrypi systemd[1]: systemd-hostnamed.service: Succeeded.
    Feb 4 10:41:53 raspberrypi CRON[476]: (pi) CMD (1/home/pi/
    Feb 4 10:41:53 raspberrypi CRON[475]: (CRON) info (No MTA installed, discarding output)
    Feb 4 10:41:54 raspberrypi dhcpcd[437]: wlan0: hardware address 00:00:00:00:00: 00 claims
    Feb 4 10:41:56 raspberrypi dhcpcd[437]: wlan0: hardware address 00:00:00:00:00: 00 claims
    Feb 4 10:41:56 raspberrypi dhcpcd[437]: wlan0: 10 second defence failed for 192 .168.0.56
    Feb 4 10:41:56 raspberrypi avahi-daemon[259]: Withdrawing address record for 19 on wlan0.
    Feb 4 10:41:56 raspberrypi avahi-daemon[259]: Leaving mDNS multicast group on i nterface wlan0.IPv4 with address
    Feb 4 10:41:56 raspberrypi dhcpcd[437]: wlan0: deleting route to
    Feb 4 10:41:56 raspberrypi dhcpcd[437]: wlan0: deleting default route via 192.1 68.0.1
    Feb 4 10:41:56 raspberrypi avahi-daemon[259]: Interface wlan0.IPv4 no longer re levant for mDNS.
    Feb 4 10:41:57 raspberrypi dhcpcd[437]: wlan0: rebinding lease of
    Feb 4 10:41:57 raspberrypi dhcpcd[437]: wlan0: probing address
    Feb 4 10:42:01 raspberrypi dhcpcd[437]: wlan0: leased for 86400 se conds
    Feb 4 10:42:01 raspberrypi avahi-daemon[259]: Joining mDNS multicast group on i nterface wlan0.IPv4 with address
    Feb 4 10:42:01 raspberrypi dhcpcd[437]: wlan0: adding route to
    Feb 4 10:42:01 raspberrypi dhcpcd[437]: wlan0: adding default route via 192.168 .0.1
    Feb 4 10:42:01 raspberrypi avahi-daemon[259]: New relevant interface wlan0.IPv4 for mDNS.
    Feb 4 10:42:01 raspberrypi avahi-daemon[259]: Registering new address record fo r on wlan0.IPv4.
    Feb 4 10:42:02 raspberrypi dhcpcd[437]: wlan0: hardware address 00:00:00:00:00: 00 claims
    Feb 4 10:42:18 raspberrypi systemd[1]: Started Session 4 of user pi.

    1. Philip Rueker Post author

      It looks like your Raspberry Pi was trying to get a valid IP address right after it triggered the script, so maybe your internet connection isn’t very stable?
      You should check the log again after logging in a bit longer before to see if there’s multiple lines of the crontab line indicating whether the crontab does indeed run okay every 5 minutes or not.
      You can also change the number of lines for the command by increasing the -n parameter.

      Please also read the article I referred to and try to follow it, as it has several tips on how to troubleshoot what might be going wrong.

  62. Andre

    After I enter & run sudo python3 using Putty, I see the “Setting LED for KXXX to VFR (255,0,0)” statements for all my airports (67). After about 5 minutes, the LED statements stop scrolling, I see Done and the LEDs no longer flash/the program seems to stop.
    If I enter & run the sudo python3 command again, this cycle repeats and ends the same way.

    1. Philip Rueker Post author

      Can you please run ./
      That should trigger the script and if that works, the crontab should work, if it doesn’t, then it means you don’t have the permissions set up correctly and might have to use chmod and chown on some of the files.

  63. Andre

    ./ does start my script. Do I need to change permissions on crontab or just the 5 files as you mention on GitHub?

    1. Philip Rueker Post author

      Just the files should be enough. If you scroll up in the comments you can see how to use the chown command.

  64. Andre

    I changed the permissions on all the files using chown – WinSCP now shows pi as the owner for all files. The only change has been when I power off/on the pi, the program starts automatically after booting instead of me having to start it manually. It is still stopping after about 8 minutes.
    Using crontab -e, I have verified the 2 bottom lines are identical to yours:
    */5 7-21 * * * /home/pi/
    05 22 * * * /home/pi/

    I re-ran tail -n 50 /var/log/syslog and below is the result – it does appear cron is running every 5 minutes but I’m not sure what the MTA not installed message is about?
    pi@raspberrypi:~ $ tail -n 50 /var/log/syslog
    Feb 4 14:04:05 raspberrypi systemd[1]: Started Getty on tty1.
    Feb 4 14:04:05 raspberrypi systemd[1]: Reached target Login Prompts.
    Feb 4 14:04:05 raspberrypi systemd[1]: Started OpenBSD Secure Shell server.
    Feb 4 14:04:05 raspberrypi systemd[1]: Reached target Multi-User System.
    Feb 4 14:04:05 raspberrypi systemd[1]: Starting Update UTMP about System Runlevel Changes…
    Feb 4 14:04:06 raspberrypi systemd[1]: systemd-rfkill.service: Succeeded.
    Feb 4 14:04:06 raspberrypi systemd[1]: systemd-update-utmp-runlevel.service: Succeeded.
    Feb 4 14:04:06 raspberrypi systemd[1]: Started Update UTMP about System Runlevel Changes.
    Feb 4 14:04:06 raspberrypi systemd[1]: Startup finished in 5.539s (kernel) + 36.897s (userspace) = 42.436s.
    Feb 4 14:04:06 raspberrypi systemd[1]: Created slice User Slice of UID 1000.
    Feb 4 14:04:06 raspberrypi systemd[1]: Starting User Runtime Directory /run/user/1000…
    Feb 4 14:04:06 raspberrypi systemd[1]: Started User Runtime Directory /run/user/1000.
    Feb 4 14:04:06 raspberrypi systemd[1]: Starting User Manager for UID 1000…
    Feb 4 14:04:07 raspberrypi systemd[452]: Listening on GnuPG cryptographic agent (ssh-agent emulation).
    Feb 4 14:04:07 raspberrypi systemd[452]: Listening on GnuPG cryptographic agent and passphrase cache (restricted).
    Feb 4 14:04:07 raspberrypi systemd[452]: Listening on GnuPG cryptographic agent and passphrase cache.
    Feb 4 14:04:07 raspberrypi systemd[452]: Reached target Timers.
    Feb 4 14:04:07 raspberrypi systemd[452]: Listening on GnuPG network certificate management daemon.
    Feb 4 14:04:07 raspberrypi systemd[452]: Listening on GnuPG cryptographic agent and passphrase cache (access for web browsers).
    Feb 4 14:04:07 raspberrypi systemd[452]: Reached target Sockets.
    Feb 4 14:04:07 raspberrypi systemd[452]: Reached target Paths.
    Feb 4 14:04:07 raspberrypi systemd[452]: Reached target Basic System.
    Feb 4 14:04:07 raspberrypi systemd[1]: Started User Manager for UID 1000.
    Feb 4 14:04:07 raspberrypi systemd[452]: Reached target Default.
    Feb 4 14:04:07 raspberrypi systemd[452]: Startup finished in 648ms.
    Feb 4 14:04:07 raspberrypi systemd[1]: Started Session 1 of user pi.
    Feb 4 14:04:13 raspberrypi dhcpcd[439]: wlan0: no IPv6 Routers available
    Feb 4 14:04:18 raspberrypi systemd[1]: systemd-fsckd.service: Succeeded.
    Feb 4 14:05:33 raspberrypi systemd-timesyncd[225]: Synchronized to time server for the first time (
    Feb 4 14:05:41 raspberrypi systemd[1]: systemd-hostnamed.service: Succeeded.
    Feb 4 14:05:54 raspberrypi systemd[1]: Started Session 3 of user pi.
    Feb 4 14:06:10 raspberrypi CRON[486]: (pi) CMD (/home/pi/
    Feb 4 14:06:10 raspberrypi CRON[485]: (CRON) info (No MTA installed, discarding output)
    Feb 4 14:10:01 raspberrypi CRON[495]: (pi) CMD (/home/pi/
    Feb 4 14:10:02 raspberrypi CRON[494]: (CRON) info (No MTA installed, discarding output)
    Feb 4 14:15:01 raspberrypi CRON[506]: (pi) CMD (/home/pi/
    Feb 4 14:15:01 raspberrypi CRON[505]: (CRON) info (No MTA installed, discarding output)
    Feb 4 14:16:00 raspberrypi systemd[1]: Started Session 7 of user pi.
    Feb 4 14:17:01 raspberrypi CRON[538]: (root) CMD ( cd / && run-parts –report /etc/cron.hourly)
    Feb 4 14:20:01 raspberrypi CRON[548]: (pi) CMD (/home/pi/
    Feb 4 14:20:02 raspberrypi systemd[1]: Starting Cleanup of Temporary Directories…
    Feb 4 14:20:02 raspberrypi CRON[547]: (CRON) info (No MTA installed, discarding output)
    Feb 4 14:20:02 raspberrypi systemd[1]: systemd-tmpfiles-clean.service: Succeeded.
    Feb 4 14:20:02 raspberrypi systemd[1]: Started Cleanup of Temporary Directories.
    Feb 4 14:25:01 raspberrypi CRON[562]: (pi) CMD (/home/pi/
    Feb 4 14:25:02 raspberrypi CRON[561]: (CRON) info (No MTA installed, discarding output)
    Feb 4 14:30:01 raspberrypi CRON[573]: (pi) CMD (/home/pi/
    Feb 4 14:30:01 raspberrypi CRON[572]: (CRON) info (No MTA installed, discarding output)
    Feb 4 14:30:51 raspberrypi crontab[587]: (pi) BEGIN EDIT (pi)
    Feb 4 14:32:52 raspberrypi crontab[587]: (pi) END EDIT (pi)

    1. Philip Rueker Post author

      I suggest you output the results of the crontab to a temporary log file to see if you can find any errors:
      So change the crontab to this:
      */5 7-21 * * * /home/pi/ > /home/pi/templog.log 2>&1

      This will output the results of the script run into a temporary file called “templog.log” in the same folder, and then I suggest you see what you can find in there (particularly when the time where you say the script stops).

  65. Andre

    I read your link on Troubleshooting Cron and verified the first five steps. I added your suggested line to crontab and have run the script for a while. As I write, the LEDs have again frozen but according to the temp.log, the program is still outputting LED data. Here is the beginning of the log – after the last line below, it continues repeating the airport data (not posted as it is a very long file):

    pkill: pidfile not valid
    Try `pkill –help’ for more information.
    pkill: pidfile not valid
    Try `pkill –help’ for more information.
    Running at 04/02/2021 16:25
    Wind animation:True
    Lightning animation:True
    Daytime Dimming:False
    External Display:True

    1. Philip Rueker Post author

      Ah ok so here might be your error.
      If you’re getting an error about the pidfiles not valid, then it basically means that the script can’t do it’s job, which is to first kill the existing running script and then trigger a new clean run of the script.
      Without it being able to kill the previous instance of the script, you basically run into a dead-lock where the new script can’t actually do it’s job, because there’s already currently a copy of the script running.

      Can you please check that the two files “” and “” exist and are owned by the “pi” user, if not, please use chown on them to give the pi user ownership of the files. If that doesn’t work, you can delete the files and they should be re-generated automatically.
      The files automatically get created when you run either ./ or ./ script (that’s what the “& echo $! > /home/pi/” is for, the store the latest script process id).

      You should only trigger the script by using the ./ script and turn them off using the ./ script to ensure that the above runs fine.

  66. Andre

    I did verify both .pid files are owned by pi. As you suggested, I had to run and before they were created. They also have read-only permissions – should I give them executable permissions?
    My system is still acting the same way – stops working after about 8 minutes.
    When I run./, I see the messages below before it executes Do you need to see the pid file values?
    pkill: pidfile not valid
    Try `pkill –help’ for more information.
    pkill: pidfile not valid
    Try `pkill –help’ for more information.

    1. Philip Rueker Post author

      I suggest you delete both files, something must have gone wrong with why they are considered not valid.
      then re-run the script and then the script and that should re-generate both files.

  67. Andre

    I deleted both files, turned off/on the pi and the script started automatically. It stopped again after about 8 minutes. It did create a but not in the pi directory.

    1. Philip Rueker Post author

      Check the logs again to see whether the script was able to run correctly now or if there’s still errors about the pidfile not being valid.
      If so, then the only other idea I have is that something is wrong with your script, so maybe copy the latest from the github.

  68. Matt R

    Philip, thanks for helping us newbies. I also am getting an error. All I’ve been configuring is the number of active LED’s in the config section and the ‘airports’ file. (my project is huge and I’m testing every 10 or so LED’s as I wire them). The lights stopped initializing on their own, so I ran on it’s own and got this at the end of the return and the script stopped.

    […Setting LED 79 for KDWX to VFR (255, 0, 0)
    Traceback (most recent call last):
    File “”, line 226, in
    pixels[i] = color
    File “/usr/local/lib/python3.7/dist-packages/”, line 314, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.7/dist-packages/”, line 280, in _set_item
    raise IndexError
    pi@raspberrypi:~ $]

    I tried to reload the files installed with in this process but it didn’t (and I’m not sure it would) help. I believe this is pointing to a conflict in python’s included packages? Thanks

    1. Philip Rueker Post author

      IndexError indicates you are trying to set more LEDs than you initialized, so make sure you increase the LED_COUNT variable in the file to be bigger-than-or-equal to the LED being addressed (note it’s 0-based, so LED 79 indicates it was the 80th LED).
      You’ll also need to update the number in the file to coincide with it.

      1. Matt R

        Thank you, this is exactly right. I entered all of the airport identifiers in my project thinking it would save time. The numbers mismatch. I appreciate your help.

    1. Philip Rueker Post author

      They are similar, but not identical, one calls, the other calls

      Can you (not turning raspberry pi on/off) run from putty the ./ and then again in a second putty window run the ./ file, while the is still running in the other window?
      As soon as you start ./ in the second window, the execution in the first should stop if everything is configured correctly.

      If not, then please check file permissions and ownership of all files again.
      If in doubt, delete the two files ( and again and then from putty run the ./ and ./ script and they should correctly generate the two files.

      If you have correctly copied the files from my instructions, then it should work once you’ve ensured all the permissions are set correctly.

  69. Adam Howard-Dobson

    Loved this project! Thanks so much for sharing the guide it made for a great lockdown project. For anyone just starting a build I am running 32 LEDs straight of the Pi without any trouble. The Pi and the LEDs are drawing less than 2A. During the build I was running the whole lot off a USB power brick. Would it be possible to add a small touchscreen that would allow you to swipe between airports?

    1. Philip Rueker Post author

      Awesome picture of your completed map, I always love to see when people share their completed projects with me and even cooler when I see it’s from all over the world like yours from England, with good weather in London even 🙂

      As for your question about the touchscreen, yes it would be possible, but you would have to write some code for the swiping action and you’ll have to look for one that is compatible with the Pi Zero, as many are designed for the bigger Raspberry Pi.
      This one here mentions it might work with a Pi Zero and guide

      1. Adam Howard-Dobson

        Ha yeah the weather’s not awful here all the time! Thanks for the links. If need be I’ll run it off a full size Pi. Will take a look at the screens out there and see what I can come up with.

  70. Scott Moody

    I have made several modifications to this project. I wanted to add one here that may help.
    Add this to the cronjob to start the script after booting. It saves you from waiting up to 5 minutes for the script to start.

    @reboot sleep 20 && /home/pi/

    The sleep 20 allows the Rpi to boot before trying to run the script.

  71. Zane

    When I try to run is gives me an error “ModuleNotFoundError: No module named RPi”. I have all the files installed into home/pi, I’m not sure what I’ve done wrong.

    pi@raspberrypi:~ $ sudo python3
    Traceback (most recent call last):
    File “”, line 5, in
    import board
    File “/usr/local/lib/python3.7/dist-packages/”, line 48, in
    from adafruit_blinka.board.raspberrypi.raspi_40pin import *
    File “/usr/local/lib/python3.7/dist-packages/adafruit_blinka/board/raspberrypi/”, line 3, in
    from adafruit_blinka.microcontroller.bcm283x import pin
    File “/usr/local/lib/python3.7/dist-packages/adafruit_blinka/microcontroller/bcm283x/”, line 2, in
    import RPi.GPIO as GPIO
    ModuleNotFoundError: No module named ‘RPi’

    1. Philip Rueker Post author

      it looks like your file ends in .txt and not .py

      If you did all the updates and installed the libraries as outlined in the github, then it should work.
      You can always just try to run the commands to install the libraries again and see if it runs without errors.

      This guide (which is also linked in the github) has some more details to possibly help troubleshoot –

      But otherwise, this guide might help you troubleshoot

      1. Zane

        When copying over, do I just copy and paste the text into putty and run it? I copied it into a notepad and saved it as .txt and placed it into the root file for the Pi, then moved it to home/pi. Only part of the install that was confusing for me, how would I make it a file that ends in .py? I googled it a bit and couldn’t figure it out. This is my 2nd time doing something with a Pi

        1. Philip Rueker Post author

          If you’re connected to the pi using putty you can create text files by typing “nano FILENAME”, so for example “nano” would start a new text file ending in .py.

          You could also download the files from the github on your computer and transfer them to the pi using a tool like WinSCP.

  72. Andre

    Referencing the crontab instructions posted on your github link:
    */5 7-21 * * * /home/pi/
    05 22 * * * /home/pi/
    as explained, the above will run the refresh script runs every 5 minutes between 7 AM and 11PM, with the last cycle running at 11:05 PM.

    I would like crontab to run the ./ script every 5 minutes between 6 AM and 10:30 PM. At 10:30 PM, I would like crontab to run ./ and keep the lights off until 6 AM the following day. How do I get the refresh script to stop running after 10:30 PM?

    1. Philip Rueker Post author

      So with the below, you’ll run every 5 minutes between 6am and 9pm (inclusive, so until 9:55pm), then on the 0th,5th,10th,15th,20th,25th minute of 10pm and then at the 30th minute of 10pm it will run lightsoff:
      */5 6-21 * * * /home/pi/
      0,5,10,15,20,25 22 * * * /home/pi/
      30 22 * * * /home/pi/

      You can find more reference on crontab here:

  73. Daniel Kapeller

    Hey. Thanks for the great instructions and for providing the GitHub software. I built mine and have two suggestions for you regarding the software.

    1) Lightning Feature

    I noticed that in the lightning display feature, it is only triggered if there is LGT reported in the METAR, which is usually only when there is distant lightning. It does not take into account cases when there is lightning more near to the airport (TS, VCTS, +TSRA, etc). I fixed this by changing:

    lightning = False if rawText.find(‘LTG’) == -1 else True


    lightning = False if ((rawText.find(‘LTG’) == -1 and rawText.find(‘TS’) == -1) or rawText.find(‘TSNO’) != -1) else True

    This way, all cases of lightning near the airport are taken account, but it is not triggered if the METAR reports the thunderstorm sensor inoperable.

    2) Wind Blinking Threshold

    This is more of a minor thing, but in the configuration part of the file, I expected the wind listed in the wind blinking threshold to be where the lights started blinking (at or above speed x, blink). It turned out to be greater than. So for example, if you have 15 in the config, an airport reporting 15 knots will not blink. This is probably more personal preference, but it makes sense for that speed to be when the blinking starts. I fixed this just be replacing > with >= in the windy variable.

    Thanks for the great guide!

    1. Philip Rueker Post author

      Thanks for the suggestions, I’ll add them to my todo list and will update the code with them soon.


  74. Phil benyo

    Update- first one built! on the the second one
    I decided to try to find a less cumbersome light source and found these BTF-lighting WS2812B presoldered LED strip- advantages to them are that they are lower profile, and distance between LED is greater.. Problem I encountered is that they use a different lighting code for the colors
    RED 255,0,0
    GRN 0,255,0
    BLUE 0,0,255 (was the same )
    purple 125,0,125
    took hours of hair pulling until a ran the neopixel test
    I did lower the output and running 50 LED nicely, will update with some pics when done

    1. John Leon

      Thanks for that tip! I just built my 5th map, this time using the WS2812B pre-wired flat LEDs from AliExpress. They work great! I had to change brightness from .5 to .05, and the dim setting from .3 to .03. Looks fantastic.

  75. Alex

    Note…on the crontab demo file on

    it shows
    */5 7-21 * * * /home/pi/
    05 22 * * * /home/pi/

    but the files on the directory are .py
    i was getting not being able to get it to work until i changed the crontab file to match .py
    is this correct?

    I also ran htop to look around and i can see sometimes up to 4 instances of running under root.
    is this normal?


    1. Philip Rueker Post author

      Nope, please recheck the github, there are, and (if you’re using a LED display) files and the 2 and files.

      The crontab should trigger the .sh files like my sample shows, which in turn ensure that only one instance of runs at any given time (by cancelling the previous run).

      1. Alex

        I thinks i messed up when i created the files , i named all of them .py

        So renamed the to and to then fixed the crontab back as your example. I guess i was too hyped up and missed that, my mistake.

        lighstoff seems to work fine now, but ./refresh goes into an endless loop, starting with

        pi@raspberrypizero:~ $ ./
        pkill: pidfile not valid
        Try `pkill –help’ for more information.
        pkill: pidfile not valid
        Try `pkill –help’ for more information.
        ./ line 3: /home/pi/metarpid.pidy: Permission denied
        pi@raspberrypizero:~ $ Running at 21/02/2021 21:10
        Wind animation:True
        Lightning animation:False
        Daytime Dimming:False
        External Display:False
        Rotating through all airports on LED display….

        i thinks i might have some permission problems?
        I have chmod as instructed. any ideas?

        1. Philip Rueker Post author

          The pidfiles should be automatically generated the first time you run the ./ and ./ script.
          If there’s something wrong, you could delete the pidfiles if they are there.
          Also check that the ownership of the files looks all good by typing “ls -al”.

          Also one of the errors says “metarpid.pidy” so you might have accidentally added a y at the end of the end of the script there, as it should be “/home/pi/” (not pidy, so no y).

          1. Alex

            i appreciate the reply.

            i did accidentally add a y when closing nano. thanks

   works fine, does turn the leds off
            when i run ./ is goes into a continuous loop, i see it load the airports and their colors again and again and can’t break the loop.

            what could be causing this?

          2. Philip Rueker Post author

            well that’s how it works if you’re using the blinking/lightning, it will loop the LEDs for however long you set the total blinktime (default 5 minutes) and then it will finish.
            That’s where the crontab comes in to then re-trigger the script again to fetch the latest weather and then again loop the LEDs for the total time.

            When you manually run the ./ to kick it off, you can break out of it by quickly hitting ctrl+c and typing ./ (while the looping will continue, so you have to type it somewhat blind), you can type ./ligh and hit the tab key to autocomplete the thing and just hit enter, or by opening a second window and typing ./ in there and it will halt the script execution in the other window (that’s what the pidfile process killing is for, to ensure that the script only runs one-at-a-time for when the crontab is running to ensure that there’s no overlap).

  76. Andre

    On 12-16-2020 Randy posted he turns his LEDs to Yellow when winds exceed 25 knots. What code changes would be needed to fade an LED from COLOR_FADE (color) to Yellow when winds speeds exceed 25 kts?

    1. Philip Rueker Post author

      You would have to define a new color for yellow, add another variable for the higher threshhold where you want to blink to yellow instead of normal fade color and then the main part will be at the blocks where the LED color decision is mine (between line 223-230) you would add another condition towards the end of the 4 long lines where it does
      In there, you would want to add another check along the lines of:
      COLOR_YELLOW if conditions["windSpeed"] > EXTREME_WIND_THRESHOLD else (the above)

  77. Andre

    Very helpful, Philip. Based on your instructions, I was able to make this work. My LEDs now flash Yellow anytime winds are reported at 25 knots or above at any location.

    Lines added:
    40) COLOR_HIGH_WINDS = (255,255,0) # Yellow
    50) HIGH_WINDS_THRESHOLD = 25 # Knots of windspeed to trigger Yellow LED indicating High Winds

    else COLOR_HIGH_WINDS if conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD
    as shown:

    224) color = COLOR_VFR if not (windy or lightningConditions) else COLOR_LIGHTNING if lightningConditions else COLOR_HIGH_WINDS if conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD else (COLOR_VFR_FADE if FADE_INSTEAD_OF_BLINK else COLOR_CLEAR) if windy else COLOR_CLEAR

    226) color = COLOR_MVFR if not (windy or lightningConditions) else COLOR_LIGHTNING if lightningConditions else COLOR_HIGH_WINDS if conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD else (COLOR_MVFR_FADE if FADE_INSTEAD_OF_BLINK else COLOR_CLEAR) if windy else COLOR_CLEAR

    228) color = COLOR_IFR if not (windy or lightningConditions) else COLOR_LIGHTNING if lightningConditions else COLOR_HIGH_WINDS if conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD else (COLOR_IFR_FADE if FADE_INSTEAD_OF_BLINK else COLOR_CLEAR) if windy else COLOR_CLEAR

    230) color = COLOR_LIFR if not (windy or lightningConditions) else COLOR_LIGHTNING if lightningConditions else COLOR_HIGH_WINDS if conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD else (COLOR_LIFR_FADE if FADE_INSTEAD_OF_BLINK else COLOR_CLEAR) if windy else COLOR_CLEAR

    1. Philip Rueker Post author

      Yes, you could just add an “OR” statement to check for if windgusts are present. So something like this:
      COLOR_HIGH_WINDS if (conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD or conditions["windGust"] == True)

      1. K4DQP

        Where does this code go exactly?

        COLOR_HIGH_WINDS if (conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD or conditions[“windGust”] == True)

        1. Philip Rueker Post author

          It would go into the lines as Andre has shown, so something like this:
          color = COLOR_VFR if not (windy or lightningConditions) else COLOR_LIGHTNING if lightningConditions else COLOR_HIGH_WINDS if (conditions[“windSpeed”] >= HIGH_WINDS_THRESHOLD or conditions[“windGust”] == True else (COLOR_VFR_FADE if FADE_INSTEAD_OF_BLINK else COLOR_CLEAR) if windy else COLOR_CLEAR

  78. Alex

    I found something interesting in my setup.
    i deleted the pid files… and

    If i comment the crontab and start the show with ./refresh the pid files are owned by pi
    and in htop i only see one process works perfect.

    But if start the show via the crontab on boot one of the pid files is owned by root,
    and in htop i see a lot of processes and the pi eventually crahses.

    What could be causing this? thanks

    1. Philip Rueker Post author

      So when you start it directly it runs as you (pi) and thus pi owns the pid file, but via crontab it will run the execution as root via the sudo and so the file ends up being owned by root and so then it can’t update the file when runs and thus you’ll run into some unexpected behaviour.

      If you run the ./refresh and ./lightsoff once yourself, the files should be owned by pi and then also crontab should be fine to be able to access them correctly, but the other way round creates some issues.

      The other workaround is, to set the two pidfiles to write for “others” by using chmod +w, so then both users should be able to write it and it should work fine too then.

  79. Andre

    What’s needed to change the LEDs flashing yellow when winds or wind gusts are 25 knots or above?
    With the code changes I listed above, winds above 25 knots or any wind gusts turn the LEDs yellow.

    1. Philip Rueker Post author

      Instead of using the conditions["windGust"] variable that just says true or false when there’s gusts, you’d have to use the conditions["windGustSpeed"] and check the speed you want to change on.

  80. Ben


    Thank you so much for all of this. I’ve never done a project like this and was thinking about just starting with the Raspberry PI and lights to make sure I could figure it all out. Do you have a certain breadboard you would recommend?

    1. Philip Rueker Post author

      Breadboards are all the same really, there’s just difference sizes and it’s not really needed for this project, I only used it while I was testing, but the final wiring is just done directly.

      But if you do want to use a breadboard, this is the one I have used.

  81. John


    Upon wiring up the mini display it became rather hot, once powered on. Wondering if something was wired incorrectly or if yours tends to carry some heat with it as it is operates?

    1. Philip Rueker Post author

      Hi, I honestly can’t tell as I never checked whether it got hot, but it seems fine in my installation running for quite a while now.

  82. Adam Howard-Dobson

    Have been refining my build and have now got a really nice process going. I’m doing my first build that’s using 100 LEDs (two bunches of 50 clipped together) and I’m getting an odd result from the second set of 50 LEDs. They show Red, Blue and Green just fine but with Magenta they flicker like mad and don’t show the correct colour at all. The first set of 50 are absolutely fine and if I swap sets around the problem always happens with the second set of 50. I have found a work around by running the second set directly back to the power supply. Any idea what might be causing this?

    1. Brian Bauer

      Are you driving the LED’s directly from the Pi? For strings over 50, it would be best to have the + and – hooked up directly to the power supply. Or you can try and lower the brightness for all LEDs. Flickering happens when the voltage has dropped past the point that the LED’s can be driven. You can also check and see what the voltage is at the end of the 100 string.
      Another thing to check is what your power supply amp is.

      1. Adam Howard-Dobson

        Hey Brian, no I’m driving the LEDs from a 5v 10A power supply. I’ve done some further testing and you’re right, the voltage drop by the end of the 100 string is quite significant. I’ve modified my wiring to introduce power at the beginning and the join point for the additional 50 and that’s solved it, looking great now.

  83. Jim Rowe

    Hi Philip – Thanks so much for sharing these instructions. I’ve wanted one of these for a while and finally built one over the winter. Project went great and I’m very pleased with the end result, which now proudly hangs over my desk. Surprisingly, I had more trouble with the construction (joining sectionals and gluing to backer) than I did with the technical stuff.

    I am, however, finding that the map freezes every few days and I need to unplug and restart. Any idea why?

    1. Philip Rueker Post author

      Hard to say, the main time I’ve seen people having random issues is if it’s a power problem, like too many LEDs running directly of the Raspberry Pi drawing too much power and that can cause unexpected behavior.

      Since it’s intermittent it’s hard to say for sure, but if a reboot fixes it, you could try to add a reboot routine to your crontab during the night, maybe that could help alleviate it.
      If you added something like this to crontab, then the raspberry would initiate a reboot at 4am (the 0 4) +5 minutes, so at 4:05am every night it would reboot.
      0 4 * * * /sbin/shutdown -r +5

      1. Jim

        Makes sense, I’ll give it a try! Thanks for your help with this awesome project.

  84. Adam

    Fun project, I just finished mine. Thanks for the inspiration! Here’s my twist: I wanted an easier way to see which station was being displayed, so I added a fast-blinking option that highlights the currently shown station,. You can see a video of it in action here:

    But to also have the wind blinking work, I needed to completely rewrite the main display loop logic and implement multi now windy stations blink slowly and the highlighted station flashes quickly, all modifiable with flags in the program. Happy to share the code if anyone’s interested

  85. K4DQP

    Very cool project! I just received my ALITOVE WS2811 lights and have two questions. I am planning on wiring directly to Raspberry PI Zero.

    At the first and last LED, there is a black connector with a black plug, one male and one female. There is also two extra wires, one red and one blue from each led (open wire).

    1. Which side of the LED string is connected to the PI? I am assuming I will clip off this black connector and wire directly to the pi, using the appropriate GPIO pins.

    2. What do I do with the extra wires coming from the last/first LED?

    1. Philip Rueker Post author

      you’ll find there’s a small arrow on the top side of the LEDs, the Pi connects into the arrow side.
      This here shows it:
      The 2 extra wires coming out of the first LED are if you want to connect an external power supply to the LEDs, but isn’t needed if you’re going to power them directly from the Pi.

      You can use pinned wires like these – to connect the Pi Pins directly into the black clip.

      1. K4DQP

        That worked. Thanks.

        Note: I made one change to the crontab procedure that seemed to work better for me. It seemed like it was timing out or just not refreshing like it should. Now it works perfect…enjoy the coffee!

        My crontab: “*/5 * * * * sudo ./”

  86. Jeremiah

    I cannot get the to work. when i attempt “sudo python3”, i get:

    File “”, line 1
    usr/bin/sudo pkill -F /home/pi/offpid
    SyntaxError: invalid syntax

    1. Philip Rueker Post author

      The shell files don’t need to be run with python.
      So you just need to type:
      to run it.

      1. Jeremiah

        Okay, that helped out a lot. So i know lightsoff is working, but my crontab isnt turning it off when i expect it to. Here is what I have in the crontab:

        */5 6-22 * * * /home/pi/
        5 22 * * * /Home/pi/

        I assumed that would run it from 6am – 11:05 and then shut it off, but it never shuts off.

        1. Philip Rueker Post author

          Your instructions show to run the refresh every 5 minutes between 6am and 10pm (inclusive) so until 10:55pm.
          But your light off is set to run at 10:05pm (22 = 10pm).
          You need to set it to 23 for 11pm.

          1. Jeremiah

            Wow, I feel dumb now. lolol. Thank you for pointing that out and helping me realize my mistake. I love this project and cant wait to get it all put together!

  87. Chris

    I hate to bug you, but I need some help. I’ve made 3 of these. On this third one, I tried a different set of lights. I also tried making a disk image copy instead of going through the whole setup. Somewhere something has gone wrong and unfortunately I’m not a programmer.

    The lights themselves are strange in that they light up white immediately when powered on. But they respond correctly to the test commands. They even turned off automatically last night. But is not lighting them up. This is the last bit of code returned when I run it manually.

    Setting LED 47 for KAPT to None (0, 0, 0)
    Traceback (most recent call last):
    File “”, line 236, in
    pixels[i] = color
    File “/usr/local/lib/python3.7/dist-packages/”, line 314, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.7/dist-packages/”, line 280, in _set_item
    raise IndexError

    Again I want to thank you. I hosted an EAA chapter party where we I helped people make these. Most were computer guys, but it was a fun event.

    If I need to rip all these lights out, so be it. I’ll just buy more of the correct ones on amazon.

    1. Chris

      I tried on a different board with new strings so it wasn’t that. It must be my disk image. Maybe can’t shortcut the setup. 😐

    2. Philip Rueker Post author

      An index error usually means you are trying to address more LEDS than you initialized in the LED_COUNT variable.
      So make sure your LED count variable is set higher than the amount of lines in your airport file.

  88. Ray

    Hi Philip, this is awesome! Thank you so much. Couple of questions: is there a way to only trigger the high winds animation if the gust spread exceeds a certain threshold?
    Also, is there a way to add the wind animations to the legend. I have the solid LEDS for VFR, MVFR, IFR, and LIFR, but is there a way to add a fifth and sixth LED to demonstrate the wind/high winds?

    Thanks again for posting this!

    1. Philip Rueker Post author

      Yes, you could modify the calculation for when the high winds animation trigger to calculate the difference between the gust speed and the wind speed instead.
      So if you change the formula on line 225 to something like this, I believe it will do what you’re asking for:
      highWinds = True if (windy and HIGH_WINDS_THRESHOLD != -1 and ((conditions["windGustSpeed"] - conditions["windSpeed"]) >= HIGH_WINDS_THRESHOLD)) else False
      You’d just then define whatever difference between the two values you’d want in the HIGH_WINDS_THRESHOLD variable. So for example if you set it to say 5 and the winds were 10 Gusting 15, then it would trigger the high winds animation.

      As for the animation legend, yes that can be done, since someone else wanted a legend before as well, I decided to just code it up now including the animations for wind and lightning.
      So if you use the new copy of from my METARMap Github, you can get the functionality.
      Here’s the instructions on how to activate it:, please let me know if all works like you’d expect.

  89. Denis

    Hi! First of all let me thank you for this great project idea and for the great instructions! I knew nothing about Raspberry but a couple of hours were enough to get everything to work!
    I do have one question. Our homebase airfield has an automatic METAR station but it is only possible to retrieve it via a login access. I found a way to create a URL that only gets the METAR without asking for the login, and which is able to determine the color for VFR, IFR etc, is there a way to send this metar and the color code to the Raspberry using another source than (I contacted them to ask if they could add the METAR to their site but they are not able to do so)

    Thanks for your help and enjoy your day!

    1. Philip Rueker Post author

      Yes it would be possible to make a second call to your URL to get the weather for that airport, but you would have to make a few changes in the main section of the script to fetch that information for that airport and add it to the list of airports.

      So you’d just do another web request (the urllib.request.urlopen(..) part) and store it in a second variable and then after the code added the conditions for the rest of the airports in the loop you would just add a section to parse your url for that condition and then add that condition in the conditionDict and append it to the airports and stationList.

      1. Denis

        Hi! I have been trying to apply the correction you mentioned to the METAR.PY as you explained me above. However, Raspberry is still kinda new to me so I must say I am struggling a little bit.. sorry to bother you with this but can you tell me how to set up the URL of my Metar in the request.urlopen… part? The URL I use is a website dedicated to display this METAR only so I don’t even need the Raspberry to search for a specific code.

        I also added the airport in the light sequence inside my Airports file, is that ok if it is mixed with the other airports taking data from aviationweather? Or does my airport need to be separated from the others?

        Sorry for the beginner questions again! Thanks anyway as the entire project is already working apart from this small detail! I owe you more than a coffee for sure!

  90. Paul

    Bought you a cup of Joe!
    Couple questions I didn’t see in the thread or instructions (I’m new to raspberrypi) :
    1) Do you recommend the breadboard first?
    2) How many points do you need to solder on the pin header to the board?

    1. Philip Rueker Post author

      1) It’s not really necessary to use the breadboard, you can also just directly hook up the pins on the Raspberry to the LED lights
      2) The minimum would be the pins needed for the LED lights per this diagram pins, but it won’t hurt to solder all of them (other than the extra time it takes) in case you want to extend functionality in the future, such as adding the mini display that would require extra pins.

  91. Paul

    ran sudo python3 and got error msg:
    file line 3
    import urllib.request
    Import Error: No Module named request

    1. Philip Rueker Post author

      That error usually indicates you tried to run it with python, not python3.

      Make sure you use python3 if you want to test it directly, or even better just use the ./ file.
      So just run ./ which will trigger the script as well.

  92. Paul

    you were right. I had typo. used python2 instead of python3.

    It just dawned on me that you have to solder the pin you want to connect to so the connection between the header pin piece and the board is solid? correct?
    curious because script ran but no lights lit up.

    Also, the example you have for the raspberry pi board above is not the same as the one in the parts list so I’m trying to figure out what the proper orientation is for using the right pins?

    1. Philip Rueker Post author

      Correct, you’ll have to solder those pins between the board and the header pin piece so there’s a solid electrical connection (which is why to be safe you’re not soldering the wrong ones, it’s easiest to just solder all of them).

      Yes, the example picture is that of a full size Raspberry Pi, but the pin order is the exact same with the smaller model. There is one pin on the board that is square instead of round, that’s pin one (top left). You can see the mapping between here:

      1. Philip Rueker Post author

        I suggest you try to manually light the LEDs first for testing as I’ve outlined further up on the page here. If you installed all the libraries and did the soldering and connecting of the pins correctly, then that should work.

        If not then I suggest to re-check the wiring and the soldering connections.

    1. Philip Rueker Post author

      Not neccesarily, though creating a bridge from ground to power may be an issue.
      If you have a de-soldering suction that would be best, if not then checking that it’s only some not-used gpio pins ( is probably (though no guarantees) fine.

  93. Paul

    I noticed when I wiggled the connections to the header pins that the red lights flickered.
    I ordered a new board.
    Can you confirm if I get the soldering right and run the file will the red lights stay on steady? or what should I expect to know I’m good and can then manage the settings via the files?

    1. Philip Rueker Post author

      Yes if you’ve correctly soldered the pins and connected them, then running the the couple commands up on the page would make the LEDs steady red until you run the pixels.deinit() command. Or by running the script, it will illuminate them based on the weather condition of the aiports listed in the airports file.

      If you have some trouble with the soldering, you can look and probably find a pre-soldered Raspberry Pi mini as well, then you just need to connect the pins.

  94. Paul

    So, I ordered a MUCH better Dremel to solder/fix the old board but I also ordered a pre-soldered board.

    I’d expect to move the SD card and connect the pins, run the script and it lights up steady?

    I have the connections as follows from lights:
    red to pin 4 on right side of board from top right (5v)
    white to pin 12 (GPIO 18/CLK/PCM)
    blue to pin 14 (GND)

    If so, any ideas on where to look next

    1. Philip Rueker Post author

      Yes that’s the right wiring.

      And yes, if it’s connected correctly, then if you run the script, the LEDs should stay illuminated based on the the weather (or blink if you’re using the wind blinking functionality and it’s windy at that LEDs airport).

  95. Paul

    Not sure if this was confusing to others but the instructions for connecting to the lights mention the white arrow but both ends of the lights are the same..only difference is one end has the male end to plug into other lights and the other end has the female the female end the correct end?? I tried this end and used female to female ELEGOO wires you recommended and only the first light lights up blue. test script doesn’t light any others up…

    also, the blue wire from the lights when plugged into the board at location 14 (GND) turns the light off

    not sure if I just have this hooked up wrong or if it is the lights or maybe a permission issue…code seems to run fine

  96. Paul

    P.S. I’m using a new board I got with pre-soldered pin header.

    I get that part with the top/arrows. You can hook up wiring from the board to either end of the light strand.

    One end I would call the male end (bottom right of the picture in link above) and female end (top right in picture). I got them to all flicker when jiggling connectors to the board around using female and and the first one to light steady when using the male end.

      1. Paul

        So I ordered a new pi board with pre-soldered pins, a new strand of the same lights and an external 5V power supply with converter.

        I put the SD card into the new board and hooked up to both the old strand and the new strand. Still nothing.
        Then hooked up the 5v power supply to the female end of the light strand using only the white data wire from lights to the board and connected the blue and red from lights to the external power supply. Now all the lights light up but only white.

        Tried to test the light colors using script above and no color changes.

        I’m at a loss.

          1. Paul

            So, I ended up having to add an external power source and wiring it that way.
            I think the issue, or one of them, is that I needed to run a ground back from the lights (off the power supply) back to the 3 on the right side. then all of a sudden they lit.

            For some reason, the lights are not working now. I went from 5 working to adding in NULL values and it stopped. Do you have to change led_count to 35 or can you leave it set a 50?

            Do these file permissions below look ok?

            pi@raspberrypi:~ $ ls -al
            total 160
            drwxr-xr-x 21 pi pi 4096 Jun 26 16:18 .
            drwxr-xr-x 3 root root 4096 May 7 10:42 ..
            -rw-r–r– 1 pi pi 28 Jun 26 15:55 airports
            -rw——- 1 pi pi 2075 Jun 26 17:18 .bash_history
            -rw-r–r– 1 pi pi 220 May 7 10:42 .bash_logout
            -rw-r–r– 1 pi pi 3523 May 7 10:42 .bashrc
            drwxr-xr-x 2 pi pi 4096 May 7 10:52 Bookshelf
            drwxr-xr-x 7 pi pi 4096 Jun 6 20:54 .cache
            drwx—— 12 pi pi 4096 Jun 26 16:16 .config
            drwx—— 2 pi pi 4096 Jun 8 18:18 .cups
            drwxr-xr-x 2 pi pi 4096 Jun 26 16:17 Desktop
            -rw-r–r– 1 pi pi 2376 May 6 11:01
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Documents
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Downloads
            drwx—— 3 pi pi 4096 May 7 11:08 .gnupg
            -rwxr-xr-x 1 pi pi 173 May 6 11:01
            drwxr-xr-x 3 pi pi 4096 May 7 10:52 .local
            -rw-r–r– 1 pi pi 5 Jun 26 16:56
            -rwxr-xr-x 1 pi pi 13071 Jun 26 17:05
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Music
            -rw-r–r– 1 pi pi 5 Jun 13 22:40
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Pictures
            -rw-r–r– 1 pi pi 275 Jun 11 22:28
            drwx—— 3 pi pi 4096 Jun 6 20:54 .pki
            drwx—— 3 pi pi 4096 Jun 14 07:11 .pp_backup
            -rw-r–r– 1 pi pi 807 May 7 10:42 .profile
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Public
            drwxr-xr-x 2 root root 4096 Jun 10 20:39 __pycache__
            -rwxr-xr-x 1 pi pi 171 May 6 11:01
            -rw-r–r– 1 pi pi 66 Jun 11 22:37 .selected_editor
            -rw-r–r– 1 pi pi 0 Jun 6 21:08 ssh
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Templates
            drwx—— 4 pi pi 4096 Jun 26 16:17 .thumbnails
            drwxr-xr-x 2 pi pi 4096 May 7 11:08 Videos
            drwx—— 3 pi pi 4096 Jun 6 21:45 .vnc
            -rw——- 1 pi pi 56 Jun 26 16:18 .Xauthority
            -rw——- 1 pi pi 2425 Jun 26 16:18 .xsession-errors
            -rw——- 1 pi pi 2425 Jun 18 22:28 .xsession-errors.old

          2. Philip Rueker Post author

            You can keep the LED_COUNT at 50, it just needs to be at least the number of LEDS in the chain (including the number of NULLs).

            Make sure that the airports file doesn’t have any blank lines.
            It should only have either airports or NULL.

            If you manually run ./ do you see an error message?

          3. Philip Rueker Post author

            Yes that’s the right pin and making sure to create common ground from the external power supply and the raspberry which you appear to also have.

            So I would just check that there’s no shorts in any of the connections.

  97. Roger Sykora

    Wow! What a great project. My son is a pilot and wanted a metar map, I thought it was a good idea, but, needed some practice before I made his. So I did, made 1 for me(37 leds) then 1 for him(102 leds). Both maps work great, I did both maps with the airport display with the Arduino card… It is a nice touch….
    I would like to add to the data displayed on the Arduino the IP Address of the Pi Zero, if I have the address I can connect to the Pi Zero with VNC without connecting a monitor, if I have previously have the wifi data loaded.
    Maybe there is an easier way to get the ipaddress of the PI Zero, if so, please let me know.
    Thank You for sharing your Project!! I Love IT!

    1. Philip Rueker Post author

      That’s awesome 🙂

      If you connect to your router web interface, most will list the name of devices connected to it, so you can find the raspberry pi listed there, that’s usually how I find the IP address.

      1. Roger Sykora

        Thanks for the speedy reply!!
        I have no problem with my map, but, for my son who may move it from home to work to ??.
        If the IP Address could be displayed it could be seen, he could easily connect.
        I guess this may be a security concern… The other thing is that he may not be as willing to make changes as I am.
        Just FYI, he wanted to have a larger Pilot map for the Metar Map so it was made from a picture of 8 maps, both sides of 4 maps, from Omaha to Lake Michigan & Superior..
        Ended out being quite a project

  98. Yaofu Zhou

    I have noticed that, although its category changes from time to time, my KTTS has never stopped lightning – does this very special runway have something special about its weather broadcast (not observed on ForeFlight)?

    I am just sharing what I am getting, with no intention to ask any debugging from you 🙂


    1. Philip Rueker Post author


      Thanks for letting me know, this was a small bug in the code that I didn’t foresee. Basically for lightning I have to scan the raw METAR text and I didn’t foresee that an airport identifier could have LTG or TS in it (like KTTS does), so that’s why it reported lightning. I fixed it now to start scanning the text after the identifier to fix it.

      I just updated the script to only start scanning the text for lightning after the airport identifier.

  99. Dominic MInella

    Good Morning Sir,

    I am able to operate my lights during the test however unable to light anything when running the program.I am not sure what I have done wrong.

    pi@raspberrypi:~ $ sudo python3
    Running at 14/08/2021 13:41
    Wind animation:False
    Lightning animation:False
    Daytime Dimming:False
    External Display:False
    Setting LED 0 for KRID to VFR (255, 0, 0)
    Setting LED 1 for KOXD to None (0, 0, 0)
    Setting LED 2 for KI67 to VFR (255, 0, 0)
    Setting LED 3 for KPVT to None (0, 0, 0)
    Setting LED 4 for KLUK to VFR (255, 0, 0)
    Setting LED 5 for KI69 to MVFR (0, 0, 255)
    Setting LED 7 for KHAO to VFR (255, 0, 0)
    Setting LED 8 for KMWO to VFR (255, 0, 0)
    Setting LED 9 for KI68 to VFR (255, 0, 0)
    Setting LED 10 for KI19 to VFR (255, 0, 0)
    Setting LED 11 for KFFO to VFR (255, 0, 0)
    Setting LED 12 for KDAY to VFR (255, 0, 0)
    Setting LED 13 for KSGH to VFR (255, 0, 0)
    Setting LED 14 for KI74 to VFR (255, 0, 0)
    Setting LED 15 for KUYF to VFR (255, 0, 0)
    Setting LED 16 for KPVT to None (0, 0, 0)
    Setting LED 17 for KOSU to VFR (255, 0, 0)
    Setting LED 18 for KTZR to VFR (255, 0, 0)
    Setting LED 19 for KLCK to VFR (255, 0, 0)
    Setting LED 20 for KCMH to VFR (255, 0, 0)
    Setting LED 21 for KLHQ to VFR (255, 0, 0)
    Setting LED 22 for KVTA to VFR (255, 0, 0)
    Setting LED 24 for KCCV to None (0, 0, 0)
    Setting LED 27 for KPKB to LIFR (0, 125, 125)
    Setting LED 31 for KCRW to VFR (255, 0, 0)
    Setting LED 35 for K3I2 to IFR (0, 255, 0)
    Setting LED 37 for KUNI to MVFR (0, 0, 255)
    Setting LED 39 for KI43 to None (0, 0, 0)
    Setting LED 40 for KPMH to VFR (255, 0, 0)
    Setting LED 41 for KDWU to VFR (255, 0, 0)
    Setting LED 42 for KHTW to None (0, 0, 0)
    Setting LED 45 for KSYM to IFR (0, 255, 0)
    Setting LED 46 for KFGX to VFR (255, 0, 0)
    Setting LED 48 for KIOB to VFR (255, 0, 0)
    Setting LED 50 for KLEX to VFR (255, 0, 0)
    Traceback (most recent call last):
    File “”, line 255, in
    pixels[i] = color
    File “/usr/local/lib/python3.7/dist-packages/”, line 300, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.7/dist-packages/”, line 266, in _set_item
    raise IndexError

    1. Philip Rueker Post author

      You got an IndexError so it looks like you’re trying to use more LEDs than you initialized.
      Increase the LED_COUNT variable to be greater than or equal to the actual amount of LEDs you’re using.

    2. Dominic MInella

      Ok I accomplished the lights task now having an issue with the mini display.

      setting up external display
      Traceback (most recent call last):
      File “/usr/local/lib/python3.7/dist-packages/adafruit_bus_device/”, line 154, in __probe_for_device
      self.i2c.writeto(self.device_address, b””)
      File “/usr/local/lib/python3.7/dist-packages/”, line 159, in writeto
      return self._i2c.writeto(address, buffer, stop=stop)
      File “/usr/local/lib/python3.7/dist-packages/adafruit_blinka/microcontroller/generic_linux/”, line 49, in writeto
      self._i2c_bus.write_bytes(address, buffer[start:end])
      File “/usr/local/lib/python3.7/dist-packages/Adafruit_PureIO/”, line 314, in write_bytes
      OSError: [Errno 121] Remote I/O error

      During handling of the above exception, another exception occurred:

      Traceback (most recent call last):
      File “/usr/local/lib/python3.7/dist-packages/adafruit_bus_device/”, line 160, in __probe_for_device
      self.i2c.readfrom_into(self.device_address, result)
      File “/usr/local/lib/python3.7/dist-packages/”, line 149, in readfrom_into
      return self._i2c.readfrom_into(address, buffer, stop=stop)
      File “/usr/local/lib/python3.7/dist-packages/adafruit_blinka/microcontroller/generic_linux/”, line 56, in readfrom_into
      readin = self._i2c_bus.read_bytes(address, end – start)
      File “/usr/local/lib/python3.7/dist-packages/Adafruit_PureIO/”, line 181, in read_bytes
      OSError: [Errno 121] Remote I/O error

      During handling of the above exception, another exception occurred:

      Traceback (most recent call last):
      File “”, line 215, in
      disp = displaymetar.startDisplay()
      File “/home/pi/”, line 18, in startDisplay
      disp = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
      File “/usr/local/lib/python3.7/dist-packages/”, line 222, in __init__
      self.i2c_device = i2c_device.I2CDevice(i2c, addr)
      File “/usr/local/lib/python3.7/dist-packages/adafruit_bus_device/”, line 50, in __init__
      File “/usr/local/lib/python3.7/dist-packages/adafruit_bus_device/”, line 163, in __probe_for_device
      raise ValueError(“No I2C device at address: 0x%x” % self.device_address)
      ValueError: No I2C device at address: 0x3c

      Thank you so much for your time and review.


  100. Ryan

    Awesome project. Built mine out and have gotten most everything taken care of from comments. Couldn’t find the answer to my issue though. I have two strands of lights, connected together. When runs it only turns the first strand of lights off.. the other lights stay on.. Any ideas?

    Thank you

    1. Philip Rueker Post author

      You probably need to increase the LED count in the script.
      In line 8 there’s a number – 50, that’s the LED count, increase it to 100 if that’s how many LEDs you are using.

      I’ll update the script for the future to have a variable so it’s clearer like the script does.

      1. Ryan

        That seems to be the ticket! Running now turns them all off! Thank you ! It’s looking great on my wall

  101. Jmaldon

    Thanks alot for this! I created a simple script to facilitate set-up:
    Simply run, it will light up each LED starting with 1, and you will be able to type in the airport code. It will move onto LED 2 and so on. Top skip the LED, just press enter.

    The idea is that you set up the map with the LEDs installed, and as LEDs light up during the setup, you type in the corresponding airport code.

    This writes directly to the “airports” file.

    See below:

    Thanks again!

  102. Paul

    Is it possible to copy an SD Card from a working unit to a new SD card for a new setup?

    I’m making another as a gift and tried just copying the working sd card to a new one and it did not seem to work.

    1. Chris

      You can make an Image of the working SD card using Raspberry Pi imager. You can then use that image to write to as many other cards as you wish.

  103. Michael Kahler

    Is it possible to run this on a Raspberry Pi 3b model? I’m currently attempting this but the LED colors don’t match at all. Also, the unit will not power the LEDs directly so i’m running an external power source but it’s still not working for some reason. Any ideas?

    1. Philip Rueker Post author

      Theoretically it should work as the pin-out is the same between a Pi 3 and a mini, but I honestly never tried it, so my practical knowledge on it is limited.
      Make sure you’re connecting the right end of the LED strand to the raspberry, there’s an input and an output side (to chain more LEDs behind).

      1. Mike Kahler

        Yeah, I’ve tried it on both sides just to be sure but it’s the same result. Power will work from both ends but only one end, the female side, takes command inputs. It seems like it’s getting commands but not the correct ones. Is there maybe a line of code that would be different between the Pi Zero and the 3b? Or maybe an issue with the version I’m running? Not sure if that matters, at this point I’m just taking shots in the dark.
        My current OS:
        PRETTY_NAME=”Raspbian GNU/Linux 10 (buster)”
        NAME=”Raspbian GNU/Linux”
        VERSION=”10 (buster)”

        1. Philip Rueker Post author

          I suggest you try running the test commands I have posted here on the page further up to manually light the lights individually and see what that yields.
          If you’ve wired things correctly, then running those commands should yield the right colors assuming the LED string isn’t faulty.

  104. Mike Kahler

    I’ve run those as well and it causes the first set of 12 lights to flicker randomly. At first I though it was a bad set of lights so I ordered another pair but had the same results. Tried multiple wires. Have an external power source that is 5v 3a. The Pi itself won’t power these lights for some reason even though I’ve seen videos of others powering this exact lights directly from the Pi. Very odd behavior and i’m not sure what I’m doing wrong.

    1. Philip Rueker Post author

      Right, so then by rule of elimination, I’d wager that there’s something up with your Pi 3b.

      1. Mike Kahler

        FYI, I got it working. The issue was the full Raspbian OS installation. I fixed this by loading Raspbian LITE. Everything is working as it should now, thank you for the help. Also, the Pi is powering the LEDS as well, same pin configuration except there is an additional ground from the Pi to the LEDs completing the circuit.

  105. james geyman

    GOT IT TO WORK; HURRAY. my “blocks” were learning about PuTTY and WinSCP and RealVNC to allow me to work on the pi zero W “headless”. Also my poor soldering of the 20 pin header block gave me a bad ground, so only my first LED would light up. Just changing the hookup to another ground on the header made it work. Finally I had to write “nano crontab -e” in the terminal line to get my crontab to stick and work. I didn’t know i needed to add nano to the line. Also I needed to learn how to do the “chmod +x and +r commands” by slowly and carefully reading what Phillip describes. As a total newbie, there is alot to learn. Quite satisfying. Thanks so much PHILLIP!!

  106. Donny

    thank you for your excellent write-up and continued expansion to the project. I was wondering if there is a simple way to add custom text to the display as well as the scrolling METAR information.
    For example:
    Displays “John Doe” for 10 seconds then continues airport WX scrolling but randomly displays the specified text. I do have an additional display but not sure if two displays can be connected to my RPI 3B. I appreciate your time.
    – Donny

    1. Philip Rueker Post author

      Connecting another display gets a bit more complicated because of the Raspberry pins and having to figure out how to address multiple displays, there’s some guidance online, but you’d have to experiment around to make it work.

      Adding some code to show some random specific text every now and then to the existing display is possible though and won’t require too many changes in the code.
      Just like currently the display will rotate through different airports based on the DISPLAY_ROTATION_SPEED (the relevant section for this is in the under the # Rotate through airports METAR on external display section) and once that one has been met, it jumps to the next airport, you could add another variable set that counts for when you want to show some random text every now and then instead of the airport code and alternate between that.
      And then you’d just need to add another function to the file like “outputRandomText” and in there set what you want to display instead of the METAR information and call that method when the new variable counter is met.

  107. Mike Kahler

    When there is no data the designated LED is off. Is there a way to make it solid white?

    1. Philip Rueker Post author

      Yes, in the file, just change the color designation in the else block in the loop.
      So, around line 251 instead of:
      color = COLOR_CLEAR

      make it
      color = COLOR_LIGHTNING

      (the COLOR_LIGHTNING happens to be set to white already)

      1. Pete

        I’m not able to get this to work. For example I’m using KBUU which is and active station with data, but is not indicating the flight category. In this instance the LED is staying off. I’ve tried a few things but no luck. Not sure if it is due to it being skipped (Lines 158-160):

        if metar.find(‘flight_category’) is None:
        print(“Missing flight condition, skipping.”)

        Any suggestions?

        1. Pete

          Actually I believe I just got it working, do you see any potential problems with this solution?

          I added another color because I wanted it different from current categories: COLOR_MISSING_DATA, then changed line 233:

          color = COLOR_MISSING DATA
          conditions = conditionDict.get(airportcode, None)
          windy = False
          highWinds = False
          lightningConditions = False

          Then Line 251-252
          color = COLOR_MISSING_DATA

          1. Philip Rueker Post author

            Yep, that is the right change if you want the LED to show a color when data is missing.

  108. Pete

    Is it possible to make the leds “breathe” instead of the current fade. Basically i want to make the brightness slowly ramp up in brightness then ramp back down instead of just flashing high/low instensity.

    This is an awesome project! Thanks for all of your work!

    1. Philip Rueker Post author

      Yes it would be possible, but you’d need to extend the logic of the loop with those interim steps between low and high to achieve the fading, so it would take a bit of rewriting of the current simpler logic that just differentiates between the two states.

  109. Paul D Ross

    Just started to get this error…any idea what might be causing it?

    Traceback (most recent call last):
    File “/home/pi/”, line 248, in
    displaymetar.outputMetar(disp, stationList[displayAirportCounter], conditionDict.get(stationList[displayAirportCounter], None))
    IndexError: list index out of range

    1. Philip Rueker Post author

      This typically indicates you are trying to address more airports than specified in the maximum LED_COUNT, so you need to increase the LED_COUNT.

    2. Chris

      I has something similar and it was just extra carriage returns at the end of the Airports file. Might try that.

  110. Bob L

    I am working on this project and am having an issue with crontab. I have read all the comments and links but I must be doing something wrong. When I use the crontab -e command, a window opens and I type in the example lines. When I type cntrl+x, nothing happens…at all. Any ideas?


  111. Bob L


    I have read all of that, and everything else I can find but it appears that the is only running one time. Not sure what to do…time to walk away for a bit, I guess…

  112. Bob L

    Ok, as usually is the case, taking a break worked. Not sure what the issue was but I have been able to light the LEDs and change the airports file.

    I would like to make a change in the legend order. Basically, move the Lightning legend display to the last LED:

    Pretty sure about changing the order of the code but not sure how to go about editing it. I would assume that I can edit the code locally without any issues or consequences, correct?

    Thanks! This is a really neat project and just ordered another pi to make one as a gift…

    1. Philip Rueker Post author

      Yes,you can change the order of the LEDs in with the section starting in line 259
      # Legend
      if SHOW_LEGEND:

      You can just make the change locally in the file on the raspberry pi, just change the offsets as appropriate to reorder them as you’d like them.

  113. Adam

    Hi Philip,

    I tried to install and run this on a Raspberry Pi Zero 2 WH but I’m getting the following error:

    File “”, line 6, in
    import board
    File “/usr/local/lib/python3.7/dist-packages/”, line 210, in
    raise NotImplementedError(“Board not supported {}”.format(board_id))
    NotImplementedError: Board not supported None

    I suspect this is due to the Zero 2 not yet being added to the library?

    Hardware checks returns:
    Hardware : BCM2835
    Revision : 902120
    Serial : 00000000c2fb4c94
    Model : Raspberry Pi Zero 2 Rev 1.0

    Any thoughts? Runs absolutely fine on an original Zero WH!


    1. Philip Rueker Post author

      It looks like they recently added support for the pi zero 2 to the circuitpython library, but possible when you installed the library it didn’t pull the latest version of the board library.

      You can try to follow the steps mentioned here to pull the latest and see if that resolves it?
      If there is issues, I suggest to post them directly to that github as they may have to update the automatic script support so this won’t happen in the future.

      1. Adam


        sudo python3 -m pip install –upgrade –force-reinstall adafruit-blinka Adafruit-PlatformDetect

        That fixed it!

        Thanks so much for the quick reply, will be buying you another coffee!

  114. James Geyman

    Super cool project. On my 9th metar led map for our local EAA. Using larger ssd1305 Oled displays given my aging eyesight. Thanks again Phillip!

  115. Ty B

    Hi all. I fear this is the first of many sub-amatuer level questions. I know nothing about coding but am excited to learn! I want to power up the lights to test everything, but I’m worried I need the power adapter because it’s the full string of 50 bulbs. Would changing the brightness to 10% be a reasonable workaround to this? Or would I need to test half and null half…then swap and test the other half? Ideally, I do not want the added mess of the 5V power adapter if I don’t absolutely have to incorporate it into the design. Thank you.

    1. Philip Rueker Post author

      Just for some testing, running all 50 bulbs should be fine, it was when I tested it. Just lower the brightness if you’re seeing issues, which directly correlates to less power used.

  116. John Housley

    I used:
    SCP C:\METAR\airports.txt pi@ to transfer the 5 files to the SD card while in the Pi
    and the system replied:
    1 file(s) copied
    but when I typed “ls” the system showed no files. Same result for the other 4 files. Any help appreciated.

    1. Philip Rueker Post author

      Make sure you are copying them into the correct default folder (/home/pi)

      I typically use the tool WinSCP, which has a graphical user interface and it’s simple to see if your files are in the right folder or not.

      1. John Housley

        Thank you. I was using another person’s notes (which were inaccurate) and found a similar correction on a Raspberry Pi forum. New command:
        SCP C:\METAR\airports.txt pi@
        worked ok and ls showed the files.
        As part of the troubleshooting, I loaded the full OS (versus lite). Will that be OK, or should I revert to the lite 32 bit?

        Thanks for the fast reply and interesting project!

        1. John Housley

          P.S. Apparently the crucial error I made in the initial copy attempt was omitting the “:” after the pi IP address. Just leaving a lesson learned trail for others that follow…

  117. John Housley

    Sorry to bother you again…I have tried changing the color for “Clear” in Configuration:
    COLOR_CLEAR = (0,0,0) # Clear
    to various other settings (for example)
    COLOR_CLEAR = (255,255,255) # Clear
    COLOR_CLEAR = (50,75,100) # Clear
    and with each change, the program fails to run at all. When I change back to (0,0,0), it works fine. Is there another change I need to make to change the color assigned to “Clear”?
    Thank you.

      1. John Housley

        It is consistent. Changing any color causes the program to not execute. I tried changing VFR (green) to white and again the program did not run. Changed it back to green and now it works again. Puzzling. I checked the colors on all lights before installing (including white) and they worked fine, so it is not the LEDs.

  118. Jarrod Rizzo

    Hi Philip! Awesome project, built one and I love it!

    Couple of questions-
    1. Lightning – how would I go about assigning a more “lightning” look to the flashes? I.e. have the lights flash a couple times and not all at the same time.
    2.Could you give some pointers on how to wire up a couple buttons to control brightness?

    1. Philip Rueker Post author

      1) You can change the BLINK_SPEED variable to something faster, so if you changed it to 0.5 it would flash every half second instead of the current default of once persecond. They will still flash all together, but it will be faster/flashier.
      2) There are very good and easy to follow guides available on adafruit, this one here – – includes buttons, so you could follow it with respect to the button parts and modify the script accordingly to listen for your button clicks during the loop and change the LED_BRIGHTNESS_DIM variable when the button is pressed.

  119. Kyle Lacey

    Running at 27/03/2022 23:18
    Wind animation:True
    Lightning animation:True
    Daytime Dimming:False
    External Display:True
    Missing flight condition, skipping.
    Missing flight condition, skipping.
    Missing flight condition, skipping.
    Missing flight condition, skipping.
    setting up external display
    Setting LED 0 for KBLM to VFR (255, 0, 0)
    Setting LED 1 for KNEL to None (0, 0, 0)
    Setting LED 2 for KWRI to VFR (255, 0, 0)
    Setting LED 3 for KTTN to VFR (255, 0, 0)
    Setting LED 4 for KSMQ to VFR (255, 0, 0)
    Setting LED 5 for KMMU to VFR (255, 0, 0)
    Setting LED 6 for KCDW to VFR (255, 0, 0)
    Setting LED 7 for KEWR to VFR (255, 0, 0)
    Setting LED 8 for KTEB to VFR (255, 0, 0)
    Setting LED 9 for KLGA to VFR (255, 0, 0)
    Setting LED 10 for KJFK to VFR (255, 0, 0)
    Setting LED 11 for KFRG to VFR (255, 0, 0)
    Setting LED 12 for KISP to VFR (255, 0, 0)
    Setting LED 13 for KHWV to VFR (255, 0, 0)
    Setting LED 14 for KFOK to VFR (255, 0, 0)
    Setting LED 15 for KHTO to MVFR (0, 0, 255)
    Setting LED 16 for KMTP to None (0, 0, 0)
    Setting LED 17 for KBID to VFR (255, 0, 0)
    Setting LED 18 for KWST to VFR (255, 0, 0)
    Setting LED 19 for KGON to VFR (255, 0, 0)
    Setting LED 21 for KIJD to VFR (255, 0, 0)
    Setting LED 22 for KHFD to VFR (255, 0, 0)
    Setting LED 23 for KMMK to VFR (255, 0, 0)
    Setting LED 24 for KHVN to VFR (255, 0, 0)
    Setting LED 25 for KBDR to VFR (255, 0, 0)
    Setting LED 26 for KOXC to MVFR (0, 0, 255)
    Setting LED 27 for KDXR to VFR (255, 0, 0)
    Setting LED 29 for KHPN to None (0, 0, 0)
    Setting LED 31 for KPOU to VFR (255, 0, 0)
    Setting LED 32 for KSWF to VFR (255, 0, 0)
    Setting LED 33 for KMGJ to VFR (255, 0, 0)
    Setting LED 35 for KMSV to MVFR (0, 0, 255)
    Setting LED 38 for KFWN to VFR (255, 0, 0)
    Setting LED 39 for K12N to None (0, 0, 0)
    Can’t open /dev/mem: Permission denied
    Traceback (most recent call last):
    File “/home/pi/”, line 272, in
    File “/usr/local/lib/python3.7/dist-packages/”, line 211, in show
    return self._transmit(self._post_brightness_buffer)
    File “/usr/local/lib/python3.7/dist-packages/”, line 167, in _transmit
    neopixel_write(, buffer)
    File “/usr/local/lib/python3.7/dist-packages/”, line 25, in neopixel_write
    return _neopixel.neopixel_write(gpio, buf)
    File “/usr/local/lib/python3.7/dist-packages/adafruit_blinka/microcontroller/bcm283x/”, line 76, in neopixel_write
    “NeoPixel support requires running with sudo, please try again!”
    RuntimeError: NeoPixel support requires running with sudo, please try again!

    any idea what i need to do to fix these errors

    1. Philip Rueker Post author

      It looks like you are running the script directly without super-user permissions (the sudo in the error message).

      It’s best if you run the script as that will automatically run the script correctly with sudo permissions.

  120. Kyle lacey

    I tried a new light strand and it works but I am still getting those errors at the end. .
    this is a great project.

    1. phil benyo

      just looked at this and your app integration is a cool upgrade- going to have to take a deeper look at this. I typically make these maps now in the winter when I am bored… have made about 12 of them so far, smaller, bigger, more lights, less lights- but app integration with phone would be a great challenge!

  121. CJ

    Hey Philip!
    Amazing project! Quick question though. Would I be able to use a 3.5-inch XPT2046 screen to display METAR information through the I’m pretty new to python and don’t have a lot of experience with it yet. Thanks Man!

    1. Philip Rueker Post author

      You would have to check which connections it is using, at a quick glance, I believe it might block the connections needed for the LED string.
      But you can probably find a compatible display if you look through the library at where they have many displays with guides on using them with Raspberry Pi.
      Ideally it will use the same simple connections as the one I’m using in which case you will only have to do small modifications to the code for the bigger screen.

    1. Philip Rueker Post author

      Yes, in principle the code should run fine on a bigger Raspberry Pi as well, it will just be costlier to buy than running it on the smaller Raspberry pi zero.

  122. Evan

    first off, thank you very much for putting this together. It is both fun to work on and I am learning a ton. One thing I am stuck on if you or anyone see this…

    When I began manually testing I was getting an failure when trying to ‘import board’ as it said that module did not exist or could not be found (something to that effect). I then went to this page and entered the first command, ran it, and then entered the second command and ran it (sudo python3 -m pip install –force-reinstall adafruit-blinka) as it seemed to try to force reinstall

    Now when I try to run the manual test (sudo python3 I get this

    Traceback (most recent call last):
    File “/home/pi/”, line 6, in
    import neopixel
    File “/usr/local/lib/python3.9/dist-packages/”, line 20, in
    import adafruit_pixelbuf
    ModuleNotFoundError: No module named ‘adafruit_pixelbuf’

    So I seem to be stuck on the manual testing step. Any guidance/thoughts would be greatly appreciated!

    Edit: I got the code to run, but my experience right now is when I plug in the strand, it gives only one bright blue LED initially, and when I run basically any command, it greatly dims the one LED. I cant get all the lights to light up, and I have tried multiple strands so I don’t think it is that issue or a power issue (using the strands suggested in this thread).

    Could this simply be a soldering issue? or does this sound more like a code issue?

    1. Philip Rueker Post author

      Did you also try the manual testing commands (which just light up all lights with one color)?

      Typically most issues with lights not quite working like you’re describing, it usually is either a soldering or wiring issue.

      1. Evan

        Hi Philip – yes, I ran the manual tests but could not get any different behavior. I tried 2 strands of lights, and I also attempted to redo some of the soldering, but it is still acting the same. I have ordered a second Pi with presoldered heads, thinking I have perhaps damaged the board itself while soldering. I’ll update results here when it arrives in a week. Thank you!

        1. Evan

          So I tried a new pi that was presoldered, but the behavior seems to still be the same.

          One thing that is odd to me – when I wire it in, IMMEDIATELY when I turn on the pi, the first light lights up blue (and only the first light). That seems odd – is that typical/expected behavior? If not, I suspect it might be a clue to the issue.

          1. Philip Rueker Post author

            No, just turning on the pi should not illuminate any of the LEDs, so that may mean you’re not connecting the right nda to the right contacts on the pi.
            Only once you initiate the LEDs with the script should they turn on.

      1. Evan

        Hmm thanks for the idea but when I try that is essentially says requirements already satisfied… I have also swapped out the pi, and the lights, so seems unlikely to be either of those.

  123. Evan

    Ok so quick update – my issue was two fold (at least):
    1) the wiring on the diagram took a little extra understanding on my end to make work since the example is no a pi zero (so I copied the layout in the photos)

    2) I didn’t realize the lights have a directional input. Using the white arrow and fixing the wiring was the winning combo.


  124. Mike Scarry

    Great code thank you! Just thought I’d add a solution to a problem that I created in case it helps anyone else: my lights would work most of the time but sometimes the blinking ones would freeze. I could verify this by looking at the legend lights – the last two or three should always blink. I ran the tail command and realized that at some point i had run crontab -e with sudo and other times without. There are separate crontabs for root (sudo) and the logged-in user (without sudo). Both crontabs were trying to run and it was causing a lock on the LEDs. I commented out the lines in the root crontab and made sure that my pi was booting into my user account in raspi-config. Thanks again!

    1. Devang Patel


      I do see that my lights lock up at random times. usually I just have to turn the pi off and then back on…

      I’ll try and check this out if its causing my problem.

      1. Evan

        I have this same issue too – normally restarting fixes it (it was happening maybe 1x per month) but now it isnt getting unstuck, and even when I reflash the issue is not resolved. Any tips?

  125. Devang Patel

    Wanted to let you know that we are still out there making these. This was my first map and I made one with the whole US. Took about 265 led’s with the legend.

    Wanted to say thanks.

  126. Spencer Hamons

    Phillip, question for you sir.

    Finally have the new house built and my METAR Map is back up and running in the new place. I noticed that I had a couple of lights that weren’t working. The only thing that I seem to notice is that the airports that aren’t reporting all have a “$” in the report, representing that the sensor requires maintenance. Check out KTPL and KILE (at least as-of 2/13/2023 at 1445 Central Time). Is this by design to not display a color if the “requires maintenance” flag is present in the METAR stream, or does the $ remove reporting from the API feed? Just curious.

    1. Spencer Hamons

      Answered my own question. Took the call to data stream and realize that when a reporting station has the “$” at the end of the METAR stream, the site does not report a “Flight Category”. I checked all three of the lights on my map that weren’t working and sure enough, all three of those sites had the “$” flag, and none are reporting Flight Category when I put the airport identifier at the end of the string.

      For anyone else that may be trying to research this, try this:

      Data for Grand Canyon Airport – which as of 2/13/23 at 1640 Central was reporting properly

      …and here is the data that is returned



      KGRK 132155Z AUTO 13009KT 6SM HZ FEW120 18/10 A2989 RMK AO2 SLP119 T01760097




      Now here is Temple, TX – an airport that is reporting that the sensor requires maintenance

      And this is the data that is returned



      KTPL 132151Z AUTO 15013KT CLR 18/10 A2992 RMK AO2 SLP126 T01830100 PWINO RVRNO $




      Notice that the one for the Grand Canyon does have a Flight Category associated with the data, the one for Temple, TX does not.

  127. Justin

    Well….I am not an expert at any of this, but usually I can figure stuff out.

    I have most everything set up. I created all the .py .sh files listed on the directions. I test ran the script and it worked.

    I shut everything down and sliced and added wires to my LED’s so they would fit my map correctly.

    I booted back up, tested all the lights, red, purple, blue, and green. All the lights lit up.

    I adjusted the airports to include “Null” and all the other airports.

    I typed “sudo python3” and it did not turn any lights on what so ever. Here is the script that it gave back to me.

    ptarmigan@raspberrypi:~ $ sudo python3
    Running at 05/03/2023 15:57
    Wind animation:False
    Lightning animation:False
    Daytime Dimming:False
    External Display:False
    Missing flight condition, skipping.
    PASM:IFR:150@29G38:3SM:BR UP:2/1:29.91:False
    PAVA:IFR:160@25G30:2SM:-RA BR:1/1:29.77:False
    Setting LED 1 for PAKI to IFR (0, 255, 0)
    Setting LED 3 for PAMY to IFR (0, 255, 0)
    Setting LED 6 for PAOO to None (0, 0, 0)
    Setting LED 8 for PAVA to IFR (0, 255, 0)
    Setting LED 9 for PAHP to None (0, 0, 0)
    Setting LED 11 for PACM to None (0, 0, 0)
    Setting LED 13 for PAEM to None (0, 0, 0)
    Setting LED 16 for PAMK to None (0, 0, 0)
    Setting LED 19 for PAUN to MVFR (0, 0, 255)
    Setting LED 22 for PANV to VFR (255, 0, 0)
    Setting LED 25 for PAHC to None (0, 0, 0)
    Setting LED 28 for PANI to VFR (255, 0, 0)
    Setting LED 30 for PALG to VFR (255, 0, 0)
    Setting LED 33 for PARS to VFR (255, 0, 0)
    Setting LED 35 for PADM to MVFR (0, 0, 255)
    Setting LED 38 for PASM to IFR (0, 255, 0)
    Setting LED 39 for PAMO to None (0, 0, 0)
    Setting LED 45 for PABE to MVFR (0, 0, 255)
    Setting LED 49 for PAQH to None (0, 0, 0)
    Traceback (most recent call last):
    File “/home/ptarmigan/”, line 260, in
    pixels[i + OFFSET_LEGEND_BY] = COLOR_VFR
    File “/usr/local/lib/python3.9/dist-packages/”, line 310, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.9/dist-packages/”, line 274, in _set_item
    raise IndexError

    I don’t understand why it ran fine before but now it wont. Also, I did this whole process before and had the same problem the 2nd time I tried to run it. I completely reformatted everything and started from scratch thinking I accidentally screwed up a file somewhere.

    Any help I can get is greatly appreciated since I have a super basic knowledge of coding.



    1. Philip Rueker Post author

      You have an IndexError which means you are trying to address more LEDs than you initialized. Increase the LED_COUNT variable to be at least the amount of LEDs you are trying to address.

  128. Evan

    Hi Philip,
    thanks so much for the ongoing support, it is greatly appreciated.

    Looking to get your thoughts on troubleshooting –
    I had the full map up and running with the display, and it would work for 3-4 weeks, then freeze. Usually a reboot would fix, but sometimes not and I would have to redo the whole drive. I eventually made a backup image to speed up the process and just reflash the image once when it froze. Recently, that has stopped working – I have tried with three different SD cards, and 2 different pi zero 2’s. No matter what I do, it is stuck (meaning the lights do regularly pull for airport updates, but the weather/flashing and display do not work).

    I re did the entire thing (without flashing) and am once again getting the same result… when I try and manually run sudo python3, I get this traceback message at the end:

    Traceback (most recent call last):
    File “/home/pi/”, line 277, in
    displaymetar.outputMetar(disp, stationList[displayAirportCounter], conditionDict.get(stationList[displayAirportCounter], None))
    IndexError: list index out of range

    I know earlier you stated that the index terror typically means the pixel/light count is not high enough, but I know that mine is (I have 83 airports+legend) and it is set to 100 (plus, it used to work). I also tried bumping it to 200 then 2000 just to check if it was something wonky and got the same result with those numbers as well.

    Only thing that seems odd to me is there is some __pycache__ folder that keeps getting created – within that there is a file called displaymetar.cpython-39.pyc

    When I look at the contents of that file in notepad, there are a bunch of strange symbols with random text that looks like something is off/corrupted. But it seems to create this file every time now no matter what I do, and if I try and delete it I get a Permission Denied, Error Code: 3 message.

    Any thoughts on what could be the culprit and the fix?

    1. Evan

      figured it out. The entire flashing and display break if there is a weather reporting issue at the dispalymetar airport. I was trying to report for KVUO which used to report fine, but for whatever reason KVUO is not reporting observations at the moment. Switching to another nearby airport with a working metar report (KPDX) allows for all the flashing/weather lights to run.

  129. John Leon

    It appears that the website changed something in their API, so things are broken at the moment. Any idea for a fix?

      1. John Leon

        It looks like the URL change is not quite enough.

        Visibility can now return a non-integer value, e.g. “10”, which breaks the script. I’ve read that wind direction can now be returned as “VRB” instead of an integer. Source for that info is Can verify that the non-integer value for visibility breaks things. Haven’t looked at the VRB thing yet.

          1. John Leon

            These 3 changes seem to do the job. The URL uses a new syntax. The old syntax is described a t as being for “maximum compatibility with the previous Text Data Server”, which imples to me it could be going away at some future date.

            Change “url =” statement to:
            url = “” + “,”.join([item for item in airports if item != “NULL”])

            Change “conditionDict =” statement to: conditionDict = { “NULL”: {“flightCategory” : “”, “windDir”: “”, “windSpeed” : 0, “windGustSpeed” : 0, “windGust” : False, “lightning”: False, “tempC” : 0, “dewpointC” : 0, “vis” : “”, “altimHg” : 0, “obs” : “”, “skyConditions” : {}, “obsTime” :

            Change vis = int(round(float(metar.find(‘visibility_statute_mi’).text))) to:
            vis = metar.find(‘visibility_statute_mi’).text

  130. Spencer H

    John, tried making the three changes you suggested, but it isn’t working for me. I don’t know crap about Python, so I’m completely dependent on the cut-and-paste method of getting this to work.

    Noticed that on the change to conditionDict statement that when I pasted the suggested changes to that section, there were brackets } } at the end of that line that were removed. Could that be missing from your suggested modifications above?

        1. John Leon

          It appears his changes were incomplete. First, it uses a URL which may become deprecated. Second, it doesn’t deal with the fact that visibility can now be a string vs integer (e.g. “10+” vs “10”). I’ll see if I can make those changes out there. I had mine break when we had a nice clear day hear and visibility was returned as 10+.

          1. Wallis McMath

            I changed my url to the url in github that Philip mentioned on 10/17 and I get
            the error http.client.InvalidURL on the statement content = urllib.request.urlopen(req).read()
            when I print the url, it only has sky condition and wind information.
            The “&hoursBefor… after the join seems out of place.
            Below is the url I used:
            url = “” + “,”.join([item for item in airports if item != “NULL”]) + “&hoursBeforeNow=5&format=xml&mostRecent=true&mostRecentForEachStation=constraint”

            I would greatly appreciate any help in getting my METAR map working again.

  131. John Leon

    Did you download the updated script or just make that URL change? I’d download the new script. There were other changes to account for visibility no longer always being an integer.

  132. Wallis McMath

    I found my issue. My airports file has additional data after the airport identifier and in my url= statement, I had replaced “.join([item for item…” with “.join(item[:4] for item…” to eliminate the additional data I had in my airports file. The additional data was causing the invalid url error.
    I will now address the visibility change now that I can read the data.

    Thanks for your response.

  133. John Leon

    A new problem arose somewhere after May, 2023. With the latest Raspberry Pi OS Lite (10/10/23), all package installation commands that start with “sudo pip3 install” fail with a message that the environment is externally managed and to setup a virtual environment.

    You can override that by appending “–break-system-packages” to the command line, but I have no idea what, if anything, that breaks.

    Worse, the command “sudo pip3 install pillow” (one of the packages needed if you are using the OLED display) fails miserably, even with the “–break-system-packages” parameter. You can’t get past that.

    Any suggestions, anyone?

  134. John Leon

    Problem solved. A new install today requires a Python virtual environment. I knew nothing about those until last night when I had to refer to my son’s online tutorial on the subject at To Philip’s credit, his software continues to shine. I merely had to make small edits to the two shell scripts to invoke python from the virtual environment.

    The only thing I can’t test (till tomorrow) is the OLED display as I won’t have spares until tomorrow. All indications are that it should work fine.

    With the passage of time, several of the packages originally specified as required are already present, so the list of dependencies to install is shorter.

    If anyone wants the install document I’ve assembled, hit me up at

  135. beau debrock

    Good afternoon. Like everyone else I had to fix/update my current programming for the website update. Appreciate all the efforts in keeping this alive. I need to ask/comment on what I ran into. When I updated the PI with the steps on github the airport list provided (which is like 23 airports) the program tested fine on my setup. I then added my old airport list of 50 locations. The and other .py code had 50 already in play so I assumed I was good. However when I tested the LED’s didn’t on myset up didn’t light and I got the error below. Anybody know what is causing this? A few minutes ago I updated all the code to increase my LED count to 60 to test and it seemed to work. Just curious about the thrown code at the end. See below.

    Setting LED 47 for KGRB to VFR (255, 0, 0)
    Setting LED 48 for KATW to VFR (255, 0, 0)
    Setting LED 49 for KOSH to VFR (255, 0, 0)
    Traceback (most recent call last):
    File “/home/pi/”, line 269, in
    pixels[i + OFFSET_LEGEND_BY] = COLOR_VFR
    File “/usr/local/lib/python3.9/dist-packages/”, line 309, in __setitem__
    self._set_item(index, r, g, b, w)
    File “/usr/local/lib/python3.9/dist-packages/”, line 273, in _set_item
    raise IndexError

    Happy to share my airpot list if you want to repeat any of this. Just advise. Again appreciate the updates!

    1. Sarah Rueker Post author

      You probably didn’t have the newer legend feature in your copy of yet.
      Woth that turned on you’d need some extra LEDs at the end.
      I just updated the script to not be enabled by default – you can do the same by setting the SHOW_LEGEND to False.

      1. beau debrock

        I switched back to 50 and updated the Show_legend to false and now all works as advertised. 1000 thank you’s for getting back to me so quickly. Reading through the available updates makes me want a build another one this winter especially with the sunrise_sunset. I have a full size country vfr map that I have been wanting to work on.

        Again many thanks!

  136. james geyman

    if you use the legacy rasperry pi OS from 5/3/23, it all works as originally ordered by Phillip. No virtual environment needed. it is the debian bullseye OS and works great.

  137. Nate Osgood

    Just wanted to leave a comment thanking you for your efforts with this project! I built a map board years ago for my home airport and have since moved away. I got a call from a friend at the airport saying the board stopped working last month. I didnt know about the API change, but the code I had used before was no longer available online, so I found yours. I have no coding background, just the ability to follow directions and understand some very basic logic. Your code was super easy to use and I was able to get the board working again as well as add the wind and lightning features. I will be adding a display the next time I am home to show the closest weather report. Thanks again!

  138. Mac Johnson

    Has anyone has issues with the map freezing and SD Card corrupting?

    I’ve done everything I can think of (Restricting write access, running the map on a UPS) and eventually after a few weeks of flawless operation, the map will eventually freeze. Upon rebooting, I find that the SD card is corrupted and all my files are gone.

    1. John Leon

      Yes, it seems to happen with irritating regularity. Sometimes it seems to correspond to power glitches/surges/outages. I’ve learned to deal with it.

      1. Mac Johnson

        If anyone finds a fix, that would be great. Mine also seems to correspond with power surges (hence the UPS). That said, even the UPS doesn’t seem to protect it.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.