forked from sigil-03/power
make SET stub + move elements into system wrapper
This commit is contained in:
parent
fd120be85e
commit
987150c9b6
6 changed files with 108 additions and 65 deletions
5
src/control.rs
Normal file
5
src/control.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
use crate::types::Error;
|
||||||
|
|
||||||
|
pub trait Control {
|
||||||
|
async fn set_power(&self) -> Result<(), Error>;
|
||||||
|
}
|
||||||
16
src/main.rs
16
src/main.rs
|
|
@ -1,21 +1,31 @@
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use monitor::Monitor;
|
|
||||||
|
|
||||||
|
mod control;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
|
mod system;
|
||||||
mod tasmota;
|
mod tasmota;
|
||||||
|
mod types;
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum Commands {
|
pub enum Commands {
|
||||||
Monitor,
|
Monitor,
|
||||||
|
#[command(subcommand)]
|
||||||
|
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 {
|
let handle = match self {
|
||||||
Self::Monitor => {
|
Self::Monitor => {
|
||||||
let m = Monitor::new_from_file(config_file).unwrap();
|
let s = system::System::new_from_file(config_file).unwrap();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
m.get_power().await.unwrap();
|
s.get_power().await.unwrap();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Self::Set(state) => {
|
||||||
|
// let c = Controller::new_from_file(config_file).unwrap();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
println!("SET");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,9 @@
|
||||||
use crate::tasmota::{PowerStatusData, StatusResponse, TasmotaInterface, TasmotaInterfaceConfig};
|
use crate::tasmota::{PowerStatusData, StatusResponse, TasmotaInterface, TasmotaInterfaceConfig};
|
||||||
|
use crate::types::Error;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("io error")]
|
|
||||||
IoError(#[from] std::io::Error),
|
|
||||||
#[error("toml parsing error")]
|
|
||||||
ParseError(#[from] toml::de::Error),
|
|
||||||
#[error("request error")]
|
|
||||||
RequestError(#[from] reqwest::Error),
|
|
||||||
#[error("JSON Parse error")]
|
|
||||||
JsonParseError(#[from] serde_json::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Monitoring {
|
pub trait Monitoring {
|
||||||
async fn get_power(&self) -> Result<isize, Error>;
|
async fn get_power(&self) -> Result<isize, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct MonitorConfig {
|
|
||||||
targets: Vec<TasmotaInterfaceConfig>,
|
|
||||||
}
|
|
||||||
impl MonitorConfig {
|
|
||||||
fn print(&self) {
|
|
||||||
for t in &self.targets {
|
|
||||||
t.print();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Monitor {
|
|
||||||
targets: Vec<TasmotaInterface>,
|
|
||||||
client: Client,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Monitor {
|
|
||||||
pub fn new_from_file(config_file: &str) -> Result<Self, Error> {
|
|
||||||
let config_str = fs::read_to_string(config_file)?;
|
|
||||||
let config: MonitorConfig = toml::from_str(&config_str)?;
|
|
||||||
Ok(Self {
|
|
||||||
targets: Monitor::load_targets(&config.targets),
|
|
||||||
client: Client::new(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_targets(targets: &Vec<TasmotaInterfaceConfig>) -> Vec<TasmotaInterface> {
|
|
||||||
let mut v = Vec::new();
|
|
||||||
for target in targets {
|
|
||||||
v.push(TasmotaInterface::new(target.clone()));
|
|
||||||
}
|
|
||||||
v
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_power(&self) -> Result<(), Error> {
|
|
||||||
for target in &self.targets {
|
|
||||||
if let Ok(res) = target.get_power().await {
|
|
||||||
target.print();
|
|
||||||
println!("* POWER: {}W", res);
|
|
||||||
println!("------------------")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
51
src/system.rs
Normal file
51
src/system.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::monitor::Monitoring;
|
||||||
|
use crate::tasmota::{TasmotaInterface, TasmotaInterfaceConfig};
|
||||||
|
use crate::types::Error;
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct SystemConfig {
|
||||||
|
components: Vec<TasmotaInterfaceConfig>,
|
||||||
|
}
|
||||||
|
impl SystemConfig {
|
||||||
|
fn print(&self) {
|
||||||
|
for t in &self.components {
|
||||||
|
t.print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct System {
|
||||||
|
components: Vec<TasmotaInterface>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub fn new_from_file(config_file: &str) -> Result<Self, Error> {
|
||||||
|
let config_str = fs::read_to_string(config_file)?;
|
||||||
|
let config: SystemConfig = toml::from_str(&config_str)?;
|
||||||
|
Ok(Self {
|
||||||
|
components: System::load_targets(&config.components),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_targets(targets: &Vec<TasmotaInterfaceConfig>) -> Vec<TasmotaInterface> {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for target in targets {
|
||||||
|
v.push(TasmotaInterface::new(target.clone()));
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_power(&self) -> Result<(), Error> {
|
||||||
|
for component in &self.components {
|
||||||
|
if let Ok(res) = component.get_power().await {
|
||||||
|
component.print();
|
||||||
|
println!("* POWER: {}W", res);
|
||||||
|
println!("------------------")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::monitor::Error;
|
use crate::{control::Control, monitor::Monitoring};
|
||||||
use crate::monitor::Monitoring;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EnergyData {
|
pub struct EnergyData {
|
||||||
|
|
@ -69,3 +68,20 @@ impl Monitoring for TasmotaInterface {
|
||||||
Ok(data.status.energy.power)
|
Ok(data.status.energy.power)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Control for TasmotaInterface {
|
||||||
|
async fn set_power(&self) -> Result<(), Error> {
|
||||||
|
let res = self
|
||||||
|
.client
|
||||||
|
.get(format!(
|
||||||
|
"http://{}/cm?cmnd=Power%20TOGGLE",
|
||||||
|
&self.config.target
|
||||||
|
))
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.text()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
20
src/types.rs
Normal file
20
src/types.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use clap::Subcommand;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("io error")]
|
||||||
|
IoError(#[from] std::io::Error),
|
||||||
|
#[error("toml parsing error")]
|
||||||
|
ParseError(#[from] toml::de::Error),
|
||||||
|
#[error("request error")]
|
||||||
|
RequestError(#[from] reqwest::Error),
|
||||||
|
#[error("JSON Parse error")]
|
||||||
|
JsonParseError(#[from] serde_json::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Clone)]
|
||||||
|
pub enum PowerState {
|
||||||
|
Off,
|
||||||
|
On,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue