{"id":2461,"date":"2019-11-08T08:12:56","date_gmt":"2019-11-08T14:12:56","guid":{"rendered":"https:\/\/nootropicdesign.com\/projectlab\/?p=2461"},"modified":"2025-08-21T06:33:17","modified_gmt":"2025-08-21T11:33:17","slug":"weather-satellite-ground-station","status":"publish","type":"post","link":"https:\/\/nootropicdesign.com\/projectlab\/2019\/11\/08\/weather-satellite-ground-station\/","title":{"rendered":"Automated Weather Satellite Ground Station"},"content":{"rendered":"<p>UPDATE: All NOAA APT satellites (NOAA-18, NOAA-19, NOAA-15) were decommissioned in 2025. NOAA-15 was decommissioned and stopped transmitting imagery at 15:28 UTC on August 19. <a href=\"https:\/\/nootropicdesign.com\/wx\/\" rel=\"noopener noreferrer\" target=\"_blank\">You can see my very last received images on my site.<\/a><\/p>\n<p>Project source code at GitHub: <a href=\"https:\/\/github.com\/nootropicdesign\/wx-ground-station\" rel=\"noopener noreferrer\" target=\"_blank\">wx-ground-station<\/a><\/p>\n<p><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station_images.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station_images.jpg\" alt=\"\" width=\"1002\" height=\"871\" class=\"alignleft size-full wp-image-2527\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station_images.jpg 1002w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station_images-980x852.jpg 980w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station_images-480x417.jpg 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1002px, 100vw\" \/><\/a><br \/>\n<br clear=\"all\"\/><\/p>\n<p>This project will show you how to create a fully automated ground station that will receive and decode NOAA weather satellite images and upload them to your own website served from an Amazon AWS S3 bucket. With this project you don&#8217;t need your own server or have to run your own website infrastructure. <a href=\"https:\/\/nootropicdesign.com\/wx\/\" rel=\"noopener noreferrer\" target=\"_blank\">Have a look at my AWS site that is updated automatically all day long<\/a>. <\/p>\n<p>Oh, you want a site like this, too? Full of images you decoded from space? Then let&#8217;s get started, my friend.<\/p>\n<p>Here&#8217;s what you&#8217;ll need:<\/p>\n<ul>\n<li>a modern Raspberry Pi (version 3 or 4), probably with Wi-Fi since it may be deployed outdoors. I used a RPi 3 model B. I have heard that a RPi Zero may not be powerful enough.<\/li>\n<li>an RTL-SDR dongle. I recommend the <a href=\"https:\/\/www.rtl-sdr.com\/buy-rtl-sdr-dvb-t-dongles\/\" rel=\"noopener noreferrer\" target=\"_blank\">RTL-SDR V3 dongle<\/a> from the excellent <a href=\"https:\/\/www.rtl-sdr.com\" rel=\"noopener noreferrer\" target=\"_blank\">RTL-SDR.COM blog<\/a>.<\/li>\n<li>an AWS account for hosting images and web content in an <a href=\"https:\/\/aws.amazon.com\/s3\/\" rel=\"noopener noreferrer\" target=\"_blank\">Amazon S3<\/a> bucket. You can sign up for the free tier for a year, and it&#8217;s still cheap after that.<\/li>\n<li>a simple dipole antenna with elements 21 inches (53.4 cm) long and that can be adjusted to have a 120 degree angle between the elements. <a href=\"http:\/\/lna4all.blogspot.com\/2017\/02\/diy-137-mhz-wx-sat-v-dipole-antenna.html\" rel=\"noopener noreferrer\" target=\"_blank\">Here&#8217;s a great article on design<\/a> or you can just buy <a href=\"https:\/\/www.rtl-sdr.com\/product\/rtl-sdr-blog-multipurpose-dipole-antenna-kit\/\" rel=\"noopener noreferrer\" target=\"_blank\">this dipole kit<\/a>, also from the RTL-SDR.COM blog.<\/li>\n<li>coaxial cable to go from your antenna to Raspberry Pi + RTL-SDR dongle. The dipole antenna kit comes with 3m of RG174 coax, but I used 10 feet of RG58 coax.<\/li>\n<\/ul>\n<p>This is a very long article with lots of steps, so take your time &#8212; I won&#8217;t be able to help everyone debug all their issues. I won&#8217;t go into the details of using a Raspberry Pi for the first time &#8212; this project assumes you know your way around the Pi and are comfortable with installing software on it. If you have never used AWS before, I suggest you set up an account and get familiar with what S3 is.<\/p>\n<p><\/p>\n<h4>Weather Satellites and RTL-SDR<\/h4>\n<p>This probably isn&#8217;t the first you&#8217;ve read about using a software defined radio (SDR) to receive weather satellite images. This type of project has been documented before. Sometimes the emphasis is on software defined radio hardware and techniques, sometimes it&#8217;s about antenna design, or maybe the article is written by a real weather enthusiast who always use the abbreviation &#8220;wx&#8221; for weather. I&#8217;m not an expert in any of these areas, but the idea of receiving images directly from weather satellites as they fly overhead has intrigued me for many years. This has all gotten a lot easier with RTL-SDR dongles, more powerful Raspberry Pi computers and simpler antenna designs that get the job done. I gave this project a try recently using <a href=\"https:\/\/www.instructables.com\/id\/Raspberry-Pi-NOAA-Weather-Satellite-Receiver\/\" rel=\"noopener noreferrer\" target=\"_blank\">this well-written Instructables<\/a> article, a totally hacked-together antenna I made, and a very old rtl-sdr dongle:<\/p>\n<p><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_wx_antenna.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_wx_antenna-1024x656.jpg\" alt=\"\" width=\"1024\" height=\"656\" class=\"alignleft size-large wp-image-2471\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_wx_antenna-1024x656.jpg 1024w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_wx_antenna-980x628.jpg 980w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_wx_antenna-480x308.jpg 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/a><br \/>\n<br clear=\"all\"\/><\/p>\n<p>and on my <em>very first attempt<\/em>, I decoded this image from NOAA19 as it passed over my area:<\/p>\n<p><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_NOAA_image.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_NOAA_image-1024x510.png\" alt=\"\" width=\"1024\" height=\"510\" class=\"alignleft size-large wp-image-2470\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_NOAA_image-1024x510.png 1024w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_NOAA_image-980x488.png 980w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/first_NOAA_image-480x239.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/a><br \/>\n<br clear=\"all\"\/><\/p>\n<p>From that moment, I was hooked. I played around with different antennas and such, but found it tedious to always copy the images from my outdoor Raspberry Pi to my computer so I could look at them. I resolved to automate the uploading of images to an S3 bucket and to improve upon the scripts from the Instructables article. This is the overall solution:<\/p>\n<p><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station-architecture.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station-architecture-1024x617.png\" alt=\"\" width=\"1024\" height=\"617\" class=\"alignleft size-large wp-image-2532\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station-architecture-1024x617.png 1024w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station-architecture-980x590.png 980w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2019\/11\/wx-ground-station-architecture-480x289.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/a><br \/>\n<br clear=\"all\"\/><\/p>\n<p><\/p>\n<h3>Amazon AWS Setup<\/h3>\n<p>Your ground station website functionality will be completely in client-side JavaScript. It will use the AWS JavaScript SDK to make API calls to S3. The scripts that run on the Raspberry Pi also use some Node.js scripts to upload to S3. There are a lot of steps to get everything set up:<\/p>\n<p><\/p>\n<h4>AWS SDK Credentials<\/h4>\n<p>The scripts that run on the Raspberry Pi use some Node.js scripts and the AWS JavaScript SDK to upload to S3. You need to get your credentials. These two articles show you how to get your credentials and store them for Node.js access:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/en_pv\/sdk-for-javascript\/v2\/developer-guide\/getting-your-credentials.html\" rel=\"noopener noreferrer\" target=\"_blank\">Getting your credentials<\/a><br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/en_pv\/sdk-for-javascript\/v2\/developer-guide\/loading-node-credentials-shared.html\" rel=\"noopener noreferrer\" target=\"_blank\">Loading Credentials in Node.js from the Shared Credentials File<\/a><\/p>\n<p>Your credentials file on the Raspberry Pi <span class=\"code\">~\/.aws\/credentials<\/span> will look like this:<\/p>\n<pre class=\"codeblock\">\r\n[default]\r\naws_access_key_id = YOUR_ACCESS_KEY_ID\r\naws_secret_access_key = YOUR_SECRET_ACCESS_KEY\r\n<\/pre>\n<p>Also set the default region where your S3 bucket will reside in <span class=\"code\">~\/.aws\/config<\/span>. For example:<\/p>\n<pre class=\"codeblock\">\r\n[default]\r\noutput = json\r\nregion = us-west-2\r\n<\/pre>\n<p><\/p>\n<h4>Create an S3 Bucket<\/h4>\n<p>Now create an S3 bucket for public website hosting. I&#8217;m using the bucket name <span class=\"code\">nootropicdesign.wx<\/span> for mine. The instructions are in this article:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/en_pv\/AmazonS3\/latest\/dev\/HostingWebsiteOnS3Setup.html\" rel=\"noopener noreferrer\" target=\"_blank\">Setting up a Static Website<\/a><\/p>\n<p>At this point you should be able to load a simple web site from your new bucket. You might want to upload a simple <span class=\"code\">index.html<\/span> file and try to load it in your browser with <span class=\"code\">http:\/\/BUCKETNAME.s3-website-REGION.amazonaws.com\/<\/span>.<\/p>\n<pre class=\"codeblock\">\r\n&lt;!doctype html&gt;\r\n&lt;html&gt;\r\n  &lt;head&gt;&lt;title&gt;S3 test&lt;\/title&gt;&lt;\/head&gt;\r\n  &lt;body&gt;Hello from S3&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p><\/p>\n<h4>Create an Identity Pool in Cognito<\/h4>\n<p>To give public users the ability to access your S3 bucket using the AWS SDK, you need to set up an identity pool and create a policy allowing them read access to your bucket. This is done using Amazon Cognito. A good guide for granting public access to your bucket is <a href=\"https:\/\/docs.aws.amazon.com\/en_pv\/sdk-for-javascript\/v2\/developer-guide\/s3-example-photos-view.html\" rel=\"noopener noreferrer\" target=\"_blank\">described in this article that shows how to serve images from an S3 bucket<\/a> (just like we are). It&#8217;s somewhat confusing to follow the steps, so take your time.<\/p>\n<p>Step 1: <a href=\"https:\/\/docs.aws.amazon.com\/en_pv\/sdk-for-javascript\/v2\/developer-guide\/getting-started-browser#getting-started-browser-create-identity-pool\" rel=\"noopener noreferrer\" target=\"_blank\">create an Amazon Cognito identity pool<\/a> called &#8220;<span class=\"code\">wx image users<\/span>&#8221; and enable access to unauthenticated identities. Be sure to select the region in the upper right of the page that matches the region where your S3 bucket was created! Make note of the role name for unauthorized users, e.g. &#8220;<span class=\"code\">Cognito_wximageusersUnauth_Role<\/span>&#8220;.<\/p>\n<p>Step 2: on the Sample Code page, select JavaScript from the Platform list. Save this code somewhere, because we need to add it to the web content later. It looks something like this:<\/p>\n<pre class=\"codeblock\">\r\n\/\/ Initialize the Amazon Cognito credentials provider\r\nAWS.config.region = 'us-west-2'; \/\/ Region\r\nAWS.config.credentials = new AWS.CognitoIdentityCredentials({\r\n  IdentityPoolId: 'us-west-2:1d02ae39-3a06-497e-b63c-799a070dd09d',\r\n});\r\n<\/pre>\n<p>Step 3: Add a Policy to the Created IAM Role. In <a href=\"https:\/\/console.aws.amazon.com\/iam\/\" rel=\"noopener noreferrer\" target=\"_blank\">IAM console<\/a>, choose <span class=\"code\">Policies<\/span>. Click <span class=\"code\">Create Policy<\/span>, then click the JSON tab and add this, substituting BUCKET_NAME with your bucket name.<\/p>\n<pre class=\"codeblock\">\r\n{\r\n   \"Version\": \"2012-10-17\",\r\n   \"Statement\": [\r\n      {\r\n         \"Effect\": \"Allow\",\r\n         \"Action\": [\r\n            \"s3:ListBucket\"\r\n         ],\r\n         \"Resource\": [\r\n            \"arn:aws:s3:::BUCKET_NAME\"\r\n         ]\r\n      }\r\n   ]\r\n}\r\n<\/pre>\n<p>Click <span class=\"code\">Review policy<\/span> and give your policy a name, like <span class=\"code\">wxImagePolicy<\/span>.<\/p>\n<p>In IAM console, click <span class=\"code\">Roles<\/span>, then choose the unauthenticated user role previously created when the identity pool was created (e.g. <span class=\"code\">Cognito_wximageusersUnauth_Role<\/span>). Click <span class=\"code\">Attach Policies<\/span>. From the <span class=\"code\">Filter policies<\/span> menu, select <span class=\"code\">Customer managed<\/span>. This will show the policy you created above. Select it and click <span class=\"code\">Attach policy<\/span>. <\/p>\n<p>Step 4. Set CORS configuration on the S3 bucket. In the S3 console for your bucket, select <span class=\"code\">Permissions<\/span>, then <span class=\"code\">CORS configuration<\/span>.<\/p>\n<pre class=\"codeblock\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\r\n&lt;CORSConfiguration xmlns=&quot;http:\/\/s3.amazonaws.com\/doc\/2006-03-01\/&quot;&gt;\r\n    &lt;CORSRule&gt;\r\n        &lt;AllowedOrigin&gt;*&lt;\/AllowedOrigin&gt;\r\n        &lt;AllowedMethod&gt;GET&lt;\/AllowedMethod&gt;\r\n        &lt;AllowedMethod&gt;HEAD&lt;\/AllowedMethod&gt;\r\n        &lt;AllowedHeader&gt;*&lt;\/AllowedHeader&gt;\r\n    &lt;\/CORSRule&gt;\r\n&lt;\/CORSConfiguration&gt;\r\n<\/pre>\n<p><\/p>\n<h3>Raspberry Pi Setup<\/h3>\n<p>Most of these instructions are from steps are from steps 2 and 3 of the <a href=\"https:\/\/www.instructables.com\/id\/Raspberry-Pi-NOAA-Weather-Satellite-Receiver\/\" rel=\"noopener noreferrer\" target=\"_blank\">Instructables<\/a> article I mentioned earlier.<\/p>\n<p><\/p>\n<h4>Install Required Packages<\/h4>\n<p>First, make sure your Raspberry Pi is up to date:<\/p>\n<pre class=\"codeblock\">\r\nsudo apt-get update\r\nsudo apt-get upgrade\r\nsudo reboot\r\n<\/pre>\n<p>Then install a set of of required packages. <\/p>\n<pre class=\"codeblock\">\r\nsudo apt-get install libusb-1.0\r\nsudo apt-get install cmake\r\nsudo apt-get install sox\r\nsudo apt-get install at\r\nsudo apt-get install predict\r\n<\/pre>\n<p>I used Node.js in some of the scripting, so if you don&#8217;t have <span class=\"code\">node<\/span> and <span class=\"code\">npm<\/span> installed, you&#8217;ll need to do that. In depth details <a href=\"https:\/\/github.com\/nodesource\/distributions\/#deb\" rel=\"noopener noreferrer\" target=\"_blank\">are here<\/a>, and I easily installed with:<\/p>\n<pre class=\"codeblock\">\r\ncurl -sL https:\/\/deb.nodesource.com\/setup_10.x | sudo -E bash -\r\nsudo apt-get install -y nodejs\r\n<\/pre>\n<p>Using your favorite editor as root (e.g. <span class=\"code\">sudo vi<\/span>), create a file <span class=\"code\">\/etc\/modprobe.d\/no-rtl.conf<\/span> and add these contents:<\/p>\n<pre class=\"codeblock\">\r\nblacklist dvb_usb_rtl28xxu\r\nblacklist rtl2832\r\nblacklist rtl2830\r\n<\/pre>\n<p><\/p>\n<h4>Build rtl-sdr<\/h4>\n<p>Even if you have rtl-sdr already built and installed, it&#8217;s important to use the version in the GitHub repo <a href=\"https:\/\/github.com\/keenerd\/rtl-sdr\" rel=\"noopener noreferrer\" target=\"_blank\">keenerd\/rtl-sdr<\/a>, as this version&#8217;s <span class=\"code\">rtl_fm<\/span> command can create the WAV file header needed to decode the data with <span class=\"code\">sox<\/span>.<\/p>\n<pre class=\"codeblock\">\r\ncd ~\r\ngit clone https:\/\/github.com\/keenerd\/rtl-sdr.git\r\ncd rtl-sdr\/\r\nmkdir build\r\ncd build\r\ncmake ..\/ -DINSTALL_UDEV_RULES=ON\r\nmake\r\nsudo make install\r\nsudo ldconfig\r\ncd ~\r\nsudo cp .\/rtl-sdr\/rtl-sdr.rules \/etc\/udev\/rules.d\/\r\nsudo reboot\r\n<\/pre>\n<p><\/p>\n<h4>Install and Configure wxtoimg<\/h4>\n<p>The program <span class=\"code\">wxtoimg<\/span> is what does the heavy lifting in this project. It decodes the audio files received by the RTL-SDR receiver and converts the data to images. The original author of wxtoimg has abandoned the project, but it is mirrored at <a href=\"https:\/\/wxtoimgrestored.xyz\/\" rel=\"noopener noreferrer\" target=\"_blank\"><span class=\"code\">wxtoimgrestored.xyz<\/span><\/a>.<\/p>\n<pre class=\"codeblock\">\r\nwget https:\/\/wxtoimgrestored.xyz\/beta\/wxtoimg-armhf-2.11.2-beta.deb\r\nsudo dpkg -i wxtoimg-armhf-2.11.2-beta.deb\r\n<\/pre>\n<p>Now run <span class=\"code\">wxtoimg<\/span> once to accept the license agreement.<\/p>\n<pre class=\"codeblock\">\r\nwxtoimg\r\n<\/pre>\n<p>Create a file <span class=\"code\">~\/.wxtoimgrc<\/span> with the location of your base station. As usual, negative latitude is southern hemisphere, and negative longitude is western hemisphere. Here&#8217;s my location in Minnesota, USA.<\/p>\n<pre class=\"codeblock\">\r\nLatitude: 45.0468\r\nLongitude: -93.4747\r\nAltitude: 315\r\n<\/pre>\n<p>The program <span class=\"code\">predict<\/span> is used by the automated scripts to predict weather satellite orbits. Run <span class=\"code\">predict<\/span> to bring up the main menu:<\/p>\n<pre class=\"codeblock\">\r\n                                      \r\n                           --== PREDICT  v2.2.3 ==--         \r\n                     Released by John A. Magliacane, KD2BD   \r\n                                    May 2006                 \r\n                                                             \r\n\r\n\r\n                            --==[ Main Menu ]==--\r\n\r\n\r\n [P]: Predict Satellite Passes          [I]: Program Information\r\n [V]: Predict Visible Passes            [G]: Edit Ground Station Information\r\n [S]: Solar Illumination Predictions    [D]: Display Satellite Orbital Data\r\n [L]: Lunar Predictions                 [U]: Update Sat Elements From File\r\n [O]: Solar Predictions                 [E]: Manually Edit Orbital Elements\r\n [T]: Single Satellite Tracking Mode    [B]: Edit Transponder Database\r\n [M]: Multi-Satellite Tracking Mode     [Q]: Exit PREDICT\r\n<\/pre>\n<p>Select option &#8216;G&#8217; from the menu to set your ground station location:<\/p>\n<pre class=\"codeblock\">\r\n\r\n                *  Ground Station Location Editing Utility  *\r\n\r\n\r\n\r\n                        Station Callsign  : KD0WUV\r\n                        Station Latitude  : 45.0468 [DegN]\r\n                        Station Longitude : 93.4747 [DegW]\r\n                        Station Altitude  : 315 [m]\r\n\r\n\r\n\r\n            Enter the callsign or identifier of your ground station\r\n<\/pre>\n<p>You can enter whatever you want for the callsign (I used my amateur radio callsign). When entering the longitude, note that positive numbers are for the western hemisphere and negative numbers are for the eastern hemisphere. This is opposite convention, so make sure you get this right or you&#8217;ll be listening when there&#8217;s no satellite overhead!<\/p>\n<p><\/p>\n<h4>Get the Automation Scripts and Configure<\/h4>\n<p>I&#8217;ve completely refactored the scripts originally posted in the Instructables article and added Node.js scripts for creating thumbnail images and uploading all images to S3. The git repo can be cloned anywhere on your Raspberry Pi. The <span class=\"code\">configure.sh<\/span> script sets the installation directory in the scripts and schedules a cron job to run the satellite pass scheduler job at midnight every night.<\/p>\n<pre class=\"codeblock\">\r\ngit clone https:\/\/github.com\/nootropicdesign\/wx-ground-station.git\r\ncd wx-ground-station\r\nsh configure.sh\r\ncd aws-s3\r\nnpm install\r\n<\/pre>\n<p>In the file <span class=\"code\">aws-s3\/upload-wx-images.js<\/span> set REGION, BUCKET, and LOCATION to the correct values. This Node.js script prepares the images for upload by creating thumbnail images, printing some metadata on the images, and creating a JSON metadata file for each image capture. The LOCATION string will be printed on the images that you capture. Here are my values just for reference.<\/p>\n<pre class=\"codeblock\">\r\nvar REGION = \"us-west-2\";\r\nvar BUCKET = \"nootropicdesign.wx\";\r\nvar LOCATION = \"nootropic design ground station, Plymouth, Minnesota, USA  45.0468, -93.4747\";\r\n<\/pre>\n<p>Also set the REGION and BUCKET correctly in the files <span class=\"code\">aws-s3\/upload-upcoming-passes.js<\/span> and <span class=\"code\">aws-s3\/remove-wx-images.js<\/span>. Plug in your own values:<\/p>\n<pre class=\"codeblock\">\r\nvar REGION = \"us-west-2\";\r\nvar BUCKET = \"nootropicdesign.wx\";\r\n<\/pre>\n<p>Now we need to make some changes to the web content. The web interface uses <a href=\"https:\/\/mapbox.com\" rel=\"noopener noreferrer\" target=\"_blank\">Mapbox<\/a> to draw the live maps of the next upcoming satellite pass. You&#8217;ll need to <a href=\"https:\/\/account.mapbox.com\/auth\/signup\/\" rel=\"noopener noreferrer\" target=\"_blank\">create an account at Mapbox<\/a> to get an access token. Their free tier lets you load 50,000 maps\/month, so you are not likely to have any real costs. When logged into Mapbox, get your account token from <a href=\"https:\/\/account.mapbox.com\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/account.mapbox.com\/<\/a>.<\/p>\n<p>Now in the file <span class=\"code\">website\/wx-ground-station.js<\/span>, set your bucket name, AWS region, AWS credentials (the Cognito identity pool info you saved above), Mapbox token, and your ground station info. Some of my values are shown here for reference.<\/p>\n<pre class=\"codeblock\">\r\nvar bucketName = 'nootropicdesign.wx';\r\nAWS.config.region = 'us-west-2'; \/\/ Region\r\nAWS.config.credentials = new AWS.CognitoIdentityCredentials({\r\n    IdentityPoolId: 'us-west-2:1d02ae39-30a6-497e-b066-795f070de089'\r\n});\r\n\r\n\/\/ Create a mapbox.com account and get access token\r\nconst MAP_BOX_ACCESS_TOKEN = 'YOUR_MAPBOX_TOKEN';\r\nconst GROUND_STATION_LAT =  45.0468;\r\nconst GROUND_STATION_LON = -93.4747;\r\nconst GROUND_STATION_NAME = 'my ground station';\r\n<\/pre>\n<p><\/p>\n<h4>Upload the Web Content to S3<\/h4>\n<p>Upload the the contents of the <span class=\"code\">website<\/span> directory to your S3 bucket using the S3 console. Since you probably edited the files on your Raspberry Pi, you might need to copy them to your computer where you are accessing AWS using a browser. Whatever the case, these files need to be uploaded to the top level of your bucket. IMPORTANT: be sure to grant public access to the files when you upload them!<\/p>\n<pre class=\"codeblock\">\r\nindex.html\r\nwx-ground-station.js\r\ntle.js\r\nlogo.png\r\n<\/pre>\n<p>Of course, you can replace <span class=\"code\">logo.png<\/span> with your own, or just remove the <span class=\"code\">&lt;img&gt;<\/span> tag from <span class=\"code\">index.html<\/span>.<\/p>\n<p><\/p>\n<h4>Test Everything Out<\/h4>\n<p>Now that everything is configured, let&#8217;s run the scheduling script to schedule recording of upcoming satellite passes. This way you can have a look today instead of waiting until they get scheduled at midnight. This step will also upload a JSON file with the upcoming passes info to your website.<\/p>\n<pre class=\"codeblock\">\r\ncd wx-ground-station\r\n.\/schedule_all.sh\r\n<\/pre>\n<p>You can now visit your AWS S3 website endpoint at <\/p>\n<pre class=\"codeblock\">\r\nhttp:\/\/BUCKETNAME.s3-website-REGION.amazonaws.com\/\r\n<\/pre>\n<p>Once again, mine is here: <a href=\"http:\/\/nootropicdesign.wx.s3-website-us-west-2.amazonaws.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/nootropicdesign.wx.s3-website-us-west-2.amazonaws.com\/<\/a><\/p>\n<p>Even though you don&#8217;t have any images captured, you should be able to see the next upcoming pass. The next thing to do is make sure the scripts work correctly to record the audio file, process it into images, and upload to your bucket. You can watch the logs in the <span class=\"code\">wx-ground-station\/logs<\/span> to debug any errors. <\/p>\n<p>The <span class=\"code\">wxtoimg<\/span> enhancements that are displayed depends on what sensors were active when the images were captured. If sensors 3 and 4 were active (usually at night), then the thermal enhancement will be shown. Otherwise a multispectral analysis enhancement will be shown.<\/p>\n<p>Not all images you capture will be good. I feel lucky if even half of my satellite passes produce recognizable images. You can clean up bad ones by using the script <span class=\"code\">aws-s3\/remove-wx-images<\/span> on the Raspberry Pi. Just provide the key to the particular capture as an argument to remove all the images and the metadata from the S3 bucket.<\/p>\n<pre class=\"codeblock\">\r\nnode aws-s3\/remove-wx-images NOAA19-20191108-162650\r\n<\/pre>\n<p>Hopefully in the next few hours you&#8217;ll be able to see some images uploaded, depending on when satellites are scheduled to fly over. You may get up to 12 passes per day, usually 2 for each of the NOAA satellites in the morning, then 2 more for each of them in the evening. Let us know if this project worked for you!<\/p>\n<p><\/p>\n<h3>Fine Tuning<\/h3>\n<p>The script <span class=\"code\">receive_and_process_satellite.sh<\/span> uses the <span class=\"code\">rtl_fm<\/span> command to read the signal from the RTL-SDR receiver. The <span class=\"code\">-p<\/span> argument sets the PPM error correction. I have mine set to 0, but you may want to adjust. See <a href=\"https:\/\/davidnelson.me\/?p=371\" rel=\"noopener noreferrer\" target=\"_blank\">this article for details<\/a>.<\/p>\n<p>I have also installed a low noise amplifier (LNA) to improve my reception (results are mixed). My LNA can be powered with a bias tee circuit and controlled with the <span class=\"code\">rtl_biast<\/span> command. If you are using an LNA like this, you can install rtl_biast <a href=\"https:\/\/www.rtl-sdr.com\/rtl-sdr-blog-v-3-dongles-user-guide\/\" rel=\"noopener noreferrer\" target=\"_blank\">as documented here<\/a> and uncomment the <span class=\"code\">rtl_biast<\/span> lines in <span class=\"code\">receive_and_process_satellite.sh<\/span> which turn the LNA on and off.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>UPDATE: All NOAA APT satellites (NOAA-18, NOAA-19, NOAA-15) were decommissioned in 2025. NOAA-15 was decommissioned and stopped transmitting imagery at 15:28 UTC on August 19. You can see my very last received images on my site. Project source code at GitHub: wx-ground-station This project will show you how to create a fully automated ground station [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[40,39,41],"tags":[],"class_list":["post-2461","post","type-post","status-publish","format-standard","hentry","category-radio","category-satellite","category-space"],"_links":{"self":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/2461","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/comments?post=2461"}],"version-history":[{"count":68,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/2461\/revisions"}],"predecessor-version":[{"id":2697,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/2461\/revisions\/2697"}],"wp:attachment":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/media?parent=2461"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/categories?post=2461"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/tags?post=2461"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}