Author Topic: How to upload from Ambient to CWOP for free using any computer without weewx  (Read 4854 times)

0 Members and 1 Guest are viewing this topic.

Offline uajqq

  • Member
  • *
  • Posts: 27
After much trial and error, here’s my method for uploading to CWOP without any special equipment and for free. All you need is a computer that’s always on. You can use a Raspberry Pi, remote server, etc. The script pulls data from the Ambient API, processes it into an APRS packet, and uploads the packet—this avoids mucking around with intercepting traffic on the local network, and has the added benefit of making it so the computer doesn’t have to be anywhere near the station itself.

This assumes you’re already registered through CWOP and have a callsign.

The script uses the ambient_api library by avryhof (https://github.com/avryhof/ambient_api). He also makes a library specifically for uploading to APRS (https://github.com/avryhof/ambient_aprs), but at the time I was trying to figure this out, I noticed it had a bug that cause coordinates to be reported in the wrong format. He has since corrected it, but by then I already had my own simplified script, which streamlines some stuff and has the added benefit of reporting zeroes when the values are actually zero, instead of omitting the data entirely. That’s a style preference, so please check out his work if you’d rather.

STEP ONE: install Python on whatever computer you’re going to be using. I suggest lots of Googling if you need instructions on how, that’s the only way I figure anything coding-related out. My version is 2.7.10; can’t guarantee any other versions.

STEP TWO: install ambient_api per the instructions on his GitHub page, or whatever other method you prefer if you’re more tech savvy.

STEP THREE: obtain Ambient API keys. Do this by emailing support@ambientweather.com and providing your Ambient device’s MAC address. You’ll get back both an application key and an API key.

STEP FOUR: copy and paste the following code into a file with a “.py” extension. You can name it whatever you want and put it anywhere you want. Edit the required values, marked by ????, in the code to customize it to your station. There should be 6 values to customize (API key, application key, callsign, latitude, longitude, and device name), so make sure you get them all.
Code: [Select]
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"] = '????'
os.environ["AMBIENT_APPLICATION_KEY"] = '????'

from ambient_api.ambientapi import AmbientAPI

callsign = '????'
latitude = ????
longitude = ????
devicename = '????' #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'

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

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')
s.send(packet+'\n')
s.shutdown(0)
s.close()

STEP FIVE: run the script once by executing ‘python [your script]’ in a terminal window. It should spit out a correctly formatted APRS packet and upload it to CWOP successfully.

STEP SIX: set a CRON job to run that script automatically at an interval of your choosing (no more than 5 minutes to be polite to the APRS servers, every 10 minutes seems to be the norm). Google how to do this on your specific device. I upload every 5 minutes so the CRON task I use is as follows:
Code: [Select]
*/5 * * * * python [path to your script]
And that should do it. Check findu to make sure your packets are coming through, and make sure your computer never goes to sleep.

Good luck!! Let me know if any of that isn’t working and I’ll do my best to help out, but for almost anything device-specific, Google is going to be smarter and faster than me.
« Last Edit: February 17, 2019, 11:53:14 AM by ewqcb »

Offline galfert

  • Global Moderator
  • Forecaster
  • *****
  • Posts: 6822
Re: How to upload from Ambient to CWOP for free using any computer
« Reply #1 on: February 16, 2019, 10:44:10 PM »
Most impressive. Thank you for sharing.

Although there are other methods to get data from an Ambient station there are some drawbacks to some of the other methods. Most notably using the WeeWx with Interceptor driver requires that your station console be on a separate WiFi network on the Raspberry Pi for the Interceptor driver to be able to work and do it's thing. It is nice to see the Ambient API being used in such a clever way.
Ecowitt GW1000 | Meteobridge on Raspberry Pi
WU: KFLWINTE111  |  PWSweather: KFLWINTE111
CWOP: FW3708  |  AWEKAS: 14814
Windy: pws-f075acbe
Weather Underground Issue Tracking
Tele-Pole

Offline kbellis

  • Forecaster
  • *****
  • Posts: 361
@Adam - Yes! This is much appreciated!! And many thanks also, to Amos Vryhof for his great work.

The fact that this procedure (so-called Method 5) allows for data to flow to CWOP without weewx is good news for a couple of reasons, I think, though the full machinations in either weewx or Method 5's delivery I've yet to plumb. The first reason: there is nothing wee about weewx. It's a massive, mature and complex set of algorithms lacking any graphical user interface; friendly or otherwise, run from a daemon or terminal in UNIX-speak, maybe not every Ambient customer's area of interest. The second reason this method is good news, or might be good news, relates to what ends up getting done to the original station's data in order to placate Automatic Packet Reporting System (APRS) formatting requirements; more specifically: pressure, barometer, and altimeter. Having an independent producer of these pressure values might (hopefully) be good to use as a check.


Offline mountainbillies

  • Member
  • *
  • Posts: 1
Hi,

I am trying to get the python script working (using Python 3.7) to send the ambient 2902 data to CWOP and followed the instructions in your post.  I got the AMBIENT api key and  application keys from my account on ambient. I get the following error:    Thanks Paul


c:\Data\Paul\AmbientWxStation>PostAmbientToCWOP.py
Traceback (most recent call last):
  File "C:\Data\Paul\AmbientWxStation\PostAmbientToCWOP.py", line 21, in <module>
    home = devices[0] #this assumes you have only one station. Increase number accordingly if you want to get data from others
IndexError: list index out of range

Offline uajqq

  • Member
  • *
  • Posts: 27
I am trying to get the python script working (using Python 3.7) to send the ambient 2902 data to CWOP and followed the instructions in your post.  I got the AMBIENT api key and  application keys from my account on ambient. I get the following error:    Thanks Paul


c:\Data\Paul\AmbientWxStation>PostAmbientToCWOP.py
Traceback (most recent call last):
  File "C:\Data\Paul\AmbientWxStation\PostAmbientToCWOP.py", line 21, in <module>
    home = devices[0] #this assumes you have only one station. Increase number accordingly if you want to get data from others
IndexError: list index out of range

If I had to guess, I'd say the script didn't successfully connect to the Ambient API, and it's saying there isn't any data (that's why it's saying 0 is out of range--if devices[] has any data, it would start with index 0). I would recommend double-checking your API credentials and trying again. Otherwise, try PMing me the script itself and I can take a look?

Offline galfert

  • Global Moderator
  • Forecaster
  • *****
  • Posts: 6822
I noticed that mountainbillies is using Windows and not Linux. Is your Python script compatible with Windows? He is also writing to a directory off the root of the C: drive which which also requires proper permissions for programs to access this location.
« Last Edit: April 15, 2019, 10:55:32 AM by galfert »
Ecowitt GW1000 | Meteobridge on Raspberry Pi
WU: KFLWINTE111  |  PWSweather: KFLWINTE111
CWOP: FW3708  |  AWEKAS: 14814
Windy: pws-f075acbe
Weather Underground Issue Tracking
Tele-Pole

Offline uajqq

  • Member
  • *
  • Posts: 27
I noticed that mountainbillies is using Windows and not Linux. Is your Python script compatible with Windows? He is also writing to the root of the C: drive which which also requires proper permissions for programs to access this location.

Python is compatible with all operating systems, so the script should work anywhere there is a proper Python installation. We know Python is working, since it's throwing error messages.

Quote
I am trying to get the python script working (using Python 3.7) to send the ambient 2902 data to CWOP and followed the instructions in your post.

Didn't notice before that you are using Python 3.7, however. Like I said in the post, I can't guarantee any other versions of Python, particularly Python 3, which is quite a bit different in many regards--I'm on Python 2.7 for compatibility issues. The script may well not work with Python 3.x. You can either try to diagnose the problem yourself, or try to install a different version of Python (a common solution, since many scripts don't work with Python 3.x). I'd recommend Googling to help with that, which is how I figure out anything coding-related anyway.

