From 31c7c2095e98a2d2021af1b71a05c535829c12c6 Mon Sep 17 00:00:00 2001 From: Ian Renton Date: Wed, 23 Sep 2026 17:30:12 +0100 Subject: [PATCH] Improve some error handling. Closes #150 --- providers/callsigndata/hamqth.py | 4 + providers/callsigndata/qrz.py | 4 + templates/add_spot.html | 2 +- templates/alerts.html | 2 +- templates/bands.html | 4 +- templates/base.html | 18 ++--- templates/cards/hamqth.html | 2 +- templates/cards/qrz.html | 2 +- templates/conditions.html | 2 +- templates/help/about.html | 20 +++++ templates/help/accuracy.html | 17 +++++ templates/help/faq.html | 123 +++++++++++++++++++++++++++++++ templates/help/help_page.html | 14 ++++ templates/help/index.html | 20 +++++ templates/help/privacy.html | 29 ++++++++ templates/help/thanks.html | 22 ++++++ templates/help/using.html | 44 +++++++++++ templates/map.html | 6 +- templates/spots.html | 8 +- templates/status.html | 2 +- 20 files changed, 321 insertions(+), 24 deletions(-) create mode 100644 templates/help/about.html create mode 100644 templates/help/accuracy.html create mode 100644 templates/help/faq.html create mode 100644 templates/help/help_page.html create mode 100644 templates/help/index.html create mode 100644 templates/help/privacy.html create mode 100644 templates/help/thanks.html create mode 100644 templates/help/using.html diff --git a/providers/callsigndata/hamqth.py b/providers/callsigndata/hamqth.py index 56a7821..0f62e39 100644 --- a/providers/callsigndata/hamqth.py +++ b/providers/callsigndata/hamqth.py @@ -1,6 +1,7 @@ import logging import urllib.parse from datetime import datetime, timedelta +from xml.parsers.expat import ExpatError import pytz import xmltodict @@ -60,6 +61,9 @@ class HamQTH(APIQueryCallsignDataProvider): # Log this failure at debug level only, not our problem if user entered the wrong password. logger.debug("HamQTH login details incorrect, failed to look up with HamQTH.") return None + except ExpatError: + logger.warning("HamQTH provided blank or malformed content when trying to authenticate") + return None except Exception: logger.exception("Exception when getting HamQTH session key") return None diff --git a/providers/callsigndata/qrz.py b/providers/callsigndata/qrz.py index 821e0f6..f3134a7 100644 --- a/providers/callsigndata/qrz.py +++ b/providers/callsigndata/qrz.py @@ -1,6 +1,7 @@ import logging import urllib.parse from datetime import datetime, timedelta +from xml.parsers.expat import ExpatError import pytz import xmltodict @@ -56,6 +57,9 @@ class QRZ(APIQueryCallsignDataProvider): # Log this failure at debug level only, not our problem if user entered the wrong password. logger.debug("QRZ.com login details incorrect, failed to look up with QRZ.") return None + except ExpatError: + logger.warning("QRZ.com provided blank or malformed content when trying to authenticate") + return None except Exception: logger.exception("Exception when getting QRZ.com session key") return None diff --git a/templates/add_spot.html b/templates/add_spot.html index 294d7c7..25106fb 100644 --- a/templates/add_spot.html +++ b/templates/add_spot.html @@ -77,7 +77,7 @@ - + diff --git a/templates/alerts.html b/templates/alerts.html index 3009080..0910d8f 100644 --- a/templates/alerts.html +++ b/templates/alerts.html @@ -85,7 +85,7 @@ - + diff --git a/templates/bands.html b/templates/bands.html index 65e5ec0..7a4cec5 100644 --- a/templates/bands.html +++ b/templates/bands.html @@ -76,8 +76,8 @@ - - + + diff --git a/templates/base.html b/templates/base.html index 42b53cb..7d6b222 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,6 +1,6 @@ {% extends "skeleton.html" %} {% block head_extra %} - + @@ -16,10 +16,10 @@ window.fetchEventSource = fetchEventSource; - - - - + + + + {% end %} {% block body %}
@@ -51,8 +51,8 @@ class="fa-solid fa-sun"> Conditions - + @@ -75,10 +75,10 @@ v{{software_version}}

- See Privacy for more information. + See Privacy for more information.
diff --git a/templates/cards/qrz.html b/templates/cards/qrz.html index 2b43f7e..5f1c30d 100644 --- a/templates/cards/qrz.html +++ b/templates/cards/qrz.html @@ -27,7 +27,7 @@
- See Privacy for more information. + See Privacy for more information.
diff --git a/templates/conditions.html b/templates/conditions.html index e4181a4..30dc16c 100644 --- a/templates/conditions.html +++ b/templates/conditions.html @@ -284,7 +284,7 @@ - + diff --git a/templates/help/about.html b/templates/help/about.html new file mode 100644 index 0000000..bdb16aa --- /dev/null +++ b/templates/help/about.html @@ -0,0 +1,20 @@ +{% extends "help_page.html" %} +{% block help_content %} + +

About Spothole

+

Spothole is a utility to aggregate "spots" from amateur radio DX clusters and xOTA spotting sites, and provide an + open JSON API as well as a website to browse the data.

+

While there are several other web-based interfaces to DX clusters, and sites that aggregate spots from various + outdoor activity programmes for amateur radio, Spothole differentiates itself by supporting a larger number of + data sources, and by being "API first" rather than just providing a web front-end. This allows other software to + be built on top of it.

+

The API is deliberately well-defined with an OpenAPI specification and API documentation. The API delivers spots in a consistent format regardless of the data + source, freeing developers from needing to know how each individual data source presents its data.

+

Spothole itself is also open source, Public Domain licenced code that anyone can take and modify. The source code is here.

+

The software was written by Ian Renton, MØTRT with code contributions by + Steven, M1SDH. The full list of thanks due to others can be found at the bottom of this page.

+

This server is running Spothole version {{software_version}}.

+ +{% end %} diff --git a/templates/help/accuracy.html b/templates/help/accuracy.html new file mode 100644 index 0000000..611f797 --- /dev/null +++ b/templates/help/accuracy.html @@ -0,0 +1,17 @@ +{% extends "help_page.html" %} +{% block help_content %} + +

Data Accuracy

+

Please note that the data coming out of Spothole is only as good as the data going in. People mis-hear and make + typos when spotting callsigns all the time. There are also plenty of cases where Spothole's data, particularly + location data, may be inaccurate. For example, there are POTA parks that span multiple US states, countries that + span multiple CQ zones, portable operators with no requirement to sign /P, etc. If you are doing something where + accuracy is important, such as contesting, you should not rely on Spothole's data to fill in any gaps in your + log.

+

In the Spothole user interface, under "Your Data", you can enter your credentials for QRZ.com and/or HamQTH if + you have them. This allows Spothole to augment its data with lookups from these services. See the following + section, Privacy, for details of how these are handled. If you are looking at the map and see lots of spots in + the geographic centre of countries, allowing these lookups will help. For QRZ.com a paid account is required to + look up operator locations.

+ +{% end %} diff --git a/templates/help/faq.html b/templates/help/faq.html new file mode 100644 index 0000000..6ae62bb --- /dev/null +++ b/templates/help/faq.html @@ -0,0 +1,123 @@ +{% extends "help_page.html" %} +{% block help_content %} + +

FAQ

+

"Spots"? "DX Clusters"? What does any of this mean?

+

This is a tool for amateur ("ham") radio users. Many amateur radio operators like to make contacts with others + who are doing something more interesting than sitting in their home "shack", such as people in rarely-seen + countries, remote islands, or on mountaintops. Such operators are often "spotted", i.e. when someone speaks to + them, they will put the details such as their operating frequency into an online system, to let others know + where to find them. A DX Cluster is one type of those systems. Most outdoor radio awards programmes, such as + "Parks on the Air" (POTA) have their own websites for posting spots.

+

Spothole is an "aggregator" for those spots, so it checks lots of different services for data, and brings it all + together in one place. So no matter what kinds of interesting spots you are looking for, you can find them + here.

+

As well as spots, it also provides a similar feed of "alerts". This is where amateur radio users who are going to + interesting places soon will announce their intentions.

+

What are "DX", "DE" and modes?

+

In amateur radio terminology, the "DX" contact is the "interesting" one that is using the frequency shown and + looking for callers. They might be on a remote island or just in a local park, but either way it's interesting + enough that someone has "spotted" them. The callsign listed under "DE" is the person who entered the spot of the + "DX" operator. "Modes" are the type of communication they are using. For example you might see "CW" which is + Morse Code, or voice "modes" like SSB or FM, or more exotic "data" modes which are used for computer-to-computer + communication.

+

What data sources are supported?

+

Spothole can retrieve spots from: Telnet-based DX clusters, the + Reverse Beacon Network (RBN), the APRS Internet Service (APRS-IS), POTA, + SOTA, WWFF, GMA, WWBOTA, HEMA, Parks 'n' Peaks, ZLOTA, WOTA, LLOTA, WWTOTA, Tiles on the Air, the UK + Packet Repeater Network, and any site based on the xOTA + software by nischu.

+

Spothole can retrieve alerts from: NG3K, POTA, + SOTA, WWFF, Parks 'n' Peaks, WOTA and + BOTA. It also fetches contest dates from + WA7BNM Contest Calendar and RSGB contest calendars.

+

Spothole can retrieve solar and propagation condition data from HamQSL, the + NOAA Space Weather Prediction Center, the Lowell GIRO Data Center and prop.kc2g.com + by KC2G.

+

Spothole can also perform lookups for callsign data on behalf of the user from QRZ.com and HamQTH.

+

Note that the server owner has not necessarily enabled all these data sources. In particular it is common to + disable RBN, to avoid the server being swamped with FT8 traffic, and to disable APRS-IS and UK Packet Net so + that the server only displays stations where there is likely to be an operator physically present for a QSO.

+

Between the various data sources, the following activities / special interest groups are supported: Contests, + DXpeditions, Aeronautical Mobile, Maritime Mobile, EME/Moonbounce, Amateur Satellite, QRP, Parks on the Air + (POTA), Summits on the Air (SOTA), Worldwide Flora & Fauna (WWFF), Global Mountain Activity (GMA), Worldwide + Bunkers on the Air (WWBOTA), HuMPs Excluding Marilyns Award (HEMA), Islands on the Air (IOTA), Mills on the Air + (MOTA), the Amateur Radio Lighthouse Society (ARLHS), International Lighthouse Lightship Weekend (ILLW), Silos + on the Air (SIOTA), World Castles Award (WCA), New Zealand on the Air (ZLOTA), Keith Roget Memorial National + Parks Award (KRMNPA), South Australia National Parks and Conservation Parks Award (SANPCPA), Wainwrights on the + Air (WOTA), Beaches on the Air (BOTA), Lagos y Lagunas On the Air (LLOTA), Towers on the Air, Tiles on + the Air, Worked All Britain (WAB), Worked All Ireland (WAI), Diploma Municipios de España (DME), Diploma + Faros de España (FEA), Diploma Muesos de España (DMUE), Diploma Castillos de España (DCE), Diploma Monumentos y + Vestigios de España (DMVE), Diploma Estaciones de Ferrocarril de España (DEFE), Diploma Teatri Musei e Belle + Arti (DTMBA), British Inland Waterways on the Air (BIWOTA), Castles on the Air (COTA), Polish Gmina Award (PGA), + Diplôme des Moulins de France (DMF), RaDAR Rally, and Toilets on the Air.

+

As of the time of writing in August 2026, I think Spothole captures most radio programmes that have a + defined, downloadable reference list, and almost certainly those that have a spotting/alerting API. If you know + of one I've missed, please let me know!

+

Why can I filter spots by both Activity and Source? Isn't that basically the same thing?

+

Mostly, but not quite. While POTA spots generally come from the POTA source and so on, there are a few + exceptions:

+
    +
  1. Sources like GMA and Parks 'n' Peaks provide spots for multiple different programmes (activities).
  2. +
  3. Cluster spots may name activities in their comment, in which case the source remains the Cluster, but an + activity is assigned. +
  4. +
  5. Some activities, such as Worked all Britain (WAB), don't have their own spotting site and can only + be identified through comments on spots retrieved from other sources. +
  6. +
+

Spothole's web interface exists not just for the end user, but also as a reference implementation for the API, so + I have chosen to demonstrate both methods of filtering.

+

How is this better than DXheat, DXsummit, POTA's own website, etc?

+

It's probably not? But it's nice to have choice.

+

I think it's got three key advantages over those sites:

+
    +
  1. It provides a public, well-documented API with an OpenAPI + specification. Other sites don't have official APIs or don't bother documenting them publicly, because + they want people to use their web page. I like Spothole's web page, but you don't have to use it—if + you're a programmer, you can build your own software on Spothole's API. Spothole does the hard work of + taking all the various data sources and providing a consistent, well-documented data set. You can then do + the fun bit of writing your own application. +
  2. +
  3. It grabs data from a lot more sources. I've seen other sites that pull in DX Cluster and POTA spots + together, but nothing on the scale of what Spothole supports. +
  4. +
  5. Spothole is open source, so anyone can contribute the code to support a new data source or add new features, + and share them with the community. +
  6. +
+

Why does this website ask me if I want to install it?

+

Spothole is a Progressive Web App, which means you can install it on an Android or iOS device by opening the site + in Chrome or Safari respectively, and clicking "Install" on the pop-up panel. It'll only prompt you once, so if + you dismiss the prompt and change your mind, you'll find an Install / Add to Home Screen option on your + browser's menu.

+

Installing Spothole on your phone is completely optional, the website works exactly the same way as the "app" + does.

+

Why hasn't my spot/alert shown up yet?

+

To avoid putting too much load on the various servers that Spothole connects to, the Spothole server only polls + them once every two minutes for spots, and once every 30 minutes for alerts. (Some sources, such as DX clusters, + RBN, APRS-IS and WWBOTA use a non-polling mechanism, and their updates will therefore arrive more quickly.) Then + if you are using the web interface, that has its own rate at which it fetches the data from Spothole. This is + instant for the main spots list, with new spots appearing immediately at the top of the list, while the map and + bands displays update once a minute, and the alerts display updates once every 5 minutes. So you could be + waiting around three minutes to see a newly added spot, or 40 minutes to see a newly added alert.

+

What licence does Spothole use?

+

Spothole's source code is licenced under the Public Domain. You can write a Spothole client, run your own server, + modify it however you like, you can claim you wrote it and charge people £1000 for a copy, I don't really mind. + (Please don't do the last one. But if you're using my code for something cool, it would be nice to hear from + you!)

+

What commands are supported in the telnet server?

+

Currently, exit, and nothing else. Support for some DXSpider-like commands may be added to Spothole + in due course, but at the moment if you want to add Spothole as a telnet cluster data source to your desktop + logging application, that application must handle filtering itself.

+ +{% end %} diff --git a/templates/help/help_page.html b/templates/help/help_page.html new file mode 100644 index 0000000..a218555 --- /dev/null +++ b/templates/help/help_page.html @@ -0,0 +1,14 @@ +{% extends "../base.html" %} +{% block content %} + +
+

Spothole Help

+{% block help_content %}{% end %} +

Back

+
+ + + +{% end %} diff --git a/templates/help/index.html b/templates/help/index.html new file mode 100644 index 0000000..c86a22e --- /dev/null +++ b/templates/help/index.html @@ -0,0 +1,20 @@ +{% extends "../base.html" %} +{% block content %} + +
+

Spothole Help

+ +
+ + + +{% end %} diff --git a/templates/help/privacy.html b/templates/help/privacy.html new file mode 100644 index 0000000..6b21082 --- /dev/null +++ b/templates/help/privacy.html @@ -0,0 +1,29 @@ +{% extends "help_page.html" %} +{% block help_content %} + +

Privacy

+

Spothole collects no data about you on a permanent basis. All spots and alerts are "timed out" and deleted from + the system after a set interval, which by default is one hour for spots and one week for alerts.

+

Settings you select from Spothole's menus are sent to the server, in order to provide the data with the requested + filters. They are also stored in your browser's local storage, so that your preferences are remembered between + sessions.

+

The data you provide can optionally include your login credentials for QRZ.com and HamQTH. You can provide these + in the "Your Data" menu of most pages. If you do, Spothole will augment the data it produces with lookups from + these + services, which can for example provide more accurate markers on the map tab, and operator names when you mouse + over a DX callsign. Spothole will still work fine if you don't provide these. The values you enter are sent to + Spothole via HTTPS so are protected in transit, though of course you do have to trust Spothole with this + sensitive data in order to use this feature.

+

Any data you send as part of a query, such as your QRZ or HamQTH credentials, is used only for the lifetime of + that + query and is not saved anywhere apart from your own device.

+

Spothole uses no trackers, no ads, and no cookies.

+ {% if len(web_ui_options["support_button_html"]) > 0 %} +

Caveat: The owner of this server has chosen to inject their own content into the "spots" page. + This is designed for a "donate" or "support this server" button. The functionality of this injected content is + the responsibility of the server owner, rather than the Spothole software.

+ {% end %} +

Spothole is open source, so you can audit the code if you + like.

+ +{% end %} diff --git a/templates/help/thanks.html b/templates/help/thanks.html new file mode 100644 index 0000000..e3c26e6 --- /dev/null +++ b/templates/help/thanks.html @@ -0,0 +1,22 @@ +{% extends "help_page.html" %} +{% block help_content %} + +

Thanks

+

This project would not have been possible without those volunteers who have taken it upon themselves to run DX + clusters, xOTA programmes, DXpedition lists, callsign lookup databases, solar conditions and propagation + modelling software, and other online tools on which Spothole's data is based. The vast majority of these are not + profit-seeking and are made purely for the love of the hobby and to help others in the community. Spothole is + standing on the shoulders of giants, who deserve a huge amount of thanks for all the work they put in.

+

The following people have specifically helped develop Spothole either by contributing code, requesting features, + or helping squash bugs: Steven M1SDH, Dan S50U, Matt W1CDN, Norby LX1NO, Andrew VK3ARR, Mario DL4MFM, Mark M5TEA, + Michael G7VJR, Rob G7LAS, Ed DD5LP, Raph F4LUB, Luc ON7KEC, Richard GD4OFB, Daniel PY2TDB, Alan VK1AO, + Andrew WK1AD, Ullrich DF5WC, Wayne N3CDF, Jonathan G4IVV, Erik N2EPE, Sorin YO9TSN, Matt HB9HWI, Priit ES1TEB, + Leigh KG7WED, Jouni OH3CUF, Onno VK6FLAB, and Bruce WA7BNM. (If I've forgotten you, let me know!)

+

Spothole is also dependent on a number of Python libraries, such as pyhamtools, and many JavaScript + libraries, as well as the Font Awesome icon set and flag icons from the Noto Color Emoji set, and MIT-licenced + GeoJSON files for CQ and ITU zones from HA8TKS.

+

The project's name was suggested by Harm DK4HAA.

+

This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around + the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.

+ +{% end %} diff --git a/templates/help/using.html b/templates/help/using.html new file mode 100644 index 0000000..294c260 --- /dev/null +++ b/templates/help/using.html @@ -0,0 +1,44 @@ +{% extends "help_page.html" %} +{% block help_content %} + +

Using Spothole

+

There are a number of different ways to use Spothole, depending on what you want to do with it and your level of + technical skill:

+
    +
  1. You can use it on the web, like you are (probably) doing right now. This is how most people use it, + to look up spots and alerts, and make interesting QSOs. +
  2. +
  3. If you are using an Android or iOS device, you can "install" it on your device. Spothole is a + Progressive Web App, meaning it's not delivered through app stores, but if you open the page on Chrome + (Android) or Safari (iOS) there will be an option in the menu to install it. It will then appear in your + main app menu. +
  4. +
  5. You can embed the web interface in another website to show its spots in a custom dashboard or the + like. The usage is explained in more detail in the README file. +
  6. + {% if telnet_server_enabled %} +
  7. You can use it as a traditional telnet-based source of spots, similar to DXSpider and other software, in + your desktop logging application. To do this, set up your logger with the server address + {{ telnet_server_address }} and port {{ telnet_server_port }}. You can also access + it from a terminal with telnet {{ telnet_server_address }} {{ telnet_server_port }}. +
  8. + {% end %} +
  9. You can write your own client using the Spothole API, using the main Spothole instance to provide + data, and do whatever you like with it. The README contains guidance on how to do this, and the full API + docs are linked above. You can also find reference implementations in the form of Spothole's own web-based + front end, plus my other two tools built on Spothole: Field Spotter + and the QSO Map Tool. +
  10. +
  11. If you want to run your own version of Spothole so you can customise the configuration, such as + enabling sources that I disable on the main instance, you can do that too. The README contains not only + advice on how to set up Spothole but how to get it auto-starting with systemd, using an nginx reverse proxy, + and setting up HTTPS support with certbot. +
  12. +
  13. Finally, you can of course download the source code and develop Spothole to meet your needs. Whether + you contribute your changes back to the main repository is up to you. As usual, the README file contains + some advice on the structure of the repository, and how to get started writing your own spot provider. +
  14. +
+ +{% end %} diff --git a/templates/map.html b/templates/map.html index fc9c516..78d1441 100644 --- a/templates/map.html +++ b/templates/map.html @@ -8,7 +8,7 @@ other than a rough guide. In particular, if you are seeing lots of spots in the centre of a country, please consider opening the "Your Data" menu and providing QRZ.com and/or HamQTH credentials so that Spothole can find more accurate locations for these spots. More information can be found in the - Data Accuracy section of the About page. + Data Accuracy section of the About page. @@ -113,8 +113,8 @@ const CARTODB_API_KEY = "{{ web_ui_options.get('cartodb_api_key', '') }}"; - - + + diff --git a/templates/spots.html b/templates/spots.html index 615230c..a6f48dd 100644 --- a/templates/spots.html +++ b/templates/spots.html @@ -5,9 +5,9 @@ - - + + diff --git a/templates/status.html b/templates/status.html index 21609a7..74f3457 100644 --- a/templates/status.html +++ b/templates/status.html @@ -96,7 +96,7 @@ - +