WXforum.net
Weather Related Organizations => CWOP Forum => Topic started by: k9mjm on February 18, 2020, 10:22:51 AM
-
I was dismayed to find out that my new Ambient WS-2902A didn't have the capability of sending data directly to APRS. There were other posts describing methods for getting that data out of Ambient's REST API and into APRS, but all of them involved doing something like custom router firmware or running a script on a computer (single point of failure)...
I thought this was an excellent use for AWS Lambda. This lets you run your code in a high-availability environment, for free. You don't even have to pay for the electricity this runs on. Jeff Bezos has it covered. Steps to do it:
- Get an amateur radio license ;)
- Set up your station to report to AmbientWeather.net through the awnet phone app.
- Create an Application Key and API Key at https://dashboard.ambientweather.net/account (https://dashboard.ambientweather.net/account).
- Create yourself an account at Amazon and log in to Amazon Web Services.
- Go to the AWS Lambda service. https://console.aws.amazon.com/lambda/home?region=us-east-1#/create/function (https://console.aws.amazon.com/lambda/home?region=us-east-1#/create/function)
- Click "Create function", and choose the "Author from scratch" method. I named my function ambientToAPRS. Make sure to choose the Python 3.8 runtime.
- Replace the sample code with this (and replace the values of callAndSSID, aprsPasscode, latitude, longitude, apiKey, mac, and applicationKey - no, those are not really mine). The APRS specification designates SKY as a destination address for SKYWARN stations. In my case, that is what I used. Looks like everyone else just uses APRS as the destination.
import urllib, json, time, http.client
from urllib.request import urlopen
def lambda_handler(event, context):
# REPLACE THESE VALUES ########
mac = 'DC:4F:22:59:13:12'
apiKey = '438955956ece44d9a2984ae15e46fb162303311747ef4390b930dee08d6accea'
applicationKey = 'd984259457f445d6a6c2bda2896ca23e0430163bb8be4a49b424b86d8072779f'
# Your call and substation ID go here, e.g. KN4DVB-1
callAndSSID = 'KN4DVB-1'
# Your APRS passcode - https://apps.magicbug.co.uk/passcode/
aprsPasscode = str('124324')
# latitude must be exactly 7 chars - include leading zeros
latitude = '3612.70N'
# longitude must be exactly 9 chars - include leading zero(s)
longitude = '08141.69W'
destination = 'APRS'
#uncomment (remove the # from) the following line if you are a real, trained NWS SKYWARN watcher
#destination = 'SKY'
#########################
url = 'https://api.ambientweather.net/v1/devices/' + mac + '?apiKey=' + apiKey + '&applicationKey=' + '&endDate=&limit=1'
json_url = urlopen(url)
data = json.loads(json_url.read())
diff = time.time() - (data[0]["dateutc"]/1000)
responsebody = ""
if (diff < 800):
postbody = 'user ' + callAndSSID +' pass ' + aprsPasscode +'\n'
dhmtime = str(data[0]["date"][8:10]) + str(data[0]["date"][11:13]) + str(data[0]["date"][14:16]) + "z"
postbody += callAndSSID + '>' + destination + ',WIDE1-1:@' + dhmtime + latitude + '/' + longitude + '_'
# wind direction
postbody += 'c'
postbody += (str('000') + str(data[0]["winddir"]))[-3:]
# wind speed
postbody += 's'
postbody += (str('000') + str(round(float(data[0]["windspeedmph"]))))[-3:]
# wind gust
postbody += 'g'
postbody += (str('000') + str(round(float(data[0]["windgustmph"]))))[-3:]
# temp F
postbody += 't'
tempf = int(data[0]["tempf"])
if (tempf < 0):
postbody += "-" + (str("00") + str(tempf))[-2:]
else:
postbody += (str("000")+str(tempf))[-3:]
# rain in last hour
postbody += 'r'
postbody += (str('000') + str(int(data[0]["hourlyrainin"]*100)))[-3:]
# rain in last day
postbody += 'P'
postbody += (str('000') + str(int(data[0]["dailyrainin"]*100)))[-3:]
#humidity
postbody += "h"
postbody += (str('00') + str(data[0]["humidity"]))[-2:]
#pressure
postbody += "b"
postbody += (str('00000') + str(int(10*33.864*data[0]["baromrelin"])))[-5:]
posturl = "http://rotate.aprs2.net:8080/"
conn = http.client.HTTPConnection('rotate.aprs2.net',8080)
headers = {'Content-Type':'application/octet-stream','Accept-Type':'text/plain'}
conn.request('POST', '/', postbody, headers)
responsebody = str(conn.getresponse().read())
return {
'statusCode': 200,
'body': responsebody
}
- Save your function and test it... you should see your beautiful WX icon show up at https://aprs.fi (https://aprs.fi) .
- Go to CloudWatch Rules: https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#rules: (https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#rules:)
- Create a rule. I called mine ambientToAPRS-runner.
- In the Event Source, set it to Schedule, with fixed rate of 1 minute.
- Click "Add Target", and choose your ambientToAPRS lambda function.
- Click "Configure Details".
- Put in the name of your rule, and set state to Enabled.
- Click "Create Rule".
- Go back to aprs.fi in 10 minutes, and pull up some beautiful weather graphs for your station.
The AWS Lambda free usage tier includes 1M free requests per month and 400,000 GB-seconds of compute time per month. You will run 44,640 requests in a 31-day month (44,641 if they ever add a leap second in a 31-day month).
If you want the data copied to CWOP, my understanding is that you have to register your callsign with CWOP (I'll get on this today).
My next project: Decode the 915 MHz signal from the sensor array and push it to a local iGate on RF APRS on a solar-powered Arduino with an SDR receiver and a UV-5R transmitter.
-
Very nice!
Users should note that if they don't have a ham call sign and are using a regular CWOP ID that they should change the upload server to cwop.aprs.net instead of rotate.aprs2.net (and then APRS passcode is -1)
-
I should mention that the Lambda environment does not seem to do any DNS caching... each sequential packet is routing through a random server through the load-balancing provided by rotate.aprs2.net. Both APRS and AWS provide you with some level of high availability. I don't know how HA the AmbientWeather.net API is, but they do allow you to pull more than one observation.
I could make this account for downtime on APRS and on AmbientWeather.net by tracking the last successful push to APRS and then pushing all available observations since that timestamp from AmbientWeather.net, since they let you pull the last 200+ observations. I'll worry about that when I see downtime in excess of 10 minutes.
-
Anyone using the above code, please note that I modified it this weekend to round windspeeds to the nearest integer mph. APRS does not accept fractional windspeeds.
-
Thank you for putting this together! I just set mine up in AWS this morning and it worked beautifully.
One thing I noticed, is that it expects Latitude and Longitude as DMS formatted as DDMM.SS, whereas I assumed it was all decimal. Going to have some bad position history on aprs.fi for a couple days #-o
-
It is actually DDMM.mm
This online converter should help
https://www.directionsmag.com/site/latlong-converter/
-
Thanks for providing this code it worked great to get my WS-2902 to report to APRS and I don't even have to use a computer at home.
Any luck on decoding the signal from the 2902 to send direct from a radio?
-
Any luck on decoding the signal from the 2902 to send direct from a radio?
Sure, it's been done. Look up SDR rtl_433 and then you can feed WeeWX software. From there you can either send via APRS on the Internet or hook up a TNC with radio.
-
Another awesome sounding project.
I have been meaning to get an Amateur license for a while now for some Drone Video use.
And I have a couple UV-5R's lol
At the price point I have been considering getting an Ambient station just for the display. [tup]
-
I registered just to say thanks for this original post. After futzing with my GPS coordinates a bit it works great. I love the simplicity and creative thought.
Cheers OP!