Offline shelumiel

  • Member
  • *
  • Posts: 1
ambient_api and 'ewqcb script' in Windows 10
« Reply #7 on: May 03, 2019, 05:18:56 PM »
I'm a complete beginner in Python and spent many hours to figure out how to make things work using my Synology NAS. I ended up installing Python and ambient_api in Windows 10 as a virtual machine. I just wanted to leave step-by-step instructions for other beginners like me.  ;)

1. Download Python 2.7.16 (Windows x86-64 MSI installer, released on 03/04/19) from https://www.python.org/downloads/release/python-2716/
and install.
  * Don't forget to check "Add python.exe to Path" at the bottom of the feature page (you might need to scroll down).
  ** I found the latest Python 3 (3.7.3) doesn't work for 'ewqcb script.'

2. Get an 'API key' as well as an 'application key' from https://dashboard.ambientweather.net/account
  * You need to create each separately. 

3. Open Notepad, copy and paste the code from ewqcb's original post (STEP FOUR). Insert your information to ???? (6 in total, leave single quotation marks).
  ** I have WS-8478 which doesn't have the solar radiation sensor, thus needed to delete the following section from the script.
   
Code: [Select]
# 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)

also

# 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


4. Save the code as a Python script. (ex. Ambient_APRS.py)
 
