2020-10-09 16:31:21 +02:00
|
|
|
use color_eyre::Result;
|
2020-10-09 17:07:18 +02:00
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use std::sync::Mutex;
|
2020-10-09 13:30:37 +02:00
|
|
|
use std::thread;
|
|
|
|
use std::time::{Duration, SystemTime};
|
2020-10-09 16:31:21 +02:00
|
|
|
use thirtyfour_sync::prelude::*;
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 17:07:18 +02:00
|
|
|
const URL: &'static str = "https://my.autarco.com/";
|
2020-10-09 13:30:37 +02:00
|
|
|
const USERNAME: &'static str = "pja@vtilburg.net";
|
|
|
|
const PASSWORD: &'static str = "XXXXXXXXXXXXXXXX";
|
2020-10-09 17:07:18 +02:00
|
|
|
const POLL_INTERVAL: u64 = 300;
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 16:31:21 +02:00
|
|
|
const GECKO_DRIVER_PORT: u16 = 18019;
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 16:31:21 +02:00
|
|
|
use std::process::{Child, Command, Stdio};
|
|
|
|
|
|
|
|
struct GeckoDriver(Child);
|
|
|
|
|
|
|
|
impl GeckoDriver {
|
|
|
|
pub fn spawn() -> Result<Self> {
|
|
|
|
// This is taken from the webdriver-client crate.
|
|
|
|
let child = Command::new("geckodriver")
|
|
|
|
.arg("-b")
|
|
|
|
.arg("firefox")
|
|
|
|
.arg("--port")
|
|
|
|
.arg(format!("{}", GECKO_DRIVER_PORT))
|
|
|
|
.stdin(Stdio::null())
|
|
|
|
.stderr(Stdio::null())
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.spawn()?;
|
|
|
|
thread::sleep(Duration::new(1, 500));
|
|
|
|
|
|
|
|
Ok(GeckoDriver(child))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for GeckoDriver {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
let _ = self.0.kill();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 16:50:11 +02:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Status {
|
|
|
|
current_w: u32,
|
|
|
|
total_kwh: u32,
|
|
|
|
last_updated: u64,
|
|
|
|
}
|
2020-10-09 16:31:21 +02:00
|
|
|
|
2020-10-09 16:50:11 +02:00
|
|
|
fn login(driver: &WebDriver) -> Result<()> {
|
2020-10-09 16:31:21 +02:00
|
|
|
driver.get(URL)?;
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 16:31:21 +02:00
|
|
|
let input = driver.find_element(By::Id("username"))?;
|
2020-10-09 13:30:37 +02:00
|
|
|
input.send_keys(USERNAME)?;
|
2020-10-09 16:31:21 +02:00
|
|
|
let input = driver.find_element(By::Id("password"))?;
|
2020-10-09 13:30:37 +02:00
|
|
|
input.send_keys(PASSWORD)?;
|
2020-10-09 16:31:21 +02:00
|
|
|
let input = driver.find_element(By::Css("button[type=submit]"))?;
|
2020-10-09 13:30:37 +02:00
|
|
|
input.click()?;
|
|
|
|
|
2020-10-09 16:50:11 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn element_value(driver: &WebDriver, by: By) -> Result<u32> {
|
|
|
|
let element = driver.find_element(by)?;
|
|
|
|
let text = element.text()?;
|
|
|
|
let value = text.parse()?;
|
|
|
|
|
|
|
|
Ok(value)
|
|
|
|
}
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 17:07:18 +02:00
|
|
|
lazy_static! {
|
|
|
|
static ref STATUS: Mutex<Option<Status>> = Mutex::new(None);
|
|
|
|
}
|
|
|
|
|
2020-10-09 16:50:11 +02:00
|
|
|
fn main() -> Result<()> {
|
|
|
|
color_eyre::install()?;
|
|
|
|
|
|
|
|
let _gecko_driver = GeckoDriver::spawn()?;
|
|
|
|
let mut caps = DesiredCapabilities::firefox();
|
|
|
|
caps.set_headless()?;
|
|
|
|
let driver = WebDriver::new(&format!("http://localhost:{}", GECKO_DRIVER_PORT), &caps)?;
|
|
|
|
|
|
|
|
// Go to the My Autarco site and login
|
|
|
|
login(&driver)?;
|
|
|
|
|
|
|
|
loop {
|
2020-10-09 13:30:37 +02:00
|
|
|
// Retrieve the data from the elements
|
2020-10-09 16:50:11 +02:00
|
|
|
let last_updated = SystemTime::now()
|
2020-10-09 13:30:37 +02:00
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
|
|
|
.unwrap()
|
|
|
|
.as_secs();
|
2020-10-09 16:54:02 +02:00
|
|
|
let current_w = match element_value(&driver, By::Css("h2#pv-now b")) {
|
|
|
|
Ok(value) => value,
|
|
|
|
Err(error) => {
|
|
|
|
eprintln!("Failed to retrieve current power: {}", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let total_kwh = match element_value(&driver, By::Css("h2#pv-to-date b")) {
|
|
|
|
Ok(value) => value,
|
|
|
|
Err(error) => {
|
|
|
|
eprintln!("Failed to retrieve total energy production: {}", error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 17:07:18 +02:00
|
|
|
// Update the status
|
|
|
|
let mut status_guard = STATUS.lock().expect("Status mutex was poisoned");
|
2020-10-09 16:50:11 +02:00
|
|
|
let status = Status {
|
|
|
|
current_w,
|
|
|
|
total_kwh,
|
|
|
|
last_updated,
|
|
|
|
};
|
|
|
|
dbg!(&status);
|
2020-10-09 17:07:18 +02:00
|
|
|
status_guard.replace(status);
|
|
|
|
drop(status_guard);
|
2020-10-09 13:30:37 +02:00
|
|
|
|
2020-10-09 17:07:18 +02:00
|
|
|
// Wait the poll interval to check again!
|
|
|
|
thread::sleep(Duration::from_secs(POLL_INTERVAL));
|
2020-10-09 13:30:37 +02:00
|
|
|
}
|
|
|
|
}
|