167 lines
4.9 KiB
Rust
167 lines
4.9 KiB
Rust
use envconfig::Envconfig;
|
|
use log::{debug, info, warn};
|
|
use teloxide::{prelude::*, utils::command::BotCommand};
|
|
|
|
const VERSION: &str = env!("GIT_REVISION");
|
|
const BRANCH: &str = env!("GIT_BRANCH");
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
debug!("starting the application");
|
|
|
|
tokio::spawn(run()).await.unwrap();
|
|
}
|
|
|
|
#[derive(Envconfig, Clone)]
|
|
struct Settings {
|
|
#[envconfig(from = "ALTEREGO_TELEGRAM_TOKEN")]
|
|
pub telegram_token: String,
|
|
|
|
#[envconfig(
|
|
from = "ALTEREGO_CLIMATE_DSN",
|
|
default = "http://127.0.0.1:18081/v1/home/temperature"
|
|
)]
|
|
pub climate_dsn: String,
|
|
|
|
#[envconfig(
|
|
from = "ALTEREGO_HOSTTEMP_CMD",
|
|
default = "/opt/vc/bin/vcgencmd measure_temp"
|
|
)]
|
|
pub hosttemp_cmd: String,
|
|
}
|
|
|
|
async fn run() {
|
|
env_logger::init();
|
|
|
|
let settings = Settings::init_from_env().expect("reading config values");
|
|
let startup = std::sync::Arc::from(std::time::SystemTime::now());
|
|
|
|
let bot = teloxide::Bot::builder()
|
|
.token(&settings.telegram_token)
|
|
.build();
|
|
let bot_name = "AlterEgo";
|
|
|
|
teloxide::commands_repl(bot, bot_name, move |cx, command| {
|
|
let climate = settings.climate_dsn.clone();
|
|
let cmd: String = settings.hosttemp_cmd.clone();
|
|
let cmd: Vec<&str> = cmd.split(' ').collect();
|
|
let console_cmd = cmd.first().expect("getting console command").to_string();
|
|
let arg: String = cmd.get(1).unwrap_or(&"").to_string();
|
|
let startup = *startup;
|
|
|
|
async move { handler(cx, command, climate, console_cmd, arg, startup).await }
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[derive(serde::Deserialize, Debug)]
|
|
struct Climate {
|
|
humidity: f32,
|
|
temp: f32,
|
|
}
|
|
|
|
async fn handler(
|
|
cx: UpdateWithCx<Message>,
|
|
command: Command,
|
|
dsn: String,
|
|
console_command: String,
|
|
console_arg: String,
|
|
startup: std::time::SystemTime,
|
|
) -> ResponseResult<()> {
|
|
let request_id = uuid::Uuid::new_v4();
|
|
|
|
info!(
|
|
"incoming request xreqid={} command={:?}",
|
|
request_id, command
|
|
);
|
|
|
|
match command {
|
|
Command::Help => cx.answer(Command::descriptions()).send().await?,
|
|
Command::HostTemperature => {
|
|
info!(
|
|
"querying command {} with arg {}",
|
|
console_command, console_arg
|
|
);
|
|
|
|
let cmd = std::process::Command::new(&console_command)
|
|
.arg(&console_arg)
|
|
.stdout(std::process::Stdio::piped())
|
|
.spawn()
|
|
.expect("running vcgencmd command");
|
|
|
|
let output = cmd.wait_with_output().expect("waiting for output");
|
|
|
|
let parsed =
|
|
std::string::String::from_utf8(output.stdout).expect("casting into string");
|
|
|
|
let parsed = parsed.replace("temp=", "");
|
|
|
|
cx.answer_str(format!("Your Raspberry PI temperature is {}", parsed))
|
|
.await?
|
|
}
|
|
Command::RoomTemperature => {
|
|
info!("sending request to {}", dsn);
|
|
|
|
let response = match reqwest::get(&dsn).await {
|
|
Ok(response) => response,
|
|
Err(err) => {
|
|
warn!(
|
|
"unable to handle request xreqid={} error={:?}",
|
|
request_id, err
|
|
);
|
|
cx.answer_str(format!("something went wrong, reference to {}", request_id))
|
|
.await?;
|
|
|
|
return Err(RequestError::NetworkError(err));
|
|
}
|
|
};
|
|
|
|
let info: Climate = match response.json::<Climate>().await {
|
|
Ok(result) => result,
|
|
Err(err) => {
|
|
warn!(
|
|
"unable to handle request xreqid={} error={:?}",
|
|
request_id, err
|
|
);
|
|
cx.answer_str(format!("something went wrong, reference to {}", request_id))
|
|
.await?;
|
|
|
|
return Err(RequestError::NetworkError(err));
|
|
}
|
|
};
|
|
|
|
debug!("parsed value: {:?}", info);
|
|
|
|
cx.answer_str(format!(
|
|
"Your room temperature is {:.2} and humidity is {:.2}.",
|
|
info.temp, info.humidity
|
|
))
|
|
.await?
|
|
}
|
|
Command::VersionRequest => {
|
|
cx.answer_str(format!(
|
|
"app version is {}@{}, uptime is {} second(-s)",
|
|
VERSION,
|
|
BRANCH,
|
|
startup.elapsed().unwrap().as_secs()
|
|
))
|
|
.await?
|
|
}
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(BotCommand, Debug)]
|
|
#[command(rename = "lowercase", description = "These commands are supported:")]
|
|
enum Command {
|
|
#[command(description = "display this text.")]
|
|
Help,
|
|
#[command(description = "temperature of your room.")]
|
|
RoomTemperature,
|
|
#[command(description = "temperature of raspberry.")]
|
|
HostTemperature,
|
|
#[command(description = "prints current version.")]
|
|
VersionRequest,
|
|
}
|