5. Open Command Prompt (type 'cmd' in Search Windows)
  a. Type 'pip install ambient_api'
  b. Type 'pip install urllib3==1.24.3'
  ** If you need to uninstall those later, type 'pip uninstall' instead.

6. Now, find out where you saved the script in step 4 above, and type 'python YOUR_FILE_NAME.py' in Command Prompt
  * If correctly installed, you'll get a result like
   
Quote
FW0000>APRS,TCPIP*:@032000z000.00N/00000.0W_315/006g007t067r001p...P001h81b10138WS-0000

7. Open Task Scheduler (type in Search Windows) to automatically repeat the Python script.
   * Watch https://www.youtube.com/watch?v=n2Cr_YRQk7o to get help.

8. Finally, check your uploaded data in http://www.findu.com/cgi-bin/raw.cgi?call=FW0000


***** [Added] While the data seems to feed into CWOP smoothly with this script, it turned out coordinates are still being reported in wrong digits (fewer zeros), as ewqcb mentioned in his original post.
Quote
Failed to parse message 1
This report was not parsed as a valid APRS message: Invalid uncompressed location.
Quote
I noticed it had a bug that cause coordinates to be reported in the wrong format. He has since corrected it, but by then I already had my own simplified script, which streamlines some stuff and has the added benefit of reporting zeroes when the values are actually zero, instead of omitting the data entirely.
I wonder whether it's because the original Python module (ambient_api) got fixed after ewqcb's script, or due to another new issue. I ended up directly inserting correct coordinates as CWOP requires, disabling the entire converting section... ewqcb, could you please check whether your script works with the current ambient_api module?

(P.S. to ewqcb: It seems Python 2.7 will be discontinued in January next year. Would it be possible for you to update your original script so that it can work in Python 3 or 2.8(?) in the future? Thank you so much for helping us!)  [tup]
« Last Edit: May 03, 2019, 08:46:00 PM by shelumiel »

Offline Ron B.

  • Member
  • *
  • Posts: 2
    • Hillsdale - Tacoma,WA
There were some comments expressing concern that the code ewqcb wrote and submitted would not run under Python 3.

I took the liberty of modifying ewqcb's code so that it will now execute correctly under Python 3.
The issue I found was the way Python 3 handles strings, and the send() command.
The Python 3 send() statement expects a 'byte object' rather than a string, hence the embedded encode() statement in the send() statement

Visual Studio 2019 (free from Microsoft) was used to modify and test the code.

I am currently using Visual Studio to run the program in a loop, sending data every 5 minutes.

A big 'Thank You!!' to ewqcb for the initial effort.

Code: [Select]
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 callsign here

#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 = ????
longitude = ????

devicename = '????' #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 -1 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(('cwop.aprs.net', 14580))
s.send(mylogin.encode())
s.send(packet.encode())
s.shutdown(0)
s.close()

« Last Edit: February 23, 2020, 02:48:49 PM by Ron B. »

Offline K5GHS

  • Senior Member
  • **
  • Posts: 68
    • K5GHS's Website
So I'm having an issue with the script.   It has to do with the coordinates that are being sent to APRS.

The issue is what it is transmitting for my Latitude.  I'm putting in 33.1658 for it, and its converting and sending it out on APRS as 339.95N, which is being rejected.  Looking at another application I run with the same coordinates input, it is sending it out as 3309.95N, which it is accepting.

Longitude is -96.6593, which is outputting correctly (and matches my other application) as 09639.56W.

So either I'm putting it in wrong and its getting converted wrong, or I'm putting it in right and its getting converted wrong.  But I've double and triple checked that I'm putting it in right, so I think it has to do with the conversion the script is doing. 

Any insight?  This is with the python 3 script above.  Everything else as far as I can tell is correct, its just that little bit.  It is showing up on http://www.findu.com/cgi-bin/errors.cgi whereas the one I'm comparing it to is not, and after looking them over, its the only thing I can find different.
« Last Edit: January 13, 2020, 03:52:49 AM by K5GHS »
Joshua
K5GHS
http://www.k5ghs.radio

