from RMParserFramework.rmParser import RMParser # Mandatory include for parser definition from RMUtilsFramework.rmLogging import log # Optional include for logging from RMUtilsFramework.rmTimeUtils import * from xml.etree import ElementTree as elementTree # Your parser needed libraries import math import json class AustraliaBOM(RMParser): parserName = "Australia Weather Bureau" parserDescription = "Commonwealth of Australia Bureau of Meteorology" # file schema described here http://www.bom.gov.au/schema/doc/AMOC_V1.pdf parserEnabled = True parserInterval = 3600 # Your parser running interval in seconds parserForecast = True parserHistorical = True parserDebug = True # Don't show extra debug messages longitude = None latitude = None defaultParams = {"Forecast Area": "Terrey Hills" , "State" : "NSW" } params = {"Forecast Area": "Terrey Hills" , "State" : "NSW" } # Internal params that can be changed with API call /parser/{id}/params def isEnabledForLocation(self, timezone, lat, long): return AustraliaBOM.parserEnabled def __getForecastURLForState(self, state): URL = None if self.parserDebug: log.debug("Got a state of %s" % state) if state == "QLD": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDQ11295.xml" elif state == "NSW": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDN11060.xml" elif state == "NT": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDD10207.xml" elif state == "SA": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDS10044.xml" elif state == "TAS": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDT16710.xml" elif state == "VIC": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDV10753.xml" elif state == "WA": URL = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDW14199.xml" return URL def __distanceBetween(self, origin, destination): """ Calculate the Haversine distance. Parameters ---------- origin : tuple of float (lat, long) destination : tuple of float (lat, long) Returns ------- distance_in_km : float Examples -------- >>> origin = (48.1372, 11.5756) # Munich >>> destination = (52.5186, 13.4083) # Berlin >>> round(distance(origin, destination), 1) 504.2 """ lat1, lon1 = origin lat2, lon2 = destination radius = 6371 # km dlat = math.radians(lat2 - lat1) dlon = math.radians(lon2 - lon1) a = (math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2) * math.sin(dlon / 2)) c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) d = radius * c return d def __getNearestWMO(self, lat, lon): # From here: http://www.bom.gov.au/climate/data/stations/ # filtered on files that are available, and ones that have temp and rain # Sites with air temp ftp://ftp.bom.gov.au/anon2/home/ncc/metadata/lists_by_element/alpha/alphaAUS_3.txt # Sites with rain ftp://ftp.bom.gov.au/anon2/home/ncc/metadata/lists_by_element/alpha/alphaAUS_139.txt # Some sites don't have files. I removed them (list has historical sites that no longer produce data) wmo_locations = { ("ADELAIDE (KENT TOWN)", -34.921100, 138.621600, "SA", 94675), ("ADELAIDE (WEST TERRACE / NGAYIRDAPIRA)", -34.925700, 138.583200, "SA", 94648), ("ADELAIDE AIRPORT", -34.952400, 138.519600, "SA", 94672), ("AIREYS INLET", -38.458300, 144.088300, "VIC", 94846), ("ALBANY AIRPORT", -34.941100, 117.815800, "WA", 94802), ("ALBANY", -35.028900, 117.880800, "WA", 94801), ("ALBION PARK (SHELLHARBOUR AIRPORT)", -34.563800, 150.790000, "NSW", 95748), ("ALBURY AIRPORT AWS", -36.069000, 146.950900, "NSW", 95896), ("ALI CURUNG", -21.002500, 134.402900, "NT", 94325), ("ALICE SPRINGS AIRPORT", -23.795100, 133.889000, "NT", 94326), ("ALVA BEACH", -19.456900, 147.483300, "QLD", 95296), ("AMBERLEY AMO", -27.629700, 152.711100, "QLD", 94568), ("ANDAMOOKA", -30.449000, 137.169200, "SA", 95660), ("APPLETHORPE", -28.621700, 151.953300, "QLD", 94553), ("ARARAT PRISON", -37.276900, 142.978600, "VIC", 94834), ("ARCHERFIELD AIRPORT", -27.571600, 153.007100, "QLD", 94575), ("ARGYLE AERODROME", -16.638000, 128.451600, "WA", 94217), ("ARKAROOLA", -30.311000, 139.335700, "SA", 94676), ("ARLTUNGA", -23.456400, 134.684900, "NT", 95323), ("ARMIDALE (TREE GROUP NURSERY)", -30.524300, 151.671600, "NSW", 94773), ("ARMIDALE AIRPORT AWS", -30.527300, 151.615800, "NSW", 95773), ("AVALON AIRPORT", -38.028800, 144.478300, "VIC", 94854), ("AYR DPI RESEARCH STN", -19.616900, 147.375800, "QLD", 95295), ("BADGERYS CREEK AWS", -33.896900, 150.728100, "NSW", 94752), ("BADGINGARRA RESEARCH STN", -30.338100, 115.539400, "WA", 94603), ("BAIRNSDALE AIRPORT", -37.881800, 147.566900, "VIC", 94912), ("BALGO HILLS", -20.141700, 127.986700, "WA", 94320), ("BALLADONIA", -32.456900, 123.865300, "WA", 94642), ("BALLARAT AERODROME", -37.512700, 143.791100, "VIC", 94852), ("BALLERA GAS FIELD", -27.400800, 141.811400, "QLD", 95487), ("BALLINA AIRPORT AWS", -28.835300, 153.558500, "NSW", 94596), ("BALRANALD (RSL)", -34.639800, 143.561000, "NSW", 94696), ("BANKSTOWN AIRPORT AWS", -33.917600, 150.983700, "NSW", 94765), ("BARCALDINE POST OFFICE", -23.554400, 145.288300, "QLD", 94350), ("BARRABA (CLIFTON LANE)", -30.383300, 150.608300, "NSW", 94761), ("BARROW ISLAND AIRPORT", -20.874000, 115.406600, "WA", 95304), ("BATCHELOR AIRPORT", -13.054400, 131.025200, "NT", 94125), ("BATEMANS BAY (CATALINA COUNTRY CLUB)", -35.723400, 150.187200, "NSW", 94941), ("BATHURST AGRICULTURAL STATION", -33.428800, 149.555900, "NSW", 94730), ("BATHURST AIRPORT AWS", -33.411900, 149.654000, "NSW", 94729), ("BEAUDESERT DRUMLEY STREET", -27.970700, 152.989800, "QLD", 95575), ("BEDOURIE", -24.359700, 139.471400, "QLD", 94334), ("BEDOUT ISLAND", -19.589400, 119.100000, "WA", 94310), ("BEERBURRUM FOREST STATION", -26.958600, 152.961900, "QLD", 95566), ("BEGA AWS", -36.672200, 149.819100, "NSW", 95931), ("BELLAMBI AWS", -34.369100, 150.929100, "NSW", 94749), ("BENCUBBIN", -30.808100, 117.860300, "WA", 94632), ("BENDIGO AIRPORT", -36.741100, 144.327500, "VIC", 94855), ("BEVERLEY", -32.108300, 116.924700, "WA", 95615), ("BICHENO (COUNCIL DEPOT)", -41.873900, 148.303600, "TAS", 95989), ("BICKLEY", -32.007200, 116.136900, "WA", 95610), ("BIDYADANGA", -18.684400, 121.780300, "WA", 94202), ("BIRDSVILLE AIRPORT", -25.897500, 139.347200, "QLD", 95482), ("BLACK POINT", -11.153800, 132.143000, "NT", 94134), ("BLACKALL AIRPORT", -24.430300, 145.430600, "QLD", 95351), ("BLACKWATER AIRPORT", -23.601500, 148.807400, "QLD", 94398), ("BOLLON MARY ST", -28.033100, 147.479500, "QLD", 94513), ("BOMBALA (THERRY STREET)", -36.911300, 149.237900, "NSW", 94928), ("BOMBALA AWS", -37.001600, 149.233600, "NSW", 94929), ("BORROLOOLA AIRPORT", -16.075500, 136.304100, "NT", 94152), ("BOULIA AIRPORT", -22.911700, 139.903900, "QLD", 94333), ("BOURKE AIRPORT AWS", -30.036200, 145.952100, "NSW", 94703), ("BOWEN AIRPORT AWS", -20.015400, 148.213800, "QLD", 94383), ("BRADSHAW - ANGALLARI VALLEY (DEFENCE)", -15.439700, 130.573100, "NT", 94221), ("BRADSHAW - KOOLENDONG VALLEY (DEFENCE)", -15.185300, 130.116900, "NT", 94222), ("BRADSHAW", -14.940800, 130.809100, "NT", 94130), ("BRAIDWOOD RACECOURSE AWS", -35.425300, 149.783500, "NSW", 94927), ("BREAKWATER (GEELONG RACECOURSE)", -38.173700, 144.376500, "VIC", 94857), ("BREWARRINA HOSPITAL", -29.961400, 146.865100, "NSW", 95512), ("BRIDGETOWN", -33.948600, 116.131100, "WA", 95632), ("BRISBANE AERO", -27.391700, 153.129200, "QLD", 94578), ("BRISBANE", -27.480800, 153.038900, "QLD", 94576), ("BROKEN HILL (PATTON STREET)", -31.975900, 141.467600, "NSW", 94689), ("BROKEN HILL AIRPORT AWS", -32.001200, 141.469400, "NSW", 94691), ("BROOKTON", -32.372800, 117.008600, "WA", 94625), ("BROOME AIRPORT", -17.947500, 122.235200, "WA", 94203), ("BROWSE ISLAND", -14.109300, 123.547600, "WA", 94103), ("BRUNETTE DOWNS", -18.637000, 135.945000, "NT", 94242), ("BULGA DOWNS", -28.496700, 119.743600, "WA", 94444), ("BULMAN", -13.671500, 134.341500, "NT", 94143), ("BUNBURY", -33.356700, 115.644700, "WA", 94604), ("BUNDABERG AERO", -24.906900, 152.323000, "QLD", 94387), ("BUNDOORA (LATROBE UNIVERSITY)", -37.716300, 145.045300, "VIC", 95873), ("BURKETOWN AIRPORT", -17.748300, 139.535600, "QLD", 94260), ("BURNIE (ROUND HILL)", -41.066100, 145.943100, "TAS", 94958), ("BURRINJUCK DAM", -34.999700, 148.598400, "NSW", 94909), ("BUSHY PARK (BUSHY PARK ESTATES)", -42.709700, 146.898300, "TAS", 94964), ("BUSSELTON AERO", -33.681800, 115.402600, "WA", 95611), ("BUTLERS GORGE", -42.275300, 146.275800, "TAS", 94959), ("BYRON BAY (CAPE BYRON AWS)", -28.639900, 153.635800, "NSW", 94599), ("CABRAMURRA SMHEA AWS", -35.937100, 148.377900, "NSW", 95916), ("CAIRNS AERO", -16.873600, 145.745800, "QLD", 94287), ("CAIRNS RACECOURSE", -16.946300, 145.747400, "QLD", 94288), ("CAMDEN AIRPORT AWS", -34.039000, 150.689000, "NSW", 94755), ("CAMOOWEAL TOWNSHIP", -19.922500, 138.121400, "QLD", 94255), ("CAMPANIA (KINCORA)", -42.686700, 147.425800, "TAS", 95972), ("CAMPBELLTOWN (MOUNT ANNAN)", -34.061500, 150.773500, "NSW", 94757), ("CANBERRA AIRPORT", -35.308800, 149.200400, "NSW", 94926), ("CANTERBURY RACECOURSE AWS", -33.905700, 151.113400, "NSW", 94766), ("CANUNGRA (DEFENCE)", -28.043700, 153.187100, "QLD", 94418), ("CAPE BORDA", -35.754900, 136.595900, "SA", 95805), ("CAPE BRUNY (CAPE BRUNY)", -43.488600, 147.144400, "TAS", 95967), ("CAPE BRUNY LIGHTHOUSE", -43.489200, 147.145300, "TAS", 94967), ("CAPE FLATTERY", -14.967200, 145.310600, "QLD", 94188), ("CAPE GRIM", -40.676400, 144.692200, "TAS", 95954), ("CAPE JAFFA (THE LIMESTONE)", -36.965500, 139.716400, "SA", 94813), ("CAPE LEEUWIN", -34.372800, 115.135800, "WA", 94601), ("CAPE MORETON LIGHTHOUSE", -27.031400, 153.466100, "QLD", 94594), ("CAPE NATURALISTE", -33.537200, 115.018900, "WA", 94600), ("CAPE NELSON LIGHTHOUSE", -38.430600, 141.543700, "VIC", 94826), ("CAPE OTWAY LIGHTHOUSE", -38.855600, 143.512800, "VIC", 94842), ("CAPE SORELL", -42.198600, 145.170000, "TAS", 94974), ("CAPE WESSEL", -11.004700, 136.758600, "NT", 94147), ("CAPE WILLOUGHBY", -35.842600, 138.132700, "SA", 94822), ("CARDWELL MARINE PDE", -18.254400, 146.019200, "QLD", 94292), ("CARNAMAH", -29.688600, 115.887200, "WA", 94415), ("CARNARVON AIRPORT", -24.887800, 113.670000, "WA", 94300), ("CARNEGIE", -25.796400, 122.975300, "WA", 94451), ("CARTERS BORE", -20.935800, 139.296400, "QLD", 94347), ("CASINO AIRPORT AWS", -28.882400, 153.061800, "NSW", 94573), ("CASTERTON", -37.583100, 141.334000, "VIC", 95825), ("CASTLEMAINE PRISON", -37.080900, 144.239100, "VIC", 95853), ("CEDUNA AMO", -32.129700, 133.697600, "SA", 94653), ("CENTRAL ARNHEM PLATEAU", -13.327500, 133.086100, "NT", 94141), ("CENTRE ISLAND", -15.742600, 136.819200, "NT", 94248), ("CENTURY MINE", -18.756900, 138.705600, "QLD", 94261), ("CERBERUS", -38.364600, 145.178500, "VIC", 94898), ("CESSNOCK AIRPORT AWS", -32.788600, 151.337700, "NSW", 95771), ("CHANNEL POINT", -13.167200, 130.122600, "NT", 94121), ("CHARLES POINT", -12.389500, 130.630600, "NT", 99510), ("CHARLEVILLE AERO", -26.413900, 146.255800, "QLD", 94510), ("CHARLTON", -36.284600, 143.334100, "VIC", 94839), ("CHARTERS TOWERS AIRPORT", -20.046400, 146.270800, "QLD", 94356), ("CHRISTMAS ISLAND AERO", -10.452800, 105.687500, "WA", 96995), ("CLARE HIGH SCHOOL", -33.822600, 138.593300, "SA", 95667), ("CLERMONT AIRPORT", -22.775600, 147.621700, "QLD", 94395), ("CLEVE AERODROME", -33.708100, 136.502600, "SA", 94662), ("CLEVE", -33.701100, 136.493700, "SA", 94661), ("CLONCURRY AIRPORT", -20.666400, 140.505000, "QLD", 94335), ("COBAR AIRPORT AWS", -31.538800, 145.796400, "NSW", 94710), ("COBAR MO", -31.484000, 145.829400, "NSW", 94711), ("COCONUT ISLAND", -10.051100, 143.068600, "QLD", 94182), ("COCOS ISLAND AIRPORT", -12.189200, 96.834400, "WA", 96996), ("COEN AIRPORT", -13.760600, 143.118300, "QLD", 94183), ("COFFIN BAY (POINT AVOID)", -34.675000, 135.336200, "SA", 95649), ("COFFS HARBOUR AIRPORT", -30.318900, 153.116200, "NSW", 95729), ("COLAC (MOUNT GELLIBRAND)", -38.233300, 143.792500, "VIC", 95845), ("COLDSTREAM", -37.723900, 145.409200, "VIC", 94864), ("COLLARENEBRI (ALBERT ST)", -29.540600, 148.581700, "NSW", 95520), ("COLLIE EAST", -33.360800, 116.171700, "WA", 95621), ("COLLINSVILLE POST OFFICE", -20.553300, 147.846400, "QLD", 94360), ("COMBIENBAR AWS", -37.341600, 149.022700, "VIC", 94914), ("CONDOBOLIN AIRPORT AWS", -33.068200, 147.213300, "NSW", 95708), ("COOBER PEDY AIRPORT", -29.034700, 134.722200, "SA", 95458), ("COOKTOWN AIRPORT", -15.446100, 145.186100, "QLD", 95283), ("COOLANGATTA", -28.168100, 153.505300, "QLD", 94592), ("COOMA AIRPORT AWS", -36.293900, 148.972500, "NSW", 94921), ("COOMA VISITORS CENTRE", -36.231800, 149.124300, "NSW", 94923), ("COONABARABRAN (SHOWGROUNDS)", -31.278600, 149.278600, "NSW", 94728), ("COONABARABRAN AIRPORT AWS", -31.333000, 149.269900, "NSW", 95728), ("COONAMBLE AIRPORT AWS", -30.977600, 148.379800, "NSW", 95718), ("COONAWARRA", -37.290600, 140.825400, "SA", 94817), ("COORANBONG (LAKE MACQUARIE AWS)", -33.088700, 151.463600, "NSW", 95767), ("COOTAMUNDRA AIRPORT", -34.629900, 148.036500, "NSW", 94714), ("CORNER INLET (YANAKIE)", -38.805100, 146.193600, "VIC", 94911), ("COROWA AIRPORT", -35.988700, 146.357400, "NSW", 95895), ("CORRIGIN", -32.329200, 117.873300, "WA", 94633), ("CORRYONG AIRPORT", -36.182600, 147.894200, "VIC", 94899), ("COWLEY BEACH (DEFENCE)", -17.690500, 146.112600, "QLD", 99218), ("COWRA AIRPORT AWS", -33.838200, 148.654000, "NSW", 95721), ("CRANBOURNE BOTANIC GARDENS", -38.134800, 145.263700, "VIC", 94879), ("CREAL REEF", -20.530300, 150.377300, "QLD", 94371), ("CRESSY RESEARCH STATION", -41.725600, 147.079400, "TAS", 95969), ("CROKER ISLAND AIRPORT", -11.162900, 132.481300, "NT", 94108), ("CULTANA (DEFENCE)", -32.684500, 137.368900, "SA", 95683), ("CUMMINS AERO", -34.252400, 135.713500, "SA", 95663), ("CUNDERDIN AIRFIELD", -31.621900, 117.221700, "WA", 95625), ("CUNNAMULLA POST OFFICE", -28.068900, 145.682200, "QLD", 94500), ("CURTIN AERO", -17.576800, 123.829700, "WA", 94204), ("CURTIN SPRINGS", -25.313900, 131.757100, "NT", 94463), ("CYGNET BAY", -16.451300, 123.008700, "WA", 94201), ("DALBY AIRPORT", -27.160500, 151.263400, "QLD", 94542), ("DALWALLINU", -30.276100, 116.671400, "WA", 95629), ("DALY WATERS AIRSTRIP", -16.263700, 133.378200, "NT", 94234), ("DARTMOOR", -37.922200, 141.261400, "VIC", 95822), ("DARTMOUTH RESERVOIR", -36.535300, 147.498400, "VIC", 94888), ("DARWIN AIRPORT", -12.423900, 130.892500, "NT", 94120), ("DELAMERE WEAPONS RANGE", -15.744100, 131.918100, "NT", 94225), ("DENHAM", -25.926500, 113.532500, "WA", 94402), ("DENILIQUIN AIRPORT AWS", -35.557500, 144.945800, "NSW", 95869), ("DENNES POINT", -43.063900, 147.356700, "TAS", 94988), ("DERBY AERO", -17.370600, 123.661100, "WA", 95205), ("DEVONPORT AIRPORT", -41.170100, 146.428900, "TAS", 95960), ("DONNYBROOK", -33.571900, 115.824700, "WA", 95622), ("DOONGAN", -15.379700, 126.311400, "WA", 94215), ("DORRIGO (OLD CORAMBA RD)", -30.344400, 152.718700, "NSW", 94789), ("DOUBLE ISLAND POINT LIGHTHOUSE", -25.931900, 153.190600, "QLD", 94584), ("DOUGLAS RIVER RESEARCH FARM", -13.834500, 131.187200, "NT", 94128), ("DOVER", -43.333000, 146.998000, "TAS", 94961), ("DUBBO AIRPORT AWS", -32.220600, 148.575300, "NSW", 95719), ("DUM IN MIRRIE AIRSTRIP", -12.635000, 130.372500, "NT", 94116), ("DUNALLEY (STROUD POINT)", -42.901700, 147.789400, "TAS", 94951), ("DUNEDOO POST OFFICE", -32.016500, 149.395600, "NSW", 95727), ("DWELLINGUP", -32.710300, 116.059400, "WA", 94620), ("EAST SALE AIRPORT", -38.101700, 147.139900, "VIC", 95907), ("ECHUCA AERODROME", -36.164700, 144.764200, "VIC", 94861), ("EDENHOPE AIRPORT", -37.022200, 141.265700, "VIC", 95832), ("EDI UPPER", -36.739600, 146.467100, "VIC", 95838), ("EDINBURGH RAAF", -34.711100, 138.622200, "SA", 95676), ("EDITHBURGH", -35.112100, 137.739500, "SA", 94809), ("EILDON FIRE TOWER", -37.209100, 145.842300, "VIC", 94881), ("ELLIOTT", -17.555200, 133.543900, "NT", 94236), ("ELLISTON", -33.650100, 134.888000, "SA", 94656), ("EMERALD AIRPORT", -23.569400, 148.175600, "QLD", 94363), ("EMU CREEK STATION", -23.031400, 115.041400, "WA", 94318), ("ENEABBA", -29.818300, 115.272200, "WA", 94414), ("ERNABELLA (PUKATJA)", -26.263500, 132.177100, "SA", 94474), ("ESPERANCE AERO", -33.682500, 121.827500, "WA", 95638), ("ESPERANCE", -33.830000, 121.892500, "WA", 94638), ("ESSENDON AIRPORT", -37.727600, 144.906600, "VIC", 95866), ("EUABALONG (MOUNT HOPE AWS)", -32.826100, 145.880100, "NSW", 95682), ("EUCLA", -31.679700, 128.895800, "WA", 94647), ("EUDUNDA", -34.175400, 139.084700, "SA", 94680), ("EVANS HEAD RAAF BOMBING RANGE AWS", -29.183000, 153.396400, "NSW", 94598), ("EYRE", -32.246400, 126.300800, "WA", 94645), ("FALLS CREEK", -36.870800, 147.275500, "VIC", 94903), ("FERNY CREEK", -37.874800, 145.349600, "VIC", 94872), ("FINGAL (LEGGE STREET)", -41.642800, 147.966400, "TAS", 95974), ("FITZROY CROSSING AERO", -18.181400, 125.561900, "WA", 94206), ("FLINDERS ISLAND AIRPORT", -40.091100, 148.002400, "TAS", 94980), ("FORBES AIRPORT AWS", -33.362700, 147.920500, "NSW", 94715), ("FORREST", -30.845300, 128.109200, "WA", 95646), ("FORSTER - TUNCURRY MARINE RESCUE", -32.175600, 152.508900, "NSW", 95778), ("FOWLERS GAP AWS", -31.086300, 141.700800, "NSW", 94686), ("FRIENDLY BEACHES", -41.995300, 148.279400, "TAS", 94987), ("GABO ISLAND LIGHTHOUSE", -37.567900, 149.915800, "VIC", 94933), ("GARDEN ISLAND HSF", -32.243300, 115.683900, "WA", 95607), ("GASCOYNE JUNCTION", -25.054400, 115.210000, "WA", 94410), ("GAYNDAH AIRPORT", -25.616700, 151.615600, "QLD", 95543), ("GEEVESTON (CEMETERY ROAD)", -43.164700, 146.917500, "TAS", 94966), ("GELANTIPY", -37.220000, 148.262600, "VIC", 94913), ("GEORGETOWN AIRPORT", -18.303900, 143.530600, "QLD", 94274), ("GERALDTON AIRPORT", -28.804700, 114.698900, "WA", 94403), ("GILES METEOROLOGICAL OFFICE", -25.034100, 128.301000, "WA", 94461), ("GINGIN AERO", -31.462800, 115.864200, "WA", 95612), ("GIRILAMBONE (OKEH) AWS", -31.082400, 146.929600, "NSW", 94794), ("GLADSTONE AIRPORT", -23.869700, 151.221400, "QLD", 94381), ("GLADSTONE RADAR", -23.855300, 151.262800, "QLD", 94380), ("GLEN INNES AIRPORT AWS", -29.678000, 151.694000, "NSW", 94588), ("GLUEPOT RESERVE (GLUEPOT)", -33.762200, 140.125100, "SA", 95668), ("GOLD COAST SEAWAY", -27.939000, 153.428300, "QLD", 94580), ("GOOMALLING", -31.299400, 116.826900, "WA", 95631), ("GOONDIWINDI AIRPORT", -28.521100, 150.325600, "QLD", 94530), ("GOSFORD AWS", -33.435100, 151.361400, "NSW", 94782), ("GOSNELLS CITY", -32.048100, 115.984400, "WA", 95604), ("GOULBURN AIRPORT AWS", -34.808500, 149.731100, "NSW", 95716), ("GOULBURN TAFE", -34.749500, 149.703400, "NSW", 94716), ("GOVE AIRPORT", -12.274100, 136.820100, "NT", 94150), ("GRAFTON AIRPORT AWS", -29.758300, 153.029700, "NSW", 95570), ("GRAFTON RESEARCH STN", -29.622400, 152.960500, "NSW", 95571), ("GRAMPIANS (MOUNT WILLIAM)", -37.295000, 142.603900, "VIC", 94833), ("GREEN CAPE AWS", -37.262200, 150.050400, "NSW", 94934), ("GREENBANK (DEFENCE)", -27.693200, 152.993500, "QLD", 94419), ("GRENFELL (MANGANESE RD)", -33.893400, 148.152300, "NSW", 94725), ("GRIFFITH AIRPORT AWS", -34.248700, 146.069500, "NSW", 95704), ("GROOTE EYLANDT AIRPORT", -13.974600, 136.463000, "NT", 94153), ("GROVE (RESEARCH STATION)", -42.985800, 147.074200, "TAS", 95977), ("GULGONG POST OFFICE", -32.363400, 149.532900, "NSW", 94732), ("GUNDAGAI (NANGUS RD)", -35.064000, 148.098600, "NSW", 94890), ("GUNNEDAH AIRPORT AWS", -30.953700, 150.249400, "NSW", 95740), ("GUYRA HOSPITAL", -30.212200, 151.679400, "NSW", 94772), ("GYMPIE", -26.183100, 152.641400, "QLD", 94566), ("HALLS CREEK AIRPORT", -18.233700, 127.666600, "WA", 94212), ("HAMILTON AIRPORT", -37.648600, 142.063600, "VIC", 94829), ("HAMILTON ISLAND AIRPORT", -20.365800, 148.953600, "QLD", 94368), ("HARTZ MOUNTAIN (KEOGHS PIMPLE)", -43.200600, 146.768300, "TAS", 94977), ("HAWKER", -31.904300, 138.438800, "SA", 94673), ("HAY AIRPORT AWS", -34.541200, 144.834500, "NSW", 94702), ("HERON ISLAND RES STN", -23.441700, 151.912500, "QLD", 94386), ("HERVEY BAY AIRPORT", -25.322000, 152.881700, "QLD", 95565), ("HIGH RANGE AWS (WANGANDERRY)", -34.333500, 150.267000, "NSW", 99742), ("HILLSTON AIRPORT", -33.491500, 145.524800, "NSW", 94700), ("HINDMARSH ISLAND AWS", -35.519400, 138.817700, "SA", 94677), ("HOBART (ELLERSLIE ROAD)", -42.889700, 147.327800, "TAS", 94970), ("HOBART AIRPORT", -42.833900, 147.503300, "TAS", 94975), ("HOGAN ISLAND", -39.222500, 146.984100, "TAS", 94949), ("HOLSWORTHY AERODROME AWS", -33.992500, 150.948900, "NSW", 95761), ("HOLSWORTHY DEFENCE AWS", -34.081000, 150.900900, "NSW", 95684), ("HOPETOUN AIRPORT", -35.715100, 142.356900, "VIC", 94838), ("HOPETOUN NORTH", -33.930600, 120.128300, "WA", 95635), ("HORN ISLAND", -10.584400, 142.290000, "QLD", 94174), ("HORSHAM AERODROME", -36.669700, 142.173100, "VIC", 95839), ("HORSLEY PARK EQUESTRIAN CENTRE AWS", -33.851000, 150.856700, "NSW", 94760), ("HUGHENDEN AIRPORT", -20.819200, 144.233300, "QLD", 94343), ("HUME RESERVOIR", -36.103900, 147.032900, "NSW", 94901), ("HUNTERS HILL", -36.213600, 147.539400, "VIC", 94878), ("HYDEN", -32.441900, 118.898300, "WA", 95627), ("INGHAM COMPOSITE", -18.649400, 146.176900, "QLD", 95291), ("INJUNE POST OFFICE", -25.842800, 148.566900, "QLD", 94511), ("INNISFAIL AERODROME", -17.558100, 146.011900, "QLD", 94280), ("INNISFAIL", -17.524900, 146.034500, "QLD", 94291), ("INVERELL (RAGLAN ST)", -29.779600, 151.112100, "NSW", 95541), ("INVERELL RESEARCH CENTRE", -29.775200, 151.082000, "NSW", 94541), ("ISISFORD POST OFFICE", -24.259100, 144.440600, "QLD", 94345), ("IVANHOE AERODROME AWS", -32.883300, 144.309200, "NSW", 95697), ("JABIRU AIRPORT", -12.659200, 132.894000, "NT", 94137), ("JACUP", -33.887800, 119.109200, "WA", 95636), ("JANDAKOT AERO", -32.101100, 115.879400, "WA", 94609), ("JARRAHWOOD", -33.796400, 115.665800, "WA", 95623), ("JERVIS BAY (POINT PERPENDICULAR AWS)", -35.093600, 150.804900, "NSW", 95940), ("JERVIS BAY NSW (JERVIS BAY AIRFIELD AWS)", -35.144000, 150.697400, "NSW", 94751), ("JERVOIS", -22.949400, 136.144200, "NT", 94327), ("JULIA CREEK AIRPORT", -20.667200, 141.721400, "QLD", 94337), ("JURIEN BAY", -30.308100, 115.031100, "WA", 95600), ("KADINA AWS", -33.970300, 137.662800, "SA", 94685), ("KALBARRI", -27.711900, 114.165000, "WA", 94401), ("KALGOORLIE-BOULDER AIRPORT", -30.784700, 121.453300, "WA", 94637), ("KALUMBURU", -14.296400, 126.645300, "WA", 94100), ("KANAGULK", -37.116900, 141.803100, "VIC", 95827), ("KANGAROO FLATS (DEFENCE)", -12.793400, 130.854200, "NT", 94161), ("KAPOOKA (DEFENCE)", -35.132700, 147.251200, "NSW", 94944), ("KARIJINI NORTH", -22.299900, 118.449800, "WA", 94330), ("KARNET", -32.438900, 116.078900, "WA", 95614), ("KAROONDA", -35.090000, 139.897200, "SA", 95813), ("KARRATHA AERO", -20.709700, 116.774200, "WA", 95307), ("KATANNING", -33.685600, 117.606400, "WA", 94641), ("KATHERINE COUNTRY CLUB", -14.472800, 132.261200, "NT", 94132), ("KATOOMBA (FARNELLS RD)", -33.713900, 150.295300, "NSW", 94744), ("KEITH (MUNKORA)", -36.105800, 140.327300, "SA", 95815), ("KEITH", -36.098000, 140.355600, "SA", 94816), ("KELLALAC (WARRACKNABEAL AIRPORT)", -36.320400, 142.416100, "VIC", 94920), ("KELLERBERRIN", -31.618300, 117.721700, "WA", 95603), ("KEMPSEY AIRPORT AWS", -31.071100, 152.771700, "NSW", 94785), ("KERANG", -35.723600, 143.919600, "VIC", 94844), ("KHANCOBAN AWS", -36.230400, 148.140500, "NSW", 94919), ("KIAMA (BOMBO HEADLAND)", -34.653200, 150.860900, "NSW", 95749), ("KIMBA", -33.141600, 136.412600, "SA", 94668), ("KING ISLAND AIRPORT", -39.880400, 143.885700, "TAS", 94850), ("KINGAROY AIRPORT", -26.573700, 151.839800, "QLD", 94549), ("KINGSCOTE AERO", -35.711400, 137.523100, "SA", 95807), ("KOWANYAMA AIRPORT", -15.481800, 141.748300, "QLD", 94268), ("KUITPO FOREST RESERVE", -35.171200, 138.678300, "SA", 94683), ("KULGERA", -25.842800, 133.302700, "NT", 94466), ("KUNANYI (MOUNT WELLINGTON PINNACLE)", -42.895000, 147.235800, "TAS", 95979), ("KUNUNURRA AERO", -15.781400, 128.710000, "WA", 94216), ("KYABRAM", -36.335000, 145.063800, "VIC", 95833), ("KYANCUTTA", -33.133700, 135.552100, "SA", 94657), ("LADY ELLIOT ISLAND", -24.111600, 152.716100, "QLD", 94388), ("LAJAMANU AIRPORT", -18.332400, 130.636100, "NT", 94231), ("LAKE CARGELLIGO AIRPORT", -33.283200, 146.370600, "NSW", 95707), ("LAKE EILDON", -37.231300, 145.912400, "VIC", 94882), ("LAKE GRACE", -33.100600, 118.464700, "WA", 95637), ("LAKE JULIUS AWS", -20.116700, 139.725600, "QLD", 94348), ("LAKE LEAKE (ELIZABETH RIVER)", -42.006700, 147.797500, "TAS", 94979), ("LAKE ST CLAIR NATIONAL PARK", -42.117800, 146.177200, "TAS", 94976), ("LAKE VICTORIA STORAGE", -34.043800, 141.267600, "NSW", 94692), ("LAKES ENTRANCE (EASTERN BEACH ROAD)", -37.871700, 148.006000, "VIC", 95904), ("LAMEROO (AUSTIN PLAINS)", -35.377800, 140.537800, "SA", 94690), ("LANCELIN (DEFENCE)", -30.839200, 115.228300, "WA", 95609), ("LANCELIN", -31.016000, 115.332200, "WA", 95606), ("LARAPUNA (EDDYSTONE POINT)", -40.992800, 148.346700, "TAS", 94983), ("LARRIMAH", -15.574800, 133.213700, "NT", 94237), ("LAUNCESTON (TI TREE BEND)", -41.419400, 147.121900, "TAS", 94969), ("LAUNCESTON AIRPORT", -41.547600, 147.215600, "TAS", 95966), ("LAVERTON AERO", -28.613300, 122.423600, "WA", 94449), ("LAVERTON RAAF", -37.856500, 144.756600, "VIC", 94865), ("LEARMONTH AIRPORT", -22.240600, 114.096700, "WA", 94302), ("LEIGH CREEK AIRPORT", -30.596300, 138.421900, "SA", 94674), ("LEINSTER AERO", -27.838600, 120.703100, "WA", 95448), ("LEONORA AERO", -28.878900, 121.318600, "WA", 94450), ("LIAWENEE", -41.899700, 146.669400, "TAS", 95959), ("LIGHTNING RIDGE VISITOR INFORMATION CENT", -29.431000, 147.972200, "NSW", 94498), ("LISMORE AIRPORT AWS", -28.830500, 153.260100, "NSW", 94572), ("LITHGOW (COOERWULL)", -33.476900, 150.130300, "NSW", 94741), ("LITTLE BAY (THE COAST GOLF CLUB)", -33.982900, 151.250200, "NSW", 94780), ("LOCHINGTON", -23.942400, 147.525000, "QLD", 94399), ("LOCKHART RIVER AIRPORT", -12.785000, 143.304700, "QLD", 94186), ("LOGAN CITY WATER TREATMENT PLANT", -27.683900, 153.194700, "QLD", 95581), ("LONGERENONG", -36.672200, 142.299100, "VIC", 95835), ("LONGREACH AERO", -23.439700, 144.282800, "QLD", 94346), ("LORD HOWE ISLAND AERO", -31.542100, 159.078600, "NSW", 94995), ("LOSTOCK DAM", -32.332200, 151.459500, "NSW", 95772), ("LOW HEAD", -41.054700, 146.787400, "TAS", 95964), ("LOW ISLES LIGHTHOUSE", -16.384200, 145.559200, "QLD", 94285), ("LOW ROCKY POINT", -42.983100, 145.502500, "TAS", 95961), ("LOXTON RESEARCH CENTRE", -34.439000, 140.597800, "SA", 94682), ("LUCINDA POINT", -18.520300, 146.386100, "QLD", 94295), ("LUNCHEON HILL (FORESTRY)", -41.149200, 145.151700, "TAS", 95956), ("MAATSUYKER ISLAND LIGHTHOUSE", -43.657800, 146.271100, "TAS", 94962), ("MACKAY AERO", -21.170600, 149.179400, "QLD", 95367), ("MACKAY M.O", -21.117200, 149.216900, "QLD", 94367), ("MAITLAND AIRPORT AWS", -32.702300, 151.488100, "NSW", 94650), ("MAITLAND", -34.374500, 137.673300, "SA", 94665), ("MALENY TAMARIND ST", -26.752800, 152.851900, "QLD", 94547), ("MALLACOOTA", -37.597600, 149.728900, "VIC", 94935), ("MANDORA", -19.741900, 120.843300, "WA", 94200), ("MANDURAH", -32.521900, 115.711900, "WA", 94605), ("MANGALORE AIRPORT", -36.888600, 145.185900, "VIC", 94874), ("MANGO FARM", -13.737900, 130.683400, "NT", 94117), ("MANGROVE MOUNTAIN AWS", -33.289400, 151.210700, "NSW", 95774), ("MANINGRIDA AIRPORT", -12.056900, 134.233900, "NT", 95142), ("MANJIMUP", -34.250800, 116.145000, "WA", 94617), ("MARBLE BAR", -21.175600, 119.749700, "WA", 95317), ("MARDIE", -21.190600, 115.979700, "WA", 94306), ("MAREEBA AIRPORT", -17.070400, 145.429300, "QLD", 95286), ("MARIA ISLAND (POINT LESUEUR)", -42.662100, 148.017900, "TAS", 95988), ("MARRANGAROO (DEFENCE)", -33.434600, 150.135000, "NSW", 95686), ("MARRAWAH", -40.908900, 144.709400, "TAS", 94950), ("MARREE AERO", -29.658700, 138.068400, "SA", 95480), ("MARYBOROUGH", -25.513200, 152.715200, "QLD", 94567), ("MARYBOROUGH", -37.056000, 143.732000, "VIC", 94849), ("MAYDENA POST OFFICE", -42.756700, 146.623900, "TAS", 94963), ("MCARTHUR RIVER MINE AIRPORT", -16.442300, 136.076000, "NT", 94239), ("MCCLUER ISLAND", -11.046800, 132.979100, "NT", 94135), ("MEDINA RESEARCH CENTRE", -32.220800, 115.807500, "WA", 95608), ("MEEKATHARRA AIRPORT", -26.613600, 118.537200, "WA", 94430), ("MELBOURNE (OLYMPIC PARK)", -37.825500, 144.981600, "VIC", 95936), ("MELBOURNE AIRPORT", -37.665500, 144.832100, "VIC", 94866), ("MELTON MOWBRAY (NORTH STOCKMAN)", -42.492800, 147.198100, "TAS", 94971), ("MENINDEE POST OFFICE", -32.393700, 142.417300, "NSW", 94694), ("MENINGIE", -35.690200, 139.337500, "SA", 95814), ("MERIMBULA AIRPORT AWS", -36.907700, 149.898900, "NSW", 95929), ("MERREDIN", -31.475600, 118.278900, "WA", 95624), ("MERRIWA (ROSCOMMON)", -32.185200, 150.173700, "NSW", 95754), ("MIDDLE PERCY ISLAND", -21.662800, 150.271100, "QLD", 94372), ("MIDDLE POINT", -12.605000, 131.298800, "NT", 95121), ("MILDURA AIRPORT", -34.235800, 142.086700, "VIC", 94693), ("MILES CONSTANCE STREET", -26.656900, 150.181900, "QLD", 95529), ("MILINGIMBI AIRPORT", -12.093200, 134.891900, "NT", 94140), ("MILLENDON (SWAN VALLEY)", -31.810800, 116.022500, "WA", 94795), ("MINLATON AERO", -34.748000, 137.527600, "SA", 95659), ("MINNIPA PIRSA", -32.842700, 135.151500, "SA", 95662), ("MITCHELL POST OFFICE", -26.488800, 147.977700, "QLD", 94514), ("MONTAGUE ISLAND LIGHTHOUSE", -36.251900, 150.227500, "NSW", 94939), ("MONTO TOWNSHIP", -24.864200, 151.124700, "QLD", 94377), ("MOOMBA AIRPORT", -28.099700, 140.195600, "SA", 95481), ("MOORABBIN AIRPORT", -37.980000, 145.096200, "VIC", 94870), ("MORANBAH AIRPORT", -22.064400, 148.075800, "QLD", 94397), ("MORAWA AIRPORT", -29.203900, 116.024700, "WA", 94417), ("MOREE AERO", -29.489800, 149.847100, "NSW", 95527), ("MORNINGTON ISLAND AIRPORT", -16.662000, 139.165500, "QLD", 94254), ("MORTLAKE RACECOURSE", -38.073700, 142.774400, "VIC", 94840), ("MORUYA AIRPORT AWS", -35.900400, 150.143700, "NSW", 95937), ("MORUYA HEADS PILOT STATION", -35.909300, 150.153200, "NSW", 94937), ("MORWELL (LATROBE VALLEY AIRPORT)", -38.209400, 146.474600, "VIC", 94891), ("MOSS VALE AWS", -34.525300, 150.421700, "NSW", 94746), ("MOUNT BARKER", -34.625000, 117.636100, "WA", 94630), ("MOUNT BARKER", -35.073200, 138.846600, "SA", 94806), ("MOUNT BAW BAW", -37.838400, 146.274700, "VIC", 95901), ("MOUNT BOYCE AWS", -33.618500, 150.274100, "NSW", 94743), ("MOUNT BULLER", -37.145000, 146.439400, "VIC", 94894), ("MOUNT BUNDEY NORTH (DEFENCE)", -12.914100, 131.866300, "NT", 94162), ("MOUNT BUNDEY SOUTH (DEFENCE)", -13.088900, 131.847800, "NT", 94112), ("MOUNT CRAWFORD AWS", -34.725300, 138.927800, "SA", 94678), ("MOUNT ELIZABETH", -16.418100, 126.102500, "WA", 94211), ("MOUNT GAMBIER AERO", -37.747300, 140.773900, "SA", 94821), ("MOUNT GININI AWS", -35.529300, 148.772100, "NSW", 95925), ("MOUNT HOTHAM", -36.977200, 147.134200, "VIC", 94906), ("MOUNT ISA AERO", -20.677800, 139.487500, "QLD", 94332), ("MOUNT IVE", -32.439800, 136.067100, "SA", 94660), ("MOUNT LOFTY", -34.978400, 138.708800, "SA", 95678), ("MOUNT MAGNET AERO", -28.115600, 117.842500, "WA", 94429), ("MOUNT MOORNAPA", -37.748100, 147.142800, "VIC", 95913), ("MOUNT NOWA NOWA", -37.692400, 148.090800, "VIC", 94930), ("MOUNT READ", -41.844400, 145.541700, "TAS", 95952), ("MOUNT STUART (DEFENCE)", -19.408200, 146.762000, "QLD", 94272), ("MUDGEE AIRPORT AWS", -32.562800, 149.614900, "NSW", 94727), ("MULLEWA", -28.536700, 115.514200, "WA", 94411), ("MULURULU AWS", -33.339200, 143.400000, "NSW", 94797), ("MUNGINDI POST OFFICE", -28.978600, 148.989900, "NSW", 94520), ("MUNGLINUP WEST", -33.554700, 120.699700, "WA", 95644), ("MURCHISON", -26.895600, 115.956700, "WA", 94422), ("MURGANELLA AIRSTRIP", -11.548500, 132.926600, "NT", 94109), ("MURRAY BRIDGE (PALLAMANA AERODROME)", -35.065000, 139.227300, "SA", 95818), ("MURRAY BRIDGE", -35.123400, 139.259200, "SA", 95812), ("MURRURUNDI (HAYDON STREET)", -31.767800, 150.841800, "NSW", 94758), ("MURRURUNDI GAP AWS", -31.741600, 150.793700, "NSW", 95747), ("MURWILLUMBAH (BRAY PARK)", -28.339500, 153.380900, "NSW", 94582), ("NAMBOUR DAFF - HILLSIDE", -26.644200, 152.938300, "QLD", 95572), ("NARACOORTE AERODROME", -36.981300, 140.727000, "SA", 94820), ("NAREMBEEN", -32.065600, 118.395600, "WA", 95626), ("NAROOMA (MARINE RESCUE)", -36.214400, 150.135800, "NSW", 95935), ("NARRABRI AIRPORT AWS", -30.315400, 149.830200, "NSW", 95734), ("NARRANDERA AIRPORT AWS", -34.705000, 146.514000, "NSW", 95706), ("NARROGIN", -32.934200, 117.179700, "WA", 94627), ("NELSON BAY (NELSON HEAD)", -32.710300, 152.161200, "NSW", 95779), ("NEPTUNE ISLAND", -35.336500, 136.117400, "SA", 94804), ("NERRIGA AWS", -35.110300, 150.082600, "NSW", 94943), ("NEW MAY DOWNS", -20.590000, 139.341100, "QLD", 94349), ("NEWCASTLE NOBBYS SIGNAL STATION AWS", -32.918400, 151.798500, "NSW", 94774), ("NEWCASTLE UNIVERSITY", -32.890600, 151.706800, "NSW", 94781), ("NEWDEGATE RESEARCH STATION", -33.112900, 118.840000, "WA", 94628), ("NEWMAN AERO", -23.416700, 119.799200, "WA", 94317), ("NGAYAWILI", -11.997100, 135.572600, "NT", 95146), ("NGUKURR AIRPORT", -14.723600, 134.745600, "NT", 94106), ("NHILL AERODROME", -36.309200, 141.648600, "VIC", 94827), ("NILMA NORTH (WARRAGUL)", -38.132100, 145.986500, "VIC", 99806), ("NOARLUNGA", -35.158600, 138.505700, "SA", 94808), ("NOONA AWS", -31.726700, 144.931300, "NSW", 94798), ("NOONAMAH AIRSTRIP", -12.609900, 131.047400, "NT", 94105), ("NORAH HEAD AWS", -33.281400, 151.576600, "NSW", 95770), ("NORFOLK ISLAND AERO", -29.038900, 167.940800, "NSW", 94996), ("NORMANTON AIRPORT", -17.687200, 141.073300, "QLD", 94266), ("NORSEMAN AERO", -32.214700, 121.754700, "WA", 95642), ("NORTH ISLAND", -28.300900, 113.593700, "WA", 94405), ("NORTH SHIELDS (PORT LINCOLN AWS)", -34.599300, 135.878400, "SA", 95661), ("NORTH WALPOLE", -34.946900, 116.722200, "WA", 95647), ("NORTHAM", -31.650800, 116.658600, "WA", 94621), ("NOWRA RAN AIR STATION AWS", -34.946900, 150.535300, "NSW", 94750), ("NULLARBOR", -31.449200, 130.897600, "SA", 94651), ("NULLO MOUNTAIN AWS", -32.724400, 150.229000, "NSW", 94754), ("NURIOOTPA PIRSA", -34.476100, 139.005600, "SA", 94681), ("NYNGAN AIRPORT", -31.549500, 147.196100, "NSW", 94708), ("OAKEY AERO", -27.403400, 151.741300, "QLD", 94552), ("OBERON (ALBION ST)", -33.699300, 149.867000, "NSW", 95735), ("OENPELLI AIRPORT", -12.327200, 133.006900, "NT", 94110), ("OMEO", -37.101700, 147.600800, "VIC", 94908), ("ONGERUP", -33.963400, 118.478800, "WA", 95628), ("ONSLOW AIRPORT", -21.668900, 115.109200, "WA", 95305), ("OODNADATTA AIRPORT", -27.555300, 135.445600, "SA", 94476), ("OORALEA RACECOURSE (MACKAY TURF CLUB)", -21.170000, 149.151500, "QLD", 94352), ("ORANGE AGRICULTURAL INSTITUTE", -33.321100, 149.082800, "NSW", 95725), ("ORANGE AIRPORT AWS", -33.376800, 149.126300, "NSW", 95726), ("ORBOST", -37.692200, 148.466700, "VIC", 95918), ("ORFORD (AUBIN COURT)", -42.551900, 147.875300, "TAS", 95984), ("OUSE FIRE STATION", -42.484200, 146.710600, "TAS", 94957), ("OUYEN (POST OFFICE)", -35.068200, 142.312500, "VIC", 94831), ("PADTHAWAY SOUTH", -36.653900, 140.521200, "SA", 95823), ("PALMERVILLE", -15.999900, 144.075400, "QLD", 94276), ("PAPUNYA", -23.204400, 131.915600, "NT", 94322), ("PARABURDOO AERO", -23.172600, 117.749300, "WA", 94316), ("PARAFIELD AIRPORT", -34.797700, 138.628100, "SA", 95677), ("PARAWA (SECOND VALLEY FOREST AWS)", -35.569500, 138.286400, "SA", 94811), ("PARDOO STATION", -20.107800, 119.581100, "WA", 94311), ("PARKES AIRPORT AWS", -33.128100, 148.242800, "NSW", 95717), ("PARNDANA CFS AWS", -35.791600, 137.249600, "SA", 94807), ("PARRAMATTA NORTH (MASONS DRIVE)", -33.791700, 151.018100, "NSW", 94764), ("PATERSON (TOCAL AWS)", -32.629600, 151.591900, "NSW", 94775), ("PAYNES FIND", -29.270800, 117.683600, "WA", 94404), ("PEAK HILL POST OFFICE", -32.723500, 148.190200, "NSW", 94721), ("PEARCE RAAF", -31.666900, 116.018900, "WA", 94612), ("PEMBERTON", -34.447800, 116.043300, "WA", 95613), ("PENRITH LAKES AWS", -33.719500, 150.678300, "NSW", 94763), ("PERISHER VALLEY AWS", -36.406900, 148.405500, "NSW", 94915), ("PERTH AIRPORT", -31.927500, 115.976400, "WA", 94610), ("PERTH METRO", -31.919200, 115.872800, "WA", 94608), ("PHILLIP ISLAND PENGUIN RESERVE", -38.505800, 145.150300, "VIC", 94883), ("PINDARI DAM", -29.389900, 151.244800, "NSW", 94544), ("PINGELLY", -32.533600, 117.083100, "WA", 95616), ("PIRLANGIMPI AIRPORT", -11.402100, 130.421700, "NT", 94119), ("POINT FAWCETT", -11.762800, 130.030000, "NT", 94122), ("POINT HICKS (LIGHTHOUSE)", -37.801700, 149.274700, "VIC", 94932), ("POINT LOOKOUT", -27.436100, 153.545600, "QLD", 94593), ("POINT STUART", -12.240300, 131.878500, "NT", 94127), ("POONCARIE MAIL AGENCY", -33.385600, 142.569600, "NSW", 95692), ("PORT AUGUSTA AERO", -32.507300, 137.716900, "SA", 95666), ("PORT FAIRY AWS", -38.390600, 142.234700, "VIC", 94830), ("PORT HEDLAND AIRPORT", -20.372500, 118.631700, "WA", 94312), ("PORT KEATS AIRPORT", -14.249400, 129.528200, "NT", 95111), ("PORT MACQUARIE AIRPORT AWS", -31.433500, 152.865500, "NSW", 94786), ("PORT PIRIE AERODROME AWS", -33.237100, 137.997100, "SA", 99749), ("PORTLAND (CASHMORE AIRPORT)", -38.314800, 141.470500, "VIC", 94828), ("POUND CREEK", -38.629700, 145.810700, "VIC", 94886), ("PRICE", -34.297100, 138.001400, "SA", 95669), ("PROSERPINE AIRPORT", -20.492500, 148.555000, "QLD", 94365), ("PROSPECT RESERVOIR", -33.819300, 150.912700, "NSW", 94736), ("PUCKAPUNYAL LYON HILL (DEFENCE)", -36.938100, 145.053900, "VIC", 94858), ("PUCKAPUNYAL WEST (DEFENCE)", -37.017700, 144.854600, "VIC", 94856), ("PYRENEES (BEN NEVIS)", -37.228100, 143.200600, "VIC", 94835), ("QUIRINDI POST OFFICE", -31.508600, 150.679300, "NSW", 95746), ("RABBIT FLAT", -20.182300, 130.014800, "NT", 95322), ("RAINBOW BEACH", -25.900700, 153.089100, "QLD", 94564), ("RAVENSTHORPE", -33.580300, 120.045800, "WA", 94636), ("RED ROCKS POINT", -32.202800, 127.529700, "WA", 94644), ("REDCLIFFE", -27.216900, 153.092200, "QLD", 95591), ("REDESDALE", -37.019400, 144.520300, "VIC", 94859), ("REDLAND (ALEXANDRA HILLS)", -27.543300, 153.239400, "QLD", 94561), ("RENMARK AERO", -34.198300, 140.676600, "SA", 95687), ("RHYLL", -38.461200, 145.310100, "VIC", 94892), ("RICHMOND AIRPORT", -20.701700, 143.116700, "QLD", 94341), ("RICHMOND RAAF", -33.600400, 150.776100, "NSW", 95753), ("ROBE AIRFIELD", -37.177600, 139.805400, "SA", 95816), ("ROCKHAMPTON AERO", -23.375300, 150.477500, "QLD", 94374), ("ROCKY GULLY", -34.571400, 117.010600, "WA", 94631), ("ROEBOURNE AERO", -20.759400, 117.158300, "WA", 94308), ("ROLLESTON AIRPORT", -24.461700, 148.626400, "QLD", 94396), ("ROMA AIRPORT", -26.547700, 148.771000, "QLD", 94515), ("ROSEDALE (TURRETFIELD RESEARCH CENTRE)", -34.551900, 138.834200, "SA", 95674), ("ROSEWORTHY AWS", -34.510600, 138.676300, "SA", 95671), ("ROSS (THE BOULEVARDS)", -42.025000, 147.495300, "TAS", 94985), ("ROTTNEST ISLAND", -32.006900, 115.502200, "WA", 94602), ("ROXBY DOWNS (OLYMPIC DAM AERODROME)", -30.482900, 136.877200, "SA", 95658), ("RUTHERGLEN RESEARCH", -36.104800, 146.509400, "VIC", 95837), ("SALMON GUMS RES.STN.", -32.986900, 121.623900, "WA", 95639), ("SAMUEL HILL AERO", -22.743300, 150.657800, "QLD", 94370), ("SANDY CAPE LIGHTHOUSE", -24.729700, 153.208300, "QLD", 94390), ("SCHERGER RAAF", -12.616700, 142.086900, "QLD", 94171), ("SCONE AIRPORT AWS", -32.033500, 150.826400, "NSW", 95758), ("SCONE SCS", -32.063200, 150.927100, "NSW", 94738), ("SCORESBY RESEARCH INSTITUTE", -37.871000, 145.256100, "VIC", 95867), ("SCOTTS PEAK DAM", -43.042500, 146.272200, "TAS", 95958), ("SCOTTSDALE (WEST MINSTONE ROAD)", -41.170800, 147.488300, "TAS", 94972), ("SEVENTEEN SEVENTY", -24.156800, 151.888900, "QLD", 94384), ("SHANNON", -34.568300, 116.336700, "WA", 95617), ("SHARK BAY AIRPORT", -25.892500, 113.577200, "WA", 95402), ("SHEFFIELD SCHOOL FARM", -41.388600, 146.321900, "TAS", 94955), ("SHEOAKS", -37.907500, 144.130300, "VIC", 94863), ("SHEPPARTON AIRPORT", -36.428800, 145.394900, "VIC", 94875), ("SINGLETON DEFENCE AWS", -32.697600, 151.156400, "NSW", 99738), ("SINGLETON STP", -32.590200, 151.174300, "NSW", 94733), ("SMITHTON AERODROME", -40.834700, 145.084700, "TAS", 94953), ("SMITHVILLE AWS", -30.069200, 141.006700, "NSW", 94796), ("SNOWTOWN (RAYVILLE PARK)", -33.767600, 138.218200, "SA", 95670), ("SOUTH CHANNEL ISLAND", -38.306500, 144.801600, "VIC", 94853), ("SOUTH JOHNSTONE EXP STN", -17.605300, 145.997200, "QLD", 95292), ("SOUTH WEST ROCKS (SMOKY CAPE LIGHTHOUSE)", -30.922500, 153.087100, "NSW", 94790), ("SOUTHERN CROSS AIRFIELD", -31.235300, 119.356400, "WA", 95634), ("SPRINGSURE COMET ST", -24.123000, 148.085600, "QLD", 95362), ("SPRINGWOOD (VALLEY HEIGHTS)", -33.706500, 150.584800, "NSW", 95744), ("ST GEORGE AIRPORT", -28.048900, 148.594200, "QLD", 94517), ("ST HELENS AERODROME", -41.338100, 148.279200, "TAS", 95981), ("ST LAWRENCE", -22.347200, 149.524200, "QLD", 95369), ("STANTHORPE LESLIE PARADE", -28.661700, 151.933900, "QLD", 94550), ("STAWELL AERODROME", -37.072000, 142.740200, "VIC", 94836), ("STENHOUSE BAY", -35.279500, 136.939200, "SA", 95806), ("STRAHAN AERODROME", -42.155000, 145.290800, "TAS", 94956), ("STRATHALBYN RACECOURSE", -35.283600, 138.893400, "SA", 94814), ("STRATHBOGIE", -36.847200, 145.730800, "VIC", 95843), ("STRATHGORDON VILLAGE", -42.768100, 146.046100, "TAS", 95953), ("STREAKY BAY", -32.808400, 134.197900, "SA", 94654), ("SUNSHINE COAST AIRPORT", -26.599000, 153.091200, "QLD", 94569), ("SURAT", -27.159100, 149.070200, "QLD", 94521), ("SWAN HILL AERODROME", -35.376600, 143.541600, "VIC", 94843), ("SWAN ISLAND", -40.729200, 148.125000, "TAS", 95985), ("SWANBOURNE", -31.955800, 115.761900, "WA", 94614), ("SWANSEA (FRANCIS STREET)", -42.138100, 148.073600, "TAS", 94981), ("SWEERS ISLAND", -17.114200, 139.598100, "QLD", 94257), ("SYDNEY (OBSERVATORY HILL)", -33.860700, 151.205000, "NSW", 94768), ("SYDNEY AIRPORT AMO", -33.946500, 151.173100, "NSW", 94767), ("SYDNEY OLYMPIC PARK AWS (ARCHERY CENTRE)", -33.833800, 151.071800, "NSW", 95765), ("TABULAM (MUIRNE)", -28.755100, 152.450700, "NSW", 94587), ("TAMBO POST OFFICE", -24.881900, 146.256400, "QLD", 94355), ("TAMWORTH AIRPORT AWS", -31.074200, 150.836200, "NSW", 95762), ("TARALGA POST OFFICE", -34.404800, 149.819700, "NSW", 94735), ("TARCOOLA AERO", -30.705100, 134.578600, "SA", 94655), ("TAREE AIRPORT AWS", -31.889500, 152.512000, "NSW", 95784), ("TAROOM POST OFFICE", -25.640800, 149.795800, "QLD", 94525), ("TASMAN ISLAND", -43.239700, 148.002500, "TAS", 95986), ("TATURA INST SUSTAINABLE AG", -36.437800, 145.267200, "VIC", 95836), ("TELFER AERO", -21.712500, 122.228100, "WA", 94319), ("TEMORA AIRPORT", -34.427700, 147.511700, "NSW", 95722), ("TENNANT CREEK AIRPORT", -19.642300, 134.183300, "NT", 94238), ("TENTERFIELD (FEDERATION PARK)", -29.047900, 152.017200, "NSW", 94556), ("TERREY HILLS AWS", -33.690800, 151.225300, "NSW", 94759), ("TERRITORY GRAPE FARM", -22.451800, 133.637700, "NT", 94328), ("TEWANTIN RSL PARK", -26.391100, 153.040300, "QLD", 94570), ("TEXAS POST OFFICE", -28.854400, 151.168100, "QLD", 95533), ("THANGOOL AIRPORT", -24.493500, 150.570900, "QLD", 94376), ("THARGOMINDAH AIRPORT", -27.986700, 143.815000, "QLD", 95492), ("THE MONUMENT AIRPORT", -21.812500, 139.926700, "QLD", 94336), ("THEVENARD ISLAND", -21.460900, 115.018800, "WA", 94303), ("THREDBO AWS", -36.491700, 148.285900, "NSW", 95909), ("THREDBO VILLAGE", -36.503100, 148.303800, "NSW", 95908), ("TIBOOBURRA AIRPORT", -29.444800, 142.056700, "NSW", 95485), ("TIMBER CREEK", -15.661400, 130.480800, "NT", 94220), ("TIN CAN BAY (DEFENCE)", -25.935100, 152.964700, "QLD", 94420), ("TINDAL RAAF", -14.522900, 132.382600, "NT", 94131), ("TOCUMWAL AIRPORT", -35.817000, 145.600400, "NSW", 94877), ("TOOWOOMBA AIRPORT", -27.542500, 151.913400, "QLD", 95551), ("TOWNSVILLE AERO", -19.248300, 146.766100, "QLD", 94294), ("TOWNSVILLE- AIR WEAPONS RANGE (DEFENCE)", -19.304800, 146.243800, "QLD", 94271), ("TOWNSVILLE- FANNING RIVER (DEFENCE)", -19.783000, 146.500000, "QLD", 94273), ("TRANGIE RESEARCH STATION AWS", -31.986100, 147.948900, "NSW", 95710), ("TREPELL AIRPORT", -21.840000, 140.892500, "QLD", 94338), ("TROUGHTON ISLAND", -13.754200, 126.148500, "WA", 94102), ("TRUSCOTT", -14.090000, 126.386700, "WA", 95101), ("TUGGERANONG (ISABELLA PLAINS) AWS", -35.418400, 149.093700, "NSW", 94925), ("TUMBARUMBA POST OFFICE", -35.778000, 148.012200, "NSW", 94918), ("TUNNACK FIRE STATION", -42.454300, 147.461200, "TAS", 94960), ("ULLADULLA AWS", -35.363500, 150.482800, "NSW", 94938), ("UNIVERSITY OF QUEENSLAND GATTON", -27.543600, 152.337500, "QLD", 94562), ("URANDANGI AERODROME", -21.597900, 138.366500, "QLD", 94344), ("VARANUS ISLAND", -20.655000, 115.576900, "WA", 95303), ("VICTOR HARBOR (ENCOUNTER BAY)", -35.554400, 138.599700, "SA", 95811), ("VICTORIA RIVER DOWNS", -16.403000, 131.014500, "NT", 94232), ("VIEWBANK", -37.740800, 145.097200, "VIC", 95874), ("WAGGA WAGGA AMO", -35.158300, 147.457500, "NSW", 94910), ("WAGIN", -33.307500, 117.340300, "WA", 95618), ("WALGETT (BREWON AWS)", -30.241100, 147.532700, "NSW", 94793), ("WALGETT AIRPORT AWS", -30.037200, 148.122300, "NSW", 95715), ("WALLAN (KILMORE GAP)", -37.380700, 144.965400, "VIC", 94860), ("WALPEUP RESEARCH", -35.120100, 142.004000, "VIC", 95831), ("WALUNGURRU AIRPORT", -23.265600, 129.384400, "NT", 94321), ("WANAARING (BORRONA DOWNS AWS)", -29.761400, 143.113500, "NSW", 94407), ("WANAARING (DELTA AWS)", -30.100600, 145.333800, "NSW", 95681), ("WANAARING POST OFFICE", -29.702900, 144.148400, "NSW", 94497), ("WANDERING", -32.672200, 116.670600, "WA", 95640), ("WANGARATTA AERO", -36.420500, 146.305600, "VIC", 94889), ("WARBURTON AIRFIELD", -26.131700, 126.583900, "WA", 94457), ("WARMUN", -17.015400, 128.217400, "WA", 94213), ("WAROOKA", -34.990600, 137.399500, "SA", 94663), ("WARRA", -43.060900, 146.704000, "TAS", 95962), ("WARRACKNABEAL MUSEUM", -36.261400, 142.405000, "VIC", 94841), ("WARRNAMBOOL AIRPORT NDB", -38.286700, 142.452200, "VIC", 94837), ("WARRUWI AIRPORT", -11.650000, 133.379700, "NT", 94139), ("WARWICK", -28.206100, 152.100300, "QLD", 94555), ("WATARRKA", -24.291800, 131.549000, "NT", 94323), ("WAVE HILL", -17.386900, 131.116600, "NT", 94229), ("WEIPA AERO", -12.677800, 141.920800, "QLD", 94170), ("WELLINGTON (D&J RURAL)", -32.563500, 148.950300, "NSW", 94723), ("WEST WYALONG AIRPORT AWS", -33.938200, 147.196200, "NSW", 95709), ("WESTMERE", -37.706700, 142.937800, "VIC", 95840), ("WHITE CLIFFS AWS", -30.852200, 143.074300, "NSW", 95699), ("WHYALLA AERO", -33.053900, 137.520600, "SA", 95664), ("WILCANNIA AERODROME AWS", -31.519400, 143.385000, "NSW", 95695), ("WILLIAMSON", -22.470300, 150.178600, "QLD", 95370), ("WILLIAMTOWN RAAF", -32.793900, 151.836400, "NSW", 94776), ("WILLIS ISLAND", -16.287800, 149.965200, "QLD", 94299), ("WILLOW GROVE (BLUE ROCK RESERVOIR)", -38.080800, 146.213900, "VIC", 94900), ("WILSONS PROMONTORY LIGHTHOUSE", -39.129700, 146.424600, "VIC", 94893), ("WILUNA AERO", -26.627400, 120.219400, "WA", 95439), ("WILUNA", -26.591400, 120.225800, "WA", 94439), ("WINDORAH AIRPORT", -25.411700, 142.664700, "QLD", 94489), ("WINDY HARBOUR", -34.836100, 116.030800, "WA", 94640), ("WINTON AIRPORT", -22.361700, 143.083600, "QLD", 94342), ("WITCHCLIFFE", -34.028100, 115.104200, "WA", 95641), ("WOLLOGORANG", -17.212200, 137.946200, "NT", 94258), ("WONGAN HILLS RES.STATION", -30.840800, 116.726700, "WA", 95601), ("WONGAN HILLS", -30.891700, 116.718600, "WA", 94622), ("WONTHAGGI", -38.607800, 145.596500, "VIC", 95881), ("WOOLBROOK (WOOLBROOK ROAD)", -30.965100, 151.350500, "NSW", 94792), ("WOOLSHED", -19.416800, 146.536200, "QLD", 95293), ("WOOMERA AERODROME", -31.155800, 136.805400, "SA", 94659), ("WUDINNA AERO", -33.043000, 135.451900, "SA", 95654), ("WYNDHAM AERO", -15.510000, 128.150300, "WA", 95214), ("WYNYARD AIRPORT", -40.996400, 145.731100, "TAS", 95957), ("YAMBA PILOT STATION", -29.432500, 153.363200, "NSW", 94589), ("YAMPI SOUND (DEFENCE)", -16.767100, 123.981000, "WA", 95208), ("YANCO AGRICULTURAL INSTITUTE", -34.622200, 146.432600, "NSW", 95705), ("YARRAM AIRPORT", -38.564700, 146.747900, "VIC", 95890), ("YARRAS (MOUNT SEAVIEW)", -31.386500, 152.248200, "NSW", 94783), ("YARRAWONGA", -36.029400, 146.030500, "VIC", 94862), ("YASS (RURAL FIRE SERVICE)", -34.822500, 148.908000, "NSW", 95723), ("YEELIRRIE", -27.284200, 120.093100, "WA", 94440), ("YEPPOON THE ESPLANADE", -23.136400, 150.750600, "QLD", 94373), ("YONGALA", -33.027600, 138.756000, "SA", 94679), ("YORK", -31.899700, 116.765000, "WA", 94623), ("YOUNG AIRPORT", -34.249300, 148.247500, "NSW", 94712), ("YUENDUMU", -22.256500, 131.801100, "NT", 94324), ("YULARA AIRPORT", -25.189600, 130.973700, "NT", 94462), ("YUNTA AIRSTRIP", -32.570700, 139.564500, "SA", 94684) } closest_wmo = None closest_distance = 9999999 for i in wmo_locations: wmo_location = i[0] wmo_lat = i[1] wmo_lon = i[2] wmo_state = i[3] wmo_id = i[4] distance = self.__distanceBetween((lat, lon), (wmo_lat, wmo_lon)) if distance < closest_distance: closest_distance = distance closest_wmo = i if self.parserDebug: log.debug("Found closest observatory (%s km) %s " % (str(closest_distance), closest_wmo[0])) return { 'name': closest_wmo[0], 'lat': closest_wmo[1], 'lon': closest_wmo[2], 'state': closest_wmo[3], 'id': closest_wmo[4] } def __getObservationURLForState(self, state): # AFAICT BOM only has observation data for NSW? maybe cause its the free version? # It is possible to get full observation data: # http://www.bom.gov.au/fwo/IDN60801/IDN60801.94768.json # Where the URL is ID60801..json # 60801 must be a product ID # bom-id can be looked up here: http://www.bom.gov.au/climate/cdo/about/sitedata.shtml # wmo-id can be looked up here: http://www.bom.gov.au/climate/data/stations/ # Full list of sites here: ftp://ftp.bom.gov.au/anon2/home/ncc/metadata/sitelists/stations.zip contains both bom-id and wmo-id # Note that detailed observations only available for sites with both id's. if self.longitude is not None and self.latitude is not None: wmo = self.__getNearestWMO(self.latitude, self.longitude) code = None if wmo['state'] == "NSW": code = 'N' elif wmo['state'] == "VIC": code = 'V' elif wmo['state'] == "QLD": code = 'Q' elif wmo['state'] == "WA": code = 'W' elif wmo['state'] == "TAS": code = 'T' elif wmo['state'] == "NT": code = 'D' elif wmo['state'] == "SA": code = 'S' return "http://www.bom.gov.au/fwo/ID" + code + "60801/ID" + code + "60801." + str(wmo['id']) + ".json" return None # These are apparently manually entered at the source, so typos etc are possible def __getConditionFromWeather(self, weather): condition = None if weather == '-': return None # strip any trailing full stops weather = str.rstrip(str(weather), '.') if weather == "Rain": condition = RMParser.conditionType.LightRain elif weather == "Showers": condition = RMParser.conditionType.RainShowers elif weather == "Smoke": condition = RMParser.conditionType.Smoke elif weather == "Fine": condition = RMParser.conditionType.Fair elif weather == "Fog": condition = RMParser.conditionType.Fog elif weather == "Fog patches": condition = RMParser.conditionType.Fog elif weather == "Haze": condition = RMParser.conditionType.Haze elif weather == "Recent precip": condition = RMParser.conditionType.ShowersInVicinity elif weather == "Freezing rain": condition = RMParser.conditionType.FreezingRain elif weather == "Thunderstorm": condition = RMParser.conditionType.Thunderstorm elif weather == "Recent thunderstorm": condition = RMParser.conditionType.ThunderstormInVicinity elif weather == "Sunny": condition = RMParser.conditionType.Hot elif weather == "Mostly sunny": condition = RMParser.conditionType.Fair elif weather == "Partly cloudy": condition = RMParser.conditionType.PartlyCloudy elif weather == "Possible shower": condition = RMParser.conditionType.ShowersInVicinity elif weather == "Becoming cloudy": condition = RMParser.conditionType.FewClouds elif weather == "Cloudy": condition = RMParser.conditionType.Overcast else: log.error("Unknown weather type %s", condition) condition = None def __getValue(self, key, timestamp): timestamp = timestamp - (timestamp % 3600) if timestamp not in self.result: return None record = self.result[timestamp] # Usually I'd use __dict__ to fetch these results, but the names inside the dict don't match the enum names if key == RMParser.dataType.TEMPERATURE: return record.temperature elif key == RMParser.dataType.MINTEMP: return record.minTemperature elif key == RMParser.dataType.MAXTEMP: return record.maxTemperature elif key == RMParser.dataType.RH: return record.rh elif key == RMParser.dataType.MINRH: return record.minRh elif key == RMParser.dataType.MAXRH: return record.maxRh elif key == RMParser.dataType.WIND: return record.wind elif key == RMParser.dataType.SOLARRADIATION: return record.solarRad elif key == RMParser.dataType.SKYCOVER: return record.skyCover elif key == RMParser.dataType.RAIN: return record.rain elif key == RMParser.dataType.ET0: return record.et0 elif key == RMParser.dataType.POP: return record.pop elif key == RMParser.dataType.QPF: return record.qpf elif key == RMParser.dataType.PRESSURE: return record.pressure elif key == RMParser.dataType.DEWPOINT: return record.dewPoint else: return None def __averageFloatValues(self, datatype, timestamp, value): old_value = self.__getValue(datatype, timestamp) value = self.__toFloat(value) if value is None: value=old_value elif old_value is not None: value = (value + old_value) / 2 self.addValue(datatype, timestamp, self.__toFloat(value)) def __sumFloatValues(self, datatype, timestamp, value): old_value = self.__getValue(datatype, timestamp) value = self.__toFloat(value) if value is None: value=old_value elif old_value is not None: value = (value + old_value) self.addValue(datatype, timestamp, self.__toFloat(value)) def __parseObservationValue(self, type, value, timestamp, debug_str): # Observations are over a 30 minute period usually, and we round the timestamp # down to the nearest hour. This means we lose some data, so we check if a value # exists and either average or sum the old value. if debug_str is None: debug_str="" if timestamp is None: return debug_str if value is None or value is '-': debug_str += type + ": None " return debug_str if type == 'apparent_temp' or type == 'apparent_t': debug_str += type + ": " + str(value) + " " elif type == 'delta_t': debug_str += type + ": " + str(value) + " " elif type == 'air_temperature' or type == 'air_temp': debug_str += type + ": " + str(value) + " " self.__averageFloatValues(RMParser.dataType.TEMPERATURE, timestamp, value) elif type == 'dew_point' or type == 'dewpt': debug_str += type + ": " + str(value) + " " self.__averageFloatValues(RMParser.dataType.DEWPOINT, timestamp, value) elif type == 'pres' or type == 'press': value = self.__toFloat(value) / 10 # convert hectaPa to kiloPa debug_str += type + ": " + str(value) + " " self.__averageFloatValues(RMParser.dataType.PRESSURE, timestamp, value) elif type == 'msl_pres' or type == 'press_msl': debug_str += type + ": " + str(value) + " " elif type == 'qnh_pres' or type == 'press_qnh': debug_str += type + ": " + str(value) + " " elif type == 'press_tend': debug_str += type + ": " + str(value) + " " elif type == 'rain_hour': debug_str += type + ": " + str(value) + " " elif type == 'rain_ten': debug_str += type + ": " + str(value) + " " elif type == 'rel-humidity' or type == 'rel_hum': debug_str += type + ": " + str(value) + " " self.__averageFloatValues(RMParser.dataType.RH, timestamp, value) elif type == 'weather': debug_str += type + ": " + str(value) + " " condition = self.__getConditionFromWeather(value) if condition is not None: self.addValue(RMParser.dataType.CONDITION, timestamp, condition) elif type == 'wind_dir': debug_str += type + ": " + str(value) + " " elif type == 'wind_dir_deg': debug_str += type + ": " + str(value) + " " elif type == 'wind_spd_kmh': value = self.__toFloat(value) / 3.6 # from km/h to m/s debug_str += type + ": " + str(value) + " " self.__averageFloatValues(RMParser.dataType.WIND, timestamp, value) elif type == 'wind_spd' or type == 'wind_spd_kt': debug_str += type + ": " + str(value) + " " elif type == 'rainfall_24hr': # Rainfall for the preceeding 24hr till 9am debug_str += type + ": " + str(value) + " " self.__sumFloatValues(RMParser.dataType.RAIN, timestamp, value) elif type == 'rainfall' or type == 'rain_trace': # Rainfall since 9am today debug_str += type + ": " + str(value) + " " # NOTE: We SUM these two values to get the total for the 60 minute period. self.__sumFloatValues(RMParser.dataType.RAIN, timestamp, value) elif type == 'maximum_air_temperature': debug_str += type + ": " + str(value) + " " self.addValue(RMParser.dataType.MAXTEMP, timestamp, self.__toFloat(value)) elif type == 'minimum_air_temperature': debug_str += type + ": " + str(value) + " " self.addValue(RMParser.dataType.MINTEMP, timestamp, self.__toFloat(value)) elif type == 'cloud_oktas': # need to try and convert to a % oktas = int(value) if oktas == 0: skycover = 0.0 elif oktas == 1: skycover = 0.0625 elif oktas == 2: skycover = 0.1875 elif oktas == 3: skycover = 0.3125 elif oktas == 4: skycover = 0.4375 elif oktas == 5: skycover = 0.5625 elif oktas == 6: skycover = 0.6875 elif oktas == 7: skycover = 0.8125 elif oktas == 8: skycover = 0.875 elif oktas == 9: skycover = 100.0 self.addValue(RMParser.dataType.SKYCOVER, timestamp, self.__toFloat(value)) elif type == 'lat' or type == 'lon' or type == 'sort_order' or type == 'wmo' or type == 'name' or type == 'history_product' or type == 'local_date_time' or type == 'local_date_time_full' or type == 'aifstime_utc': return debug_str elif type == 'cloud' or type == 'cloud_type' or type == 'vis_km' or type == 'sea_state' or type == 'swell_dir_worded': return debug_str elif self.parserDebug: log.debug("Got unknown type %s" % type) debug_str += type + ": " + str(value) + " " return debug_str def __parseJSONObservationData(self, data): jsonContent = json.loads(data.read()) for observation in jsonContent['observations']['data']: timestamp = calendar.timegm(time.strptime(observation['aifstime_utc'], '%Y%m%d%H%M%S')) debug_str="" for key in observation: value = observation[key] #log.info("key = %s value = %s (%s)" % (key, value, debug_str)) debug_str=self.__parseObservationValue(key, value, timestamp, debug_str) if self.parserDebug: log.info(debug_str) timestamp = timestamp - (timestamp % 3600) if timestamp in self.result: self.__outputData(timestamp) else: log.info("Did not find: %s" % timestamp) # These are classed as "hourly results" in the API # Incoming format documented here: http://reg.bom.gov.au/catalogue/Observations-XML.pdf def __getObservationData(self, state): if self.parserDebug: log.debug("Getting observation data") URL = self.__getObservationURLForState(state) if URL == None: self.lastKnownError = "Error: Only NSW supported" return if self.parserDebug: log.debug("Got a URL of %s" % URL) # Using the default user agent results in a 403: forbidden (wtf?) data = self.openURL(URL, headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.3", "Accept":"*/*"}) if data is None: if self.parserDebug: log.debug("Did not get data") self.lastKnownError = "Error: No data received from server" return if self.parserDebug: log.debug("Retrieved observation data from BOM") self.__parseJSONObservationData(data) def __getForecastData(self, state, forecastArea): if self.parserDebug: log.debug("Getting forecast data") URL = self.__getForecastURLForState(state) if URL == None: self.lastKnownError = "Error: Invalid state, must be QLD, NSW, NT, SA, TAS, VIC or WA" return if self.parserDebug: log.debug("Got a URL of %s" % URL) data = self.openURL(URL) if data is None: if self.parserDebug: log.debug("Did not get data") self.lastKnownError = "Error: No data received from server" return if self.parserDebug: log.debug("Retrieved forecast file from BOM") foundForecastArea = False xmldata = elementTree.parse(data) if self.parserDebug: log.debug("Parsing XML looking for 'area'") for node in xmldata.getroot().getiterator(tag = "area"): if node.attrib['description'] != forecastArea: continue foundForecastArea = True if self.parserDebug: log.debug("Matched on %s" % forecastArea) # BOM provides "forecast" data for the current day, however it is incomplete. If we have observation # data, we should just use that observation_timestamp = None if len(self.result) > 0: observation_timestamp = sorted(self.result).pop() for subnode in node.getiterator(tag = "forecast-period"): subnodeDate = subnode.get("start-time-utc") subnodeTimestamp = rmTimestampFromDateAsString(subnodeDate, '%Y-%m-%dT%H:%M:%SZ') # We have more recent observation data, skip incomplete forecast data if observation_timestamp is not None and observation_timestamp > subnodeTimestamp: continue self.addUserValue(RMParser.dataType.USERDATA, subnodeTimestamp, "forecast for " + subnodeDate) mintemp = None maxtemp = None qpfAvg = 0.0 # No entry should mean no expected rainfall. pop = 0.0 # No entry should mean no expected rainfall. for element in subnode.getiterator(): type = element.get("type") if type == "air_temperature_minimum": try: mintemp = self.__toFloat(element.text) except: log.error("Cannot get minimum temperature (%s)" % element.text) elif type == "air_temperature_maximum": try: maxtemp = self.__toFloat(element.text) except: log.error("Cannot get max temperature (%s)" % element.text) elif type == "precipitation_range": try: qpfMin, _, qpfMax, _ = element.text.split() # will result in ['15', 'to', '35', 'mm'] qpfAvg = (self.__toFloat(qpfMin) + self.__toFloat(qpfMax))/2 except: log.error("Cannot get precipitation forecast (%s)" % element.text) elif type == "probability_of_precipitation": try: pop = self.__toInt(element.text.rstrip('%')) except: log.error("Cannot get probability_of_precipitation forecast (%s)" % element.text) if mintemp is not None: self.addValue(RMParser.dataType.MINTEMP, subnodeTimestamp, mintemp) if maxtemp is not None: self.addValue(RMParser.dataType.MAXTEMP, subnodeTimestamp, maxtemp) self.addValue(RMParser.dataType.POP, subnodeTimestamp, pop) self.addValue(RMParser.dataType.QPF, subnodeTimestamp, qpfAvg) if self.parserDebug: log.debug("Forecast period: %s Min Temp: %s, Max Temp: %s, POP: %s, QPF: %s" % (subnodeDate , mintemp if mintemp is not None else 'None' , maxtemp if maxtemp is not None else 'None' , pop if pop is not None else 'None' , qpfAvg if qpfAvg is not None else 'None')) # Sometimes we get a forecast result in the past, however addValue will not add a historical value, so we might get # no record if subnodeTimestamp in self.result: self.__outputData(subnodeTimestamp) else: log.debug("Forecast: %s / %s not found" % (str(subnodeTimestamp), subnodeDate)) break if foundForecastArea == False: self.lastKnownError = "Failed to find Forecast Area" return # The function that will be executed must have this name def perform(self): # settings is a dict when run outside of the full code base, so use that to check if we can fetch from self.settings.location or not if not isinstance(self.settings, dict): self.latitude = self.settings.location.latitude self.longitude = self.settings.location.longitude self.__getObservationData(self.params["State"]) self.__getForecastData( self.params["State"], self.params["Forecast Area"]) if self.parserDebug: log.debug("Parsing done") if self.parserDebug: for time_period in sorted(self.result): self.__outputData(time_period) def __toFloat(self, value): try: if value is None: return value return float(value) except: log.warn("Failed to convert %s into a float" % value) return None def __toInt(self, value): try: if value is None: return value return int(value) except: log.warn("Failed to convert %s into an int" % value) return None def __outputData(self, timestamp): rec = self.result[timestamp] out = datetime.utcfromtimestamp(rec.timestamp).strftime('%Y-%m-%d %H:%M:%S') + \ ", temp=" + `rec.temperature` + \ ", minTemp=" + `rec.minTemperature` + \ ", maxTemp=" + `rec.maxTemperature` + \ ", rain=" + `rec.rain` + \ ", et0=" + `rec.et0` + \ ", rh=" + `rec.rh` + \ ", pop=" + `rec.pop` + \ ", qpf=" + `rec.qpf` + \ ", condition=" + `rec.condition` + \ ", pressure=" + `rec.pressure` + \ ", dewPoint=" + `rec.dewPoint` + \ ", wind=" + `rec.wind` + \ ", userData=" + `rec.userData` log.debug("%s : %s" % (str(timestamp), out)) if __name__ == '__main__': p = AustraliaBOM() p.latitude = -27.3818618 p.longitude = 152.7123378 p.perform()