122 lines
5.8 KiB
Python
122 lines
5.8 KiB
Python
#!/usr/bin/env python
|
|
|
|
import os
|
|
from socket import *
|
|
import datetime
|
|
import math
|
|
import sqlite3
|
|
import pytz
|
|
|
|
def roundTime(dt=None, roundTo=300):
|
|
if dt == None : dt = datetime.datetime.now()
|
|
seconds = (dt - dt.min).seconds
|
|
rounding = (seconds+roundTo/2) // roundTo * roundTo
|
|
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
|
|
|
|
conn = sqlite3.connect('/home/stoat/abewx/stoat.db')
|
|
c = conn.cursor()
|
|
c.execute('CREATE TABLE IF NOT EXISTS precipitation (dtg TEXT PRIMARY KEY, precip real)')
|
|
|
|
os.environ["AMBIENT_ENDPOINT"] = 'https://api.ambientweather.net/v1'
|
|
os.environ["AMBIENT_API_KEY"] = '5eeaadda004744a284ecbfdc22dcb852ca86b8a488d2456bb638a346ee5adf7f'
|
|
os.environ["AMBIENT_APPLICATION_KEY"] = '7eb31955d49c41f08e447b23a9dfc8be23992e8ffe3b41f98d9c9c68319e0e2e'
|
|
|
|
from ambient_api.ambientapi import AmbientAPI
|
|
|
|
callsign = 'FW6696'
|
|
latitude = 38.344299
|
|
longitude = -81.6789
|
|
devicename = 'WS2902A' #This identifies your equipment/software. You can put anything you want. I use 'WS2902A', which is the model of weather station I have
|
|
#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.
|
|
|
|
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'
|
|
latitude = '3820.66N'
|
|
|
|
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)
|
|
dailyrain = str(int(round(weather.get('dailyrainin')*100))).zfill(3) #this value IS supposed to be "rain since local midnight," so it is always reported
|
|
rainhour = str(int(weather.get('hourlyrainin')*100)).zfill(3)
|
|
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'
|
|
|
|
dtg = roundTime(datetime.datetime.utcnow())
|
|
olddtg = dtg - datetime.timedelta(days=3)
|
|
local_tz = pytz.timezone('US/Eastern')
|
|
utc = pytz.utc
|
|
localdate = datetime.datetime.now(local_tz).date()
|
|
localmidnight = local_tz.localize(datetime.datetime.combine(localdate, datetime.time(0, 0)), is_dst=None)
|
|
utc_midnighttoday = localmidnight.astimezone(utc).replace(tzinfo=None)
|
|
utc_midnightyesterday = utc_midnighttoday - datetime.timedelta(hours=24)
|
|
prev24 = dtg - datetime.timedelta(hours=24)
|
|
|
|
c.execute("INSERT OR REPLACE INTO precipitation (dtg, precip) values (?, ?)",(dtg, dailyrain))
|
|
conn.commit()
|
|
|
|
try:
|
|
c.execute("SELECT precip FROM precipitation WHERE dtg = (?)",(prev24,))
|
|
prev24value = c.fetchone()[0]
|
|
print(prev24value)
|
|
c.execute("SELECT precip FROM precipitation WHERE dtg = (?)",(utc_midnightyesterday,))
|
|
prevmidnightvalue = c.fetchone()[0]
|
|
print(prevmidnightvalue)
|
|
c.execute("SELECT precip FROM precipitation WHERE dtg = (?)",(utc_midnighttoday,))
|
|
currentmidnightvalue = c.fetchone()[0]
|
|
print(currentmidnightvalue)
|
|
rain24 = currentmidnightvalue - prev24value + int(dailyrain)
|
|
print(rain24)
|
|
past24hoursrain = str(int(rain24)).zfill(3)
|
|
print(past24hoursrain)
|
|
except:
|
|
past24hoursrain = '...'
|
|
print(past24hoursrain)
|
|
|
|
|
|
|
|
# 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'r''r'
|
|
#'r' + past24hoursrain + 'p'
|
|
#past24hoursrain = '...'
|
|
#packet = callsign + '>APRS,TCPIP*:@' + datetime.datetime.utcnow().strftime("%d%H%M") + 'z' + latitude + '/' + longitude + '_' + winddir + '/' + windspeed + 'g' + windgust + 't' + temp + 'r' + rainhour + 'p' + past24hoursrain.zfill(3) + 'P' + dailyrain + 'h' + humidity + 'b' + pressure + luminosity + devicename
|
|
packet = callsign + '>APRS,TCPIP*:@' + datetime.datetime.utcnow().strftime("%d%H%M") + 'z' + latitude + '/' + longitude + '_' + winddir + '/' + windspeed + 'g' + windgust + 't' + temp + 'r' + rainhour + 'P' + dailyrain + 'h' + humidity + 'b' + pressure + luminosity + devicename
|
|
print(packet) #prints the assembled packet for debugging purposes
|
|
|
|
#send the packet
|
|
s = socket(AF_INET, SOCK_STREAM)
|
|
s.connect(('cwop.aprs.net', 14580))
|
|
s.send(('user ' + callsign + ' pass -1 vers Python\n').encode())
|
|
s.send((packet+'\n').encode())
|
|
s.shutdown(0)
|
|
s.close()
|
|
|
|
|
|
c.close()
|
|
conn.close()
|