#!/bin/env python3 import os import requests import pytz from datetime import datetime, timedelta from PIL import Image from PIL import ImageFont from PIL import ImageDraw from io import BytesIO from geopy.geocoders import Nominatim FONT_SIZE = 40 FONT_SIZE_SMALL = 20 TEXT_COLOR = (255, 255, 255, 255) def invert_back_white(img): pixels = img.load() for y in range(img.size[1]): for x in range(img.size[0]): r, g, b, _ = pixels[x, y] if abs(r - g) < 5 and abs(r - g) < 5 and abs(b - g) < 5: pixels[x, y] = (255 - r, 255 - g, 255 - b, 255) def scale_to_height(img, new_height): width, height = img.size new_width = int(new_height * width / height) return img.resize((new_width, new_height)) def scale_to_width(img, new_width): width, height = img.size new_height = int(new_width * height / width) return img.resize((new_width, new_height)) def main(): now = datetime.now(pytz.utc) earlier = now - timedelta(hours=1) params = { 'start': earlier.isoformat(), 'end': now.isoformat(), 'status': 'good', } resp = requests.get('https://network.satnogs.org/api/observations', params=params) obs = resp.json() obs = reversed(sorted(obs, key=lambda x: x['end'])) for ob in obs: if ob['waterfall'] is not None: break if ob['waterfall'] is None: print("No observations with waterfall found") return resp = requests.get('https://db.satnogs.org/api/satellites/%s/' % ob['norad_cat_id']) sat_name = resp.json()['name'] sat_img_url = None if 'image' in resp.json().keys(): sat_img_url = "https://db-satnogs.freetls.fastly.net/media/%s" % ( resp.json()['image']) geolocator = Nominatim( user_agent= "satnogs-demo-display - https://forgejo.zenerdio.de/sebastian/satnogs-demo-display" ) mode_desc = ob['transmitter_mode'] frequency = ob['observation_frequency'] / 1_000_000 coord = "%f, %f" % (ob['station_lat'], ob['station_lng']) address = geolocator.reverse(coord, exactly_one=True, language="en").raw['address'] city = address.get('city', '') country = address.get('country', '') station_location = "" if city != "": station_location += "near " + city + " " if country != "": station_location += "in " + country resp = requests.get(ob['waterfall']) waterfall = Image.open(BytesIO(resp.content)).convert('RGBA') invert_back_white(waterfall) waterfall = scale_to_height(waterfall, 1024) water_width, _ = waterfall.size logo = Image.open("satnogs-logo.png").convert('RGBA') logo_w, logo_h = logo.size invert_back_white(logo) sat_img = None if sat_img_url is not None: resp = requests.get(sat_img_url) sat_img_aplha = Image.open(BytesIO(resp.content)).convert('RGBA') alpha_chan = sat_img_aplha.convert('RGBA').split()[-1] sat_img = Image.new("RGBA", sat_img_aplha.size, (255, 255, 255, 255)) sat_img.paste(sat_img_aplha, mask=alpha_chan) sat_img_width, sat_img_height = sat_img.size if sat_img_width > sat_img_height: sat_img = scale_to_width(sat_img, 500) else: sat_img = scale_to_height(sat_img, 500) img = Image.new('RGBA', (1280, 1024)) draw = ImageDraw.Draw(img) draw.rectangle((0, 0, 1280, 1024), fill=(0, 0, 0, 255)) station_name = ob['station_name'] if len(station_name) > 20: station_name = station_name[:20] + "..." infos = "Satellite: %s\nStation: %s\n%s\nMode: %s\nFrequency: %f MHz\nStart: %s\nEnd: %s" % ( sat_name, station_name, station_location, mode_desc, frequency, ob['start'], ob['end']) font = ImageFont.truetype("Montserrat-Regular.otf", FONT_SIZE) draw.text((water_width + 100, logo_h + 50), infos, TEXT_COLOR, font=font) img.paste(waterfall, (0, 0)) img.paste(logo, (water_width + 100, 20)) if sat_img != None: img.paste(sat_img, (water_width + 100, 480)) font = ImageFont.truetype("Montserrat-Regular.otf", FONT_SIZE_SMALL) draw.text((950, 1000), "Geocoding by Nominatim/OSM", TEXT_COLOR, font=font) img.save('waterfall_tmp.png') os.rename('waterfall_tmp.png', 'waterfall.png') if __name__ == '__main__': main()