diff --git a/docs/CLAUDE.md b/CLAUDE.md similarity index 98% rename from docs/CLAUDE.md rename to CLAUDE.md index d4d2a1c..9ea7c25 100644 --- a/docs/CLAUDE.md +++ b/CLAUDE.md @@ -71,10 +71,10 @@ The HamSCI Contesting and DXing Dashboard is a real-time web application designe ### Key Documents -- [docs/REQUIREMENTS.md](REQUIREMENTS.md) - Formal requirements specification (primary reference) -- [README.md](../README.md) - Complete technical documentation -- [OPERATOR_GUIDE.md](../OPERATOR_GUIDE.md) - User guide for radio operators -- [CONTRIBUTING.md](../CONTRIBUTING.md) - Developer contribution guidelines +- [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md) - Formal requirements specification (primary reference) +- [README.md](README.md) - Complete technical documentation +- [OPERATOR_GUIDE.md](OPERATOR_GUIDE.md) - User guide for radio operators +- [CONTRIBUTING.md](CONTRIBUTING.md) - Developer contribution guidelines - [HamSCI Workshop 2025 Poster](references/Ruzankski,%20Owen%20-%20FRC_W3USR_POSTER%20-%20HamSCI%20Workshop%202025.pdf) - Project overview and goals - [FRC Proposal](references/20250123%20FRC%20Proposal.pdf) - Detailed project proposal @@ -184,7 +184,7 @@ When modifying [docs/REQUIREMENTS.md](REQUIREMENTS.md): ### On First Message 1. Read [docs/REQUIREMENTS.md](REQUIREMENTS.md) to understand the project -2. Read [docs/CLAUDE.md](CLAUDE.md) (this file) to understand the AI contribution history +2. Read [CLAUDE.md](CLAUDE.md) (this file) to understand the AI contribution history 3. Check `git log` to see recent changes 4. Ask the user what they would like to work on @@ -457,7 +457,7 @@ For questions about this project or the use of AI assistance, please refer to th - Updated `templates/index_ft.html` and `templates/index_wcount.html`: replaced `https://unpkg.com/leaflet/...` with `vendor/leaflet/...` - Updated `README.md` and `docs/CLAUDE.md` -**Note**: `static/vendor/` is not git-tracked. Re-run the download commands in README.md → "Offline Basemap Files" and "Leaflet Vendor Files" sections after any `git clean` or fresh clone. +**Note**: `static/vendor/` and GeoJSON files are git-tracked and included in the repository. No separate download is needed after a fresh clone. **Files Modified**: - `static/vendor/leaflet/` — new directory (leaflet.js, leaflet.css, images/) @@ -647,7 +647,7 @@ This documentation file is part of the HamSCI Contesting and DXing Dashboard pro **Recommended Citation Format**: ``` This project was developed with assistance from Claude (Anthropic) AI assistant. -See docs/CLAUDE.md for detailed contribution history. +See CLAUDE.md for detailed contribution history. ``` --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1233eaa..b151fa8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,8 +48,8 @@ Before contributing, ensure you have: 1. **Clone the repository:** ```bash - git clone https://github.com/hamsci/contesting-dashboard.git - cd contesting-dashboard + git clone https://github.com/HamSCI/frc_contesting.git + cd frc_contesting ``` 2. **Create virtual environment:** @@ -171,7 +171,7 @@ def fetch_wspr_spots(lastInterval=15): # Variables: lowercase with underscores spot_count = 0 -rx_callsign = "KD3ALD" +rx_callsign = "W3USR" # Constants: UPPERCASE with underscores CONTEST_BANDS = ["160m", "80m", "40m", "20m", "15m", "10m"] @@ -247,7 +247,7 @@ function loadSpots() { // Variables: camelCase let spotCount = 0; -const rxCallsign = "KD3ALD"; +const rxCallsign = "W3USR"; // Constants: SCREAMING_SNAKE_CASE const CONTEST_BANDS = ["160m", "80m", "40m", "20m", "15m", "10m"]; @@ -440,8 +440,8 @@ If you'd like to help set up testing infrastructure, please reach out! 3. Screenshots (if UI changes) **When using AI assistance (Claude, etc.):** -1. Review [docs/CLAUDE.md](docs/CLAUDE.md) for project context and guidelines -2. Update docs/CLAUDE.md session history if making significant contributions +1. Review [CLAUDE.md](CLAUDE.md) for project context and guidelines +2. Update CLAUDE.md session history if making significant contributions 3. Follow the offline-first constraints (no CDN dependencies) 4. Reference requirement IDs when implementing features @@ -572,7 +572,7 @@ If applicable, add screenshots ## Environment - Browser: [e.g., Chrome 120] - OS: [e.g., Windows 11] -- Dashboard URL: [e.g., http://dash.kd3ald.com] +- Dashboard URL: [e.g., http://192.168.1.100:5000] - Time of occurrence: [e.g., 2026-01-07 14:30 UTC] ## Additional Context @@ -661,7 +661,7 @@ For technical questions, feel free to open a discussion or contact the maintaine ### Project Documentation - [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md) - Formal requirements specification -- [docs/CLAUDE.md](docs/CLAUDE.md) - AI assistance history and guidelines +- [CLAUDE.md](CLAUDE.md) - AI assistance history and guidelines - [README.md](README.md) - Complete technical documentation - [OPERATOR_GUIDE.md](OPERATOR_GUIDE.md) - User guide for operators @@ -700,7 +700,7 @@ Contributors will be recognized in: ## License -By contributing to this project, you agree that your contributions will be licensed under the same license as the project (to be determined - likely MIT or GPL). +By contributing to this project, you agree that your contributions will be licensed under the GNU General Public License v3.0. --- @@ -722,4 +722,4 @@ Bud Trench, AA3B **Thank you for contributing to HamSCI and advancing amateur radio science!** -*73 de KD3ALD* +*73 de HamSCI* diff --git a/OPERATOR_GUIDE.md b/OPERATOR_GUIDE.md index 2ed6615..848a4da 100644 --- a/OPERATOR_GUIDE.md +++ b/OPERATOR_GUIDE.md @@ -1,8 +1,10 @@ # HamSCI Contesting Dashboard - Operator Quick Reference -**Station:** KD3ALD Personal Space Weather Station -**Location:** FN21ni (Northern New Jersey) -**Dashboard:** http://dash.kd3ald.com +> **Note for station operators:** This guide is a template. Replace `YOUR_CALLSIGN`, `YOUR_GRID`, and `http://YOUR_DASHBOARD_URL` throughout with your station's actual callsign, Maidenhead grid square, and dashboard URL. + +**Station:** YOUR_CALLSIGN Personal Space Weather Station +**Location:** YOUR_GRID +**Dashboard:** http://YOUR_DASHBOARD_URL --- @@ -10,7 +12,7 @@ ### What This Dashboard Shows -This dashboard displays **real-time HF propagation conditions** by showing decoded WSPR, FT8, and FT4 spots from the KD3ALD receiver. Each spot represents a successful digital mode reception, indicating that a particular band is open to that location. +This dashboard displays **real-time HF propagation conditions** by showing decoded WSPR, FT8, and FT4 spots from your receiver. Each spot represents a successful digital mode reception, indicating that a particular band is open to that location. **Use this dashboard to answer:** - ✅ What bands are currently open? @@ -154,7 +156,7 @@ Amateur radio contest zones (1-40) defined by CQ Magazine. Used for zone multipl **Example Zones:** - Zone 3: West Coast USA - Zone 4: Central USA -- Zone 5: East Coast USA (includes KD3ALD receiver) +- Zone 5: East Coast USA - Zone 14-16, 20: Europe - Zone 25: Japan @@ -320,11 +322,11 @@ Europe spots (last 15 min): --- -## Understanding Your Receiver (KD3ALD PSWS) +## Understanding Your Receiver (YOUR_CALLSIGN PSWS) ### What the Receiver Does -The Personal Space Weather Station at KD3ALD **continuously monitors all HF bands** using: +The Personal Space Weather Station at YOUR_CALLSIGN **continuously monitors all HF bands** using: - **RX-888 MkII SDR** (software defined radio) - **30 MHz bandwidth** (covers 0.3-30 MHz simultaneously!) - **KA9Q-radio software** (multichannel receiver) @@ -333,7 +335,7 @@ The Personal Space Weather Station at KD3ALD **continuously monitors all HF band ### Data Collection -**Receiver location:** FN21ni grid square (Northern New Jersey) +**Receiver location:** YOUR_GRID grid square **What it decodes:** - WSPR on all amateur bands (2200m through 6m) @@ -354,13 +356,13 @@ The Personal Space Weather Station at KD3ALD **continuously monitors all HF band ### Receiver Limitations **Important to know:** -- ⚠️ **One receiver only:** Dashboard shows propagation **TO** KD3ALD (FN21ni) -- ⚠️ **Not transmitting:** KD3ALD receiver is RX-only (doesn't transmit) +- ⚠️ **One receiver only:** Dashboard shows propagation **TO** YOUR_CALLSIGN (YOUR_GRID) +- ⚠️ **Not transmitting:** YOUR_CALLSIGN receiver is RX-only (doesn't transmit) - ⚠️ **Local noise:** Urban QTH may have higher noise floor - ⚠️ **Antenna limitations:** Small active antenna (not a beam or large wire) **What this means for you:** -- **Dashboard shows:** What stations can hear at KD3ALD location +- **Dashboard shows:** What stations can hear at YOUR_CALLSIGN location - **Dashboard doesn't show:** What you'll hear at YOUR location - **But:** HF propagation is generally reciprocal, so it's a good indicator! @@ -383,7 +385,7 @@ Use this dashboard as a **guide** for band conditions, but always verify with yo **Solutions:** 1. **Clear browser cache:** Ctrl+F5 (Windows) or Cmd+Shift+R (Mac) -2. **Check internet connection:** GeoJSON files are large (~18MB) +2. **Check browser console:** Open DevTools (F12) and look for loading errors 3. **Try different browser:** Chrome, Firefox, or Edge 4. **Disable browser extensions:** Some ad blockers interfere with maps @@ -468,16 +470,14 @@ Shows **actual measured propagation** from your local region, not predictions or ## Contact and Support **Dashboard Operator:** -Owen Ruzanski, KD3ALD -Email: owen.ruzanski@scranton.edu +YOUR_CALLSIGN +[Your contact information] **Receiver Station:** -KD3ALD, Grid FN21ni -Northern New Jersey, USA +YOUR_CALLSIGN, Grid YOUR_GRID **Project Website:** -University of Scranton W3USR Amateur Radio Club -HamSCI Personal Space Weather Station Project +HamSCI Personal Space Weather Station Project — https://hamsci.org/ **Report Issues:** - Receiver offline @@ -499,6 +499,6 @@ HamSCI Personal Space Weather Station Project --- -**73 de KD3ALD - Good DX!** +**73 de YOUR_CALLSIGN - Good DX!** *For technical documentation, see [README.md](README.md)* diff --git a/README.md b/README.md index 7d187be..5c71795 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The HamSCI Contesting and DXing Dashboard is a real-time web application designe ``` ┌─────────────────────────────────────────────┐ -│ PSWS Receiver (KD3ALD) │ +│ Your PSWS Receiver │ │ RX-888 SDR + KA9Q-radio + WSPRDaemon │ │ Decodes WSPR/FT8/FT4 on all HF bands │ └─────────────────┬───────────────────────────┘ @@ -113,7 +113,7 @@ The HamSCI Contesting and DXing Dashboard is a real-time web application designe │ Frontend JavaScript │ │ ┌──────────────┐ ┌───────────────┐ │ │ │ map_ft.js │ │ table_ft.js │ │ -│ │ (730 lines) │ │ (183 lines) │ │ +│ │ (735 lines) │ │ (223 lines) │ │ │ │ - Leaflet │ │ - Regional │ │ │ │ - Filtering │ │ aggregation│ │ │ │ - Markers │ │ - Band matrix│ │ @@ -131,7 +131,7 @@ The HamSCI Contesting and DXing Dashboard is a real-time web application designe ### Data Flow 1. **Data Collection:** PSWS receiver decodes WSPR/FT8/FT4 spots continuously -2. **Storage:** Spots written to MongoDB with metadata (callsign, grid, frequency, SNR, time, mode) +2. **Ingestion:** WSPRDaemon calls `storedb/storedb.sh` after each decode cycle, which upserts spots into MongoDB 3. **API Request:** Frontend requests spots via `/spots?lastInterval=15` 4. **Processing:** Backend queries MongoDB for spots in time window, converts grids to coordinates 5. **Client Filtering:** JavaScript applies band/country/zone/mode filters @@ -156,7 +156,7 @@ The HamSCI Contesting and DXing Dashboard is a real-time web application designe ### Prerequisites - Python 3.8 or higher -- MongoDB 4.x or higher (with WSPRDaemon database) +- MongoDB 4.x or higher - Modern web browser (Chrome, Firefox, Safari, Edge) - PSWS receiver system (RX-888 + KA9Q-radio + WSPRDaemon) @@ -189,46 +189,13 @@ See [requirements.txt](requirements.txt) for the complete list: - geopy>=2.2.0 - Geocoding - python-dotenv>=0.19.0 - Environment variable management -### GeoJSON Data Files +### Static Data Files -The following GeoJSON files must be present in `static/js/` (used for point-in-polygon filtering): +All required static data files are included in the repository — no separate downloads needed: -- `countries.geojson` (14MB) - Country boundaries -- `continents.geojson` (4KB) - Continent boundaries -- `cqzones.geojson` (2.7MB) - CQ zone polygons (40 zones) -- `ituzones.geojson` (1.5MB) - ITU zone polygons (90 zones) - -These files are included in the repository. - -### Offline Basemap Files - -The following files provide the offline map background and **must be downloaded separately** — they are not tracked by git due to their size. Run the setup commands below to download them to `static/vendor/basemap/`: - -```bash -mkdir -p static/vendor/basemap -curl -sL https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/50m/physical/ne_50m_land.json -o static/vendor/basemap/ne_50m_land.json -curl -sL https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/50m/cultural/ne_50m_admin_0_countries.json -o static/vendor/basemap/ne_50m_admin_0_countries.json -curl -sL https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/50m/cultural/ne_50m_admin_1_states_provinces.json -o static/vendor/basemap/states-50m.json -``` - -- `ne_50m_land.json` (2.7MB) - Land mass polygons (ocean/land fill) -- `ne_50m_admin_0_countries.json` (4.5MB) - Country border outlines -- `states-50m.json` (1.6MB) - State/province border outlines - -### Leaflet Vendor Files - -Leaflet 1.9.4 is vendored locally and must also be downloaded separately: - -```bash -mkdir -p static/vendor/leaflet/images -curl -sL https://unpkg.com/leaflet@1.9.4/dist/leaflet.js -o static/vendor/leaflet/leaflet.js -curl -sL https://unpkg.com/leaflet@1.9.4/dist/leaflet.css -o static/vendor/leaflet/leaflet.css -curl -sL https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png -o static/vendor/leaflet/images/marker-icon.png -curl -sL https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png -o static/vendor/leaflet/images/marker-icon-2x.png -curl -sL https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png -o static/vendor/leaflet/images/marker-shadow.png -curl -sL https://unpkg.com/leaflet@1.9.4/dist/images/layers.png -o static/vendor/leaflet/images/layers.png -curl -sL https://unpkg.com/leaflet@1.9.4/dist/images/layers-2x.png -o static/vendor/leaflet/images/layers-2x.png -``` +- **GeoJSON boundary files** (`static/js/`) — country, continent, CQ zone, and ITU zone polygons used for client-side filtering +- **Offline basemap** (`static/vendor/basemap/`) — Natural Earth land, country border, and state/province GeoJSON files for the offline map background +- **Leaflet 1.9.4** (`static/vendor/leaflet/`) — map library and marker images, vendored locally so no CDN is required --- @@ -254,16 +221,42 @@ The application uses environment variables for secure credential management. **IMPORTANT:** Never commit the `.env` file to git! It's already in `.gitignore`. +### MongoDB Authentication Setup + +If your MongoDB instance does not yet have a user configured, create one before running the app: + +```bash +mongosh +``` + +```js +use wspr_db +db.createUser({ + user: "wspr_user", + pwd: "choose_a_strong_password", + roles: [{ role: "readWrite", db: "wspr_db" }] +}) +``` + +Then set the matching credentials in your `.env` file: + +```bash +MONGODB_USERNAME=wspr_user +MONGODB_PASSWORD=choose_a_strong_password +``` + +> **Note:** By default, MongoDB on a fresh install has no authentication enabled. It is strongly recommended to enable authentication, especially if the machine is network-accessible. See the [MongoDB security checklist](https://www.mongodb.com/docs/manual/administration/security-checklist/) for details. + ### Receiver Station Configuration Set the receiver callsign and Maidenhead grid square in your `.env` file: ```bash -RECEIVER_CALLSIGN=KD3ALD -RECEIVER_GRIDSQUARE=FN21ni +RECEIVER_CALLSIGN=W1ABC +RECEIVER_GRIDSQUARE=FN42hx ``` -The backend reads these values at startup and serves them to the frontend via the `/config` API endpoint. The grid square can be 4-character (e.g., `FN21`) or 6-character (e.g., `FN21ni`). +Replace `W1ABC` with your station callsign and `FN42hx` with your Maidenhead grid square. The grid square can be 4-character (e.g., `FN42`) or 6-character (e.g., `FN42hx`). The backend reads these values at startup and serves them to the frontend via the `/config` API endpoint. ### Band Color Configuration @@ -301,7 +294,7 @@ Fetch spots for map display with full propagation details. "tx_sign": "W1ABC", "tx_lat": 42.3601, "tx_lon": -71.0589, - "rx_sign": "KD3ALD", + "rx_sign": "W3USR", "rx_lat": 40.7589, "rx_lon": -74.2215, "frequency": 14.097, @@ -347,8 +340,8 @@ Serve receiver station configuration to the frontend. **Response Format:** ```json { - "receiver_callsign": "KD3ALD", - "receiver_grid": "FN21ni" + "receiver_callsign": "W3USR", + "receiver_grid": "FN21ej" } ``` @@ -440,7 +433,7 @@ Each document represents one decoded WSPR/FT8/FT4 spot. { _id: ObjectId("..."), callsign: "W1ABC", // Transmitter callsign - rx_callsign: "KD3ALD", // Receiver callsign + rx_callsign: "W3USR", // Receiver callsign grid: "FN42hx", // 6-character Maidenhead grid square frequency: 14.097062, // Frequency in MHz band: "20m", // Band designation @@ -495,7 +488,7 @@ frc_contesting/ │ │ ├── cqzones.geojson # CQ zones (2.7MB) │ │ ├── ituzones.geojson # ITU zones (1.5MB) │ │ └── turf.min.js # Geospatial library (591KB) -│ └── vendor/ # Third-party libraries (not git-tracked, download separately) +│ └── vendor/ # Third-party libraries (git-tracked) │ ├── leaflet/ # Leaflet 1.9.4 │ │ ├── leaflet.js │ │ ├── leaflet.css @@ -504,6 +497,9 @@ frc_contesting/ │ ├── ne_50m_land.json # Land mass fill (2.7MB) │ ├── ne_50m_admin_0_countries.json # Country borders (4.5MB) │ └── states-50m.json # State/province borders (1.6MB) +├── storedb/ # WSPRDaemon → MongoDB ingestion +│ ├── storedb.sh # Shell wrapper called by WSPR_LOGGING_CMD +│ └── storedb.py # Reads decoded spots and upserts into MongoDB ├── templates/ # Flask HTML templates │ ├── both.html # Combined map + table view │ ├── index_ft.html # Map view @@ -517,6 +513,44 @@ frc_contesting/ └── README.md # This file ``` +### WSPRDaemon Integration + +The dashboard receives spot data via a script called by WSPRDaemon after each decode cycle. This is configured with the `WSPR_LOGGING_CMD` variable in `wsprdaemon.conf`. + +#### Setup + +1. Add the following line to `~/wsprdaemon/wsprdaemon.conf` (in the site-specific section near the top), replacing the path with the actual location of your cloned repo: + + ```bash + WSPR_LOGGING_CMD="/path/to/frc_contesting/storedb/storedb.sh" + ``` + + For example, if the repo is cloned to `/home/w3usr/frc_contesting`: + ```bash + WSPR_LOGGING_CMD="/home/w3usr/frc_contesting/storedb/storedb.sh" + ``` + +2. Restart WSPRDaemon to pick up the change: + + ```bash + wsprdaemon -z && wsprdaemon -A + ``` + +#### How it works + +After each decode cycle, WSPRDaemon calls [storedb/storedb.sh](storedb/storedb.sh), which activates the virtual environment and runs [storedb/storedb.py](storedb/storedb.py). The Python script reads the decoded spots from `/dev/shm/wsprdaemon/uploads/wsprnet/spots.txt` and upserts them into the `wspr_db.spots` MongoDB collection. Upsert is used to avoid duplicates if the script is called more than once for the same cycle. + +Credentials and receiver configuration are read from `.env` — no hardcoded values. + +#### Manual test + +To verify the integration before restarting WSPRDaemon: + +```bash +/path/to/frc_contesting/storedb/storedb.sh +mongosh "mongodb://YOUR_USER:YOUR_PASSWORD@localhost:27017/admin" --eval "db.getSiblingDB('wspr_db').spots.countDocuments()" --quiet +``` + ### Running the Development Server ```bash @@ -551,7 +585,7 @@ python web-ft.py - Use browser DevTools Console to debug JavaScript **Database Changes:** -- Connect to MongoDB: `mongo --host $MONGODB_HOST --port $MONGODB_PORT -u $MONGODB_USERNAME -p` +- Connect to MongoDB: `mongosh "mongodb://$MONGODB_USERNAME:$MONGODB_PASSWORD@$MONGODB_HOST:$MONGODB_PORT"` - Query spots: `db.spots.find().sort({date: -1, time: -1}).limit(10)` ### Adding New Filters @@ -590,43 +624,54 @@ To add a new client-side filter: ### Production Deployment with Gunicorn +Install gunicorn into the virtual environment and run with 4 worker processes, binding to all interfaces: + ```bash -# Install gunicorn +source venv/bin/activate pip install gunicorn - -# Run with 4 worker processes -gunicorn -w 4 -b 0.0.0.0:5000 app:app - -# Or with systemd service -sudo systemctl start hamsci-dashboard +gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app()" ``` -### Systemd Service File +The dashboard will be accessible at `http://YOUR_IP:5000` from any machine on the network. -Create `/etc/systemd/system/hamsci-dashboard.service`: +### Systemd Service File (autostart on boot) + +Create `/etc/systemd/system/frc-dashboard.service`, replacing `YOUR_USER` and `/path/to/frc_contesting` with your actual username and repo path: ```ini [Unit] -Description=HamSCI Contesting Dashboard -After=network.target +Description=FRC Contesting Dashboard +After=network.target mongod.service [Service] -User=hamsci -Group=hamsci -WorkingDirectory=/opt/hamsci-dashboard -Environment="PATH=/opt/hamsci-dashboard/venv/bin" -ExecStart=/opt/hamsci-dashboard/venv/bin/gunicorn -w 4 -b 0.0.0.0:5000 app:app +User=YOUR_USER +Group=YOUR_USER +WorkingDirectory=/path/to/frc_contesting +Environment="PATH=/path/to/frc_contesting/venv/bin" +ExecStart=/path/to/frc_contesting/venv/bin/gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app()" +Restart=on-failure [Install] WantedBy=multi-user.target ``` +Then enable and start the service: + +```bash +sudo systemctl daemon-reload +sudo systemctl enable frc-dashboard +sudo systemctl start frc-dashboard +sudo systemctl status frc-dashboard +``` + ### Nginx Reverse Proxy +If you want to serve the dashboard on port 80 (or with HTTPS), use nginx as a reverse proxy. Replace `your.hostname.com` with your actual hostname or IP: + ```nginx server { listen 80; - server_name dash.kd3ald.com; + server_name your.hostname.com; location / { proxy_pass http://127.0.0.1:5000; @@ -635,7 +680,7 @@ server { } location /static { - alias /opt/hamsci-dashboard/static; + alias /path/to/frc_contesting/static; expires 1h; } } @@ -764,7 +809,7 @@ server { ### Related Documentation - [Requirements Document](docs/REQUIREMENTS.md) - Formal requirements specification -- [Claude AI Assistance Documentation](docs/CLAUDE.md) - AI contribution history and guidelines +- [Claude AI Assistance Documentation](CLAUDE.md) - AI contribution history and guidelines - [Operator Guide](OPERATOR_GUIDE.md) - User guide for radio operators - [Contributing Guide](CONTRIBUTING.md) - Developer contribution guidelines - [Archive Documentation](_archive/README.md) - Legacy code reference @@ -832,9 +877,6 @@ Special thanks to: Dr. Nathaniel Frissell (W2NAF) University of Scranton, Department of Physics/Engineering -**Dashboard URL:** -http://dash.kd3ald.com (when operational) - --- *Last updated March 2026 as part of the HamSCI PSWS Dashboard Development project.* diff --git a/storedb/storedb.py b/storedb/storedb.py new file mode 100644 index 0000000..15402e7 --- /dev/null +++ b/storedb/storedb.py @@ -0,0 +1,68 @@ +import os +from pymongo import MongoClient +from dotenv import load_dotenv + +load_dotenv(os.path.join(os.path.dirname(__file__), '..', '.env')) + +mongodb_host = os.getenv('MONGODB_HOST', 'localhost') +mongodb_port = os.getenv('MONGODB_PORT', '27017') +mongodb_username = os.getenv('MONGODB_USERNAME') +mongodb_password = os.getenv('MONGODB_PASSWORD') +mongodb_database = os.getenv('MONGODB_DATABASE', 'wspr_db') +receiver_callsign = os.getenv('RECEIVER_CALLSIGN', 'Unknown') + +if mongodb_username and mongodb_password: + uri = f"mongodb://{mongodb_username}:{mongodb_password}@{mongodb_host}:{mongodb_port}" +else: + uri = f"mongodb://{mongodb_host}:{mongodb_port}" + +client = MongoClient(uri) +collection = client[mongodb_database]['spots'] + + +def frequency_to_band(freq_mhz): + if 0.136 <= freq_mhz < 0.137: return "2200m" + if 0.472 <= freq_mhz < 0.479: return "630m" + if 1.8 <= freq_mhz < 2.0: return "160m" + if 3.5 <= freq_mhz < 4.0: return "80m" + if 5.2 <= freq_mhz < 5.5: return "60m" + if 7.0 <= freq_mhz < 7.3: return "40m" + if 10.1 <= freq_mhz < 10.15: return "30m" + if 14.0 <= freq_mhz < 14.35: return "20m" + if 18.068 <= freq_mhz < 18.168: return "17m" + if 21.0 <= freq_mhz < 21.45: return "15m" + if 24.89 <= freq_mhz < 24.99: return "12m" + if 28.0 <= freq_mhz < 29.7: return "10m" + if 50.0 <= freq_mhz < 54.0: return "6m" + if 144.0 <= freq_mhz < 148.0: return "2m" + return "Unknown" + + +SPOTS_FILE = '/dev/shm/wsprdaemon/uploads/wsprnet/spots.txt' + +with open(SPOTS_FILE, 'r') as f: + for line in f: + parts = line.strip().split() + if len(parts) < 8: + continue + + freq_mhz = float(parts[5]) + callsign = parts[6].strip('<>') + + document = { + "date": parts[0], + "time": parts[1], + "snr": float(parts[2]), + "db": int(parts[3]), + "drift": float(parts[4]), + "frequency": freq_mhz, + "callsign": callsign, + "grid": parts[7], + "rx_callsign": receiver_callsign, + "mode": "wspr", + "band": frequency_to_band(freq_mhz), + } + + # Upsert on natural key to avoid duplicates if called multiple times + key = {k: document[k] for k in ("date", "time", "callsign", "frequency")} + collection.update_one(key, {"$set": document}, upsert=True) diff --git a/storedb/storedb.sh b/storedb/storedb.sh new file mode 100755 index 0000000..08b3f88 --- /dev/null +++ b/storedb/storedb.sh @@ -0,0 +1,4 @@ +#!/bin/bash +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +source "$REPO_DIR/venv/bin/activate" +python3 "$REPO_DIR/storedb/storedb.py"