add set functionality to control outlets

This commit is contained in:
sigil-03 2025-04-06 15:21:38 -06:00
parent 987150c9b6
commit 633a57ff23
5 changed files with 42 additions and 22 deletions

View file

@ -1,5 +1,5 @@
use crate::types::Error; use crate::types::{Error, PowerState};
pub trait Control { pub trait Control {
async fn set_power(&self) -> Result<(), Error>; async fn set_power(&self, state: PowerState) -> Result<(), Error>;
} }

View file

@ -6,26 +6,31 @@ mod system;
mod tasmota; mod tasmota;
mod types; mod types;
#[derive(Parser)]
pub struct PowerCommand {
index: usize,
#[command(subcommand)]
state: types::PowerState,
}
#[derive(Subcommand)] #[derive(Subcommand)]
pub enum Commands { pub enum Commands {
Monitor, Monitor,
#[command(subcommand)] Set(PowerCommand),
Set(types::PowerState),
} }
impl Commands { impl Commands {
pub async fn execute(self, config_file: &str) { pub async fn execute(self, config_file: &str) {
let handle = match self {
Self::Monitor => {
let s = system::System::new_from_file(config_file).unwrap(); let s = system::System::new_from_file(config_file).unwrap();
tokio::spawn(async move {
s.get_power().await.unwrap(); let handle = match self {
}) Self::Monitor => tokio::spawn(async move {
} s.try_get_power().await.unwrap();
Self::Set(state) => { }),
Self::Set(command) => {
// let c = Controller::new_from_file(config_file).unwrap(); // let c = Controller::new_from_file(config_file).unwrap();
tokio::spawn(async move { tokio::spawn(async move {
println!("SET"); s.try_set_power(command.index, command.state).await.unwrap();
}) })
} }
}; };

View file

@ -1,6 +1,7 @@
use crate::control::Control;
use crate::monitor::Monitoring; use crate::monitor::Monitoring;
use crate::tasmota::{TasmotaInterface, TasmotaInterfaceConfig}; use crate::tasmota::{TasmotaInterface, TasmotaInterfaceConfig};
use crate::types::Error; use crate::types::{self, Error};
use reqwest::Client; use reqwest::Client;
use serde::Deserialize; use serde::Deserialize;
use std::fs; use std::fs;
@ -38,7 +39,7 @@ impl System {
v v
} }
pub async fn get_power(&self) -> Result<(), Error> { pub async fn try_get_power(&self) -> Result<(), Error> {
for component in &self.components { for component in &self.components {
if let Ok(res) = component.get_power().await { if let Ok(res) = component.get_power().await {
component.print(); component.print();
@ -48,4 +49,10 @@ impl System {
} }
Ok(()) Ok(())
} }
pub async fn try_set_power(&self, index: usize, state: types::PowerState) -> Result<(), Error> {
//TODO: check bounds
self.components[index].set_power(state).await?;
Ok(())
}
} }

View file

@ -1,7 +1,11 @@
use reqwest::Client; use reqwest::Client;
use serde::Deserialize; use serde::Deserialize;
use crate::{control::Control, monitor::Monitoring}; use crate::{
control::Control,
monitor::Monitoring,
types::{Error, PowerState},
};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct EnergyData { pub struct EnergyData {
@ -70,18 +74,21 @@ impl Monitoring for TasmotaInterface {
} }
impl Control for TasmotaInterface { impl Control for TasmotaInterface {
async fn set_power(&self) -> Result<(), Error> { async fn set_power(&self, state: PowerState) -> Result<(), Error> {
let res = self let cmd = match state {
PowerState::Off => "OFF",
PowerState::On => "ON",
};
let _res = self
.client .client
.get(format!( .get(format!(
"http://{}/cm?cmnd=Power%20TOGGLE", "http://{}/cm?cmnd=Power%20{}",
&self.config.target &self.config.target, cmd
)) ))
.send() .send()
.await? .await?
.text() .text()
.await?; .await?;
Ok(()) Ok(())
} }
} }

View file

@ -1,4 +1,5 @@
use clap::Subcommand; use clap::Parser;
use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -13,7 +14,7 @@ pub enum Error {
JsonParseError(#[from] serde_json::Error), JsonParseError(#[from] serde_json::Error),
} }
#[derive(Subcommand, Clone)] #[derive(Serialize, Deserialize, Parser, Clone)]
pub enum PowerState { pub enum PowerState {
Off, Off,
On, On,