Open
Description
Code
use chrono::{Local, Timelike, Utc};
use tokio_postgres::{NoTls, Row};
use tokio::time::Duration;
use tokio_postgres::types::ToSql;
type GenericError = Box<dyn std::error::Error>;
async fn get_temperature(config: &Configuration) -> Result<f32, GenericError>{
let esp32_host = format!("http://{}/temperature", config.controller_ip_address).to_string();
let resp = reqwest::get(esp32_host)
.await?
.text()
.await?;
let value = resp.parse::<f32>().unwrap();
return Ok(value);
}
async fn manage_ac(on: bool) -> Result<(), GenericError>{
log_ac_command(if on { "turn_on" } else { "turn_off"}, "").await?;
return Ok(());
}
async fn postgres_command(sql: &str, params: &[&(dyn ToSql + Sync)] ) -> Result<u64, Box<dyn std::error::Error>> {
let dev_postgress = "host=localhost user=user password=password dbname=dbname";
let (client, connection) = tokio_postgres::connect(dev_postgress, NoTls).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
log_message(format!("connection error: {}", e).as_str());
}
});
let result = client.execute( sql, params).await?;
log_message(format!("Command Result: {}", result).as_str());
Ok(result)
}
async fn postgres_query(sql: &str, params: &[&(dyn ToSql + Sync)] ) -> Result<Vec<Row>, Box<dyn std::error::Error>> {
let dev_postgress = "host=localhost user=user password=password dbname=xxx";
let (client, connection) = tokio_postgres::connect(dev_postgress, NoTls).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
log_message(format!("connection error: {}", e).as_str());
}
});
let result = client.query( sql, params).await?;
log_message(format!("Query [{}] was successful", sql).as_str());
Ok(result)
}
async fn log_temperature(temperature: f32) -> Result<(), Box<dyn std::error::Error>>{
let insert = "INSERT INTO temperature(timestamp, value) VALUES($1, $2)";
let timestamp = Local::now();
let result = postgres_command(insert, &[×tamp, &temperature]).await?;
log_message(format!("Temperature Log Result: {}", result).as_str());
Ok(())
}
struct Configuration {
active_hours_utc: (u32, u32),
controller_ip_address: String,
loop_interval_seconds: Duration,
target_temperature: f32,
}
async fn read_config_value_as_string(name: &str) -> Result<String, Box<dyn std::error::Error>>{
let sql = "SELECT value FROM configuration where name = '$1'";
let rows = postgres_query(sql, &[&name]).await?;
Ok(rows[0].get(0))
}
async fn read_config() -> Result<Configuration, Box<dyn std::error::Error>> {
let target_temp_str = read_config_value_as_string("target_temperature").await?;
let loop_interval_str = read_config_value_as_string("loop_interval_seconds").await?;
let controller_ip = read_config_value_as_string("controller_ip_address").await?;
let config = Configuration {
active_hours_utc : (20, 11),
target_temperature : target_temp_str.parse().unwrap(),
loop_interval_seconds: Duration::from_secs(loop_interval_str.parse().unwrap()),
controller_ip_address: controller_ip.parse().unwrap()
};
Ok(config)
}
async fn log_ac_command(command: &str, state: &str) -> Result<(), Box<dyn std::error::Error>>{
let insert = "INSERT INTO ac_management(timestamp, command, state) VALUES($1, $2, $3)";
let timestamp = Local::now();
let result = postgres_command(insert, &[×tamp, &command, &state]).await?;
log_message(format!("Temperature Log Result: {}", result).as_str());
Ok(())
}
fn log_message(message: &str) -> () {
let timestamp = Local::now();
println!("{} {:?}", timestamp.format("%Y-%m-%d %H:%M:%S%.3f %:z"), message);
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = read_config().await?;
let target_temp = config.target_temperature;
let mut ac_is_on = false;
let mut last_read = -1.0;
// exit(0);
loop {
let temperature = get_temperature(&config).await;
match temperature {
Ok(t) => {
last_read = t;
log_message(format!("The temperature is {}", t).as_str());
let result = log_temperature(t).await;
match result {
Ok(()) => {
log_message(format!("Successful write to DB").as_str());
}
Err(err) => log_message(format!("Error writing to DB: {}", err).as_str())
}
}
Err(err) => {
log_message(format!("Temperature retrieval error: {}", err).as_str());
}
}
let current_hour = Utc::now().hour();
let (start_hour, stop_hour) = config.active_hours_utc;
let app_is_active = current_hour >= start_hour
&& (start_hour <= stop_hour && current_hour < stop_hour)
|| (start_hour > stop_hour && current_hour < stop_hour);
if !app_is_active && ac_is_on {
match manage_ac(false).await {
Ok(()) => {
ac_is_on = false;
log_message("AC was turned off because the application is deactivated");
}
Err(err) => {
log_message(format!("Error occurred when turning AC off: {}", err).as_str());
}
}
}
if app_is_active {
if last_read < target_temp && ac_is_on {
match manage_ac(false).await {
Ok(()) => {
ac_is_on = false;
log_message(format!("AC was turned off because temperature went down to {}", last_read).as_str());
}
Err(err) => {
log_message(format!("Error occurred when turning AC off: {}", err).as_str());
}
}
} else if last_read > target_temp + 2.0 && !ac_is_on {
match manage_ac(true).await {
Ok(()) => {
ac_is_on = true;
log_message(format!("AC was turned on because temperature went up to {}", last_read).as_str());
}
Err(err) => {
log_message(format!( "Error occurred when turning AC on: {}", err).as_str());
}
}
}
}
tokio::time::sleep(config.loop_interval_seconds).await;
}
}
Meta
rustc --version --verbose
:
rustc 1.57.0 (f1edd0429 2021-11-29)
binary: rustc
commit-hash: f1edd0429582dd29cccacaf50fd134b05593bd9c
commit-date: 2021-11-29
host: x86_64-unknown-linux-gnu
release: 1.57.0
LLVM version: 13.0.0
Error output
Compiling stats_collector v0.1.0 (/home/al/work/smart/master/stats_collector)
thread 'rustc' panicked at 'attempted to read from stolen value: rustc_middle::mir::Body', compiler/rustc_mir_transform/src/check_unsafety.rs:445:36
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
note: rustc 1.57.0 (f1edd0429 2021-11-29) running on x86_64-unknown-linux-gnu
note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin
note: some of the compiler flags provided by cargo are hidden
query stack during panic:
#0 [unsafety_check_result] unsafety-checking `manage_ac`
#1 [analysis] running analysis passes on this crate
end of query stack
error: could not compile `stats_collector`
Backtrace
<backtrace>