The EU-operated Sentinel-2 satellites are constantly monitoring the Earth’s surface, producing several terabytes of data every day, but if we want to be notified when a new satellite image of a specific area is available, unfortunately there are not many services available. In this post, I will show you how to create your own email notification service in Python.
The motivation
If you are familiar with Satmapper.hu or you have already browsed the content of the site, you know that under the Satellite Images menu item, the latest Sentinel-2 satellite images are available from two locations. These images are updated when the cloud cover is less than 30% . To generate this data, you must first download a satellite image of the examined area, which should be as cloud-free as possible, and then process it with the software of choice.
But how does the user know when new satellite imagery is available for an observed area? After some research, I found out that such service is not really available. Fortunately Python is a great tool to fill gaps like that, so here is ho I solved this issue…
Requirements
Before we write a single line of code, it’s always important to think about what requirements our program should meet. In this case, they are the following:
- The code should search for a new satellite image based on a Shapefile
- Cloud coverage percentage should be a serach parameter
- Search frequency should be adjustable
- If the code finds a new satellite image, it should send an email with the most important data imagery data
- If the email was sent, the code should pause the search
Prerequisites
Before your start coding, you will need an Open Access Hub user account, as the code will search this database for new satellite images. Registration on the site is free and will be activated within approximately 24 hours.
In addition to Open Access Hub registration, the following Python libraries are required:
The most important from the list above is Sentinelsat, which will allow us to connect to the Open Access Hub and then extract data from it. Once you’re done with these, you can start coding.
The Python code
Open an empty Python file and start typing the following lines.
The first lines will call the directories needed later and specify the path to the Shapefile of your observed locations. In this example, I will use the shapefile of Budapest.
#################### # Import libraries # #################### import os import geopandas as gpd from sentinelsat import SentinelAPI, read_geojson, geojson_to_wkt from datetime import date from datetime import datetime import smtplib, ssl import time import schedule ########################## # Define shape file path # ########################## fp_place='shape_file/budapest/budapest.shp'
In the next section, we provide the login information required for the Open Access Hub and the addresses required to send the e-mail. Important: If you use a Gmail account to send email, you will have to enable “Less secure apps” access in your settings, or your program will not be able to use the account to send mail.
I strongly advise you to use a Gmail account which you don’t mind making more vulnerable due to this setting. For maximum security, it’s a good idea to create a brand new account that you will only use for this notifier service.
#################### # Basic parameters # #################### # Open Access Hub login data oah_user='USERNAME' # Your Open Access Hub username oah_pass='PASSWORD' # Your Open Access Hub password #E-mail data port = 465 # Email client port for SSL smtp_server = "smtp.gmail.com" #SMTP server sender_email = "XXXX@gmail.com" # Enter sender e-mail address receiver_email = "YYYY@gmail.com" # Enter receiver e-mail address password = "MAILPASSWORD" # Enter sender e-mail password
Next we have to give the search parameters and read in the previously specified Shapefile. The search parameters can be changed freely and it is worth browsing the Sentinelsat documentation for more options. With the max_cloud variable we can tell the code to send a notification only if the cloud cover of the new satellite image is between 0-30%.
##################################################### # Search parameters - See sentinelsat documentation # ##################################################### start_date='NOW-1DAY' end_date='NOW' platformname='Sentinel-2' processinglevel = 'Level-2A' min_cloud=0 max_cloud=100 ################################# # Open shapefile and get bounds # ################################# shapefile = gpd.read_file(fp_place) shapefile_EPSG4326=shapefile.to_crs(epsg=4326) shp_bounds=shapefile_EPSG4326.total_bounds lonmin=shapefile_EPSG4326.total_bounds[0] latmin=shapefile_EPSG4326.total_bounds[1] lonmax=shapefile_EPSG4326.total_bounds[2] latmax=shapefile_EPSG4326.total_bounds[3] # Create wkt of shapefile wkt = "POINT(%f %f %f %f)" % (float(lonmin) , float(latmin), float(lonmax), float(latmax))
The next step is to create the function that will perform the most important part of our entire code. This snippet first connects to the Open Access Hub API page and then looks at how many satellite imagery match the search criteria.
If this number is greater than zero, it will download the satellite image data, then the code will create the text of the notification email and send it to the email address previously specified. When this is done, the program will sleep for 23 hours.
It is also important to get some feedback on how the code is performing, therefore we should print a console message after each important operation.
################################################### # Create function for data check and mail sending # ################################################### def job(): #Checking Sentinel data on SciHub, based on search requirements api = SentinelAPI(oah_user,oah_pass, 'https://apihub.copernicus.eu/apihub/') count=api.count(area=wkt, date=(start_date, end_date), platformname=platformname,area_relation='Contains',raw=None,cloudcoverpercentage=(min_cloud,max_cloud),limit=20, processinglevel = processinglevel) now = datetime.now() now = now.strftime("%d/%m/%Y %H:%M:%S") print(now+' - Checking for new data') if count>0: # Write available image data to dataframe products = api.query(area=wkt, date=(start_date, end_date), platformname=platformname,area_relation='Contains',raw=None,cloudcoverpercentage=(min_cloud,max_cloud),limit=20, processinglevel = processinglevel) products_df = api.to_dataframe(products) detail=products_df.iat[0,4] # Get and format important data of satellite imagery img_sat=products_df.iloc[0,36] # Get satellite name img_proc_lvl=products_df.iloc[0,37] # Get image processing level img_date=products_df.iloc[0,4][6:16] # Get acquisition date img_time=products_df.iloc[0,4][17:25] # Get acquisition time img_cloud=str(products_df.iloc[0,19])[:5]+' %' # Get cloud coverage #Prepare e-mail content subject="New satellite image available - "+img_date body="Properites if the new satellite imagery is the following.\n\n"+'Satellite: '+img_sat+'\n'+'Processing level: '+img_proc_lvl+'\n'+'Timestamp of imagery: '+img_date+', '+img_time+'\n'+'Cloud cover percentage: '+img_cloud message=f'Subject:{subject}\n\n{body}' #Send e-mail and go to sleep context = ssl.create_default_context() with smtplib.SMTP_SSL(smtp_server, port, context=context) as server: server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message.encode("utf8")) now = datetime.now() now = now.strftime("%d/%m/%Y %H:%M:%S") print(now+' - Mail has been sent') time.sleep(82800) #23 hours return else: # If no new image available, print message print(now+' - There is no new data available') return
Once we have written the function, there is nothing left but to schedule its execution. To do this, I used the schedule command set to run hourly.
######################################################## # Run function every hour - See schedule documentation # ######################################################## schedule.every().hour.do(job) while True: schedule.run_pending() time.sleep(1)
We are almost done, we just need to start the program on a computer that is running 0-24 and has an internet connection. For this, I use a relatively cheap and low power Raspberry Pi Model B + with Raspberry Pi operating system.
The sent e-mail looks like this in Gmal (with hungarian text):
I hope this post was useful for those who are interested in Sentinel-2 image processing in Python and I also hope that this post was not too scary for those who are not so familiar with programming languages.
The code above and the shapefile in the example are available on GitHub even in Jupyter Notebook format with comment in English and Hungarian.