Collin County, TX  Grid: EM13qd  CWOP: AV590
Skywarn Repeaters:  147.180 Primary 146.740 Secondary
100% Emergency Powered Ham Radio Station (540AH Batteries/Solar Rechargeable)
Ambient Weather WS-2000
Ecowitt GW1000

Offline Ron B.

  • Member
  • *
  • Posts: 2
    • Hillsdale - Tacoma,WA
Sorry about that....  I am NOT a Python programmer, but I found the problem.  The issue you had will only occur if the minutes portion of the decimal degree calculation is less than 10, which in your case, it is 09.95.  The leading zero is being dropped.  The string value needs to be 5 places long (including the decimal point), but the 'zfill' statement is only padding the minutes portion with zeros to 2 places, when it should be 5.  This is an error in the original post, and affects both latitude AND longitude for certain values.  You will find the corrected code below.  All that was needed was to change zfill(2) to zfill(5) in four places.

Code: [Select]
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 callsign here

#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 = ????
longitude = ????

devicename = '????' #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(5) + 'S'
else:
latitude = str(int(latitude)).zfill(2) + str(round(60*(latitude - int(latitude)),2)).zfill(5) + 'N'
if longitude < 0:
longitude = abs(longitude)
longitude = str(int(longitude)).zfill(3) + str(round(60*(longitude - int(longitude)),2)).zfill(5) + 'W'
else:
longitude = str(int(longitude)).zfill(3) + str(round(60*(longitude - int(longitude)),2)).zfill(5) + '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 -1 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(('cwop.aprs.net', 14580))
s.send(mylogin.encode())
s.send(packet.encode())
s.shutdown(0)
s.close()

Offline K5GHS

  • Senior Member
  • **
  • Posts: 68
    • K5GHS's Website
That's okay, I appreciate you fixing it so quickly.  I just redid it and we're up and running nicely now.

You know more about python than me, that's for sure.

Thanks again!
Joshua
K5GHS
http://www.k5ghs.radio

Collin County, TX  Grid: EM13qd  CWOP: AV590
Skywarn Repeaters:  147.180 Primary 146.740 Secondary
100% Emergency Powered Ham Radio Station (540AH Batteries/Solar Rechargeable)
Ambient Weather WS-2000
Ecowitt GW1000

Offline planohog

  • Member
  • *
  • Posts: 6
First, Thank you !!!!!!!!!!!!!   I have been fooling around with this stuff for over a year and only picked it back up again because I had
wanted to learn more about APRS. 
I was able to plug and play your script .  The only thing was the rendering of my location.
The charts showed me off about 15 miles or so, no matter how I adjusted the coodinates.
I hard wired them and it worked perfect for me.  Its ok because Im stationary .
right below the section where Lat Long is converted to strings.
The coordinates have been changed slightly for security .
I entered

latitude='2834.45N'
longitude='09400.92W

right above the following line.

