├── README.md ├── aprswx.py ├── credentials.py └── stations.py /README.md: -------------------------------------------------------------------------------- 1 | # aprswx - sending weather messages from aprs.fi to DAPNET 2 | ## What this is doing 3 | The script `aprswx.py` fetches wather information from aprs.fi on listed 4 | stations in `stations.py` and sends these into predefined rubrics in 5 | DAPNET to be published via POCSAG. 6 | ## Configuration 7 | Basic configuration is done in two files: 8 | ### Configuration of your credentials in `credentials.py` 9 | Fill the corresponding variables with your information: 10 | `#!/usr/bin/python` 11 | 12 | `# -*- coding: utf-8 -*-` 13 | 14 | `dapnetuser="YOURDAPNETWEB-USERNAME"` 15 | 16 | `dapnetpasswd="YOURDAPNETWEB-PASSWORD"` 17 | 18 | `aprsapikey="YOURAPRS.FI-APIKEY"` 19 | 20 | ### Configuration of the weather-stations in `stations.py` 21 | The weather-stations are configured by filling the infos into the 22 | configuration-array as given in the example. Here is the meaning of: 23 | * callsign: Callsign of the station in aprs.fi 24 | * qth: Location of the station 25 | * rubric: Rubric on DAPNET, to which the weather-message should be posted 26 | * slot: Number of the message-slot (between 1 to 10), on that the message should be placed 27 | * unit: Measurement scale for temperature: c means Celsius, f means Fahrenheit 28 | 29 | ## Installation in crontab 30 | To run the script periodically, it would be recommended to place it 31 | within your users crontab with `crontab -e`. Here you could use 32 | following line: 33 | 34 | ` */20 * * * * cd /path/to/aprswx.py && ./aprswx.py > /dev/null` 35 | 36 | This would send out the weather-messages 3 time an hour on 0, 37 | 20 and 40 minutes. 38 | ## Credits 39 | Credits goes to the DAPNET-team (see https://hampager.de), which 40 | provides a wonderful POCSAG-Network on amateur radio. 41 | 42 | Also credits are going to aprs.fi for providing the wx-data via it's API. 43 | 44 | ## Usage 45 | This software is for usage on amateur radio only! 73 de Kim DG9VH 46 | -------------------------------------------------------------------------------- /aprswx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import requests 5 | import datetime 6 | import time 7 | import sys 8 | from requests.auth import HTTPBasicAuth 9 | 10 | reload(sys) 11 | sys.setdefaultencoding('utf8') 12 | 13 | execfile("credentials.py") 14 | execfile("stations.py") 15 | 16 | debug = False 17 | try: 18 | if sys.argv[1] == "-d" or sys.argv[1] == "--d": 19 | debug = True 20 | except: 21 | pass 22 | 23 | target_area = "" 24 | 25 | try: 26 | if sys.argv[2] == "-t" or sys.argv[1] == "--target": 27 | target_area = "aprswx-"+sys.argv[3] 28 | except: 29 | pass 30 | 31 | print target_area 32 | 33 | def send_DAPNET(entry, station): 34 | # This function is for creating and sending messages to DAPNET 35 | # attention: Timestamp in aprs.fi is epoch! 36 | ts_epoch = float(entry["time"]) 37 | # so lets calculate and format in hhmm-format 38 | msgtime = datetime.datetime.fromtimestamp(ts_epoch).strftime('%H%M') 39 | msgtime_raw = datetime.datetime.fromtimestamp(ts_epoch) 40 | nowtime = datetime.datetime.now() 41 | difference = nowtime - msgtime_raw 42 | difference_days = difference.days 43 | if difference_days > 0: 44 | print "Message outdated for ", station["callsign"] 45 | return 46 | # now it's time for building up the message itself 47 | msg = msgtime + "z " + station["callsign"] + "/" + station["qth"] + ": " 48 | highwinds = False 49 | # WX-data in try-blocks, because not every WX-station delivers all data 50 | try: 51 | print station["unit"] 52 | if station["unit"] == "c": 53 | temperature = entry["temp"] + "C " 54 | msg+=temperature 55 | if station["unit"] == "f": 56 | temperature = float(entry["temp"]) 57 | fahrenheit = 9.0/5.0 * temperature + 32.0 58 | temperature = str(round(fahrenheit,1)) + "F " 59 | msg+=temperature 60 | except: 61 | pass 62 | 63 | try: 64 | if float(entry["wind_speed"]) == 0: 65 | wind = "w: no " 66 | else: 67 | wind = "w: " + entry["wind_speed"]+ "m/s=" + entry["wind_direction"] + "deg " 68 | msg+=wind 69 | if float(entry["wind_speed"]) > 10: 70 | highwinds = True 71 | msg += "high! " 72 | except: 73 | pass 74 | 75 | try: 76 | humidity = "h: " + entry["humidity"] + "% " 77 | msg+=humidity 78 | except: 79 | pass 80 | 81 | try: 82 | pressure = "hPa: " + entry["pressure"] + " " 83 | msg+=pressure 84 | except: 85 | pass 86 | 87 | try: 88 | rain = "r: " + entry["rain_1h"] + "mm/h" 89 | msg+=rain 90 | except: 91 | pass 92 | 93 | # preparing the post-message 94 | post={ "rubricName": station["rubric"], "text": msg[:80], "number": station["slot"] } 95 | print post , len(msg) 96 | if len(msg) > 80: 97 | print "Message too long!!!", station["callsign"] 98 | sendingtime = datetime.datetime.now().hour%4 99 | if debug: 100 | print "Debug mode ON" 101 | sendingtime = 0 102 | else: 103 | print "Debug mode OFF" 104 | if highwinds or 0 == sendingtime: 105 | # and sending it to DAPNET 106 | print "Sending to DAPNET" 107 | 108 | # resp = requests.post('https://hampager.de/api/news/', json=post, auth=HTTPBasicAuth(dapnetuser, dapnetpasswd)) 109 | resp = requests.post('http://44.149.166.27:8080/news/', json=post, auth=HTTPBasicAuth(dapnetuser, dapnetpasswd)) 110 | if resp.status_code != 201: 111 | print "Error at", station["callsign"] 112 | print('POST /news/ {}'.format(resp.status_code)) 113 | else: 114 | print "Message sent for ", station["callsign"] 115 | time.sleep(2) 116 | 117 | 118 | # let the party begin! 119 | stations_count = len(stations) 120 | querystring="" 121 | 122 | # the following has to be done for each WX-station in the list 123 | for i in range(0,stations_count): 124 | # due to query-rate-limits on aprs.fi and maximum of 20 stations per 125 | # query we have to work in portions 126 | if i > 0 and (i % 20) == 0: 127 | # fetching data from aprs.fi 128 | querystring=querystring[:-1] 129 | print "Query APRS.fi: " + querystring 130 | response = requests.get("https://api.aprs.fi/api/get?name="+querystring+"&what=wx&apikey="+aprsapikey+"&format=json") 131 | wx = json.loads(response.text) 132 | entries = (wx["entries"]) 133 | 134 | # lets do something good with the stuff we got 135 | for entry in entries: 136 | try: 137 | station = (item for item in stations if item["callsign"] == entry["name"]).next() 138 | # calling send-function above 139 | if target_area != "": 140 | if target_area == station["rubric"]: 141 | send_DAPNET(entry, station) 142 | else: 143 | send_DAPNET(entry, station) 144 | # time.sleep(5) 145 | except: 146 | print "No data from %s \n" %(entry["name"]) 147 | pass 148 | querystring = ""; 149 | querystring+=stations[i]["callsign"]+"," 150 | 151 | querystring=querystring[:-1] 152 | # now we have a few stations left to procede, so lets do the rest here, 153 | # same as above, as you see 154 | response = requests.get("https://api.aprs.fi/api/get?name="+querystring+"&what=wx&apikey="+aprsapikey+"&format=json") 155 | wx = json.loads(response.text) 156 | entries = (wx["entries"]) 157 | for entry in entries: 158 | try: 159 | station = (item for item in stations if item["callsign"] == entry["name"]).next() 160 | # send_DAPNET(entry, station) 161 | if target_area != "": 162 | if target_area == station["rubric"]: 163 | send_DAPNET(entry, station) 164 | else: 165 | send_DAPNET(entry, station) 166 | 167 | except: 168 | print "No data from %s \n" %(entry["name"]) 169 | pass 170 | -------------------------------------------------------------------------------- /credentials.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | dapnetuser="MYCALL" 4 | dapnetpasswd="MYDAPNETPASSWORD" 5 | aprsapikey="MYAPRSAPIKEY" 6 | -------------------------------------------------------------------------------- /stations.py: -------------------------------------------------------------------------------- 1 | stations = [ 2 | #hs-30 3 | {'callsign':'HS3LIQ-2','qth':'Nakhon Ratchasima','rubric':'aprswx-hs-30','slot':1,'unit':'c'}, 4 | #ct-pt-11 5 | {'callsign':'CR7AUX-13','qth':'Oeiras','rubric':'aprswx-ct-pt-11','slot':1,'unit':'c'}, 6 | #us-ca-ven 7 | {'callsign':'FW2594','qth':'Oak View','rubric':'aprswx-us-ca-ven','slot':1,'unit':'f'}, 8 | {'callsign':'EW1856','qth':'St. Susana','rubric':'aprswx-us-ca-ven','slot':2,'unit':'f'}, 9 | #us-ct-nhv 10 | {'callsign':'EW0704','qth':'Seymour','rubric':'aprswx-us-ct-nhv','slot':1,'unit':'f'}, 11 | #us-in-ham 12 | {'callsign':'NF9K-13','qth':'Noblesville','rubric':'aprswx-us-in-ham','slot':1,'unit':'f'}, 13 | #us-nc-gas 14 | {'callsign':'KN4MGS-13','qth':'Mt.Holly','rubric':'aprswx-us-nc-gas','slot':1,'unit':'f'}, 15 | #us-nc-ncc191 16 | {'callsign':'W4DNA','qth':'Goldsboro','rubric':'aprswx-us-nc-ncc191','slot':1,'unit':'f'}, 17 | #us-nj-con 18 | {'callsign':'DW3142','qth':'Loudon','rubric':'aprswx-us-nh-con','slot':1,'unit':'f'}, 19 | #us-nj-mid 20 | {'callsign':'KB2EAR-13','qth':'Kendall P.','rubric':'aprswx-us-nj-mid','slot':1,'unit':'f'}, 21 | #us-nj-mon 22 | {'callsign':'K2IE-13','qth':'Strathmore','rubric':'aprswx-us-nj-mon','slot':1,'unit':'f'}, 23 | #us-nv-nvc031 24 | {'callsign':'EW6551','qth':'Reno','rubric':'aprswx-us-nv-nvc031','slot':1,'unit':'f'}, 25 | #us-sc-sc 26 | {'callsign':'CW7235','qth':'Sumter','rubric':'aprswx-us-sc-sc','slot':1,'unit':'f'}, 27 | {'callsign':'EW9963','qth':'Cherryvale','rubric':'aprswx-us-sc-sc','slot':2,'unit':'f'}, 28 | {'callsign':'KK4F','qth':'Sumter','rubric':'aprswx-us-sc-sc','slot':3,'unit':'f'}, 29 | #us-va-vac059 30 | #us-va-vac199 31 | {'callsign':'DW3433','qth':'Yorktown','rubric':'aprswx-us-va-vac199','slot':1,'unit':'f'}, 32 | {'callsign':'NM4SH','qth':'Poquoson','rubric':'aprswx-us-va-vac199','slot':2,'unit':'f'}, 33 | {'callsign':'EW1731','qth':'Poquoson','rubric':'aprswx-us-va-vac199','slot':3,'unit':'f'}, 34 | {'callsign':'EW9762','qth':'East Hampton','rubric':'aprswx-us-va-vac199','slot':4,'unit':'f'}, 35 | {'callsign':'W4AWS','qth':'Gloucester Pt.','rubric':'aprswx-us-va-vac199','slot':5,'unit':'f'}, 36 | #us-va-vac735 37 | # Saarland 38 | {'callsign':'CW3322','qth':'Geislautern','rubric':'aprswx-dl-sl','slot':1,'unit':'c'}, 39 | {'callsign':'DC0VZ-6','qth':'Gersweiler','rubric':'aprswx-dl-sl','slot':2,'unit':'c'}, 40 | {'callsign':'DF5VL-5','qth':'Puettlingen','rubric':'aprswx-dl-sl','slot':3,'unit':'c'}, 41 | {'callsign':'EW9191','qth':'Neunkirchen','rubric':'aprswx-dl-sl','slot':4,'unit':'c'}, 42 | {'callsign':'CW8033','qth':'Illingen','rubric':'aprswx-dl-sl','slot':5,'unit':'c'}, 43 | {'callsign':'DO7VLR-5','qth':'Hangard','rubric':'aprswx-dl-sl','slot':6,'unit':'c'}, 44 | {'callsign':'DO2IO-13','qth':'Neunkirchen','rubric':'aprswx-dl-sl','slot':7,'unit':'c'}, 45 | # Rheinland-Pfalz 46 | {'callsign':'DH2PG-6','qth':'Oberpierscheid','rubric':'aprswx-dl-rp','slot':1,'unit':'c'}, 47 | {'callsign':'DB5WY-13','qth':'Pottum','rubric':'aprswx-dl-rp','slot':2,'unit':'c'}, 48 | {'callsign':'DH2PG-5','qth':'Koblenz','rubric':'aprswx-dl-rp','slot':3,'unit':'c'}, 49 | {'callsign':'DK5WB-6','qth':'Dannstadt','rubric':'aprswx-dl-rp','slot':4,'unit':'c'}, 50 | {'callsign':'EW4164','qth':'Bad Bergz.','rubric':'aprswx-dl-rp','slot':5,'unit':'c'}, 51 | # Nordrhein-Westfalen 52 | {'callsign':'DB0DBN-13','qth':'Koenigsw.','rubric':'aprswx-dl-nw','slot':1,'unit':'c'}, 53 | {'callsign':'DF2ET-13','qth':'Bochum','rubric':'aprswx-dl-nw','slot':2,'unit':'c'}, 54 | {'callsign':'DK4DAX-2','qth':'Koeln','rubric':'aprswx-dl-nw','slot':3,'unit':'c'}, 55 | {'callsign':'DB0SDA-2','qth':'Aachen','rubric':'aprswx-dl-nw','slot':4,'unit':'c'}, 56 | {'callsign':'DO5NE-1','qth':'Neuss','rubric':'aprswx-dl-nw','slot':5,'unit':'c'}, 57 | {'callsign':'EW5030','qth':'Dueren','rubric':'aprswx-dl-nw','slot':6,'unit':'c'}, 58 | {'callsign':'CW0539','qth':'Frechen','rubric':'aprswx-dl-nw','slot':7,'unit':'c'}, 59 | {'callsign':'DB0WML','qth':'Klein Reken','rubric':'aprswx-dl-nw','slot':8,'unit':'c'}, 60 | {'callsign':'DL5BQ-11','qth':'Herten','rubric':'aprswx-dl-nw','slot':9,'unit':'c'}, 61 | {'callsign':'DB0WXR','qth':'Recklinghsn.','rubric':'aprswx-dl-nw','slot':10,'unit':'c'}, 62 | # Hessen 63 | {'callsign':'EDDF','qth':'Frankfurt','rubric':'aprswx-dl-he','slot':1,'unit':'c'}, 64 | {'callsign':'EW0954','qth':'Bebra','rubric':'aprswx-dl-he','slot':2,'unit':'c'}, 65 | {'callsign':'DW8965','qth':'Cornberg','rubric':'aprswx-dl-he','slot':3,'unit':'c'}, 66 | {'callsign':'DB0PET-13','qth':'Fulda','rubric':'aprswx-dl-he','slot':4,'unit':'c'}, 67 | {'callsign':'DG3FBL-13','qth':'Moerfelden','rubric':'aprswx-dl-he','slot':5,'unit':'c'}, 68 | {'callsign':'DB0REI-10','qth':'Gruenberg','rubric':'aprswx-dl-he','slot':6,'unit':'c'}, 69 | {'callsign':'DB0XIN-6','qth':'Nauheim','rubric':'aprswx-dl-he','slot':7,'unit':'c'}, 70 | # Baden-Wuerttemberg 71 | {'callsign':'EW1423','qth':'Esslingen','rubric':'aprswx-dl-bw','slot':1,'unit':'c'}, 72 | {'callsign':'DL2GKM-6','qth':'Reutlingen','rubric':'aprswx-dl-bw','slot':2,'unit':'c'}, 73 | {'callsign':'DW5072','qth':'Bad Saeckingen','rubric':'aprswx-dl-bw','slot':3,'unit':'c'}, 74 | {'callsign':'DL1GFM-6','qth':'Koenigsfeld','rubric':'aprswx-dl-bw','slot':4,'unit':'c'}, 75 | {'callsign':'DW7013','qth':'Todtnau','rubric':'aprswx-dl-bw','slot':5,'unit':'c'}, 76 | {'callsign':'EW8122','qth':'Markdorf','rubric':'aprswx-dl-bw','slot':6,'unit':'c'}, 77 | {'callsign':'DG2GG-6','qth':'Hinterzarten','rubric':'aprswx-dl-bw','slot':7,'unit':'c'}, 78 | {'callsign':'CW3451','qth':'Regensdorf','rubric':'aprswx-dl-bw','slot':8,'unit':'c'}, 79 | {'callsign':'DB0LHR-6','qth':'Lahr','rubric':'aprswx-dl-bw','slot':9,'unit':'c'}, 80 | {'callsign':'D0852','qth':'Eningen u.A.','rubric':'aprswx-dl-bw','slot':10,'unit':'c'}, 81 | # Schleswig-Holstein 82 | {'callsign':'CW4548','qth':'Geestacht','rubric':'aprswx-dl-sh','slot':1,'unit':'c'}, 83 | {'callsign':'DC8LV','qth':'Itzehoe','rubric':'aprswx-dl-sh','slot':2,'unit':'c'}, 84 | {'callsign':'EW1131','qth':'Huettblek','rubric':'aprswx-dl-sh','slot':3,'unit':'c'}, 85 | {'callsign':'DD9LH-1','qth':'Wesseln','rubric':'aprswx-dl-sh','slot':4,'unit':'c'}, 86 | {'callsign':'DL8JF','qth':'Goeldenitz','rubric':'aprswx-dl-sh','slot':5,'unit':'c'}, 87 | {'callsign':'DB0HHN','qth':'Huettblek','rubric':'aprswx-dl-sh','slot':6,'unit':'c'}, 88 | {'callsign':'DJ3LE','qth':'Silberstedt','rubric':'aprswx-dl-sh','slot':7,'unit':'c'}, 89 | # Berlin 90 | {'callsign':'EW8282','qth':'Biesdorf','rubric':'aprswx-dl-be','slot':1,'unit':'c'}, 91 | {'callsign':'DM1AS-13','qth':'Berlin','rubric':'aprswx-dl-be','slot':2,'unit':'c'}, 92 | # Niedersachsen 93 | {'callsign':'EW9005','qth':'Laatzen','rubric':'aprswx-dl-ni','slot':1,'unit':'c'}, 94 | {'callsign':'DO1TBO-13','qth':'Osnabrueck','rubric':'aprswx-dl-ni','slot':2,'unit':'c'}, 95 | {'callsign':'DW4240','qth':'Ohrum','rubric':'aprswx-dl-ni','slot':3,'unit':'c'}, 96 | {'callsign':'DB0WAD-13','qth':'Wittingen','rubric':'aprswx-dl-ni','slot':4,'unit':'c'}, 97 | {'callsign':'DL6MM-4','qth':'Negenborn','rubric':'aprswx-dl-ni','slot':5,'unit':'c'}, 98 | {'callsign':'DB0USL-10','qth':'Uslar','rubric':'aprswx-dl-ni','slot':6,'unit':'c'}, 99 | # Meklenburg-Vorpommern 100 | {'callsign':'DL9GRB-6','qth':'Bad Doberan','rubric':'aprswx-dl-mv','slot':1,'unit':'c'}, 101 | {'callsign':'EW3693','qth':'Schwerin','rubric':'aprswx-dl-mv','slot':2,'unit':'c'}, 102 | # Sachsen 103 | {'callsign':'DH8TOM-3','qth':'Leipzig','rubric':'aprswx-dl-sn','slot':1,'unit':'c'}, 104 | {'callsign':'FW1711','qth':'Dresden','rubric':'aprswx-dl-sn','slot':2,'unit':'c'}, 105 | {'callsign':'DL1DUR-2','qth':'Zittau','rubric':'aprswx-dl-sn','slot':3,'unit':'c'}, 106 | # Bayern 107 | {'callsign':'DW1024','qth':'Neubiberg','rubric':'aprswx-dl-by','slot':1,'unit':'c'}, 108 | {'callsign':'DL3NBY','qth':'Gerach','rubric':'aprswx-dl-by','slot':2,'unit':'c'}, 109 | {'callsign':'DC3RJ-4','qth':'Nuernberg','rubric':'aprswx-dl-by','slot':3,'unit':'c'}, 110 | {'callsign':'DB0DAH-13','qth':'Altomuenster','rubric':'aprswx-dl-by','slot':4,'unit':'c'}, 111 | {'callsign':'DB7MJ-6','qth':'Sonthofen','rubric':'aprswx-dl-by','slot':5,'unit':'c'}, 112 | {'callsign':'DO7DH-5','qth':'Unterneukirchen','rubric':'aprswx-dl-by','slot':6,'unit':'c'}, 113 | # Thueringen 114 | {'callsign':'DL2AKT-13','qth':'Hohenf.','rubric':'aprswx-dl-th','slot':1,'unit':'c'}, 115 | {'callsign':'DW5049','qth':'Jena','rubric':'aprswx-dl-th','slot':2,'unit':'c'}, 116 | {'callsign':'DB0SBN','qth':'Wangenheim','rubric':'aprswx-dl-th','slot':3,'unit':'c'}, 117 | {'callsign':'DB0SLF','qth':'Arnsgereuth','rubric':'aprswx-dl-th','slot':4,'unit':'c'}, 118 | {'callsign':'DB0SBL','qth':'Gotha','rubric':'aprswx-dl-th','slot':5,'unit':'c'}, 119 | {'callsign':'DB0MGN-WX','qth':'Meiningen','rubric':'aprswx-dl-th','slot':6,'unit':'c'}, 120 | # Brandenburg 121 | {'callsign':'DM1RG-6','qth':'Luckenwalde','rubric':'aprswx-dl-bb','slot':1,'unit':'c'}, 122 | {'callsign':'DC7DOC','qth':'Potsdam','rubric':'aprswx-dl-bb','slot':2,'unit':'c'}, 123 | {'callsign':'DB0TA','qth':'Bernau','rubric':'aprswx-dl-bb','slot':3,'unit':'c'}, 124 | {'callsign':'DO5JWA-6','qth':'Zehdenick','rubric':'aprswx-dl-bb','slot':4,'unit':'c'}, 125 | {'callsign':'DB0LY-6','qth':'Lychen','rubric':'aprswx-dl-bb','slot':5,'unit':'c'}, 126 | {'callsign':'DL7AND-1','qth':'Berlin','rubric':'aprswx-dl-bb','slot':6,'unit':'c'}, 127 | {'callsign':'DH1BSK','qth':'Frankfurt/O','rubric':'aprswx-dl-bb','slot':7,'unit':'c'}, 128 | {'callsign':'DL2BWO-13','qth':'Bernau','rubric':'aprswx-dl-bb','slot':8,'unit':'c'}, 129 | {'callsign':'DM5RC','qth':'Cottbus','rubric':'aprswx-dl-bb','slot':9,'unit':'c'}, 130 | # Sachsen-Anhalt 131 | {'callsign':'FW2924','qth':'Dieskau','rubric':'aprswx-dl-st','slot':1,'unit':'c'}, 132 | {'callsign':'DM1AD-13','qth':'Magdeburg','rubric':'aprswx-dl-st','slot':2,'unit':'c'}, 133 | {'callsign':'DG0CCO-13','qth':'Tangerm.','rubric':'aprswx-dl-st','slot':3,'unit':'c'}, 134 | {'callsign':'DG0CDC-13','qth':'Stendal','rubric':'aprswx-dl-st','slot':4,'unit':'c'}, 135 | {'callsign':'DL8MYG','qth':'Colbitz','rubric':'aprswx-dl-st','slot':5,'unit':'c'}, 136 | {'callsign':'DM4JH-5','qth':'Dessau','rubric':'aprswx-dl-st','slot':6,'unit':'c'}, 137 | {'callsign':'DO1AA','qth':'Coswig','rubric':'aprswx-dl-st','slot':7,'unit':'c'}, 138 | # Bremen 139 | # Luxemburg 140 | {'callsign':'LX1US-WX','qth':'Mertzig','rubric':'aprswx-lx','slot':1,'unit':'c'}, 141 | {'callsign':'EW1663','qth':'Martelange','rubric':'aprswx-lx','slot':2,'unit':'c'}, 142 | {'callsign':'EX_ELLX','qth':'Luxembourg','rubric':'aprswx-lx','slot':3,'unit':'c'}, 143 | {'callsign':'EW5454','qth':'Remich','rubric':'aprswx-lx','slot':4,'unit':'c'}, 144 | {'callsign':'LX0WX-13','qth':'Groesteen','rubric':'aprswx-lx','slot':5,'unit':'c'}, 145 | {'callsign':'EW6950','qth':'Kehlen','rubric':'aprswx-lx','slot':6,'unit':'c'}, 146 | #Oesterreich 147 | #OE1 148 | {'callsign':'OE1HTB-13','qth':'Mauerbach','rubric':'aprswx-oe-oe1','slot':1,'unit':'c'}, 149 | {'callsign':'EW2609','qth':'Wien','rubric':'aprswx-oe-oe1','slot':2,'unit':'c'}, 150 | {'callsign':'OE3WYC-1','qth':'Wien','rubric':'aprswx-oe-oe1','slot':3,'unit':'c'}, 151 | {'callsign':'OE3BUB-10','qth':'Gerasdorf','rubric':'aprswx-oe-oe1','slot':4,'unit':'c'}, 152 | {'callsign':'DW4277','qth':'Leopoldsd.','rubric':'aprswx-oe-oe1','slot':5,'unit':'c'}, 153 | {'callsign':'DW3857','qth':'Moedling','rubric':'aprswx-oe-oe1','slot':6,'unit':'c'}, 154 | # {'callsign':'OE3ZK-13','qth':'Wien','rubric':'aprswx-oe-oe1','slot':7,'unit':'c'}, 155 | #OE2 156 | {'callsign':'OE2ATN','qth':'Leogang','rubric':'aprswx-oe-oe2','slot':1,'unit':'c'}, 157 | #OE3 158 | {'callsign':'OE3RGB-13','qth':'Heidenr.','rubric':'aprswx-oe-oe3','slot':1,'unit':'c'}, 159 | {'callsign':'OE3UKW','qth':'Schweinbarth','rubric':'aprswx-oe-oe3','slot':2,'unit':'c'}, 160 | {'callsign':'FW1957','qth':'Felixdorf','rubric':'aprswx-oe-oe3','slot':3,'unit':'c'}, 161 | {'callsign':'EW6786','qth':'JN77TX','rubric':'aprswx-oe-oe3','slot':4,'unit':'c'}, 162 | {'callsign':'OE3MNS-4','qth':'Judenau','rubric':'aprswx-oe-oe3','slot':5,'unit':'c'}, 163 | #OE4 164 | # {'callsign':'OE4CEN','qth':'Leogang','rubric':'aprswx-oe-oe4','slot':1,'unit':'c'}, 165 | #OE5 166 | {'callsign':'OE5XFR','qth':'Frauenmarkt','rubric':'aprswx-oe-oe5','slot':1,'unit':'c'}, 167 | {'callsign':'OE5RPP','qth':'St. Georgen','rubric':'aprswx-oe-oe5','slot':2,'unit':'c'}, 168 | #OE6 169 | {'callsign':'OE6XWG','qth':'Eggersdorf','rubric':'aprswx-oe-oe6','slot':1,'unit':'c'}, 170 | # 171 | {'callsign':'OE6CUD-6','qth':'Graz','rubric':'aprswx-oe-oe6','slot':2,'unit':'c'}, 172 | {'callsign':'OE6JWD-11','qth':'Graz-Umgb.','rubric':'aprswx-oe-oe6','slot':3,'unit':'c'}, 173 | {'callsign':'OE6SDG','qth':'GU Nord','rubric':'aprswx-oe-oe6','slot':4,'unit':'c'}, 174 | {'callsign':'EW7329','qth':'GU SuedWest','rubric':'aprswx-oe-oe6','slot':5,'unit':'c'}, 175 | {'callsign':'DW3361','qth':'SuedStmk','rubric':'aprswx-oe-oe6','slot':6,'unit':'c'}, 176 | # {'callsign':'OE6POD-11','qth':'Murtal','rubric':'aprswx-oe-oe6','slot':7,'unit':'c'}, 177 | # {'callsign':'EW1996','qth':'Ennstal-Sued','rubric':'aprswx-oe-oe6','slot':8,'unit':'c'}, 178 | #OE7 179 | {'callsign':'OE7XEI-13','qth':'Hall','rubric':'aprswx-oe-oe7','slot':1,'unit':'c'}, 180 | {'callsign':'OE7XKT','qth':'Kaltenbach','rubric':'aprswx-oe-oe7','slot':2,'unit':'c'}, 181 | {'callsign':'DW2619','qth':'Kirchbichl','rubric':'aprswx-oe-oe7','slot':3,'unit':'c'}, 182 | {'callsign':'DW5225','qth':'Patsch','rubric':'aprswx-oe-oe7','slot':4,'unit':'c'}, 183 | {'callsign':'OE7BSH-WX','qth':'Kitzbuehel','rubric':'aprswx-oe-oe7','slot':5,'unit':'c'}, 184 | {'callsign':'OE7SBH-WX','qth':'Kaltenbach','rubric':'aprswx-oe-oe7','slot':6,'unit':'c'}, 185 | {'callsign':'OE7MFI-13','qth':'St.Ulrich','rubric':'aprswx-oe-oe7','slot':7,'unit':'c'}, 186 | {'callsign':'OE7AOT','qth':'Hochfilzen','rubric':'aprswx-oe-oe7','slot':8,'unit':'c'}, 187 | #OE8 188 | {'callsign':'OE8LCK-13','qth':'Klagenfurt','rubric':'aprswx-oe-oe8','slot':1,'unit':'c'}, 189 | #OE9 190 | {'callsign':'OE9TFH-11','qth':'Brand','rubric':'aprswx-oe-oe9','slot':1,'unit':'c'}, 191 | {'callsign':'OE9XVI-6','qth':'Feldkirch','rubric':'aprswx-oe-oe9','slot':2,'unit':'c'}, 192 | {'callsign':'OE9XPT-6','qth':'Grabs','rubric':'aprswx-oe-oe9','slot':3,'unit':'c'}, 193 | {'callsign':'OE9FWV','qth':'Feldkirch','rubric':'aprswx-oe-oe9','slot':4,'unit':'c'}, 194 | #F-01 195 | 196 | #F-02 197 | {'callsign':'FM1HN','qth':'Le Gros-Morne','rubric':'aprswx-f-02','slot':1,'unit':'c'}, 198 | #F-03 199 | {'callsign':'BLFVP','qth':'St.-Georges','rubric':'aprswx-f-03','slot':1,'unit':'c'}, 200 | #F-04 201 | {'callsign':'FR5ZU','qth':'Salazie','rubric':'aprswx-f-04','slot':1,'unit':'c'}, 202 | {'callsign':'FW3203','qth':'Les Avirons','rubric':'aprswx-f-04','slot':2,'unit':'c'}, 203 | #F-06 204 | #F-11 205 | {'callsign':'CW1292','qth':'Clamart','rubric':'aprswx-f-11','slot':1,'unit':'c'}, 206 | {'callsign':'LFPG','qth':'Charles-de-Gaulle','rubric':'aprswx-f-11','slot':2,'unit':'c'}, 207 | {'callsign':'F6CNB-13','qth':'Saulx-l.-C.','rubric':'aprswx-f-11','slot':3,'unit':'c'}, 208 | {'callsign':'F5GSJ-13','qth':'Ozoir-la-F.','rubric':'aprswx-f-11','slot':4,'unit':'c'}, 209 | {'callsign':'F1HKX-13','qth':'Bailly-Carrois','rubric':'aprswx-f-11','slot':5,'unit':'c'}, 210 | #F-24 211 | {'callsign':'EW5775','qth':'Chartes-s.-C.','rubric':'aprswx-f-24','slot':1,'unit':'c'}, 212 | #F-27 213 | #F-28 214 | #F-32 215 | #F-44 216 | {'callsign':'EW3886','qth':'Walbourg','rubric':'aprswx-f-44','slot':1,'unit':'c'}, 217 | {'callsign':'FW2868','qth':'Metz','rubric':'aprswx-f-44','slot':2,'unit':'c'}, 218 | {'callsign':'F4EEH-13','qth':'Avrecourt','rubric':'aprswx-f-44','slot':3,'unit':'c'}, 219 | #F-52 220 | {'callsign':'EW2977','qth':'Plouharnel','rubric':'aprswx-f-52','slot':1,'unit':'c'}, 221 | {'callsign':'CW5839','qth':'Nanteuil','rubric':'aprswx-f-52','slot':2,'unit':'c'}, 222 | {'callsign':'DW7198','qth':'St-Maurice','rubric':'aprswx-f-52','slot':3,'unit':'c'}, 223 | {'callsign':'DW7784','qth':'Sille-le-G.','rubric':'aprswx-f-52','slot':4,'unit':'c'}, 224 | {'callsign':'DW1329','qth':'Vernantes','rubric':'aprswx-f-52','slot':5,'unit':'c'}, 225 | {'callsign':'DW6925','qth':'Damgan','rubric':'aprswx-f-52','slot':6,'unit':'c'}, 226 | {'callsign':'EW0490','qth':'St-Brev.l.P.','rubric':'aprswx-f-52','slot':7,'unit':'c'}, 227 | {'callsign':'FW0623','qth':'St-Gereon','rubric':'aprswx-f-52','slot':8,'unit':'c'}, 228 | {'callsign':'DW3787','qth':'Suce-sur-Erdre','rubric':'aprswx-f-52','slot':9,'unit':'c'}, 229 | #F-53 230 | #F-75 231 | #F-76 232 | #F-84 233 | #F-93 234 | #F-94 235 | #F-com 236 | #pa-lb 237 | {'callsign':'PE2KMV-10','qth':'Valkenburg','rubric':'aprswx-pa-lb','slot':1,'unit':'c'}, 238 | {'callsign':'CW6175','qth':'Kerkrade','rubric':'aprswx-pa-lb','slot':2,'unit':'c'}, 239 | #pa-gr 240 | {'callsign':'EW0051','qth':'Groningen','rubric':'aprswx-pa-gr','slot':1,'unit':'c'}, 241 | #pa-nh 242 | {'callsign':'CW0449','qth':'Amsterdam-N','rubric':'aprswx-pa-nh','slot':1,'unit':'c'}, 243 | #vk-nsw 244 | {'callsign':'FW4109','qth':'Moree','rubric':'aprswx-vk-nsw','slot':1,'unit':'c'}, 245 | {'callsign':'VK2AAK','qth':'Nabiac','rubric':'aprswx-vk-nsw','slot':2,'unit':'c'}, 246 | {'callsign':'CW8496','qth':'Orange','rubric':'aprswx-vk-nsw','slot':3,'unit':'c'}, 247 | #vk-nt 248 | {'callsign':'YPDN','qth':'Nightcliff','rubric':'aprswx-vk-nt','slot':1,'unit':'c'}, 249 | {'callsign':'FW3886','qth':'McMinns L.','rubric':'aprswx-vk-nt','slot':2,'unit':'c'}, 250 | {'callsign':'VK8ZKZ-1','qth':'PG66VH','rubric':'aprswx-vk-nt','slot':3,'unit':'c'}, 251 | #vk-qld 252 | {'callsign':'EW7672','qth':'Cairns','rubric':'aprswx-vk-qld','slot':1,'unit':'c'}, 253 | {'callsign':'DW2907','qth':'Merryvale','rubric':'aprswx-vk-qld','slot':2,'unit':'c'}, 254 | {'callsign':'VK4QM-13','qth':'Roma','rubric':'aprswx-vk-qld','slot':3,'unit':'c'}, 255 | #vk-sa 256 | {'callsign':'DW7913','qth':'Kingscote','rubric':'aprswx-vk-sa','slot':1,'unit':'c'}, 257 | {'callsign':'VK5TRM-13','qth':'Berri','rubric':'aprswx-vk-sa','slot':2,'unit':'c'}, 258 | {'callsign':'CW8216','qth':'Quorn','rubric':'aprswx-vk-sa','slot':3,'unit':'c'}, 259 | #vk-tas 260 | {'callsign':'VK7NDH-1','qth':'Burnie','rubric':'aprswx-vk-tas','slot':1,'unit':'c'}, 261 | {'callsign':'DW0841','qth':'Kingston','rubric':'aprswx-vk-tas','slot':2,'unit':'c'}, 262 | {'callsign':'EW1822','qth':'Launceston','rubric':'aprswx-vk-tas','slot':3,'unit':'c'}, 263 | #vk-vic 264 | {'callsign':'DW7779','qth':'Geelong West','rubric':'aprswx-vk-vic','slot':1,'unit':'c'}, 265 | {'callsign':'VK3XJB-1','qth':'Shepparton','rubric':'aprswx-vk-vic','slot':2,'unit':'c'}, 266 | {'callsign':'DW4311','qth':'Healesville','rubric':'aprswx-vk-vic','slot':3,'unit':'c'}, 267 | #vk-wa 268 | {'callsign':'DW8667','qth':'Two Rocks','rubric':'aprswx-vk-wa','slot':1,'unit':'c'}, 269 | {'callsign':'DW7333','qth':'Bridgetown','rubric':'aprswx-vk-wa','slot':2,'unit':'c'}, 270 | {'callsign':'CW6083','qth':'Tom Price','rubric':'aprswx-vk-wa','slot':3,'unit':'c'}, 271 | ] 272 | 273 | print stations 274 | --------------------------------------------------------------------------------