commit
8030ef70ff
@ -0,0 +1,242 @@
|
|||||||
|
# OpenHamClock
|
||||||
|
|
||||||
|
**A modern, open-source amateur radio dashboard - spiritual successor to HamClock**
|
||||||
|
|
||||||
|
*In memory of Elwood Downey, WB0OEW, creator of the original HamClock*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
OpenHamClock is a web-based kiosk-style application that provides real-time space weather, radio propagation information, and other data useful to amateur radio operators. It's designed to run on any platform with a web browser, with special consideration for Raspberry Pi deployments.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Current Features (v1.0.0)
|
||||||
|
|
||||||
|
- **World Map with Day/Night Terminator**
|
||||||
|
- Real-time gray line display
|
||||||
|
- Sun position tracking
|
||||||
|
- DE and DX location markers with path visualization
|
||||||
|
|
||||||
|
- **Time Displays**
|
||||||
|
- UTC time (large, prominent display)
|
||||||
|
- Local time with date
|
||||||
|
- Uptime counter
|
||||||
|
|
||||||
|
- **Location Information**
|
||||||
|
- DE (your location) with Maidenhead grid square
|
||||||
|
- DX (target location) with grid square
|
||||||
|
- Short path and long path bearing
|
||||||
|
- Distance calculation
|
||||||
|
- Sunrise/sunset times for both locations
|
||||||
|
|
||||||
|
- **Space Weather Panel**
|
||||||
|
- Solar Flux Index (SFI)
|
||||||
|
- Sunspot Number
|
||||||
|
- K-Index and A-Index
|
||||||
|
- X-Ray flux
|
||||||
|
- Overall conditions assessment
|
||||||
|
|
||||||
|
- **Band Conditions**
|
||||||
|
- Visual display for all HF bands
|
||||||
|
- Color-coded conditions (Good/Fair/Poor)
|
||||||
|
- VHF band status
|
||||||
|
|
||||||
|
- **DX Cluster Feed**
|
||||||
|
- Live spot display (placeholder for API integration)
|
||||||
|
- Frequency, callsign, comment, and time
|
||||||
|
|
||||||
|
- **POTA Activity**
|
||||||
|
- Parks on the Air activator tracking
|
||||||
|
- Reference, frequency, and mode display
|
||||||
|
|
||||||
|
### Planned Features (Roadmap)
|
||||||
|
|
||||||
|
- [ ] Live API integration for space weather (NOAA, hamqsl.com)
|
||||||
|
- [ ] Real DX cluster connectivity (Telnet/WebSocket)
|
||||||
|
- [ ] Live POTA/SOTA API integration
|
||||||
|
- [ ] Satellite tracking
|
||||||
|
- [ ] VOACAP propagation predictions
|
||||||
|
- [ ] Contest calendar integration
|
||||||
|
- [ ] Hamlib/flrig radio control
|
||||||
|
- [ ] Rotator control
|
||||||
|
- [ ] Customizable panel layout
|
||||||
|
- [ ] Multiple map projections
|
||||||
|
- [ ] ADIF log file integration
|
||||||
|
- [ ] RESTful API for external control
|
||||||
|
- [ ] Touch screen support
|
||||||
|
- [ ] Alarm/alert system
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Option 1: Direct Browser Use
|
||||||
|
|
||||||
|
Simply open `index.html` in any modern web browser. No server required!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone or download the files
|
||||||
|
firefox index.html
|
||||||
|
# or
|
||||||
|
chromium-browser index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: Raspberry Pi Kiosk Mode
|
||||||
|
|
||||||
|
1. **Install Raspberry Pi OS** (Desktop version recommended)
|
||||||
|
|
||||||
|
2. **Copy OpenHamClock files**
|
||||||
|
```bash
|
||||||
|
mkdir ~/openhamclock
|
||||||
|
cp index.html ~/openhamclock/
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Run the setup script**
|
||||||
|
```bash
|
||||||
|
chmod +x setup-pi.sh
|
||||||
|
./setup-pi.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Manual Kiosk Setup** (alternative)
|
||||||
|
```bash
|
||||||
|
# Install unclutter to hide mouse cursor
|
||||||
|
sudo apt-get install unclutter
|
||||||
|
|
||||||
|
# Create autostart entry
|
||||||
|
mkdir -p ~/.config/autostart
|
||||||
|
cat > ~/.config/autostart/openhamclock.desktop << EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=OpenHamClock
|
||||||
|
Exec=chromium-browser --kiosk --noerrdialogs --disable-infobars --incognito file:///home/pi/openhamclock/index.html
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 3: Local Web Server
|
||||||
|
|
||||||
|
For advanced features (future API integrations), run with a local server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python 3
|
||||||
|
cd openhamclock
|
||||||
|
python3 -m http.server 8080
|
||||||
|
|
||||||
|
# Then open http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 4: Electron Desktop App (Future)
|
||||||
|
|
||||||
|
Coming soon: Packaged desktop applications for Windows, macOS, and Linux.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Edit the following values in `index.html` to customize:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Your callsign
|
||||||
|
const [callsign, setCallsign] = useState('YOUR_CALL');
|
||||||
|
|
||||||
|
// Your location (lat, lon)
|
||||||
|
const [deLocation, setDeLocation] = useState({ lat: 39.7392, lon: -104.9903 });
|
||||||
|
|
||||||
|
// Default DX location
|
||||||
|
const [dxLocation, setDxLocation] = useState({ lat: 35.6762, lon: 139.6503 });
|
||||||
|
```
|
||||||
|
|
||||||
|
### Future Configuration File
|
||||||
|
|
||||||
|
A separate `config.js` will be provided for easier configuration:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// config.js (coming soon)
|
||||||
|
export default {
|
||||||
|
callsign: 'K0CJH',
|
||||||
|
location: {
|
||||||
|
lat: 39.7392,
|
||||||
|
lon: -104.9903
|
||||||
|
},
|
||||||
|
theme: 'dark',
|
||||||
|
panels: ['clock', 'map', 'weather', 'dx', 'bands'],
|
||||||
|
// ... more options
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Display Resolutions
|
||||||
|
|
||||||
|
OpenHamClock is responsive and works at various resolutions:
|
||||||
|
|
||||||
|
| Resolution | Recommended Use |
|
||||||
|
|------------|-----------------|
|
||||||
|
| 800x480 | Small Pi displays, Inovato Quadra |
|
||||||
|
| 1024x600 | 7" Pi touchscreens |
|
||||||
|
| 1280x720 | HD ready monitors |
|
||||||
|
| 1600x960 | Recommended for full features |
|
||||||
|
| 1920x1080 | Full HD monitors |
|
||||||
|
| 2560x1440 | Large displays, high detail |
|
||||||
|
|
||||||
|
## API Data Sources (Planned)
|
||||||
|
|
||||||
|
| Data | Source | Status |
|
||||||
|
|------|--------|--------|
|
||||||
|
| Space Weather | NOAA SWPC | Planned |
|
||||||
|
| Band Conditions | hamqsl.com | Planned |
|
||||||
|
| DX Cluster | Various Telnet nodes | Planned |
|
||||||
|
| POTA | pota.app API | Planned |
|
||||||
|
| SOTA | sotawatch.org | Planned |
|
||||||
|
| Satellites | N2YO, CelesTrak | Planned |
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
|
||||||
|
- **Frontend**: React 18 (single-file, no build required)
|
||||||
|
- **Styling**: CSS-in-JS with CSS variables for theming
|
||||||
|
- **Maps**: SVG-based rendering (no external tiles)
|
||||||
|
- **Data**: Currently static, API integration planned
|
||||||
|
|
||||||
|
### Browser Support
|
||||||
|
|
||||||
|
- Chrome/Chromium 80+
|
||||||
|
- Firefox 75+
|
||||||
|
- Safari 13+
|
||||||
|
- Edge 80+
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
None! OpenHamClock loads React and Babel from CDN for simplicity.
|
||||||
|
|
||||||
|
For offline/airgapped deployments, download these files:
|
||||||
|
- react.production.min.js
|
||||||
|
- react-dom.production.min.js
|
||||||
|
- babel.min.js
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Areas where help is needed:
|
||||||
|
|
||||||
|
1. **API Integrations** - Connect to live data sources
|
||||||
|
2. **Satellite Tracking** - SGP4 propagator implementation
|
||||||
|
3. **Map Improvements** - Better landmass rendering, additional projections
|
||||||
|
4. **Testing** - Various Pi models and display sizes
|
||||||
|
5. **Documentation** - User guides, translations
|
||||||
|
6. **Design** - UI/UX improvements, accessibility
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - Free for personal and commercial use.
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
- **Elwood Downey, WB0OEW** - Creator of the original HamClock. His work inspired thousands of amateur radio operators worldwide. Rest in peace, OM.
|
||||||
|
- **Amateur Radio Community** - For continued innovation and the spirit of experimentation.
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
- **GitHub**: [github.com/your-repo/openhamclock](https://github.com)
|
||||||
|
- **Email**: your-email@example.com
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**73 de K0CJH**
|
||||||
|
|
||||||
|
*"The original HamClock will cease to function in June 2026. OpenHamClock aims to carry on Elwood's legacy with a modern, open-source implementation that the community can maintain and improve together."*
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
/**
|
||||||
|
* OpenHamClock Configuration
|
||||||
|
*
|
||||||
|
* Edit this file to customize your OpenHamClock instance.
|
||||||
|
* After making changes, refresh the browser to apply.
|
||||||
|
*
|
||||||
|
* For Raspberry Pi: Edit this file at ~/openhamclock/config.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
const OpenHamClockConfig = {
|
||||||
|
// ========================================
|
||||||
|
// STATION INFORMATION
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// Your callsign (displayed in header)
|
||||||
|
callsign: "K0CJH",
|
||||||
|
|
||||||
|
// Your location (DE - "This End")
|
||||||
|
// Find coordinates: https://www.latlong.net/
|
||||||
|
location: {
|
||||||
|
lat: 39.7392, // Latitude (positive = North, negative = South)
|
||||||
|
lon: -104.9903 // Longitude (positive = East, negative = West)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Default DX location (far end for path calculations)
|
||||||
|
// Set to a frequently worked location, or leave as default
|
||||||
|
defaultDX: {
|
||||||
|
lat: 35.6762, // Tokyo, Japan
|
||||||
|
lon: 139.6503
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// DISPLAY OPTIONS
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// Theme: 'dark' (default), 'light' (coming soon)
|
||||||
|
theme: "dark",
|
||||||
|
|
||||||
|
// Time format: '24h' or '12h'
|
||||||
|
timeFormat: "24h",
|
||||||
|
|
||||||
|
// Date format: 'iso' (YYYY-MM-DD), 'us' (MM/DD/YYYY), 'eu' (DD/MM/YYYY)
|
||||||
|
dateFormat: "iso",
|
||||||
|
|
||||||
|
// Show seconds in time display
|
||||||
|
showSeconds: true,
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// PANELS TO DISPLAY
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// Enable/disable individual panels
|
||||||
|
panels: {
|
||||||
|
utcClock: true,
|
||||||
|
localClock: true,
|
||||||
|
worldMap: true,
|
||||||
|
deInfo: true,
|
||||||
|
dxInfo: true,
|
||||||
|
spaceWeather: true,
|
||||||
|
bandConditions: true,
|
||||||
|
dxCluster: true,
|
||||||
|
potaActivity: true,
|
||||||
|
sotaActivity: false, // Coming soon
|
||||||
|
satellites: false, // Coming soon
|
||||||
|
contests: false // Coming soon
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// MAP OPTIONS
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
map: {
|
||||||
|
// Map style: 'standard', 'terrain', 'minimal'
|
||||||
|
style: "standard",
|
||||||
|
|
||||||
|
// Show day/night terminator (gray line)
|
||||||
|
showTerminator: true,
|
||||||
|
|
||||||
|
// Show grid lines
|
||||||
|
showGrid: true,
|
||||||
|
|
||||||
|
// Show path between DE and DX
|
||||||
|
showPath: true,
|
||||||
|
|
||||||
|
// Path style: 'greatCircle' or 'straight'
|
||||||
|
pathStyle: "greatCircle"
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// DX CLUSTER SETTINGS
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
dxCluster: {
|
||||||
|
// Enable live DX cluster connection
|
||||||
|
enabled: false, // Set to true when API is implemented
|
||||||
|
|
||||||
|
// Cluster node (Telnet)
|
||||||
|
node: "dxc.nc7j.com",
|
||||||
|
port: 7373,
|
||||||
|
|
||||||
|
// Login callsign (usually your call)
|
||||||
|
login: "K0CJH",
|
||||||
|
|
||||||
|
// Filter options
|
||||||
|
filters: {
|
||||||
|
// Only show spots for these bands (empty = all bands)
|
||||||
|
bands: [], // e.g., ["20m", "40m", "15m"]
|
||||||
|
|
||||||
|
// Only show these modes (empty = all modes)
|
||||||
|
modes: [], // e.g., ["FT8", "CW", "SSB"]
|
||||||
|
|
||||||
|
// Minimum spot age to display (minutes)
|
||||||
|
maxAge: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// POTA/SOTA SETTINGS
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
pota: {
|
||||||
|
enabled: true,
|
||||||
|
|
||||||
|
// Filter by state/region (empty = all)
|
||||||
|
regions: [], // e.g., ["K-CO", "K-WY"]
|
||||||
|
|
||||||
|
// Maximum number of spots to show
|
||||||
|
maxSpots: 10
|
||||||
|
},
|
||||||
|
|
||||||
|
sota: {
|
||||||
|
enabled: false,
|
||||||
|
|
||||||
|
// Filter by association (empty = all)
|
||||||
|
associations: [], // e.g., ["W7C", "W0C"]
|
||||||
|
|
||||||
|
maxSpots: 10
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// SPACE WEATHER DATA SOURCES
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
dataRefresh: {
|
||||||
|
// Refresh interval in seconds
|
||||||
|
spaceWeather: 300, // 5 minutes
|
||||||
|
bandConditions: 300, // 5 minutes
|
||||||
|
dxCluster: 5, // 5 seconds (live)
|
||||||
|
pota: 60, // 1 minute
|
||||||
|
sota: 60 // 1 minute
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// SOUND/ALERTS (Coming Soon)
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
alerts: {
|
||||||
|
enabled: false,
|
||||||
|
|
||||||
|
// Sound alerts for new DX spots
|
||||||
|
dxClusterSound: false,
|
||||||
|
|
||||||
|
// Alert for specific DXCC entities
|
||||||
|
watchedEntities: [], // e.g., ["VP8", "3Y", "P5"]
|
||||||
|
|
||||||
|
// Alert for space weather events
|
||||||
|
spaceWeatherAlert: false
|
||||||
|
},
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// ADVANCED
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
advanced: {
|
||||||
|
// Enable debug logging
|
||||||
|
debug: false,
|
||||||
|
|
||||||
|
// Custom CSS (appended to page)
|
||||||
|
customCSS: "",
|
||||||
|
|
||||||
|
// API endpoints (for self-hosted data servers)
|
||||||
|
apiEndpoints: {
|
||||||
|
spaceWeather: null, // null = use default
|
||||||
|
dxCluster: null,
|
||||||
|
pota: null,
|
||||||
|
sota: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export for use in main application
|
||||||
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
module.exports = OpenHamClockConfig;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
OpenHamClock Development Server
|
||||||
|
|
||||||
|
A simple HTTP server for OpenHamClock with API proxy capabilities.
|
||||||
|
This allows the application to fetch live data from external sources
|
||||||
|
without CORS issues.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 server.py [port]
|
||||||
|
|
||||||
|
Default port: 8080
|
||||||
|
Open http://localhost:8080 in your browser
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
Python 3.7+
|
||||||
|
requests library (optional, for API proxy)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import http.server
|
||||||
|
import socketserver
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8080
|
||||||
|
|
||||||
|
# API endpoints for live data
|
||||||
|
API_ENDPOINTS = {
|
||||||
|
'solarflux': 'https://services.swpc.noaa.gov/json/solar-cycle/observed-solar-flux.json',
|
||||||
|
'kindex': 'https://services.swpc.noaa.gov/json/planetary_k_index_1m.json',
|
||||||
|
'xray': 'https://services.swpc.noaa.gov/json/goes/primary/xrays-7-day.json',
|
||||||
|
'sunspots': 'https://services.swpc.noaa.gov/json/solar-cycle/sunspots.json',
|
||||||
|
'pota': 'https://api.pota.app/spot/activator',
|
||||||
|
'bands': 'https://www.hamqsl.com/solarxml.php', # HamQSL solar data
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpenHamClockHandler(http.server.SimpleHTTPRequestHandler):
|
||||||
|
"""Custom HTTP handler with API proxy support."""
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
# Handle API proxy requests
|
||||||
|
if self.path.startswith('/api/'):
|
||||||
|
self.handle_api()
|
||||||
|
else:
|
||||||
|
# Serve static files
|
||||||
|
super().do_GET()
|
||||||
|
|
||||||
|
def handle_api(self):
|
||||||
|
"""Proxy API requests to avoid CORS issues."""
|
||||||
|
endpoint = self.path.replace('/api/', '').split('?')[0]
|
||||||
|
|
||||||
|
if endpoint not in API_ENDPOINTS:
|
||||||
|
self.send_error(404, f"Unknown API endpoint: {endpoint}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
url = API_ENDPOINTS[endpoint]
|
||||||
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Fetching: {url}")
|
||||||
|
|
||||||
|
# Make the request
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url,
|
||||||
|
headers={'User-Agent': 'OpenHamClock/1.0'}
|
||||||
|
)
|
||||||
|
|
||||||
|
with urllib.request.urlopen(req, timeout=10) as response:
|
||||||
|
data = response.read()
|
||||||
|
content_type = response.headers.get('Content-Type', 'application/json')
|
||||||
|
|
||||||
|
# Send response
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-Type', content_type)
|
||||||
|
self.send_header('Access-Control-Allow-Origin', '*')
|
||||||
|
self.send_header('Cache-Control', 'max-age=60')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(data)
|
||||||
|
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
print(f"[ERROR] Failed to fetch {endpoint}: {e}")
|
||||||
|
self.send_error(502, f"Failed to fetch data: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] {e}")
|
||||||
|
self.send_error(500, str(e))
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
"""Custom logging format."""
|
||||||
|
if args[0].startswith('GET /api/'):
|
||||||
|
return # Already logged in handle_api
|
||||||
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] {args[0]}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Change to the directory containing this script
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
os.chdir(script_dir)
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print(" OpenHamClock Development Server")
|
||||||
|
print("=" * 50)
|
||||||
|
print()
|
||||||
|
print(f" Serving from: {script_dir}")
|
||||||
|
print(f" URL: http://localhost:{PORT}")
|
||||||
|
print(f" Press Ctrl+C to stop")
|
||||||
|
print()
|
||||||
|
print(" Available API endpoints:")
|
||||||
|
for name, url in API_ENDPOINTS.items():
|
||||||
|
print(f" /api/{name}")
|
||||||
|
print()
|
||||||
|
print("=" * 50)
|
||||||
|
print()
|
||||||
|
|
||||||
|
with socketserver.TCPServer(("", PORT), OpenHamClockHandler) as httpd:
|
||||||
|
httpd.allow_reuse_address = True
|
||||||
|
try:
|
||||||
|
httpd.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nServer stopped.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# OpenHamClock Raspberry Pi Setup Script
|
||||||
|
# Configures Pi for kiosk mode operation
|
||||||
|
#
|
||||||
|
# Usage: chmod +x setup-pi.sh && ./setup-pi.sh
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo " OpenHamClock Raspberry Pi Setup"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if running on Raspberry Pi
|
||||||
|
if [ ! -f /proc/device-tree/model ]; then
|
||||||
|
echo "Warning: This doesn't appear to be a Raspberry Pi."
|
||||||
|
echo "Continuing anyway..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the current user
|
||||||
|
CURRENT_USER=$(whoami)
|
||||||
|
HOME_DIR=$(eval echo ~$CURRENT_USER)
|
||||||
|
OPENHAMCLOCK_DIR="$HOME_DIR/openhamclock"
|
||||||
|
|
||||||
|
echo "Installing for user: $CURRENT_USER"
|
||||||
|
echo "Install directory: $OPENHAMCLOCK_DIR"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Update system
|
||||||
|
echo ">>> Updating system packages..."
|
||||||
|
sudo apt-get update -qq
|
||||||
|
|
||||||
|
# Install required packages
|
||||||
|
echo ">>> Installing required packages..."
|
||||||
|
sudo apt-get install -y -qq \
|
||||||
|
chromium-browser \
|
||||||
|
unclutter \
|
||||||
|
xdotool \
|
||||||
|
x11-xserver-utils
|
||||||
|
|
||||||
|
# Create OpenHamClock directory if it doesn't exist
|
||||||
|
echo ">>> Setting up OpenHamClock directory..."
|
||||||
|
mkdir -p "$OPENHAMCLOCK_DIR"
|
||||||
|
|
||||||
|
# Copy index.html if it exists in the current directory
|
||||||
|
if [ -f "index.html" ]; then
|
||||||
|
cp index.html "$OPENHAMCLOCK_DIR/"
|
||||||
|
echo ">>> Copied index.html to $OPENHAMCLOCK_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the autostart directory
|
||||||
|
echo ">>> Configuring autostart..."
|
||||||
|
mkdir -p "$HOME_DIR/.config/autostart"
|
||||||
|
|
||||||
|
# Create autostart entry for OpenHamClock
|
||||||
|
cat > "$HOME_DIR/.config/autostart/openhamclock.desktop" << EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=OpenHamClock
|
||||||
|
Comment=Amateur Radio Dashboard
|
||||||
|
Exec=/bin/bash $OPENHAMCLOCK_DIR/start-kiosk.sh
|
||||||
|
Terminal=false
|
||||||
|
Hidden=false
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create kiosk start script
|
||||||
|
echo ">>> Creating kiosk start script..."
|
||||||
|
cat > "$OPENHAMCLOCK_DIR/start-kiosk.sh" << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# OpenHamClock Kiosk Mode Launcher
|
||||||
|
#
|
||||||
|
|
||||||
|
# Wait for desktop to be ready
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Disable screen blanking and power management
|
||||||
|
xset s off
|
||||||
|
xset -dpms
|
||||||
|
xset s noblank
|
||||||
|
|
||||||
|
# Hide the mouse cursor after 3 seconds of inactivity
|
||||||
|
unclutter -idle 3 -root &
|
||||||
|
|
||||||
|
# Kill any existing Chromium processes
|
||||||
|
pkill -f chromium-browser || true
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Start Chromium in kiosk mode
|
||||||
|
chromium-browser \
|
||||||
|
--kiosk \
|
||||||
|
--noerrdialogs \
|
||||||
|
--disable-infobars \
|
||||||
|
--disable-session-crashed-bubble \
|
||||||
|
--disable-restore-session-state \
|
||||||
|
--disable-features=TranslateUI \
|
||||||
|
--check-for-update-interval=31536000 \
|
||||||
|
--disable-component-update \
|
||||||
|
--overscroll-history-navigation=0 \
|
||||||
|
--incognito \
|
||||||
|
"file://$HOME/openhamclock/index.html"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x "$OPENHAMCLOCK_DIR/start-kiosk.sh"
|
||||||
|
|
||||||
|
# Create a stop script
|
||||||
|
cat > "$OPENHAMCLOCK_DIR/stop-kiosk.sh" << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Stop OpenHamClock kiosk mode
|
||||||
|
pkill -f chromium-browser
|
||||||
|
pkill -f unclutter
|
||||||
|
echo "OpenHamClock stopped."
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x "$OPENHAMCLOCK_DIR/stop-kiosk.sh"
|
||||||
|
|
||||||
|
# Create a restart script
|
||||||
|
cat > "$OPENHAMCLOCK_DIR/restart-kiosk.sh" << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Restart OpenHamClock
|
||||||
|
$HOME/openhamclock/stop-kiosk.sh
|
||||||
|
sleep 2
|
||||||
|
$HOME/openhamclock/start-kiosk.sh &
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x "$OPENHAMCLOCK_DIR/restart-kiosk.sh"
|
||||||
|
|
||||||
|
# Create systemd service for headless operation (optional)
|
||||||
|
echo ">>> Creating systemd service (for headless operation)..."
|
||||||
|
sudo tee /etc/systemd/system/openhamclock.service > /dev/null << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=OpenHamClock Kiosk
|
||||||
|
After=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=$CURRENT_USER
|
||||||
|
Environment=DISPLAY=:0
|
||||||
|
ExecStart=/bin/bash $OPENHAMCLOCK_DIR/start-kiosk.sh
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Disable screen blanking in config.txt
|
||||||
|
echo ">>> Configuring boot options..."
|
||||||
|
if ! grep -q "consoleblank=0" /boot/cmdline.txt 2>/dev/null; then
|
||||||
|
sudo sed -i '$ s/$/ consoleblank=0/' /boot/cmdline.txt 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure GPU memory for better graphics (optional)
|
||||||
|
if ! grep -q "gpu_mem=" /boot/config.txt 2>/dev/null; then
|
||||||
|
echo "gpu_mem=128" | sudo tee -a /boot/config.txt > /dev/null 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "========================================"
|
||||||
|
echo " Setup Complete!"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
echo "OpenHamClock has been installed to: $OPENHAMCLOCK_DIR"
|
||||||
|
echo ""
|
||||||
|
echo "Files created:"
|
||||||
|
echo " - $OPENHAMCLOCK_DIR/index.html (main application)"
|
||||||
|
echo " - $OPENHAMCLOCK_DIR/start-kiosk.sh (start in kiosk mode)"
|
||||||
|
echo " - $OPENHAMCLOCK_DIR/stop-kiosk.sh (stop kiosk)"
|
||||||
|
echo " - $OPENHAMCLOCK_DIR/restart-kiosk.sh (restart kiosk)"
|
||||||
|
echo ""
|
||||||
|
echo "Auto-start:"
|
||||||
|
echo " OpenHamClock will automatically start on next boot."
|
||||||
|
echo ""
|
||||||
|
echo "Manual commands:"
|
||||||
|
echo " Start: ~/openhamclock/start-kiosk.sh"
|
||||||
|
echo " Stop: ~/openhamclock/stop-kiosk.sh"
|
||||||
|
echo " Restart: ~/openhamclock/restart-kiosk.sh"
|
||||||
|
echo ""
|
||||||
|
echo "To disable auto-start:"
|
||||||
|
echo " rm ~/.config/autostart/openhamclock.desktop"
|
||||||
|
echo ""
|
||||||
|
echo "Reboot recommended to apply all changes."
|
||||||
|
echo ""
|
||||||
|
echo "73 de OpenHamClock!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -p "Would you like to reboot now? (y/N) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
sudo reboot
|
||||||
|
fi
|
||||||
Loading…
Reference in new issue