HomeServer/src/temperature.rs

97 lines
2.7 KiB
Rust

use std::{
net::IpAddr,
sync::{Arc, Mutex},
time::Duration,
};
use actix_web::web::Data;
use anyhow::{bail, Result};
use dns_lookup::{lookup_addr, lookup_host};
use reqwest::Client;
use crate::{
db::DataBase,
since_epoch,
task_scheduler::{Scheduler, Task},
};
pub struct Thermostat {
device: String,
}
impl Thermostat {
pub fn new(device: impl ToString) -> Self {
Self {
device: device.to_string(),
}
}
pub async fn set_temperature(&self, temperature: f32) -> Result<()> {
let ips = lookup_host(&self.device)?;
if ips.is_empty() {
bail!("could not resolve device name {}", self.device);
}
let resp = Client::new()
.post(format!("http://{}/ext_t?temp={}", ips[0], temperature))
.send()
.await?;
if !resp.status().is_success() {
bail!("response error");
}
Ok(())
}
}
#[derive(Debug)]
pub enum ThermometerChange {
Temperature(f32),
Humidity(f32),
}
pub struct Thermometer;
impl Thermometer {
pub fn push_change(
change: ThermometerChange,
ip: IpAddr,
db: Data<Arc<Mutex<DataBase>>>,
scheduler: Data<Scheduler>,
) -> Result<()> {
let db_lock = db.lock().unwrap();
let device_id = lookup_addr(&ip)?.trim_end_matches(".fritz.box").to_string();
if db_lock.device_exists(&device_id)? {
match change {
ThermometerChange::Temperature(temp) => {
db_lock.write(&device_id, since_epoch()?, "temperature", temp)?;
for action_set in db_lock.action_sets(&device_id)? {
if let Some(push_device) = action_set.push_device() {
if action_set.parameter("temperature") && push_device == device_id {
if let Some(receive_device) = action_set.receive_device() {
scheduler.add_task(Task::one_shot(
Duration::from_secs(0),
Box::pin(async move {
let _ = Thermostat::new(receive_device)
.set_temperature(temp);
}),
));
}
}
}
}
}
ThermometerChange::Humidity(humid) => {
db_lock.write(&device_id, since_epoch()?, "humidity", humid)?;
}
}
}
Ok(())
}
}