mirror of
				https://gitea.farpn.net/w1cdn/mwtchahrd.git
				synced 2025-11-03 13:36:36 -06:00 
			
		
		
		
	Merge pull request 'Spot UI frames to spothole.app' (#13) from spothole into dev
Reviewed-on: https://gitea.farpn.net/w1cdn/mwtchahrd/pulls/13
This commit is contained in:
		@@ -8,6 +8,7 @@ authors = ["Chris, N6CTA  <mail@n6cta.com>"]
 | 
				
			|||||||
anyhow = "1.0"
 | 
					anyhow = "1.0"
 | 
				
			||||||
chrono = "0.4"
 | 
					chrono = "0.4"
 | 
				
			||||||
clap = { version = "4", features = ["derive"] }
 | 
					clap = { version = "4", features = ["derive"] }
 | 
				
			||||||
 | 
					reqwest = { version = "0.12.24", features = ["json", "blocking"] }
 | 
				
			||||||
serde_json = "1.0.145"
 | 
					serde_json = "1.0.145"
 | 
				
			||||||
socket2 = "0.5"
 | 
					socket2 = "0.5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								README.md
									
									
									
									
									
								
							@@ -57,6 +57,30 @@ mwtchahrd -i <IP> -p <PORT> [-c <CHANNEL>] [-d] [-u]
 | 
				
			|||||||
- `-u, --ui_only`  
 | 
					- `-u, --ui_only`  
 | 
				
			||||||
  Only display frames with a UI payload. When this flag is set, frames that are not UI are skipped.
 | 
					  Only display frames with a UI payload. When this flag is set, frames that are not UI are skipped.
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					- `-b, --uip <UIP>`
 | 
				
			||||||
 | 
					  Send UDP to what IP address (e.g. 127.0.0.1) [default: 127.0.0.1].
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					- `-k, --uport <UPORT>`
 | 
				
			||||||
 | 
					  Send UDP to what port (e.g. 8000; 55555 disables UDP) [default: 55555].
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					- `-s, --spotter <SPOTTER>`            
 | 
				
			||||||
 | 
					  Spotter callsign (e.g. W1CDN).
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					- `-o, --spothole`                     
 | 
				
			||||||
 | 
					  Spot UI frames to a Spothole server.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					- `-O, --spothole-alt <SPOTHOLE_ALT>` 
 | 
				
			||||||
 | 
					  Provide a different URL than https://spothole.app/api/v1/spot.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					- `-f, --freq <FREQ>`                 
 | 
				
			||||||
 | 
					  Spotting frequency [default: 14105000].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `-h, --help`                         
 | 
				
			||||||
 | 
					  Print help.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					- `-V, --version`                      
 | 
				
			||||||
 | 
					  Print version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Examples
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Monitoring All Frames
 | 
					### Monitoring All Frames
 | 
				
			||||||
@@ -83,6 +107,14 @@ Monitor only UI frames:
 | 
				
			|||||||
mwtchahrd -i 127.0.0.1 -p 8000 -u
 | 
					mwtchahrd -i 127.0.0.1 -p 8000 -u
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Spotting to [Spothole.app](https://spothole.app) API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sends only UI frames and mode is hardcoded as `PKT`. Spot from callsign `W1CDN` and report fixed frequency 14.105 MHz:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					mwtchahrd --ip 192.168.0.6 --port 8000 --spotter W1CDN --spothole --freq 14105000
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Code Overview
 | 
					## Code Overview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **Validation Functions:**  
 | 
					- **Validation Functions:**  
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										52
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -11,6 +11,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
 | 
				
			|||||||
use std::net::UdpSocket;
 | 
					use std::net::UdpSocket;
 | 
				
			||||||
use std::net::Ipv4Addr;
 | 
					use std::net::Ipv4Addr;
 | 
				
			||||||
use serde_json::json;
 | 
					use serde_json::json;
 | 
				
			||||||
 | 
					use reqwest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Validate that the provided port string can be parsed into a u16 and is nonzero.
 | 
					/// Validate that the provided port string can be parsed into a u16 and is nonzero.
 | 
				
			||||||
fn validate_port(port: &str) -> Result<u16, String> {
 | 
					fn validate_port(port: &str) -> Result<u16, String> {
 | 
				
			||||||
@@ -62,6 +63,19 @@ struct Cli {
 | 
				
			|||||||
    /// Spotter callsign (e.g. W1CDN)
 | 
					    /// Spotter callsign (e.g. W1CDN)
 | 
				
			||||||
    #[arg(short = 's', long)]
 | 
					    #[arg(short = 's', long)]
 | 
				
			||||||
    spotter: Option<String>,
 | 
					    spotter: Option<String>,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Spot UI frames to a Spothole server
 | 
				
			||||||
 | 
					    #[arg(short = 'o', long, default_value_t = false)]
 | 
				
			||||||
 | 
					    spothole: bool,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Provide a different URL than https://spothole.app/api/v1/spot
 | 
				
			||||||
 | 
					    #[arg(short = 'O', long)]
 | 
				
			||||||
 | 
					    spothole_alt: Option<String>,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Spotting frequency
 | 
				
			||||||
 | 
					    #[arg(short = 'f', long, default_value_t = 14105000)]
 | 
				
			||||||
 | 
					    freq: u32,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Convert a byte slice into a hex-dump string for debugging purposes.
 | 
					/// Convert a byte slice into a hex-dump string for debugging purposes.
 | 
				
			||||||
@@ -363,6 +377,14 @@ fn handle_frame(frame: &AgwFrame, cli: &Cli, buffers: &mut BufferManager) {
 | 
				
			|||||||
    let basic_destination = hdr.callto_str();
 | 
					    let basic_destination = hdr.callto_str();
 | 
				
			||||||
    let timestamp = Local::now().format("%H:%M:%S").to_string();
 | 
					    let timestamp = Local::now().format("%H:%M:%S").to_string();
 | 
				
			||||||
    let spotter = &cli.spotter;
 | 
					    let spotter = &cli.spotter;
 | 
				
			||||||
 | 
					    let freq = &cli.freq;
 | 
				
			||||||
 | 
					    //let spothole_alt = &cli.spothole_alt;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // If user provides an alternate Spothole URL, use that one
 | 
				
			||||||
 | 
					    let spothole_url = match &cli.spothole_alt {
 | 
				
			||||||
 | 
					        Some(spothole_alt) => spothole_alt,
 | 
				
			||||||
 | 
					        None => &"https://spothole.app/api/v1/spot".to_string(),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Filter and compute the text from the payload only once.
 | 
					    // Filter and compute the text from the payload only once.
 | 
				
			||||||
    let text = filter_text(&frame.payload);
 | 
					    let text = filter_text(&frame.payload);
 | 
				
			||||||
@@ -400,6 +422,35 @@ fn handle_frame(frame: &AgwFrame, cli: &Cli, buffers: &mut BufferManager) {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    // If Spothole is enabled
 | 
				
			||||||
 | 
					    if summary == "UI" && cli.spothole {
 | 
				
			||||||
 | 
					        // curl --request POST --header "Content-Type: application/json" 
 | 
				
			||||||
 | 
					        //  --data '{"dx_call":"M0TRT","time":1760019539, "freq":14200000, 
 | 
				
			||||||
 | 
					        //  "comment":"Test spot please ignore", "de_call":"M0TRT"}' https://spothole.app/api/v1/spot
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        println!("spothole_url: {}", spothole_url);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // POST JSON
 | 
				
			||||||
 | 
					        let packet = json!({
 | 
				
			||||||
 | 
					            "dx_call": &source,
 | 
				
			||||||
 | 
					            "de_call": &spotter,
 | 
				
			||||||
 | 
					            "freq": &freq,
 | 
				
			||||||
 | 
					            "comment": &text,
 | 
				
			||||||
 | 
					            "mode": "PKT",
 | 
				
			||||||
 | 
					            "mode_type": "DATA",
 | 
				
			||||||
 | 
					            "mode_source": "SPOT",
 | 
				
			||||||
 | 
					            "time": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let client = reqwest::blocking::Client::new();
 | 
				
			||||||
 | 
					        let res = client.post(spothole_url)
 | 
				
			||||||
 | 
					            .json(&packet)
 | 
				
			||||||
 | 
					            .send();
 | 
				
			||||||
 | 
					        println!("res = {res:?}");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Send UDP
 | 
					    // Send UDP
 | 
				
			||||||
    if cli.uport != 55555 {
 | 
					    if cli.uport != 55555 {
 | 
				
			||||||
        let uaddr = format!("{}:{}", cli.uip, cli.uport);
 | 
					        let uaddr = format!("{}:{}", cli.uip, cli.uport);
 | 
				
			||||||
@@ -411,6 +462,7 @@ fn handle_frame(frame: &AgwFrame, cli: &Cli, buffers: &mut BufferManager) {
 | 
				
			|||||||
            "spotter": &spotter,
 | 
					            "spotter": &spotter,
 | 
				
			||||||
            "summary": &summary,
 | 
					            "summary": &summary,
 | 
				
			||||||
            "text": &text,
 | 
					            "text": &text,
 | 
				
			||||||
 | 
					            "freq": &freq,
 | 
				
			||||||
            "timestamp": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(),
 | 
					            "timestamp": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(),
 | 
				
			||||||
            "type": "data"
 | 
					            "type": "data"
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user