windir= str(weather.get('windir'


I hope this helps anyone that is having issues with actual location.
I am super happy  !! 

Thanks Again.
Terry
(davis vantage vue) ( not online )
(Ambinet 2902 )  logging APRS ,WU and ambient.
https://dashboard.ambientweather.net/devices/public/0e2f5de506737d924bd4402ae1bd16fb



Offline k9mjm

  • Member
  • *
  • Posts: 4
If you want to replicate the data from Ambient's API to APRS/CWOP for free using high availability serverless cloud computing, see:

https://www.wxforum.net/index.php?topic=38809.msg399050#msg399050

Offline danoh

  • AmbientCWOP.com
  • Contributor
  • ***
  • Posts: 103
    • AmbientCWOP
To bump an old post:

Code: [Select]
if latitude < 0:
    latitude = abs(latitude)
    latitude = str(int(latitude)).zfill(2) + str(round(60*(latitude - int(latitude)),2)).zfill(5) + 'S'
else:
    latitude = str(int(latitude)).zfill(2) + str(round(60*(latitude - int(latitude)),2)).zfill(5) + 'N'

if longitude < 0:
    longitude = abs(longitude)
    longitude = str(int(longitude)).zfill(3) + str(round(60*(longitude - int(longitude)),2)).zfill(5) + 'W'
else:
    longitude = str(int(longitude)).zfill(3) + str(round(60*(longitude - int(longitude)),2)).zfill(5) + 'E'

The above code is returning:

097007.8W for decimal lon of -97.1300670

That's not correct.

Through experimentation, I've kind of narrowed it down to if there is a 0 in the decimal coords thousandths and ten-thousandths position, it will return a bad value.

Any ideas?

Ambient Weather station CWOP connector: AmbientCWOP.com

Offline galfert

  • Global Moderator
  • Forecaster
  • *****
  • Posts: 6822
To me it looks like the wrong approach was used when using zfill for a decimal number. There are times when you need to place leading zeros in front of the results. Like if the result is 7.8 that would need to become 07.8 but we aren't done yet. The problem is that zfill is being attempted to be used to pack not just the front of the results also the end of the results and this is not possible in the manner implemented. Because the results in this example needs to be 07.80 and that can't be accomplished to pad both the front and the end of the results with a zero using zfill (not that I know of). I think the minutes needs to be split up into two parts. The part before the decimal which is the minutes and then the part after the decimal which is the decimal minutes needs to be derived at separately and then combined to form the final result.

I took a stab at it and I came up with this code below.
UPDATE: both Latitude and Longitude now included in code.

Code: [Select]
if latitude < 0:
    latitude = abs(latitude)
    latitude = str(int(latitude)).zfill(2) + str(int(60*(latitude - int(latitude)))).zfill(2) + '.' + str(int(round(round(60*(latitude - int(latitude)),2)%1,2)*100)).zfill(2) + 'S'
else:
    latitude = str(int(latitude)).zfill(2) + str(int(60*(latitude - int(latitude)))).zfill(2) + '.' + str(int(round(round(60*(latitude - int(latitude)),2)%1,2)*100)).zfill(2) + 'N'


if longitude < 0:
    longitude = abs(longitude)
    longitude = str(int(longitude)).zfill(3) + str(int(60*(longitude - int(longitude)))).zfill(2) + '.' + str(int(round(round(60*(longitude - int(longitude)),2)%1,2)*100)).zfill(2) + 'W'
else:
    longitude = str(int(longitude)).zfill(3) + str(int(60*(longitude - int(longitude)))).zfill(2) + '.' + str(int(round(round(60*(longitude - int(longitude)),2)%1,2)*100)).zfill(2) + 'E'

My coding is probably not pretty and there may be a way to do this more efficiently, but that would be above my knowledge of Python. I just broke it down and made it a puzzle to solve all the individual parts and then combine them for the final result. It works now! By the way I only code with Python 3. So if it doesn't work for you then I may have done something that doesn't work in Python 2.
« Last Edit: March 12, 2020, 10:31:26 AM by galfert »
Ecowitt GW1000 | Meteobridge on Raspberry Pi
WU: KFLWINTE111  |  PWSweather: KFLWINTE111
CWOP: FW3708  |  AWEKAS: 14814
Windy: pws-f075acbe
Weather Underground Issue Tracking
Tele-Pole

Offline danoh

  • AmbientCWOP.com
  • Contributor
  • ***
  • Posts: 103
    • AmbientCWOP
Thanks galfert, I'll give that code a try tomorrow.  Did you do the same for both lat and lon?
Ambient Weather station CWOP connector: AmbientCWOP.com

Offline galfert

  • Global Moderator
  • Forecaster
  • *****
  • Posts: 6822
Thanks galfert, I'll give that code a try tomorrow.  Did you do the same for both lat and lon?

I've updated my code above to include both Latitude and Longitude.
Ecowitt GW1000 | Meteobridge on Raspberry Pi
WU: KFLWINTE111  |  PWSweather: KFLWINTE111
CWOP: FW3708  |  AWEKAS: 14814
Windy: pws-f075acbe
Weather Underground Issue Tracking
Tele-Pole

Offline galfert

  • Global Moderator
  • Forecaster
  • *****
  • Posts: 6822
For anyone using this Latitude / Longitude code above, there is a rounding problem in certain circumstances. The code needs to be revised to fix this problem.

See here for details of the problem:
https://www.wxforum.net/index.php?topic=39019.msg402743#msg402743

Ecowitt GW1000 | Meteobridge on Raspberry Pi
WU: KFLWINTE111  |  PWSweather: KFLWINTE111
CWOP: FW3708  |  AWEKAS: 14814
Windy: pws-f075acbe
Weather Underground Issue Tracking
Tele-Pole