The information on this page describes a process I followed in 2018, and it is already quite outdated. I wouldn't recommend following these steps, but I'm keeping it up for posterity.
I will not go into the details of the new, modern approach I am using now, there are other guides that do that already.
To briefly summarize, the new setup uses SatDump's autotrack feature. It can be run with or without a GUI, which makes it a great tool for one-shot manual captures and experimentation in addition to automation. You can monitor my satdump session online at any time by visiting satdump.kevin-dee.com. My setup still uses a Raspberry Pi 3B+ which is remotely situated with the antenna and RTL-SDR USB device. The digitized signal is then served over my local wireless LAN using SpyServer to the server that hosts this website, which is running satdump as a systemd service and processing the signal into image products which are stored locally. At this time, the final products are not available online.
One great advantage of using satdump is that the software configuration made it trivial to set up reception of similar downlinks from the Russian weather satellite Meteor-M2. Although the Meteor line of satellites dates back to the 1960s, the Meteor-M series began launching around the same time as the last of the NOAA's series of polar-orbiting satellites was being launched. It's very nice to get the improved resolution and added imaging bands on the Meteor-M2 sensor with a ground station intended for the NOAA satellites by means of a simple software tweak!
Check out a full-size false-color Meteor-M2 image that I received on the afternoon of August 19th, 2024.
This page details my process for setting up @BarronWeather, an automated twitter account that uploads Earth-imaging content received by radio directly from orbiting NOAA satellites.
There is a lot of important background information that goes into understanding the systems which this project works with. If you are an expert, feel free to skip ahead, otherwise please read a little about the NOAA satellites.
The NOAA has a series of sun-synchronous weather satellites, of which there are currently 3 operational (at the time I am writing this). They are NOAA-15, -18, and -19, and you can check their current operational status at the NOAA Office of Satellite Product Operations website.
These satellites have an imager on board known as the Advanced Very High Resolution Radiometer (AVHRR). The AVHRR continually scans the Earth below the satellite, and it sends data back to the NOAA by a variety of protocols. The Automatic Picture Transmission protocol (APT) is of interest to us. This protocol has been used for decades on a number of NOAA and international weather satellites. With the right equipment, while the satellite is overhead, the APT transmission can be received and interpreted into an image.
I won't detail the antenna process too much because there are many great guides already out there, but I still have some resources to share, and I can describe my antenna.
To receive the signal, an antenna suited for the signal must be used. Since the signal is right-hand circular polarized (RHCP), an antenna with right-handedness should be used as well. The best choice remains to use a quadrifilar helix (QFH) antenna. If you have access to a large enough laser cutter and some half-inch plywood, you are welcome to download my files for a QFH antenna.
If you're looking to create a more permanent setup like mine, I recommend constructing the mast out of PVC pipe and making the antenna elements out of copper refrigeration coil to maximize stiffness.
I'm going to go into the gory details of setting up a Raspberry Pi for those who have never used one before. If you're experienced with Pi, skip to step 1b. This project was my introduction to Raspberry Pi and Linux, so I remember how frustrating it can be at times. That being said, I think learning to use these types of systems is well worth it.
The Raspberry Pi is a single-board computer (SBC) designed for use with the Raspberry Pi OS (aka Raspbian) which is based on Debian Linux. At the time of writing this, the Raspberry Pi 4 is the most current version, but I would recommend using the 3B+ version for this project, and using the Raspbian Stretch OS. To get started with your Pi, you will need a 5V 2.5A microUSB power supply, a microSD card (16-32 GB preferrably), and a computer capable of reading/writing to the microSD card. First-time setup is much recommended with a keyboard, mouse, and HDMI monitor for temporary use with the Pi, but it can be done "headless" if you know what you're doing.
The microSD card is analogous to the hard drive or SSD of a desktop computer, and it needs to be loaded with the operating system for the Pi to use. Download the OS of your choice to your computer from the Raspberry Pi Foundation index of images. I recommend the 2019-04-09 version, as it is the most recent version of Raspbian Stretch. To install the image onto the microSD card, I recommend using Balena Etcher. Usage is straightforward, simply select the image (typically a .zip), specify the target location (the microSD card), and go. Once the flashing process is done, eject the card and put it in the Pi before powering it up.
Once you have loaded up the Pi for the first time, complete any prompts as they appear. These are related to localization, WiFi setup, and other important things. It's also good practice to change your password from the default. Either in a prompt, or by running sudo raspi-config
and navigating to time zone selection under localization options. Set the time zone to UTC-0 (GMT). This is important for the automated processes coming later. Connect your Pi to the internet however you see fit. I also recommend enabling SSH so you can access the Pi later without needing the keyboard, mouse, and monitor.
This project utilizes a bundle of software which you can install with the following lines.
sudo apt-get update
sudo apt-get upgrade
sudo reboot
sudo apt-get install libusb-1.0 cmake at sox predict python-setuptools git libxft2 python3-pip
sudo pip3 install twython
It's wise to blacklist certain things that may interfere with SDR from loading in the kernel.
sudo nano /etc/modprobe.d/bl.conf
Add in the following entries:
blacklist dvb_usb_rtl28xxu
blacklist rtl2830
blacklist rtl2832
Some of the remaining, more specialized software is less simple to install. First is wxtoimg
.
wget https://wxtoimgrestored.xyz/beta/wxtoimg-armhf-2.11.2-beta.deb
sudo dpkg -i wxtoimg-armhf-2.11.2-beta.deb
Next is rtl-sdr.
git clone https://github.com/keenerd/rtl-sdr.git
cd rtl-sdr
mkdir build
cd build
cmake ../ -DINSTALL_UDEV_RULES=ON
make
sudo make install
sudo ldconfig
cd
sudo cp ./rtl-sdr/rtl-sdr.rules /etc/udev/rules.d/
If you have your RTL-SDR USB device, now would be a good time to plug it in, reboot again, and run sudo rtl_test
. It should return some information including the device name and sample rate.
Run predict
once to set up your ground station location. You can find your latitude and longitude on google maps.
Run wxtoimg
once to accept the terms.
Set up your ground station location in wxtoimg by editing the following file: sudo nano ~/.wxtoimgrc
Add the lines with your location, using negative values for south and west.
Latitude: XX.XXXX
Longitude: XX.XXXX
Altitude: XX
With all the prerequisite software installed and configured, the only thing left to do is prepare the bash and python scripts that automate scheduling satellite passes, recording and processing them, and sharing the results.
Start by preparing the directories which will store the scripts and products
mkdir weather
cd weather
mkdir scripts
mkdir products
cd products
mkdir audios
mkdir images
cd ~/weather/scripts
Now we will write the scripts. Most are done in bash, except the twitter script, which uses python.
The first script should be created in ~/weather/scripts
by sudo nano receive_and_process_satellite.sh
. This one is responsible for the actual reception of the satellite signal, and processing it into image files. It also calls the python script to tweet the image products.
#!/bin/bash
# $1 = Satellite Name
# $2 = Frequency
# $3 = FileName base
# $4 = TLE File
# $5 = EPOC start time
# $6 = Time to capture
sudo timeout $6 rtl_fm -f ${2}M -s 60k -g 45 -p 55 -E wav -E deemp -F 9 - | sox -t wav - ~/weather/products/audios/$3.wav rate 11025
PassStart=`expr $5 + 90`
if [ -e $3.wav ]
then
/usr/local/bin/wxmap -T "${1}" -H $4 -p 0 -l 0 -o $PassStart ~/weather/products/images/${3}-map.png
/usr/local/bin/wxtoimg -m ~/weather/products/images/${3}-map.png -e ZA ~/weather/products/audios/$3.wav ~/weather/products/images/$3.png
# REMOVE THE NEXT 2 (TWO) LINES TO DISABLE TWITTER FUNCTIONALITY
sleep 60
~/weather/scripts/weathertweeter.py ~/weather/products/images/${3}.png ${3}
fi
Create this script with sudo nano schedule_satellite.sh
. This script schedules the pass of an individual satellite into you Pi's job queue.
#!/bin/bash
PREDICTION_START=`/usr/bin/predict -t /home/pi/weather/scripts/weather.tle -p "${1}" | head -1`
PREDICTION_END=`/usr/bin/predict -t /home/pi/weather/scripts/weather.tle -p "${1}" | tail -1`
var2=`echo $PREDICTION_END | cut -d " " -f 1`
MAXELEV=`/usr/bin/predict -t /home/pi/weather/scripts/weather.tle -p "${1}" | awk -v max=0 '{if($5>max){max=$5}}END{print max}'`
while [ `date --date="TZ=\"UTC\" @${var2}" +%D` == `date +%D` ]; do
START_TIME=`echo $PREDICTION_START | cut -d " " -f 3-4`
var1=`echo $PREDICTION_START | cut -d " " -f 1`
var3=`echo $START_TIME | cut -d " " -f 2 | cut -d ":" -f 3`
TIMER=`expr $var2 - $var1 + $var3`
OUTDATE=`date --date="TZ=\"UTC\" $START_TIME" +%Y%m%d-%H%M%S`
if [ $MAXELEV -gt 19 ]
then
echo ${1//" "}${OUTDATE} $MAXELEV
echo "/home/pi/weather/scripts/receive_and_process_satellite.sh \"${1}\" $2 ${1//" "}${OUTDATE} /home/pi/weather/scripts/weather.tle $var1 $TIMER" | at `date --date="TZ=\"UTC\" $START_TIME" +"%H:%M %D"`
fi
nextpredict=`expr $var2 + 60`
PREDICTION_START=`/usr/bin/predict -t /home/pi/weather/scripts/weather.tle -p "${1}" $nextpredict | head -1`
PREDICTION_END=`/usr/bin/predict -t /home/pi/weather/scripts/weather.tle -p "${1}" $nextpredict | tail -1`
MAXELEV=`/usr/bin/predict -t /home/pi/weather/scripts/weather.tle -p "${1}" $nextpredict | awk -v max=0 '{if($5>max){max=$5}}END{print max}'`
var2=`echo $PREDICTION_END | cut -d " " -f 1`
done
Create this script with sudo nano schedule_all.sh
. This script will be run by cron once daily to schedule the satellite passes for that day.
#!/bin/bash
# Update Satellite Information
wget -qr https://www.celestrak.com/NORAD/elements/weather.txt -O /home/pi/weather/scripts/weather.txt
grep "NOAA 15" /home/pi/weather/scripts/weather.txt -A 2 > /home/pi/weather/scripts/weather.tle
grep "NOAA 18" /home/pi/weather/scripts/weather.txt -A 2 >> /home/pi/weather/scripts/weather.tle
grep "NOAA 19" /home/pi/weather/scripts/weather.txt -A 2 >> /home/pi/weather/scripts/weather.tle
#Remove all AT jobs
for i in `atq | awk '{print $1}'`;do atrm $i;done
#Schedule Satellite Passes:
/home/pi/weather/scripts/schedule_satellite.sh "NOAA 19" 137.1000
/home/pi/weather/scripts/schedule_satellite.sh "NOAA 18" 137.9125
/home/pi/weather/scripts/schedule_satellite.sh "NOAA 15" 137.6200
Schedule this to run once daily by adding the following line to your cron with crontab -e
. If you don't want to wait for midnight UTC0 to test things, execute the script yourself. After an execution, you should be able to run atq
to see the list of queued jobs corresponding to a satellite pass.
1 0 * * * sh ~/weather/scripts/schedule_all.sh
This script is entirely optional. It is called by receive_and_process_satellite.sh
to tweet final image products to a linked twitter account. Create it with sudo nano weathertweeter.py
.You must replace the ***YOUR_KEY***
parts of the file with your consumer/access keys and secrets, as obtained from the twitter API.
#!/usr/bin/env python3
import sys
from twython import Twython
CONSUMER_KEY = '***YOUR_KEY***'
CONSUMER_SECRET ='***YOUR_KEY***'
ACCESS_KEY = '***YOUR_KEY***'
ACCESS_SECRET = '***YOUR_KEY***'
api = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET)
photo = open(sys.argv[1], 'rb')
response = api.upload_media(media=photo)
api.update_status(status=sys.argv[2], media_ids=[response['media_id']])
Make each of the scripts executable with sudo chmod +x scriptname
.