u
This commit is contained in:
@@ -178,6 +178,7 @@ async fn discover_and_create_config(
|
||||
server_url: server,
|
||||
api_key: key,
|
||||
poll_interval_secs: 60,
|
||||
command_url: None,
|
||||
devices,
|
||||
};
|
||||
|
||||
@@ -408,6 +409,36 @@ async fn collect_device_data(device: &DeviceConfig) -> Vec<Reading> {
|
||||
readings
|
||||
}
|
||||
|
||||
// Switch a device on or off
|
||||
async fn switch_device(device: &DeviceConfig, turn_on: bool) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let client = ApiClient::new(&device.tapo_email, &device.tapo_password);
|
||||
|
||||
match device.device_type.as_str() {
|
||||
"P110" | "P115" => {
|
||||
let plug = client.p110(&device.ip).await?;
|
||||
if turn_on {
|
||||
plug.on().await?;
|
||||
} else {
|
||||
plug.off().await?;
|
||||
}
|
||||
}
|
||||
"P100" | "P105" => {
|
||||
let plug = client.p100(&device.ip).await?;
|
||||
if turn_on {
|
||||
plug.on().await?;
|
||||
} else {
|
||||
plug.off().await?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(format!("Unknown device type: {}", device.device_type).into());
|
||||
}
|
||||
}
|
||||
|
||||
info!("[Switch] Device {} turned {}", device.name, if turn_on { "ON" } else { "OFF" });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_agent(config: Config) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -449,6 +480,9 @@ async fn run_agent(config: Config) -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
});
|
||||
|
||||
// Clone devices for command handling in main loop
|
||||
let devices_for_commands = config.devices.clone();
|
||||
|
||||
// Connection and sending loop
|
||||
let mut reconnect_delay = Duration::from_secs(1);
|
||||
let max_reconnect_delay = Duration::from_secs(60);
|
||||
@@ -512,6 +546,35 @@ async fn run_agent(config: Config) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Handle incoming WebSocket messages
|
||||
msg = read.next() => {
|
||||
match msg {
|
||||
Some(Ok(Message::Text(text))) => {
|
||||
// Handle incoming commands from server
|
||||
if let Ok(cmd) = serde_json::from_str::<serde_json::Value>(&text) {
|
||||
if cmd.get("type").and_then(|v| v.as_str()) == Some("command") {
|
||||
let device_name = cmd.get("device").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let action = cmd.get("action").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let value = cmd.get("value").and_then(|v| v.as_i64()).unwrap_or(0);
|
||||
|
||||
info!("[Command] Received: device={}, action={}, value={}", device_name, action, value);
|
||||
|
||||
// Find matching device in our config
|
||||
if let Some(device) = devices_for_commands.iter().find(|d| d.name == device_name) {
|
||||
if action == "set_state" {
|
||||
let turn_on = value > 0;
|
||||
info!("[Command] Switching {} {}", device_name, if turn_on { "ON" } else { "OFF" });
|
||||
|
||||
let device_clone = device.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = switch_device(&device_clone, turn_on).await {
|
||||
error!("[Command] Failed to switch {}: {}", device_clone.name, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
warn!("[Command] Unknown device: {}", device_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Ok(Message::Ping(data))) => {
|
||||
let _ = write.send(Message::Pong(data)).await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user