Skip to content

Instantly share code, notes, and snippets.

@trevor229
Created July 25, 2021 08:49
Show Gist options
  • Save trevor229/ae01bed2184312756822633fd1831701 to your computer and use it in GitHub Desktop.
Save trevor229/ae01bed2184312756822633fd1831701 to your computer and use it in GitHub Desktop.
Script for using the Ambient Weather API to upload data to APRS/CWOP
# Ambient Weather API APRS/CWOP upload script from this thread https://www.wxforum.net/index.php?topic=36181.0
# Originally written by uajqq and Ron B.
# Modified by me (trevor229) for amateur radio use (added a few new variables)
# Be aware there are apparently some issues with the coordinates not being rounded properly in some cases. Read the thread above for more info. It works fine for me though.
# When using this script, make sure it is not running more than once per 5 minutes, as CWOP requests.
import os
from socket import *
from datetime import datetime, time
import math
os.environ["AMBIENT_ENDPOINT"] = 'https://api.ambientweather.net/v1'
os.environ["AMBIENT_API_KEY"] = '????' # Your API key here
os.environ["AMBIENT_APPLICATION_KEY"] = '????' # Your Application API key here
from ambient_api.ambientapi import AmbientAPI
callsign = '????' # Your CWOP/Amateur callsign here
passwd = '-1' # Leave as -1 unless you are an amateur radio operator and have a passcode from [email protected]
aprs_server = 'cwop.aprs.net' # Leave alone unless you are an amateur radio operator and have a passcode from [email protected]
#IMPORTANT: lat/long must be listed in DECIMAL DEGREES (DD.DDDD). Number of digits doesn't really matter. Use positive values for N/E, negative for S/W. The program then converts to degrees decimal minutes (DD MM.MMMM), which is the format APRS requires.
latitude = 00.000
longitude = 00.000
devicename = 'Ambient WS2000' #This identifies your equipment/software. You can put anything you want. I use 'Ambient WS2000', which is the model of weather station I have
api = AmbientAPI()
devices = api.get_devices()
home = devices[0] #this assumes you have only one station. Increase number accordingly if you want to get data from others
weather= home.last_data
#convert coordinates to degrees decimal minutes
if latitude < 0:
latitude = abs(latitude)
latitude = str(int(latitude)).zfill(2) + str(round(60*(latitude - int(latitude)),2)).zfill(2) + 'S'
else:
latitude = str(int(latitude)).zfill(2) + str(round(60*(latitude - int(latitude)),2)).zfill(2) + 'N'
if longitude < 0:
longitude = abs(longitude)
longitude = str(int(longitude)).zfill(3) + str(round(60*(longitude - int(longitude)),2)).zfill(2) + 'W'
else:
longitude = str(int(longitude)).zfill(3) + str(round(60*(longitude - int(longitude)),2)).zfill(2) + 'E'
winddir = str(weather.get('winddir')).zfill(3)
windspeed = str(int(math.ceil(weather.get('windspeedmph')))).zfill(3)
windgust = str(int(math.ceil(weather.get('windgustmph')))).zfill(3)
if weather.get('tempf') < 0:
temp = '-' + str(int(round(weather.get('tempf')))).zfill(2)
else:
temp = str(int(round(weather.get('tempf')))).zfill(3)
rainhour = str(int(weather.get('hourlyrainin')*100)).zfill(3) #technically this is RATE of rain per hour, not AMOUNT per hour, but seems to be tolerated?
past24hoursrain = str(int(weather.get('dailyrainin')*100)).zfill(3) #at the moment, the Ambient API does not provide "rain in last hour", so no way to calculate "rain in last 24 hours." The API can only report "rain since local midnight." Therefore this only gets reported after 23:45 local time, so rain since midnight is reasonably close to rain in last 24 hours
dailyrain = str(int(weather.get('dailyrainin')*100)).zfill(3) #this value IS supposed to be "rain since local midnight," so it is always reported
pressure = str(int(weather.get('baromrelin')/0.0029529983071445)).zfill(5) #pressure is supposed to be reported to APRS in "altimiter" (QNH) format, that is, relative. The system itself corrects the pressure to sea level based on your station's listed elevation, so make sure that's accurate
humidity = str(int(weather.get('humidity')%100)).zfill(2) #uses modulus operator % so that 100% is given as '00'
# If luminosity is above 999 W/m^2, APRS wants a lowercase L
if weather.get('solarradiation') >= 1000:
luminosity = 'l' + str(int(round(weather.get('solarradiation'))) % 1000).zfill(3)
else:
luminosity = 'L' + str(int(round(weather.get('solarradiation')))).zfill(3)
# Time reported in Zulu (UTC). 24-hour rain workaround still has to be local time, though
packet = callsign + '>APRS,TCPIP*:@' + datetime.utcnow().strftime("%d%H%M") + 'z' + latitude + '/' + longitude + '_' + winddir + '/' + windspeed + 'g' + windgust + 't' + temp + 'r' + rainhour + 'p' + (past24hoursrain if datetime.now().time() >= time(23,45) else '...') + 'P' + dailyrain + 'h' + humidity + 'b' + pressure + luminosity + devicename + '\n'
mylogin = 'user ' + callsign + ' pass ' + passwd + ' vers Python\n'
print(mylogin) #print user string for debugging purposes
print(packet) #prints the assembled packet for debugging purposes
#send the packet
s = socket(AF_INET, SOCK_STREAM)
s.connect((aprs_server, 14580))
s.send(mylogin.encode())
s.send(packet.encode())
s.shutdown(0)
s.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment