diff --git a/README.md b/README.md
index 031c599..622cfb7 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,6 @@ Supported data sources include DX Clusters, the Reverse Beacon Network (RBN), th
You can access the public version's web interface at [https://spothole.app](https://spothole.app), and see [https://spothole.app/apidocs](https://spothole.app/apidocs) for the API details.
-Please note this URL is not necessarily final, and the API is likely to change as the project works its way towards v1.0. Please do not build anything on the Spothole API yet!
-
### Running your own copy
To download and set up Spothole on a Debian server, run the following commands. Other operating systems will likely be similar.
diff --git a/core/constants.py b/core/constants.py
index 8b7f964..f581033 100644
--- a/core/constants.py
+++ b/core/constants.py
@@ -3,7 +3,7 @@ from data.band import Band
# General software
SOFTWARE_NAME = "Spothole by M0TRT"
-SOFTWARE_VERSION = "1.0"
+SOFTWARE_VERSION = "0.1"
# HTTP headers used for spot providers that use HTTP
HTTP_HEADERS = {"User-Agent": SOFTWARE_NAME + " " + SOFTWARE_VERSION + " (operated by " + SERVER_OWNER_CALLSIGN + ")"}
diff --git a/data/spot.py b/data/spot.py
index 0b3c4ee..ea714fb 100644
--- a/data/spot.py
+++ b/data/spot.py
@@ -103,8 +103,17 @@ class Spot:
sig_refs_names: list = None
# Activation score. SOTA only
activation_score: int = None
- # Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
+
+
+ # Display guidance (optional)
+
+ # Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field
+ # Spotter. Does not include the "fa-" prefix.
icon: str = "question"
+ # Colour to represent this spot, if a client chooses to colour spots based on their frequency band, using PSK
+ # Reporter's default colours. HTML colour e.g. hex. A contrast colour is also provided which will be black or white.
+ band_color: str = None
+ band_contrast_color: str = None
# Timing info
@@ -183,6 +192,8 @@ class Spot:
if self.freq and not self.band:
band = lookup_helper.infer_band_from_freq(self.freq)
self.band = band.name
+ self.band_color = band.color
+ self.band_contrast_color = band.contrast_color
# Mode from comments or bandplan
if self.mode:
diff --git a/spothole.py b/spothole.py
index 71b1259..6386a59 100644
--- a/spothole.py
+++ b/spothole.py
@@ -7,7 +7,8 @@ import sys
from diskcache import Cache
from core.cleanup import CleanupTimer
-from core.config import config, WEB_SERVER_PORT
+from core.config import config, WEB_SERVER_PORT, SERVER_OWNER_CALLSIGN
+from core.constants import SOFTWARE_NAME, SOFTWARE_VERSION
from core.lookup_helper import lookup_helper
from core.status_reporter import StatusReporter
from server.webserver import WebServer
@@ -62,6 +63,8 @@ if __name__ == '__main__':
root.addHandler(handler)
logging.info("Starting...")
+ logging.info(
+ "This is " + SOFTWARE_NAME + " version " + SOFTWARE_VERSION + ". This instance is run by " + SERVER_OWNER_CALLSIGN + ".")
# Shut down gracefully on SIGINT
signal.signal(signal.SIGINT, shutdown)
@@ -90,7 +93,7 @@ if __name__ == '__main__':
cleanup_timer.start()
# Set up web server
- web_server = WebServer(spots=spots, alerts= alerts, status_data=status_data, port=WEB_SERVER_PORT)
+ web_server = WebServer(spots=spots, alerts=alerts, status_data=status_data, port=WEB_SERVER_PORT)
web_server.start()
# Set up status reporter
diff --git a/webassets/apidocs/openapi.yml b/webassets/apidocs/openapi.yml
index b0c8e7a..a14e8e6 100644
--- a/webassets/apidocs/openapi.yml
+++ b/webassets/apidocs/openapi.yml
@@ -827,6 +827,14 @@ components:
type: string
descripton: Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
example: tree
+ band_color:
+ type: string
+ descripton: Colour to represent this spot, if a client chooses to colour spots based on their frequency band, using PSK Reporter's default colours. HTML colour e.g. hex.
+ example: #ff0000"
+ band_contrast_color:
+ type: string
+ descripton: Black or white, whichever best contrasts with "band_color".
+ example: "white"
source:
type: string
description: Where we got the alert from.
diff --git a/webassets/css/style.css b/webassets/css/style.css
index 8368778..0037c6e 100644
--- a/webassets/css/style.css
+++ b/webassets/css/style.css
@@ -142,6 +142,12 @@ div#map {
font-family: var(--bs-body-font-family) !important;
}
+a.leaflet-popup-callsign-link {
+ color: black;
+ font-weight: bold;
+ text-decoration: none;
+}
+
/* GENERAL MOBILE SUPPORT */
diff --git a/webassets/js/map.js b/webassets/js/map.js
index d57aff2..b4923b8 100644
--- a/webassets/js/map.js
+++ b/webassets/js/map.js
@@ -33,6 +33,7 @@ function updateMap() {
spots.forEach(function (s) {
if (s["dx_location_good"]) {
let m = L.marker([s["dx_latitude"], s["dx_longitude"]], {icon: getIcon(s)});
+ m.bindPopup(getTooltipText(s));
markersLayer.addLayer(m);
}
});
@@ -42,14 +43,75 @@ function updateMap() {
function getIcon(s) {
return L.ExtraMarkers.icon({
icon: "fa-" + s["icon"],
- iconColor: "white", // todo
- markerColor: "black", // todo
+ iconColor: s["band_contrast_color"],
+ markerColor: s["band_color"],
shape: 'circle',
prefix: 'fa',
svg: true
});
}
+// Tooltip text for the markers
+function getTooltipText(s) {
+ // Format DX flag
+ var dx_flag = "";
+ if (s["dx_flag"] && s["dx_flag"] != null && s["dx_flag"] != "") {
+ dx_flag = s["dx_flag"];
+ }
+
+ // Format the frequency
+ var mhz = Math.floor(s["freq"] / 1000000.0);
+ var khz = Math.floor((s["freq"] - (mhz * 1000000.0)) / 1000.0);
+ var hz = Math.floor(s["freq"] - (mhz * 1000000.0) - (khz * 1000.0));
+ var hz_string = (hz > 0) ? hz.toFixed(0)[0] : "";
+ var freq_string = `${mhz.toFixed(0)}${khz.toFixed(0).padStart(3, '0')}${hz_string}`
+
+ // Format comment
+ var commentText = "";
+ if (s["comment"] != null) {
+ commentText = escapeHtml(s["comment"]);
+ }
+
+ // Sig or fallback to source
+ var sigSourceText = s["source"];
+ if (s["sig"]) {
+ sigSourceText = s["sig"];
+ }
+
+ // Format sig_refs
+ var sig_refs = "";
+ if (s["sig_refs"]) {
+ sig_refs = s["sig_refs"].map(s => `${s}`).join(", ");
+ }
+
+ // DX
+ const shortCall = s["dx_call"].split("/").sort(function (a, b) {
+ return b.length - a.length;
+ })[0];
+ ttt = `${dx_flag}
`;
+
+ // Frequency & band
+ ttt += ` ${freq_string} (${s["band"]})`;
+ // Mode
+ if (s["mode"] != null) {
+ ttt += ` ${s["mode"]}`;
+ }
+ ttt += "
";
+
+ // Source / SIG / Ref
+ ttt += ` ${sigSourceText} ${sig_refs}
`;
+
+ // Time
+ ttt += ` ${moment.unix(s["time"]).fromNow()}`;
+
+ // Comment
+ if (commentText.length > 0) {
+ ttt += `
${commentText}`;
+ }
+
+ return ttt;
+}
+
// Load server options. Once a successful callback is made from this, we then query spots and set up the timer to query
// spots repeatedly.
function loadOptions() {
@@ -57,8 +119,8 @@ function loadOptions() {
// Store options
options = jsonData;
- // Add CSS for band bullets and band toggle buttons
- addBandColourCSS(options["bands"]);
+ // Add CSS for band toggle buttons
+ addBandToggleColourCSS(options["bands"]);
// Populate the filters panel
generateBandsMultiToggleFilterCard(options["bands"]);
diff --git a/webassets/js/spotandmap.js b/webassets/js/spotandmap.js
index 8021a5d..58a8c37 100644
--- a/webassets/js/spotandmap.js
+++ b/webassets/js/spotandmap.js
@@ -4,14 +4,13 @@ const REFRESH_INTERVAL_SEC = 60;
// Storage for the spot data that the server gives us.
var spots = []
-// Dynamically add CSS code for the band bullets and band toggle buttons to be in the appropriate colour.
+// Dynamically add CSS code for the band toggle buttons to be in the appropriate colour.
// Some band names contain decimal points which are not allowed in CSS classes, so we text-replace them to "p".
-function addBandColourCSS(band_options) {
+function addBandToggleColourCSS(band_options) {
var $style = $('