From 81aaad48722b859bc62b0c6ff8998297c71b4fbb Mon Sep 17 00:00:00 2001 From: bossanova808 Date: Wed, 16 Oct 2024 02:53:46 +0000 Subject: [PATCH] [weather.ozweather] 2.1.2 --- weather.ozweather/addon.xml | 10 +- weather.ozweather/changelog.txt | 4 + weather.ozweather/default.py | 5 +- .../resources/IDR00004.background.png | Bin 0 -> 21849 bytes .../resources/lib/abc/abc_video.py | 46 +---- .../resources/lib/bom/bom_forecast.py | 58 +++--- .../resources/lib/bom/bom_location.py | 35 ++-- .../resources/lib/bom/bom_radar.py | 111 +++++----- .../lib/bom/bom_radar_scrape_latest.py | 4 +- weather.ozweather/resources/lib/common.py | 189 ------------------ weather.ozweather/resources/lib/forecast.py | 46 +++-- weather.ozweather/resources/lib/locations.py | 25 ++- weather.ozweather/resources/lib/ozweather.py | 2 + weather.ozweather/resources/lib/store.py | 150 +++++++------- 14 files changed, 251 insertions(+), 434 deletions(-) create mode 100644 weather.ozweather/resources/IDR00004.background.png delete mode 100644 weather.ozweather/resources/lib/common.py diff --git a/weather.ozweather/addon.xml b/weather.ozweather/addon.xml index 7d773e76a..6502b1e23 100644 --- a/weather.ozweather/addon.xml +++ b/weather.ozweather/addon.xml @@ -1,16 +1,17 @@ - + + Weather forecasting and radar images for Australia using Bureau of Meteorology data Weather forecasting and radar images for Australia using Bureau of Meteorology data. For full features (animated radars & ABC weather videos) - make sure you install the replacement skin files - see information at the addon wiki (https://kodi.wiki/index.php?title=Add-on:Oz_Weather). - Use of this addon implies you agree to the following terms and conditions - http://reg.bom.gov.au/other/copyright.shtml and http://reg.bom.gov.au/other/disclaimer.shtml + Use of this addon implies you agree to the following terms and conditions - https://reg.bom.gov.au/other/copyright.shtml and https://reg.bom.gov.au/other/disclaimer.shtml all en GPL-3.0-only @@ -22,8 +23,9 @@ icon.png fanart.jpg - 2.1.1 - - Add Latitude and Longitude to Window data for skins that display 'season' using (arguably dubious) logic + v2.1.2 +- Remove old common code, instead use new script.module.bossanova808 +- Fix for occasional error with missing national radar background diff --git a/weather.ozweather/changelog.txt b/weather.ozweather/changelog.txt index ae59be684..719b08488 100644 --- a/weather.ozweather/changelog.txt +++ b/weather.ozweather/changelog.txt @@ -1,3 +1,7 @@ +v2.1.2 +- Remove old common code, instead use new script.module.bossanova808 +- Fix for occasional error with missing national radar background + 2.1.1 - Add Latitude and Longitude to Window data for skins that display 'season' using (arguably dubious) logic diff --git a/weather.ozweather/default.py b/weather.ozweather/default.py index 5f3ced4dc..49b2c6a20 100644 --- a/weather.ozweather/default.py +++ b/weather.ozweather/default.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import sys +from bossanova808 import exception_logger from resources.lib import ozweather # This is kept as minimal as possible per @enen92's advice that: @@ -8,5 +9,5 @@ # Hence, you'll see a performance gain if you store your codebase in a "module" if __name__ == "__main__": - ozweather.run(sys.argv) - + with exception_logger.log_exception(): + ozweather.run(sys.argv) diff --git a/weather.ozweather/resources/IDR00004.background.png b/weather.ozweather/resources/IDR00004.background.png new file mode 100644 index 0000000000000000000000000000000000000000..fe02273358874898f8e04015c99369c1b06b0860 GIT binary patch literal 21849 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 2023_05 - CURRENT ABC VIDEO URL NOTES -# view the source on: https://www.abc.net.au/news/weather -# search for 'mp4' -# Regex in Store.py used to match the URL format -# Multiple matches will be found - first is a definition/download link (.mpg) -# 2nd is the highest quality stream (720p) - the one we want. -# https://mediacore-live-production.akamaized.net/video/01/im/Z/0m.mp4 - -# < 2023_05 - LEGACY INFO -# note date and quality level variables... -# view source on https://www.abc.net.au/news/newschannel/weather-in-90-seconds/ and find mp4 to see this list, -# the end of the URL can change regularly -# {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_1000k.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '928', 'width': '1024', 'height': '576', 'filesize': '11657344'} -# {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_256k.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '170', 'width': '320', 'height': '180', 'filesize': '2472086'} -# {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_512k.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '400', 'width': '512', 'height': '288', 'filesize': '5328218'} -# {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_trw.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '1780', 'width': '1280', 'height': '720', 'filesize': '21599356'} -# Other URLs - should match any of these -# https://abcmedia.akamaized.net/news/news24/wins/201409/WINm_Update1_0909_VSB03WF2_512k.mp4& -# https://abcmedia.akamaized.net/news/news24/wins/201409/WINs_Weather2_0209_trw.mp4 + Logger.info("\nTesting scraping of ABC Weather Video - here's the 'Best' link:\n") + Logger.info(get_abc_weather_video_link()) diff --git a/weather.ozweather/resources/lib/bom/bom_forecast.py b/weather.ozweather/resources/lib/bom/bom_forecast.py index 5039d1590..6af561cc1 100644 --- a/weather.ozweather/resources/lib/bom/bom_forecast.py +++ b/weather.ozweather/resources/lib/bom/bom_forecast.py @@ -6,12 +6,16 @@ import math import xbmc -# Small hack to allow for unit testing - see common.py for explanation +# Allow for unit testing this file +# This brings this addon's resources, and bossanova808 module stuff into scope +# (when running this module outside Kodi) if not xbmc.getUserAgent(): sys.path.insert(0, '../../..') + sys.path.insert(0, '../../../../script.module.bossanova808/resources/lib') from resources.lib.store import Store -from resources.lib.common import * +from bossanova808.utilities import * +from bossanova808.logger import Logger """ (See bottom of this file for BOM API output examples!) @@ -137,16 +141,15 @@ def bom_forecast(geohash): try: r = requests.get(bom_api_area_information_url) area_information = r.json()["data"] - log(area_information) + Logger.debug(area_information) if area_information: location_timezone_text = area_information['timezone'] - log(f"Location timezone from BOM is {location_timezone_text}") + Logger.debug(f"Location timezone from BOM is {location_timezone_text}") location_timezone = pytz.timezone(location_timezone_text) # For any date comparisons - this is the localised now... now = datetime.datetime.now(location_timezone) - except: - log(f'Error retrieving area information from {bom_api_area_information_url}') + Logger.error(f'Error retrieving area information from {bom_api_area_information_url}') # Get CURRENT OBSERVATIONS try: @@ -154,20 +157,19 @@ def bom_forecast(geohash): current_observations = r.json()["data"] weather_data['ObservationsUpdated'] = utc_str_to_local_str(r.json()["metadata"]["issue_time"], time_zone=location_timezone) weather_data['ObservationsStation'] = r.json()["data"]['station']['name'] - log(current_observations) - + Logger.debug(current_observations) except: - log(f'Error retrieving current observations from {bom_api_current_observations_url}') + Logger.error(f'Error retrieving current observations from {bom_api_current_observations_url}') return False # Get WARNINGS try: r = requests.get(bom_api_warnings_url) warnings = r.json()["data"] - log(warnings) + Logger.debug(warnings) except: - log(f'Error retrieving warnings from {bom_api_warnings_url}') + Logger.error(f'Error retrieving warnings from {bom_api_warnings_url}') # Get 7-DAY FORECAST try: @@ -176,10 +178,10 @@ def bom_forecast(geohash): weather_data['ForecastUpdated'] = utc_str_to_local_str(r.json()["metadata"]["issue_time"], time_zone=location_timezone) weather_data['ForecastRegion'] = r.json()["metadata"]["forecast_region"].title() weather_data['ForecastType'] = r.json()["metadata"]["forecast_type"].title() - log(forecast_seven_days) + Logger.debug(forecast_seven_days) except: - log(f'Error retrieving seven day forecast from {bom_api_forecast_seven_days_url}') + Logger.error(f'Error retrieving seven day forecast from {bom_api_forecast_seven_days_url}') return False # FUTURE? @@ -234,15 +236,15 @@ def bom_forecast(geohash): # AT = Ta + 0.33•ρ − 0.70•ws − 4.00 else: try: - log("Feels Like not provided by BOM. Attempting to calculate feels like...but will likely fail...") + Logger.warning("Feels Like not provided by BOM. Attempting to calculate feels like...but will likely fail...") water_vapour_pressure = current_observations['humidity'] * 6.105 * math.exp((17.27 * current_observations['temp'])/(237.7 + current_observations['temp'])) calculated_feels_like = current_observations['temp'] + (0.33 * water_vapour_pressure) - (0.70 * current_observations['wind']['speed_kilometre']) - 4.00 weather_data['Current.FeelsLike'] = calculated_feels_like weather_data['Current.Ozw_FeelsLike'] = calculated_feels_like - log(f"Success! Using calculated feels like of {calculated_feels_like}") + Logger.info(f"Success! Using calculated feels like of {calculated_feels_like}") # Not provided, could not calculate it, so set it to the current temp (avoids Kodi showing a random '0' value!) except: - log("Feels like not provided, could not calculate - setting to current temperature to avoid kodi displaying random 0s.") + Logger.error("Feels like not provided, and also could not calculate - setting to current temperature to avoid kodi displaying random 0s.") weather_data['Current.FeelsLike'] = str(round(current_observations['temp'])) # WARNINGS @@ -251,7 +253,7 @@ def bom_forecast(geohash): for i, warning in enumerate(warnings): # Warnings body...only major warnings as we don't need every little message about sheep grazing etc... if warning['warning_group_type'] == 'major': - # Don't really care when it was issue, if it hasn't expired, it's current, so show it.. + # Don't really care when it was issue, if it hasn't expired, it's current, so show it... # warning_issued = utc_str_to_local_str(warning['issue_time'], local_format='%d/%m %I:%M%p', time_zone=location_timezone) # Time signature on the expiry is different for some reason?! # Remove the completely unnecessary fractions of a second... @@ -318,7 +320,7 @@ def bom_forecast(geohash): descriptor_from_short_text = forecast_seven_days[i]['short_text'].lower() descriptor_from_short_text = descriptor_from_short_text.replace(' ', '_').replace('.', '').strip() if descriptor_from_short_text in Store.WEATHER_CODES: - log("Using short text as icon descriptor as this is often more reliable than the actual icon_descriptor") + Logger.debug("Using short text as icon descriptor as this is often more reliable than the actual icon_descriptor") icon_descriptor = descriptor_from_short_text # Now we have some sort of icon descriptor, try and get the actual icon_code try: @@ -327,11 +329,11 @@ def bom_forecast(geohash): else: icon_code = Store.WEATHER_CODES[icon_descriptor] except KeyError: - log(f'Could not find icon code for BOM icon_descriptor: {forecast_seven_days[i]["icon_descriptor"]} and from short text {descriptor_from_short_text}') + Logger.error(f'Could not find icon code for BOM icon_descriptor: {forecast_seven_days[i]["icon_descriptor"]} and from short text {descriptor_from_short_text}') # Pop the missing icon descriptor into the outlook to make it easier for people to report in the forum thread set_key(weather_data, i, "Outlook", f"[{forecast_seven_days[i]['icon_descriptor']}] {forecast_seven_days[i]['short_text']}") - log(f"Icon descriptor is: {icon_descriptor}, icon code is {icon_code}") + Logger.debug(f"Icon descriptor is: {icon_descriptor}, icon code is {icon_code}") set_keys(weather_data, i, ["OutlookIcon", "ConditionIcon"], f'{icon_code}.png') set_keys(weather_data, i, ["FanartCode"], icon_code) @@ -346,20 +348,20 @@ def bom_forecast(geohash): temp_max = forecast_seven_days[i]['temp_max'] if i == 0 and not temp_max: if forecast_seven_days[i]['now']['now_label'] == "Tomorrow's Max": - log("Using now->temp_now as now->now_label is Tomorrow's Max") + Logger.debug("Using now->temp_now as now->now_label is Tomorrow's Max") temp_max = forecast_seven_days[i]['now']['temp_now'] elif forecast_seven_days[i]['now']['later_label'] == "Tomorrow's Max": - log("Using now->temp_later as now->later_label is Tomorrow's Max") + Logger.debug("Using now->temp_later as now->later_label is Tomorrow's Max") temp_max = forecast_seven_days[i]['now']['temp_later'] set_keys(weather_data, i, ["HighTemp", "HighTemperature"], temp_max) temp_min = forecast_seven_days[i]['temp_min'] if i == 0 and not temp_min: if forecast_seven_days[i]['now']['now_label'] == 'Overnight Min': - log("Using now->temp_now as now->now_label is Overnight Min") + Logger.debug("Using now->temp_now as now->now_label is Overnight Min") temp_min = forecast_seven_days[i]['now']['temp_now'] elif forecast_seven_days[i]['now']['later_label'] == 'Overnight Min': - log("Using now->temp_later as now->later_label is Overnight Min") + Logger.debug("Using now->temp_later as now->later_label is Overnight Min") temp_min = forecast_seven_days[i]['now']['temp_later'] set_keys(weather_data, i, ["LowTemp", "LowTemperature"], temp_min) @@ -411,19 +413,19 @@ def bom_forecast(geohash): ########################################################### -# MAIN (only for unit testing outside of Kodi) +# MAIN (only for unit testing outside Kodi) if __name__ == "__main__": geohashes_to_test = ['r1r11df', 'r1f94ew'] for geohash in geohashes_to_test: - log(f'Getting weather data from BOM for geohash "{geohash}"') + Logger.info(f'Getting weather data from BOM for geohash "{geohash}"') test_data = bom_forecast(geohash) for key in sorted(test_data): if test_data[key] == "?" or test_data[key] == "na": - log("**** MISSING: ") - log(f'{key}: "{test_data[key]}"') + Logger.info("**** MISSING: ") + Logger.info(f'{key}: "{test_data[key]}"') """ BOM API diff --git a/weather.ozweather/resources/lib/bom/bom_location.py b/weather.ozweather/resources/lib/bom/bom_location.py index 9e1e13699..ac1f422d4 100644 --- a/weather.ozweather/resources/lib/bom/bom_location.py +++ b/weather.ozweather/resources/lib/bom/bom_location.py @@ -2,11 +2,16 @@ import sys import xbmc -# Small hack to allow for unit testing - see common.py for explanation +# Allow for unit testing this file +# This brings this addon's resources, and bossanova808 module stuff into scope +# (when running this module outside Kodi) if not xbmc.getUserAgent(): sys.path.insert(0, '../../..') + sys.path.insert(0, '../../../../script.module.bossanova808/resources/lib') from resources.lib.bom.bom_radar import * +from bossanova808.utilities import * +from bossanova808.logger import Logger def get_bom_locations_for(text): @@ -20,17 +25,17 @@ def get_bom_locations_for(text): try: r = requests.get(Store.BOM_API_LOCATIONS_URL, params={'search': text}) for result in r.json()['data']: - log(result) + Logger.debug(result) locations.append(f'{result["name"]}, {result["state"]} {result["postcode"]} ({result["geohash"]})') location_geohashes.append(result["geohash"]) - log(locations) - log(location_geohashes) + Logger.debug(locations) + Logger.debug(location_geohashes) return locations, location_geohashes except Exception as inst: - log(f'Exception getting locations from {Store.BOM_API_LOCATIONS_URL} for search term {text}') - log(str(inst)) + Logger.error(f'Exception getting locations from {Store.BOM_API_LOCATIONS_URL} for search term {text}') + Logger.error(str(inst)) raise @@ -46,7 +51,7 @@ def find_bom_location(): if keyboard.isConfirmed() and keyboard.getText() != '': text = keyboard.getText() - log("Doing locations search for " + text) + Logger.info("Doing locations search for " + text) locations, location_geohashes = get_bom_locations_for(text) # Now get them to choose an actual location from the returned matched @@ -64,9 +69,9 @@ def find_bom_location(): location_info_url = f'https://api.weather.bom.gov.au/v1/locations/{location_geohashes[selected]}' try: location_info = requests.get(location_info_url).json()['data'] - log(location_info) + Logger.debug(location_info) except: - log("Error retrieving location info for geohash {location_geohashes[selected]}") + Logger.debug("Error retrieving location info for geohash {location_geohashes[selected]}") raise # Save the geohash and latitude and longitude of the location @@ -76,22 +81,22 @@ def find_bom_location(): ADDON.setSetting(sys.argv[1] + 'Lon', str(location_info['longitude'])) # Use the lat, long to find the closest radar radar = closest_radar_to_lat_lon((location_info['latitude'], location_info['longitude'])) - log(f'Closest radar found: {radar}') + Logger.info(f'Closest radar found: {radar}') ADDON.setSetting('Radar' + sys.argv[1][-1] + 'Lat', str(radar[0])) ADDON.setSetting('Radar' + sys.argv[1][-1] + 'Lon', str(radar[1])) ADDON.setSetting(sys.argv[1] + 'ClosestRadar', f'{radar[2]} - {radar[3]}') + ########################################################### -# MAIN (only for unit testing outside of Kodi) +# MAIN (only for unit testing outside Kodi) if __name__ == "__main__": places_to_test = ['3032', 'ascot vale', 'MYRTLE BANK', 'no_results'] for place in places_to_test: - log(f'Testing location term "{place}"') + Logger.info(f'Testing location term "{place}"') get_bom_locations_for(place) - log('') - + Logger.info('') """ { @@ -111,4 +116,4 @@ def find_bom_location(): "response_timestamp": "2021-04-28T04:50:20Z" } } -""" \ No newline at end of file +""" diff --git a/weather.ozweather/resources/lib/bom/bom_radar.py b/weather.ozweather/resources/lib/bom/bom_radar.py index f5dfd0789..a92a385c4 100644 --- a/weather.ozweather/resources/lib/bom/bom_radar.py +++ b/weather.ozweather/resources/lib/bom/bom_radar.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import ftplib import glob -import os import shutil import sys import time @@ -11,12 +10,16 @@ from math import sin, cos, sqrt, atan2, radians import xbmc -# Small hack to allow for unit testing - see common.py for explanation +# Allow for unit testing this file +# This brings this addon's resources, and bossanova808 module stuff into scope +# (when running this module outside Kodi) if not xbmc.getUserAgent(): sys.path.insert(0, '../../..') + sys.path.insert(0, '../../../../script.module.bossanova808/resources/lib') +from bossanova808.utilities import * +from bossanova808.logger import Logger from resources.lib.store import Store -from resources.lib.common import * # noinspection PyPep8Naming @@ -48,9 +51,9 @@ def closest_radar_to_lat_lon(point): closest_distance = 10000 for radar in Store.BOM_RADAR_LOCATIONS: distance = get_distance(point, (radar[0], radar[1])) - log(f'Point {point}, radar {radar}, distance {distance}') + Logger.debug(f'Point {point}, radar {radar}, distance {distance}') if distance < closest_distance: - log(f'Setting closest radar to {radar}') + Logger.debug(f'Setting closest radar to {radar}') closest_radar = radar closest_distance = distance @@ -110,23 +113,27 @@ def download_background(radar_code, file_name, path): # Download the backgrounds only if we don't have them yet if not os.path.isfile(path + out_file_name): - log("Downloading missing background image....[%s] as [%s]" % (file_name, out_file_name)) + Logger.debug("Downloading missing background image....[%s] as [%s]" % (file_name, out_file_name)) - if "background.png" in file_name and '00004' in file_name: - url_to_get = Store.BOM_RADAR_BACKGROUND_FTPSTUB + 'IDE00035.background.png' + if file_name == 'IDR00004.background.png': + # Special case: national radar background periodically seems to be missing from BOM ftp? Use a local copy... + Logger.debug("Copying local copy of national radar background") + # No need to do this if we're unit testing outside Kodi + if CWD: + shutil.copy(f"{CWD}/resources/IDR00004.background.png", f"{path}/background.png") else: url_to_get = Store.BOM_RADAR_BACKGROUND_FTPSTUB + file_name - try: - radar_image = urllib.request.urlopen(url_to_get) - with open(path + "/" + out_file_name, "wb") as fh: - fh.write(radar_image.read()) + try: + radar_image = urllib.request.urlopen(url_to_get) + with open(path + "/" + out_file_name, "wb") as fh: + fh.write(radar_image.read()) - except Exception as e: - log(f"Failed to retrieve radar background image: {url_to_get}, exception: {str(e)}") + except Exception as e: + Logger.error(f"Failed to retrieve radar background image: {url_to_get}, exception: {str(e)}") else: - log(f"Using cached {out_file_name}") + Logger.debug(f"Using cached {out_file_name}") def prepare_backgrounds(radar_code, path): @@ -134,7 +141,7 @@ def prepare_backgrounds(radar_code, path): Download backgrounds for given radar """ - log("Calling prepareBackgrounds on [%s]" % radar_code) + Logger.debug("Calling prepareBackgrounds on [%s]" % radar_code) download_background(radar_code, "IDR.legend.0.png", path) download_background(radar_code, "background.png", path) @@ -160,18 +167,18 @@ def build_images(radar_code, path, loop_path): # grab the current time as 12 digit 0 padded string time_now = format(int(time.time()), '012d') - log("build_images(%s)" % radar_code) - log("Overlay loop path: " + loop_path) - log("Backgrounds path: " + path) + Logger.debug("build_images(%s)" % radar_code) + Logger.debug("Overlay loop path: " + loop_path) + Logger.debug("Backgrounds path: " + path) - log("Deleting any radar overlays older than an hour, that's long enough to see what has passed plus not take too long to loop") + Logger.info("Deleting any radar overlays older than an hour, that's long enough to see what has passed plus not take too long to loop") current_files = glob.glob(loop_path + "/*.png") for count, file in enumerate(current_files): filetime = os.path.getmtime(file) - two_hours_ago = time.time() - (1 * 60 * 60) - if filetime < two_hours_ago: + time_ago = time.time() - (1 * 60 * 60) + if filetime < time_ago: os.remove(file) - log("Deleted aged radar image " + str(os.path.basename(file))) + Logger.debug("Deleted aged radar image " + str(os.path.basename(file))) # rename the currently kept radar backgrounds to prevent Kodi caching from displaying stale images current_files = glob.glob(loop_path + "/*.png") @@ -187,12 +194,12 @@ def build_images(radar_code, path, loop_path): try: os.makedirs(path) success = True - log("Successfully created " + path) + Logger.debug("Successfully created " + path) except: attempts += 1 time.sleep(0.1) if not success: - log("ERROR: Failed to create directory for radar background images!") + Logger.error("ERROR: Failed to create directory for radar background images!") return # ...and create the folder for the radar loop if it does not yet exist @@ -204,24 +211,24 @@ def build_images(radar_code, path, loop_path): try: os.makedirs(loop_path) success = True - log("Successfully created " + loop_path) + Logger.debug("Successfully created " + loop_path) except: attempts += 1 time.sleep(0.1) if not success: - log("ERROR: Failed to create directory for loop images!") + Logger.error("ERROR: Failed to create directory for loop images!") return # If for any reason we're missing any background images, this will go get them... prepare_backgrounds(radar_code, path) - # Ok so we should have the backgrounds...now it is time get the current radar loop + # OK so we should have the backgrounds...now it is time get the current radar loop # first we retrieve a list of the available files via ftp - log("Download the radar loop") + Logger.debug("Download the radar loop") files = [] - log("Log in to BOM FTP") + Logger.debug("Log in to BOM FTP") attempts = 0 ftp = None @@ -236,13 +243,13 @@ def build_images(radar_code, path, loop_path): time.sleep(1) if not ftp: - log("Failed after 3 attempt to connect to BOM FTP - can't update radar loop") + Logger.error("Failed after 3 attempt to connect to BOM FTP - can't update radar loop") return ftp.login("anonymous", "anonymous@anonymous.org") ftp.cwd("/anon/gen/radar/") - log("Get files list") + Logger.debug("Get files list") # connected, so let's get the list try: # BOM FTP still, in 2021, does not support the nicer mdst() operation @@ -250,20 +257,20 @@ def build_images(radar_code, path, loop_path): files.sort(reverse=True) except ftplib.error_perm as resp: if str(resp) == "550 No files found": - log("No files in BOM ftp directory!") + Logger.error("No files in BOM ftp directory!") else: - log("Something wrong in the ftp bit of radar images") - log(str(resp)) + Logger.error("Something wrong in the ftp bit of radar images") + Logger.error(str(resp)) - log("Download new files, and rename existing files, to avoid Kodi caching issues with the animated radar") - # ok now we need just the matching radar files... - # Maximum of 25 files (125 minutes, just over 2 hours, at 5 minutes each) + Logger.debug("Download new files, and rename existing files, to avoid Kodi caching issues with the animated radar") + # OK now we need just the matching radar files... + # Maximum of 13 files (65 minutes, just over an hour, at 5 minutes each) loop_pic_names = [] for f in files: if radar_code in f: loop_pic_names.insert(0, f) - if len(loop_pic_names) > 25: - log("Retrieved names of latest 25 radar images (2 hours), that's enough.") + if len(loop_pic_names) > 13: + Logger.debug("Retrieved names of latest 13 radar images (1 hour), that's enough.") break # Download the actual images @@ -276,8 +283,8 @@ def build_images(radar_code, path, loop_path): if f[-3:] == "png": image_to_retrieve = Store.BOM_RADAR_FTPSTUB + f output_file = time_now + "." + f - log("Retrieving new radar image: " + image_to_retrieve) - log("Output to file: " + output_file) + Logger.debug("Retrieving new radar image: " + image_to_retrieve) + Logger.debug("Output to file: " + output_file) try: radar_image = urllib.request.urlopen(image_to_retrieve) @@ -285,13 +292,13 @@ def build_images(radar_code, path, loop_path): fh.write(radar_image.read()) except Exception as e: - log(f"Failed to retrieve radar image: {image_to_retrieve}, exception: {str(e)}") + Logger.error(f"Failed to retrieve radar image: {image_to_retrieve}, exception: {str(e)}") else: - log("Using cached radar image: " + time_now + "." + f) + Logger.debug("Using cached radar image: " + time_now + "." + f) ########################################################### -# MAIN - for testing outside of Kodi +# MAIN - for testing outside Kodi if __name__ == "__main__": @@ -299,24 +306,24 @@ def build_images(radar_code, path, loop_path): if len(sys.argv) > 1 and sys.argv[1] == "clean": # noinspection PyBroadException try: - log("\n\nCleaning test-outputs folder") + Logger.debug("\n\nCleaning test-outputs folder") shutil.rmtree(os.getcwd() + "/test-outputs/") except: pass - log("\nCurrent files in test-outputs:\n") + Logger.debug("\nCurrent files in test-outputs:\n") for dir_path, dir_names, filenames in os.walk(os.getcwd() + "/test-outputs/"): for name in dir_names: - log(os.path.join(dir_path, name)) + Logger.debug(os.path.join(dir_path, name)) for name in filenames: - log(os.path.join(dir_path, name)) + Logger.debug(os.path.join(dir_path, name)) test_radars = ["IDR023", "IDR00004"] for test_radar in test_radars: backgrounds_path = os.getcwd() + "/test-outputs/backgrounds/" + test_radar + "/" overlay_loop_path = os.getcwd() + "/test-outputs/loop/" + test_radar + "/" - log(f'\nTesting getting radar images from the BOM for {test_radar}\n') + Logger.debug(f'\nTesting getting radar images from the BOM for {test_radar}\n') build_images(test_radar, backgrounds_path, overlay_loop_path) - log(os.listdir(backgrounds_path)) - log(os.listdir(overlay_loop_path)) + Logger.debug(os.listdir(backgrounds_path)) + Logger.debug(os.listdir(overlay_loop_path)) diff --git a/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py b/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py index 6ccc22ef7..4e715f0b4 100644 --- a/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py +++ b/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py @@ -1,4 +1,6 @@ -# N.B. THIS IS (NOT YET?) DIRECTLY RUN BY XBMC - IS JUST AN AID FOR DEVELOPMENT +# N.B. THIS IS NOT DIRECTLY RUN BY KODI - IS JUST AN AID FOR DEVELOPMENT +# Gives python and JS ready lists of BOM radar locations, run by: +# python3 bom_radar_scrape_latest.py import re import requests diff --git a/weather.ozweather/resources/lib/common.py b/weather.ozweather/resources/lib/common.py deleted file mode 100644 index 81c8a2707..000000000 --- a/weather.ozweather/resources/lib/common.py +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Handy utility functions for Kodi Addons -By bossanova808 -Free in all senses.... -VERSION 0.2.3 2021-06-21 -(For Kodi Matrix & later) -""" -import sys -import traceback - -import xbmc -import xbmcvfs -import xbmcgui -import xbmcaddon - -ADDON = xbmcaddon.Addon() -ADDON_NAME = ADDON.getAddonInfo('name') -ADDON_ID = ADDON.getAddonInfo('id') -ADDON_ICON = ADDON.getAddonInfo('icon') -ADDON_AUTHOR = ADDON.getAddonInfo('author') -ADDON_VERSION = ADDON.getAddonInfo('version') -ADDON_ARGUMENTS = f'{sys.argv}' -CWD = ADDON.getAddonInfo('path') -LANGUAGE = ADDON.getLocalizedString -PROFILE = xbmcvfs.translatePath(ADDON.getAddonInfo('profile')) -KODI_VERSION = xbmc.getInfoLabel('System.BuildVersion') -# noinspection SpellCheckingInspection -USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" -HOME_WINDOW = xbmcgui.Window(10000) -WEATHER_WINDOW = xbmcgui.Window(12600) - - -""" -Determine if we are unit testing outside of Kodi, or actually running within Kodi -Because we're using Kodi stubs https://romanvm.github.io/Kodistubs/ we can't rely on 'import xbmc' failing -So we use this hack - Kodi will return a user agent string, but Kodistubs just returns an empty string. -If we are unit testing, change logs -> print - -In other files, minimal code to make this work is: - -# Small hack to allow for unit testing - see common.py for explanation -if not xbmc.getUserAgent(): - sys.path.insert(0, '../../..') # modify this depending on actual level - assumes resources/lib/something/file.py - -from resources.lib.store import Store -from resources.lib.common import * -..etc - -""" - -unit_testing = False -if not xbmc.getUserAgent(): - - xbmc = None - unit_testing = True - KODI_VERSION = 'N/A' - - print("\nNo user agent, must be unit testing.\n") - - def log(message, exception_instance=None, level=None): - print(f'DEBUG {level}: {message}') - if exception_instance: - print(f'EXCEPTION: {traceback.format_exc(exception_instance)}') - - -else: - - def log(message, exception_instance=None, level=xbmc.LOGDEBUG): - """ - Log a message to the Kodi debug log, if debug logging is turned on. - - :param message: required, the message to log - :param exception_instance: optional, an instance of some Exception - :param level: optional, the Kodi log level to use, default LOGDEBUG but can override with level=xbmc.LOGINFO - """ - - message = f'### {ADDON_NAME} {ADDON_VERSION} - {message}' - message_with_exception = message + f' ### Exception: {traceback.format_exc(exception_instance)}' - - if exception_instance is None: - xbmc.log(message, level) - else: - xbmc.log(message_with_exception, level) - - def set_property(window, name, value=""): - """ - Set a property on a window. - To clear a property, provide an empty string - - :param window: Required. The Kodi window on which to set the property. - :param name: Required. Name of the property. - :param value: Optional (defaults to ""). Set the property to this value. An empty string clears the property. - """ - if value is None: - window.clearProperty(name) - - value = str(value) - if value: - log(f'Setting window property {name} to value {value}') - window.setProperty(name, value) - else: - log(f'Clearing window property {name}') - window.clearProperty(name) - - def get_property(window, name): - """ - Return the value of a window property - @param window: - @param name: - @return: - """ - return window.getProperty(name) - - - def get_property_as_bool(window, name): - """ - Return the value of a window property as a boolean - @param window: - @param name: - @return: - """ - return window.getProperty(name).lower() == "true" - - - def send_kodi_json(human_description, json_string): - """ - Send a JSON command to Kodi, logging the human description, command, and result returned. - - :param human_description: Required. A human sensible description of what the command is aiming to do/retrieve. - :param json_string: Required. The json command to send. - """ - log(f'KODI JSON RPC command: {human_description} [{json_string}]') - result = xbmc.executeJSONRPC(json_string) - log(f'KODI JSON RPC result: {result}') - return result - - - def get_setting(setting): - """ - Helper function to get string type from settings - - @param setting: - @return: setting value - """ - return ADDON.getSetting(setting).strip() - - - def get_setting_as_bool(setting): - """ - Helper function to get bool type from settings - - @param setting: - @return: setting value as boolean - """ - return get_setting(setting).lower() == "true" - - - def notify(message, notification_type=xbmcgui.NOTIFICATION_ERROR, duration=5000): - """ - Send a notification to the user via the Kodi GUI - - @param message: the message to send - @param notification_type: xbmcgui.NOTIFICATION_ERROR (default), xbmcgui.NOTIFICATION_WARNING, or xbmcgui.NOTIFICATION_INFO - @param duration: time to display notification in milliseconds, default 5000 - @return: None - """ - dialog = xbmcgui.Dialog() - - dialog.notification(ADDON_NAME, - message, - notification_type, - duration) - - -def footprints(startup=True): - """ - Log the startup of an addon, and key Kodi details that are helpful for debugging - - :param startup: optional, default True. If true, log the startup of an addon, otherwise log the exit. - """ - if startup: - log(f'Starting...', level=xbmc.LOGINFO) - log(f'Kodi Version: {KODI_VERSION}', level=xbmc.LOGINFO) - log(f'Addon arguments: {ADDON_ARGUMENTS}', level=xbmc.LOGINFO) - else: - log(f'Exiting...', level=xbmc.LOGINFO) - - diff --git a/weather.ozweather/resources/lib/forecast.py b/weather.ozweather/resources/lib/forecast.py index ac83876dd..5a019d909 100644 --- a/weather.ozweather/resources/lib/forecast.py +++ b/weather.ozweather/resources/lib/forecast.py @@ -1,3 +1,7 @@ +from bossanova808.constants import * +from bossanova808.utilities import * +from bossanova808.logger import Logger + # noinspection PyPackages from .abc.abc_video import * # noinspection PyPackages @@ -10,7 +14,7 @@ def clear_properties(): """ Clear all properties on the weather window in preparation for an update. """ - log("Clearing all weather window properties") + Logger.info("Clearing all weather window properties") try: set_property(WEATHER_WINDOW, 'Weather.IsFetched') set_property(WEATHER_WINDOW, 'Daily.IsFetched') @@ -92,7 +96,7 @@ def clear_properties(): set_property(WEATHER_WINDOW, 'Day%i.LowTemperature' % count) set_property(WEATHER_WINDOW, 'Day%i.Outlook' % count) set_property(WEATHER_WINDOW, 'Day%i.LongOutlookDay' % count) - set_property(WEATHER_WINDOW, 'Day%i.OutlookIcon' % count ) + set_property(WEATHER_WINDOW, 'Day%i.OutlookIcon' % count) set_property(WEATHER_WINDOW, 'Day%i.ConditionIcon' % count) set_property(WEATHER_WINDOW, 'Day%i.FanartCode' % count) set_property(WEATHER_WINDOW, 'Day%i.ShortDate' % count) @@ -116,8 +120,8 @@ def clear_properties(): set_property(WEATHER_WINDOW, 'Daily.%i.ShortDate' % count) set_property(WEATHER_WINDOW, 'Daily.%i.ShortDay' % count) - except Exception as inst: - log("********** Oz Weather Couldn't clear all the properties, sorry!!", inst) + except Exception: + Logger.error("********** Oz Weather Couldn't clear all the properties, sorry!!") # noinspection PyShadowingNames @@ -130,18 +134,19 @@ def forecast(geohash, radar_code): """ extended_features = ADDON.getSettingBool('ExtendedFeaturesToggle') - log(f'Extended features: {extended_features}') + Logger.debug(f'Extended features: {extended_features}') purge_backgrounds = ADDON.getSettingBool('PurgeRadarBackgroundsOnNextRefresh') - log(f'Purge Backgrounds: {purge_backgrounds}') + Logger.debug(f'Purge Backgrounds: {purge_backgrounds}') # Has the user requested we refresh the radar backgrounds on next weather fetch? if purge_backgrounds: + Logger.info("Purging all radar backgrounds") dump_all_radar_backgrounds() ADDON.setSetting('PurgeRadarBackgroundsOnNextRefresh', 'false') # Get the radar images first - because it looks better on refreshes if extended_features: - log(f'Getting radar images for {radar_code}') + Logger.debug(f'Getting radar images for {radar_code}') backgrounds_path = xbmcvfs.translatePath( "special://profile/addon_data/weather.ozweather/radarbackgrounds/" + radar_code + "/") overlay_loop_path = xbmcvfs.translatePath( @@ -159,8 +164,8 @@ def forecast(geohash, radar_code): # utc - get from filename of oldest and newest - it's the last number before the .png utc_oldest = oldest_file.split('.')[-2] utc_newest = newest_file.split('.')[-2] - log(f"utc_oldest {utc_oldest}") - log(f"utc_newest {utc_newest}") + Logger.debug(f"utc_oldest {utc_oldest}") + Logger.debug(f"utc_newest {utc_newest}") time_oldest = utc_str_to_local_str(utc_oldest, "%Y%m%d%H%M") time_newest = utc_str_to_local_str(utc_newest, "%Y%m%d%H%M") @@ -172,12 +177,12 @@ def forecast(geohash, radar_code): weather_data = None if geohash: - log(f'Using the BOM API. Getting weather data for {geohash}') + Logger.info(f'Using the BOM API. Getting weather data for {geohash}') weather_data = bom_forecast(geohash) # At this point, we should have _something_ - if not, log the issue, and we're done... if not weather_data: - log("Unable to get weather_data from BOM - internet connection issue or addon not configured?", level=xbmc.LOGINFO) + Logger.error("Unable to get weather_data from BOM - internet connection issue or addon not configured?") return # We have weather_data - set all the properties on Kodi's weather window... @@ -186,12 +191,12 @@ def forecast(geohash, radar_code): # Get the ABC 90-second weather video link if extended features is enabled if extended_features: - log("Getting the ABC weather video link") + Logger.info("Getting the ABC weather video link") url = get_abc_weather_video_link() if url: set_property(WEATHER_WINDOW, 'Video.1', url) - # And announce everything is fetched.. + # And announce everything is fetched... set_property(WEATHER_WINDOW, "Weather.IsFetched", "true") set_property(WEATHER_WINDOW, "Daily.IsFetched", "true") set_property(WEATHER_WINDOW, "Today.IsFetched", "true") @@ -204,7 +209,7 @@ def get_weather(): Gets the latest observations, forecast and radar images for the currently chosen location """ - log("*** Updating Weather Data ***") + Logger.info("*** Updating Weather Data ***") # Nice neat updates - clear out all set window data first... clear_properties() @@ -216,29 +221,29 @@ def get_weather(): try: skin_in_use = xbmc.getSkinDir().split('.')[1] set_property(WEATHER_WINDOW, 'SkinInUse', skin_in_use) - except: + except IndexError: pass # Retrieve the currently chosen location geohash & radar code geohash = ADDON.getSetting(f'Location{sys.argv[1]}BOMGeoHash') radar = ADDON.getSetting(f'Radar{sys.argv[1]}') or ADDON.getSetting(f'Location{sys.argv[1]}ClosestRadar') - # With the new closest radar system, the radar is store as e.g. 'Melbourne - IDR023' so strip the name off... + # With the new closest radar system, the radar is stored as e.g. 'Melbourne - IDR023' so strip the name off... split_code = radar.split(' - ') if len(split_code) > 1: - log(f"Radar code: transforming [{radar}] to: [{split_code[-1]}]") + Logger.warning(f"Radar code: transforming [{radar}] to: [{split_code[-1]}]") radar = split_code[-1] if not geohash: - log("No BOM location geohash - can't retrieve weather data!") + Logger.error("No BOM location geohash - can't retrieve weather data!") return # If we don't have a radar code, get the national radar by default if not radar: radar = 'IDR00004' - log(f'Radar code empty for location, so using default radar code {radar} (= national radar)') + Logger.warning(f'Radar code empty for location, so using default radar code {radar} (= national radar)') - log(f'Current location: BOM geohash "{geohash}", radar code {radar}') + Logger.info(f'Current location: BOM geohash "{geohash}", radar code {radar}') # Now scrape the weather data & radar images forecast(geohash, radar) @@ -265,4 +270,3 @@ def get_weather(): set_property(WEATHER_WINDOW, 'Forecast.Latitude', latitude) set_property(WEATHER_WINDOW, 'Forecast.Longitude', longitude) set_property(WEATHER_WINDOW, 'Forecast.Updated', time.strftime("%d/%m @ %H:%M").lower()) - diff --git a/weather.ozweather/resources/lib/locations.py b/weather.ozweather/resources/lib/locations.py index 1fa471a19..218a8eeed 100644 --- a/weather.ozweather/resources/lib/locations.py +++ b/weather.ozweather/resources/lib/locations.py @@ -1,20 +1,20 @@ -# noinspection PyPackages -from .common import * +from bossanova808.utilities import * +from bossanova808.logger import Logger def refresh_locations(): """ Get the user's location and radar code choices from the addon settings, and set them as window properties """ - log("Refreshing locations from settings") + Logger.info("Refreshing locations from settings") location1 = ADDON.getSetting('Location1BOM') or "" location2 = ADDON.getSetting('Location2BOM') or "" location3 = ADDON.getSetting('Location3BOM') or "" - log("Location1: " + location1) - log("Location2: " + location2) - log("Location3: " + location3) + Logger.info("Location1: " + location1) + Logger.info("Location2: " + location2) + Logger.info("Location3: " + location3) locations = 0 @@ -32,18 +32,18 @@ def refresh_locations(): set_property(WEATHER_WINDOW, 'Location3', location3) # and set count of locations - log(f"Total locations: {locations}") + Logger.info(f"Total locations: {locations}") set_property(WEATHER_WINDOW, 'Locations', str(locations)) - log("Refreshing radar locations from settings") + Logger.info("Refreshing radar locations from settings") radar1 = ADDON.getSetting('Radar1') or ADDON.getSetting('Location1ClosestRadar') or "" radar2 = ADDON.getSetting('Radar2') or ADDON.getSetting('Location2ClosestRadar') or "" radar3 = ADDON.getSetting('Radar3') or ADDON.getSetting('Location3ClosestRadar') or "" - log("Radar1: " + radar1) - log("Radar2: " + radar2) - log("Radar3: " + radar3) + Logger.info("Radar1: " + radar1) + Logger.info("Radar2: " + radar2) + Logger.info("Radar3: " + radar3) radars = 0 @@ -58,6 +58,5 @@ def refresh_locations(): set_property(WEATHER_WINDOW, 'Radar3', radar3) # and set count of radars - log(f"Total radars: {radars}") + Logger.info(f"Total radars: {radars}") set_property(WEATHER_WINDOW, 'Radars', str(radars)) - diff --git a/weather.ozweather/resources/lib/ozweather.py b/weather.ozweather/resources/lib/ozweather.py index bdcdda9cc..38745359c 100644 --- a/weather.ozweather/resources/lib/ozweather.py +++ b/weather.ozweather/resources/lib/ozweather.py @@ -10,6 +10,8 @@ # noinspection PyPackages from .abc.abc_video import * +from bossanova808.utilities import * + def run(args): """ diff --git a/weather.ozweather/resources/lib/store.py b/weather.ozweather/resources/lib/store.py index fddfbb5c5..0aace1055 100644 --- a/weather.ozweather/resources/lib/store.py +++ b/weather.ozweather/resources/lib/store.py @@ -26,81 +26,83 @@ class Store: # The master URL is: http://www.bom.gov.au/australia/radar/about/radar_site_info.shtml # Can cross check with: https://github.com/theOzzieRat/bom-radar-card/blob/master/src/bom-radar-card.ts around line 130 - # Automatically generated by bom_radar_scraper_latest.py from http://www.bom.gov.au/australia/radar/about/radar_site_info.shtml + # (Python) Automatically generated by bom_radar_scraper_latest.py from http://www.bom.gov.au/australia/radar/info/nt_info.shtml BOM_RADAR_LOCATIONS = [ - # http://www.bom.gov.au/australia/radar/info/nsw_info.shtml - (-29.96, 146.81, "Brewarrina", "IDR933"), - (-35.66, 149.51, "Canberra (Captain's Flat)", "IDR403"), - (-29.62, 152.97, "Grafton", "IDR283"), - (-33.55, 145.52, "Hillston", "IDR943"), - (-29.50, 149.85, "Moree", "IDR533"), - (-31.0240, 150.1915, "Namoi (Blackjack Mountain)", "IDR693"), - (-32.730, 152.027, "Newcastle", "IDR043"), - (-29.033, 167.933, "Norfolk Island", "IDR623"), - (-33.701, 151.210, "Sydney (Terrey Hills)", "IDR713"), - (-35.17, 147.47, "Wagga Wagga", "IDR553"), - (-34.264, 150.874, "Wollongong (Appin)", "IDR033"), - (-32.74, 148.70, "Yeoval", "IDR963"), - # http://www.bom.gov.au/australia/radar/info/vic_info.shtml - (-37.86, 144.76, "Melbourne", "IDR023"), - (-34.28, 141.59, "Mildura", "IDR973"), - (-37.89, 147.56, "Bairnsdale", "IDR683"), - (-35.99, 142.01, "Rainbow", "IDR953"), - (-36.03, 146.03, "Yarrawonga", "IDR493"), - # http://www.bom.gov.au/australia/radar/info/qld_info.shtml - (-19.88, 148.08, "Bowen", "IDR243"), - (-27.39, 153.13, "Brisbane Airport", "IDR1053"), - (-27.718, 153.240, "Brisbane (Mt. Stapylton)", "IDR663"), - (-16.82, 145.68, "Cairns", "IDR193"), - (-23.5494, 148.2392, "Emerald (Central Highlands)", "IDR723"), - (-23.86, 151.26, "Gladstone", "IDR233"), - (-18.99, 144.99, "Greenvale", "IDR743"), - (-25.957, 152.577, "Gympie (Mt Kanigan)", "IDR083"), - (-23.43, 144.29, "Longreach", "IDR563"), - (-21.12, 149.22, "Mackay", "IDR223"), - (-27.61, 152.54, "Marburg", "IDR503"), - (-16.67, 139.17, "Mornington Island", "IDR363"), - (-20.7114, 139.5553, "Mount Isa", "IDR753"), - (-20.75, 143.14, "Richmond", "IDR1073"), - (-25.696, 149.898, "Taroom", "IDR983"), - (-19.42, 146.55, "Townsville (Hervey Range)", "IDR733"), - (-26.44, 147.35, "Warrego", "IDR673"), - (-12.67, 141.92, "Weipa", "IDR783"), - (-16.288, 149.965, "Willis Island", "IDR413"), - # http://www.bom.gov.au/australia/radar/info/wa_info.shtml - (-34.94, 117.80, "Albany", "IDR313"), - (-17.95, 122.23, "Broome", "IDR173"), - (-24.88, 113.67, "Carnarvon", "IDR053"), - (-20.65, 116.69, "Dampier", "IDR153"), - (-31.78, 117.95, "South Doodlakine", "IDR583"), - (-33.83, 121.89, "Esperance", "IDR323"), - (-28.80, 114.70, "Geraldton", "IDR063"), - (-25.03, 128.30, "Giles", "IDR443"), - (-18.23, 127.66, "Halls Creek", "IDR393"), - (-30.79, 121.45, "Kalgoorlie-Boulder", "IDR483"), - (-22.10, 114.00, "Learmonth", "IDR293"), - (-33.097, 119.009, "Newdegate", "IDR383"), - (-32.39, 115.87, "Perth (Serpentine)", "IDR703"), - (-31.93, 115.98, "Perth Airport", "IDR263"), - (-20.37, 118.63, "Port Hedland", "IDR163"), - (-30.36, 116.29, "Watheroo", "IDR793"), - (-15.45, 128.12, "Wyndham", "IDR073"), - # http://www.bom.gov.au/australia/radar/info/sa_info.shtml - (-34.617, 138.469, "Adelaide (Buckland Park)", "IDR643"), - (-35.33, 138.50, "Adelaide (Sellicks Hill)", "IDR463"), - (-32.13, 133.70, "Ceduna", "IDR333"), - (-37.75, 140.77, "Mt Gambier", "IDR143"), - (-31.16, 136.80, "Woomera", "IDR273"), - # http://www.bom.gov.au/australia/radar/info/tas_info.shtml - (-43.1122, 147.8061, "Hobart (Mt Koonya)", "IDR763"), - (-41.181, 145.579, "West Takone", "IDR523"), - (-42.83, 147.51, "Hobart Airport", "IDR373"), - # http://www.bom.gov.au/australia/radar/info/nt_info.shtml - (-23.82, 133.90, "Alice Springs", "IDR253"), - (-12.46, 130.93, "Darwin/Berrimah", "IDR633"), - (-12.27, 136.82, "Gove", "IDR1123"), - (-14.51, 132.45, "Katherine/Tindal", "IDR423"), - (-11.6494, 133.38, "Warruwi", "IDR773") + # http://www.bom.gov.au/australia/radar/info/nsw_info.shtml + (-29.96, 146.81, "Brewarrina", "IDR933"), + (-35.66, 149.51, "Canberra (Captain's Flat)", "IDR403"), + (-29.62, 152.97, "Grafton", "IDR283"), + (-33.55, 145.52, "Hillston", "IDR943"), + (-29.50, 149.85, "Moree", "IDR533"), + (-31.0240, 150.1915, "Namoi (Blackjack Mountain)", "IDR693"), + (-32.730, 152.027, "Newcastle", "IDR043"), + (-29.033, 167.933, "Norfolk Island", "IDR623"), + (-33.701, 151.210, "Sydney (Terrey Hills)", "IDR713"), + (-35.17, 147.47, "Wagga Wagga", "IDR553"), + (-34.264, 150.874, "Wollongong (Appin)", "IDR033"), + (-32.74, 148.70, "Yeoval", "IDR963"), + # http://www.bom.gov.au/australia/radar/info/vic_info.shtml + (-37.86, 144.76, "Melbourne", "IDR023"), + (-34.28, 141.59, "Mildura", "IDR973"), + (-37.89, 147.56, "Bairnsdale", "IDR683"), + (-35.99, 142.01, "Rainbow", "IDR953"), + (-36.03, 146.03, "Yarrawonga", "IDR493"), + # http://www.bom.gov.au/australia/radar/info/qld_info.shtml + (-19.88, 148.08, "Bowen", "IDR243"), + (-27.39, 153.13, "Brisbane Airport", "IDR1053"), + (-27.718, 153.240, "Brisbane (Mt. Stapylton)", "IDR663"), + (-16.82, 145.68, "Cairns", "IDR193"), + (-23.5494, 148.2392, "Emerald (Central Highlands)", "IDR723"), + (-23.86, 151.26, "Gladstone", "IDR233"), + (-18.99, 144.99, "Greenvale", "IDR743"), + (-25.957, 152.577, "Gympie (Mt Kanigan)", "IDR083"), + (-23.43, 144.29, "Longreach", "IDR563"), + (-21.12, 149.22, "Mackay", "IDR223"), + (-27.61, 152.54, "Marburg", "IDR503"), + (-16.67, 139.17, "Mornington Island", "IDR363"), + (-20.7114, 139.5553, "Mount Isa", "IDR753"), + (-20.75, 143.14, "Richmond", "IDR1073"), + (-25.696, 149.898, "Taroom", "IDR983"), + (-27.2740, 151.9930, "Toowoomba", "IDR1083"), + (-19.42, 146.55, "Townsville (Hervey Range)", "IDR733"), + (-26.44, 147.35, "Warrego", "IDR673"), + (-12.67, 141.92, "Weipa", "IDR783"), + (-16.288, 149.965, "Willis Island", "IDR413"), + # http://www.bom.gov.au/australia/radar/info/wa_info.shtml + (-34.94, 117.80, "Albany", "IDR313"), + (-17.95, 122.23, "Broome", "IDR173"), + (-24.88, 113.67, "Carnarvon", "IDR053"), + (-24.88, 113.67, "Carnarvon", "IDR1143"), + (-20.65, 116.69, "Dampier", "IDR153"), + (-31.78, 117.95, "South Doodlakine", "IDR583"), + (-33.83, 121.89, "Esperance", "IDR323"), + (-28.80, 114.70, "Geraldton", "IDR063"), + (-25.03, 128.30, "Giles", "IDR443"), + (-18.23, 127.66, "Halls Creek", "IDR393"), + (-30.79, 121.45, "Kalgoorlie-Boulder", "IDR483"), + (-22.10, 114.00, "Learmonth", "IDR293"), + (-33.097, 119.009, "Newdegate", "IDR383"), + (-32.39, 115.87, "Perth (Serpentine)", "IDR703"), + (-31.93, 115.98, "Perth Airport", "IDR263"), + (-20.37, 118.63, "Port Hedland", "IDR163"), + (-30.36, 116.29, "Watheroo", "IDR793"), + (-15.45, 128.12, "Wyndham", "IDR073"), + # http://www.bom.gov.au/australia/radar/info/sa_info.shtml + (-34.617, 138.469, "Adelaide (Buckland Park)", "IDR643"), + (-35.33, 138.50, "Adelaide (Sellicks Hill)", "IDR463"), + (-32.13, 133.70, "Ceduna", "IDR333"), + (-37.75, 140.77, "Mt Gambier", "IDR143"), + (-31.16, 136.80, "Woomera", "IDR273"), + # http://www.bom.gov.au/australia/radar/info/tas_info.shtml + (-43.1122, 147.8061, "Hobart (Mt Koonya)", "IDR763"), + (-41.181, 145.579, "West Takone", "IDR523"), + (-42.83, 147.51, "Hobart Airport", "IDR373"), + # http://www.bom.gov.au/australia/radar/info/nt_info.shtml + (-23.82, 133.90, "Alice Springs", "IDR253"), + (-12.46, 130.93, "Darwin/Berrimah", "IDR633"), + (-12.27, 136.82, "Gove", "IDR1123"), + (-14.51, 132.45, "Katherine/Tindal", "IDR423"), + (-11.6494, 133.38, "Warruwi", "IDR773") ] DAYS = {"Mon": "Monday",