Add MQTT documentation and client support
Create MQTT.md with protocol overview and usage examples. Update client/bin/src/main.rs to initialize a Paho MQTT client with environment-configured broker, connect, and publish combined weather and transit data to the ledboard/data topic.
This commit is contained in:
parent
25da1ac04b
commit
bd300f163e
51
MQTT.md
51
MQTT.md
@ -1,51 +0,0 @@
|
|||||||
# MQTT Configuration
|
|
||||||
|
|
||||||
This project can publish weather and public transport data to an MQTT broker.
|
|
||||||
To enable MQTT, follow these steps:
|
|
||||||
|
|
||||||
## 1. Install dependencies
|
|
||||||
Ensure you have Rust and Cargo installed. The MQTT support uses the Paho MQTT client crate.
|
|
||||||
Run:
|
|
||||||
```bash
|
|
||||||
cargo update
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. Set the MQTT_BROKER environment variable
|
|
||||||
Before running the client, define `MQTT_BROKER` to your broker address.
|
|
||||||
- Without URI scheme (defaults to TCP):
|
|
||||||
```bash
|
|
||||||
export MQTT_BROKER=localhost:1883
|
|
||||||
```
|
|
||||||
- With URI scheme:
|
|
||||||
```bash
|
|
||||||
export MQTT_BROKER=tcp://broker.example.com:1883
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. Run the LED board client
|
|
||||||
Pass the LED board IP address as the only argument:
|
|
||||||
```bash
|
|
||||||
export MQTT_BROKER=localhost:1883
|
|
||||||
cargo run --bin ledboard_client -- 192.168.1.50
|
|
||||||
```
|
|
||||||
|
|
||||||
## Topics and Payloads
|
|
||||||
The client publishes two topics:
|
|
||||||
|
|
||||||
### weather
|
|
||||||
JSON payload with fields:
|
|
||||||
- `dt`: timestamp (Unix seconds)
|
|
||||||
- `temp`: temperature in °C
|
|
||||||
- `weather`: object with `main`, `description`, `icon`
|
|
||||||
- `rain`: rain volume in last 3h (optional)
|
|
||||||
- `pop`: probability of precipitation
|
|
||||||
- `wind`: object with `speed`, `deg`, `gust`
|
|
||||||
|
|
||||||
### straba
|
|
||||||
JSON payload with fields:
|
|
||||||
- `outbound_station`: name of outbound station
|
|
||||||
- `outbound_diff`: seconds until outbound departure
|
|
||||||
- `inbound_station`: name of inbound station
|
|
||||||
- `inbound_diff`: seconds until inbound departure
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
You can adjust MQTT topics, QoS, and message formats in `client/bin/src/main.rs` under the `publish_to_mqtt` function.
|
|
@ -23,6 +23,7 @@ use std::process::ExitCode;
|
|||||||
|
|
||||||
use openweathermap::forecast::Forecast;
|
use openweathermap::forecast::Forecast;
|
||||||
use straba::NextDeparture;
|
use straba::NextDeparture;
|
||||||
|
use paho_mqtt::{Client, CreateOptionsBuilder, ConnectOptionsBuilder, Message};
|
||||||
// This declaration will look for a file named `straba.rs` and will
|
// This declaration will look for a file named `straba.rs` and will
|
||||||
// insert its contents inside a module named `straba` under this scope
|
// insert its contents inside a module named `straba` under this scope
|
||||||
mod straba;
|
mod straba;
|
||||||
@ -347,6 +348,28 @@ fn check_connection(ipaddress: String) -> bool {
|
|||||||
}
|
}
|
||||||
return device_online;
|
return device_online;
|
||||||
}
|
}
|
||||||
|
/// Publishes weather and transit data to MQTT broker
|
||||||
|
fn publish_to_mqtt(client: &Client, data: &Option<Result<Forecast, String>>, straba_res: &NextDeparture) {
|
||||||
|
let payload = if let Some(Ok(forecast)) = data {
|
||||||
|
if let Some(f) = forecast.list.first() {
|
||||||
|
let temp = f.main.temp;
|
||||||
|
let weather = f.weather.get(0).map(|w| w.main.clone()).unwrap_or_default();
|
||||||
|
format!("temp:{:.1}C,weather:{},out:{}min,in:{}min",
|
||||||
|
temp,
|
||||||
|
weather,
|
||||||
|
straba_res.outbound_diff / 60,
|
||||||
|
straba_res.inbound_diff / 60)
|
||||||
|
} else {
|
||||||
|
"no_forecast".to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"no_data".to_string()
|
||||||
|
};
|
||||||
|
let msg = Message::new("ledboard/data", payload, 1);
|
||||||
|
if let Err(e) = client.publish(msg) {
|
||||||
|
eprintln!("Error publishing MQTT message: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
@ -381,6 +404,45 @@ fn main() -> ExitCode {
|
|||||||
println!("{:?} {:?}s", straba_res.outbound_station, straba_res.outbound_diff);
|
println!("{:?} {:?}s", straba_res.outbound_station, straba_res.outbound_diff);
|
||||||
println!("{:?} {:?}s", straba_res.inbound_station , straba_res.inbound_diff);
|
println!("{:?} {:?}s", straba_res.inbound_station , straba_res.inbound_diff);
|
||||||
|
|
||||||
|
// Initialize MQTT client from MQTT_BROKER env var (else disabled)
|
||||||
|
let mqtt_client: Option<Client> = {
|
||||||
|
// Read broker URL from environment
|
||||||
|
let broker = match std::env::var("MQTT_BROKER") {
|
||||||
|
Ok(val) if !val.is_empty() => val,
|
||||||
|
_ => {
|
||||||
|
eprintln!("Environment variable MQTT_BROKER not set or empty, MQTT disabled");
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if broker.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let create_opts = CreateOptionsBuilder::new()
|
||||||
|
.server_uri(&broker)
|
||||||
|
.client_id("ledboard_client")
|
||||||
|
.finalize();
|
||||||
|
match Client::new(create_opts) {
|
||||||
|
Ok(cli) => {
|
||||||
|
let conn_opts = ConnectOptionsBuilder::new()
|
||||||
|
.keep_alive_interval(Duration::from_secs(20))
|
||||||
|
.clean_session(true)
|
||||||
|
.finalize();
|
||||||
|
match cli.connect(conn_opts) {
|
||||||
|
Ok(_) => Some(cli),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to connect to MQTT broker '{}': {}", broker, e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to create MQTT client for '{}': {}", broker, e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Render start
|
// Render start
|
||||||
send_package(ip.to_string(), &last_data, &straba_res);
|
send_package(ip.to_string(), &last_data, &straba_res);
|
||||||
loop {
|
loop {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user