gauge revamp... fingers crossed
All checks were successful
Build .deb on release / Build-Deb (push) Successful in 1m52s
All checks were successful
Build .deb on release / Build-Deb (push) Successful in 1m52s
This commit is contained in:
parent
9d9755515d
commit
65e86c2359
122
Cargo.lock
generated
122
Cargo.lock
generated
|
@ -17,18 +17,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.8.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"once_cell",
|
|
||||||
"version_check",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.6.10"
|
version = "0.6.10"
|
||||||
|
@ -119,12 +107,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arc-swap"
|
|
||||||
version = "1.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
@ -494,17 +476,6 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.18"
|
version = "0.8.18"
|
||||||
|
@ -878,15 +849,6 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
|
@ -1091,7 +1053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.3",
|
"hashbrown",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1359,45 +1321,6 @@ version = "2.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "metrics"
|
|
||||||
version = "0.22.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77b9e10a211c839210fd7f99954bda26e5f8e26ec686ad68da6a32df7c80e782"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"portable-atomic",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "metrics-prometheus"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b3e1316f9ef05b91f4d0e0a0da5b620ba919d336280b83b36be096b86c030fdd"
|
|
||||||
dependencies = [
|
|
||||||
"arc-swap",
|
|
||||||
"metrics",
|
|
||||||
"metrics-util",
|
|
||||||
"once_cell",
|
|
||||||
"prometheus",
|
|
||||||
"sealed",
|
|
||||||
"smallvec",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "metrics-util"
|
|
||||||
version = "0.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2670b8badcc285d486261e2e9f1615b506baff91427b61bd336a472b65bbf5ed"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"hashbrown 0.13.1",
|
|
||||||
"metrics",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miette"
|
name = "miette"
|
||||||
version = "5.10.0"
|
version = "5.10.0"
|
||||||
|
@ -1731,12 +1654,6 @@ version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "portable-atomic"
|
|
||||||
version = "1.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -2280,18 +2197,6 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sealed"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote 1.0.33",
|
|
||||||
"syn 2.0.43",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.9.2"
|
version = "2.9.2"
|
||||||
|
@ -2633,17 +2538,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tesla-charge-controller"
|
name = "tesla-charge-controller"
|
||||||
version = "1.0.31"
|
version = "1.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap 4.4.11",
|
"clap 4.4.11",
|
||||||
"env_logger 0.10.1",
|
"env_logger 0.10.1",
|
||||||
"if_chain",
|
"if_chain",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
|
"lazy_static 1.4.0",
|
||||||
"libmodbus-rs",
|
"libmodbus-rs",
|
||||||
"log 0.4.20",
|
"log 0.4.20",
|
||||||
"metrics",
|
|
||||||
"metrics-prometheus",
|
|
||||||
"notify-debouncer-mini",
|
"notify-debouncer-mini",
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"rocket",
|
"rocket",
|
||||||
|
@ -3463,26 +3367,6 @@ dependencies = [
|
||||||
"is-terminal",
|
"is-terminal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.7.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.7.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote 1.0.33",
|
|
||||||
"syn 2.0.43",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tesla-charge-controller"
|
name = "tesla-charge-controller"
|
||||||
version = "1.0.31"
|
version = "1.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MITNFA"
|
license = "MITNFA"
|
||||||
description = "Controls Tesla charge rate based on solar charge data"
|
description = "Controls Tesla charge rate based on solar charge data"
|
||||||
|
@ -23,8 +23,6 @@ thiserror = "1.0"
|
||||||
rocket = { version = "0.5", features = ["json"] }
|
rocket = { version = "0.5", features = ["json"] }
|
||||||
include_dir = "0.7"
|
include_dir = "0.7"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
metrics = "0.22"
|
|
||||||
metrics-prometheus = "0.6.0"
|
|
||||||
prometheus = "0.13"
|
prometheus = "0.13"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -32,3 +30,4 @@ serialport = "4.3"
|
||||||
libmodbus-rs = "0.8.3"
|
libmodbus-rs = "0.8.3"
|
||||||
if_chain = "1.0.2"
|
if_chain = "1.0.2"
|
||||||
notify-debouncer-mini = { version = "0.4.1", default-features = false }
|
notify-debouncer-mini = { version = "0.4.1", default-features = false }
|
||||||
|
lazy_static = "1.4"
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use metrics::{describe_gauge, gauge, Gauge, Label, Unit};
|
use lazy_static::lazy_static;
|
||||||
|
use prometheus::{
|
||||||
|
core::{AtomicI64, GenericGauge},
|
||||||
|
register_gauge, register_int_gauge, register_int_gauge_vec, Gauge, IntGauge, IntGaugeVec,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
@ -20,153 +24,82 @@ use crate::{
|
||||||
types::{CarState, FromDriveState},
|
types::{CarState, FromDriveState},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Metrics {
|
lazy_static! {
|
||||||
battery_level: Gauge,
|
pub static ref BATTERY_LEVEL: IntGauge =
|
||||||
charge_rate: Gauge,
|
register_int_gauge!("tesla_battery_level", "Battery level",).unwrap();
|
||||||
charge_request: Gauge,
|
pub static ref CHARGE_RATE: Gauge =
|
||||||
charge_enable_request: Gauge,
|
register_gauge!("tesla_charge_rate", "Charge rate",).unwrap();
|
||||||
charger_connected: Gauge,
|
pub static ref CHARGE_REQUEST: IntGauge =
|
||||||
inside_temp: Gauge,
|
register_int_gauge!("tesla_charge_request", "Requested charge rate",).unwrap();
|
||||||
outside_temp: Gauge,
|
pub static ref CHARGE_ENABLE_REQUEST: IntGauge =
|
||||||
battery_heater: Gauge,
|
register_int_gauge!("tesla_charge_enable_request", "Charge enable request",).unwrap();
|
||||||
climate_on: Gauge,
|
pub static ref CHARGER_CONNECTED: IntGauge =
|
||||||
preconditioning: Gauge,
|
register_int_gauge!("tesla_charger_connected", "Charger connected",).unwrap();
|
||||||
remote_heater_control_enabled: Gauge,
|
pub static ref INSIDE_TEMP: Gauge =
|
||||||
is_auto_conditioning_on: Gauge,
|
register_gauge!("tesla_inside_temp", "Inside temperature",).unwrap();
|
||||||
driver_temp_setting: Gauge,
|
pub static ref OUTSIDE_TEMP: Gauge =
|
||||||
passenger_temp_setting: Gauge,
|
register_gauge!("tesla_outside_temp", "Outside temperature",).unwrap();
|
||||||
tesla_online: Gauge,
|
pub static ref BATTERY_HEATER: IntGauge =
|
||||||
charging_state: ChargingStateGauges,
|
register_int_gauge!("tesla_battery_heater", "Battery heater",).unwrap();
|
||||||
cabin_overheat_protection: CabinOverheatProtectionGauges,
|
pub static ref CLIMATE_ON: IntGauge =
|
||||||
hvac_auto: HvacAutoRequestGauges,
|
register_int_gauge!("tesla_climate_on", "Climate control",).unwrap();
|
||||||
home: Gauge,
|
pub static ref PRECONDITIONING: IntGauge =
|
||||||
sentry_mode: Gauge,
|
register_int_gauge!("tesla_preconditioning", "Preconditioning",).unwrap();
|
||||||
sentry_mode_available: Gauge,
|
pub static ref REMOTE_HEATER_CONTROL_ENABLED: IntGauge = register_int_gauge!(
|
||||||
charger_actual_current: Gauge,
|
|
||||||
charger_phases: Gauge,
|
|
||||||
charger_pilot_current: Gauge,
|
|
||||||
charger_power: Gauge,
|
|
||||||
charger_voltage: Gauge,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Metrics {
|
|
||||||
fn new() -> Self {
|
|
||||||
describe_gauge!("tesla_battery_level", Unit::Percent, "Battery level");
|
|
||||||
let battery_level = gauge!("tesla_battery_level");
|
|
||||||
describe_gauge!("tesla_charge_rate", "Charge rate");
|
|
||||||
let charge_rate = gauge!("tesla_charge_rate");
|
|
||||||
describe_gauge!("tesla_charge_request", "Requested charge rate");
|
|
||||||
let charge_request = gauge!("tesla_charge_request");
|
|
||||||
describe_gauge!("tesla_charge_enable_request", "Charge enable request");
|
|
||||||
let charge_enable_request = gauge!("tesla_charge_enable_request");
|
|
||||||
describe_gauge!("tesla_charger_connected", "Charger connected");
|
|
||||||
let charger_connected = gauge!("tesla_charger_connected");
|
|
||||||
describe_gauge!("tesla_inside_temp", "Inside temperature");
|
|
||||||
let inside_temp = gauge!("tesla_inside_temp");
|
|
||||||
describe_gauge!("tesla_outside_temp", "Outside temperature");
|
|
||||||
let outside_temp = gauge!("tesla_outside_temp");
|
|
||||||
describe_gauge!("tesla_battery_heater", "Battery heater");
|
|
||||||
let battery_heater = gauge!("tesla_battery_heater");
|
|
||||||
describe_gauge!("tesla_climate_on", "Climate control");
|
|
||||||
let climate_on = gauge!("tesla_climate_on");
|
|
||||||
describe_gauge!("tesla_preconditioning", "Preconditioning");
|
|
||||||
let preconditioning = gauge!("tesla_preconditioning");
|
|
||||||
describe_gauge!(
|
|
||||||
"tesla_remote_heater_control_enabled",
|
"tesla_remote_heater_control_enabled",
|
||||||
"Remote heater control enabled"
|
"Remote heater control enabled",
|
||||||
);
|
)
|
||||||
let remote_heater_control_enabled = gauge!("tesla_remote_heater_control_enabled");
|
.unwrap();
|
||||||
describe_gauge!("tesla_is_auto_conditioning_on", "Auto conditioning on");
|
pub static ref IS_AUTO_CONDITIONING_ON: IntGauge =
|
||||||
let is_auto_conditioning_on = gauge!("tesla_is_auto_conditioning_on");
|
register_int_gauge!("tesla_is_auto_conditioning_on", "Auto conditioning on",).unwrap();
|
||||||
describe_gauge!("tesla_driver_temp_setting", "Driver temp");
|
pub static ref DRIVER_TEMP_SETTING: Gauge =
|
||||||
let driver_temp_setting = gauge!("tesla_driver_temp_setting");
|
register_gauge!("tesla_driver_temp_setting", "Driver temp",).unwrap();
|
||||||
describe_gauge!("tesla_passenger_temp_setting", "Passenger temp");
|
pub static ref PASSENGER_TEMP_SETTING: Gauge =
|
||||||
let passenger_temp_setting = gauge!("tesla_passenger_temp_setting");
|
register_gauge!("tesla_passenger_temp_setting", "Passenger temp",).unwrap();
|
||||||
describe_gauge!("tesla_online", "Tesla online");
|
pub static ref TESLA_ONLINE: IntGauge =
|
||||||
let tesla_online = gauge!("tesla_online");
|
register_int_gauge!("tesla_online", "Tesla online",).unwrap();
|
||||||
describe_gauge!("tesla_charging_state", "Tesla charging state");
|
pub static ref HOME: IntGauge = register_int_gauge!("tesla_home", "Is home",).unwrap();
|
||||||
let charging_state = ChargingStateGauges::new();
|
pub static ref SENTRY_MODE: IntGauge =
|
||||||
describe_gauge!(
|
register_int_gauge!("tesla_sentry_mode", "Sentry mode",).unwrap();
|
||||||
|
pub static ref SENTRY_MODE_AVAILABLE: IntGauge =
|
||||||
|
register_int_gauge!("tesla_sentry_mode_available", "Sentry mode available",).unwrap();
|
||||||
|
pub static ref CHARGER_ACTUAL_CURRENT: IntGauge =
|
||||||
|
register_int_gauge!("tesla_charger_actual_current", "Charger actual current",).unwrap();
|
||||||
|
pub static ref CHARGER_PHASES: IntGauge =
|
||||||
|
register_int_gauge!("tesla_charger_phases", "Charger phases",).unwrap();
|
||||||
|
pub static ref CHARGER_PILOT_CURRENT: IntGauge =
|
||||||
|
register_int_gauge!("tesla_charger_pilot_current", "Charger pilot current",).unwrap();
|
||||||
|
pub static ref CHARGER_POWER: IntGauge =
|
||||||
|
register_int_gauge!("tesla_charger_power", "Charger power",).unwrap();
|
||||||
|
pub static ref CHARGER_VOLTAGE: IntGauge =
|
||||||
|
register_int_gauge!("tesla_charger_voltage", "Charger voltage",).unwrap();
|
||||||
|
pub static ref CHARGING_STATE: IntGaugeVec =
|
||||||
|
register_int_gauge_vec!("tesla_charging_state", "Tesla charging state", &["state"])
|
||||||
|
.unwrap();
|
||||||
|
pub static ref CABIN_OVERHEAT_PROTECTION: IntGaugeVec = register_int_gauge_vec!(
|
||||||
"tesla_cabin_overheat_protection_state",
|
"tesla_cabin_overheat_protection_state",
|
||||||
"Cabin overheat protection state"
|
"Cabin overheat protection state",
|
||||||
);
|
&["state"]
|
||||||
let cabin_overheat_protection = CabinOverheatProtectionGauges::new();
|
)
|
||||||
describe_gauge!("tesla_hvac_auto_request", "HVAC auto");
|
.unwrap();
|
||||||
let hvac_auto = HvacAutoRequestGauges::new();
|
pub static ref HVAC_AUTO: IntGaugeVec =
|
||||||
describe_gauge!("tesla_home", "Is home");
|
register_int_gauge_vec!("tesla_hvac_auto_request", "HVAC auto", &["state"]).unwrap();
|
||||||
let home = gauge!("tesla_home");
|
|
||||||
describe_gauge!("tesla_sentry_mode", "Sentry mode");
|
|
||||||
let sentry_mode = gauge!("tesla_sentry_mode");
|
|
||||||
describe_gauge!("tesla_sentry_mode_available", "Sentry mode available");
|
|
||||||
let sentry_mode_available = gauge!("tesla_sentry_mode_available");
|
|
||||||
|
|
||||||
describe_gauge!("tesla_charger_actual_current", "Charger actual current");
|
|
||||||
let charger_actual_current = gauge!("tesla_charger_actual_current");
|
|
||||||
describe_gauge!("tesla_charger_phases", "Charger phases");
|
|
||||||
let charger_phases = gauge!("tesla_charger_phases");
|
|
||||||
describe_gauge!("tesla_charger_pilot_current", "Charger pilot current");
|
|
||||||
let charger_pilot_current = gauge!("tesla_charger_pilot_current");
|
|
||||||
describe_gauge!("tesla_charger_power", "Charger power");
|
|
||||||
let charger_power = gauge!("tesla_charger_power");
|
|
||||||
describe_gauge!("tesla_charger_voltage", "Charger voltage");
|
|
||||||
let charger_voltage = gauge!("tesla_charger_voltage");
|
|
||||||
|
|
||||||
Self {
|
|
||||||
battery_level,
|
|
||||||
charge_rate,
|
|
||||||
charge_request,
|
|
||||||
charge_enable_request,
|
|
||||||
charger_connected,
|
|
||||||
inside_temp,
|
|
||||||
outside_temp,
|
|
||||||
battery_heater,
|
|
||||||
climate_on,
|
|
||||||
preconditioning,
|
|
||||||
remote_heater_control_enabled,
|
|
||||||
is_auto_conditioning_on,
|
|
||||||
driver_temp_setting,
|
|
||||||
passenger_temp_setting,
|
|
||||||
tesla_online,
|
|
||||||
charging_state,
|
|
||||||
cabin_overheat_protection,
|
|
||||||
hvac_auto,
|
|
||||||
home,
|
|
||||||
sentry_mode,
|
|
||||||
sentry_mode_available,
|
|
||||||
charger_actual_current,
|
|
||||||
charger_phases,
|
|
||||||
charger_pilot_current,
|
|
||||||
charger_power,
|
|
||||||
charger_voltage,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChargingStateGauges {
|
struct ChargingStateGauges {
|
||||||
charging: Gauge,
|
charging: GenericGauge<AtomicI64>,
|
||||||
stopped: Gauge,
|
stopped: GenericGauge<AtomicI64>,
|
||||||
disconnected: Gauge,
|
disconnected: GenericGauge<AtomicI64>,
|
||||||
other: Gauge,
|
other: GenericGauge<AtomicI64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChargingStateGauges {
|
impl ChargingStateGauges {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let charging = gauge!(
|
let charging = CHARGING_STATE.with_label_values(&["charging"]);
|
||||||
"tesla_charging_state",
|
let stopped = CHARGING_STATE.with_label_values(&["stopped"]);
|
||||||
vec![Label::new("state", String::from("charging"))]
|
let disconnected = CHARGING_STATE.with_label_values(&["disconnected"]);
|
||||||
);
|
let other = CHARGING_STATE.with_label_values(&["other"]);
|
||||||
let stopped = gauge!(
|
|
||||||
"tesla_charging_state",
|
|
||||||
vec![Label::new("state", String::from("stopped"))]
|
|
||||||
);
|
|
||||||
let disconnected = gauge!(
|
|
||||||
"tesla_charging_state",
|
|
||||||
vec![Label::new("state", String::from("disconnected"))]
|
|
||||||
);
|
|
||||||
let other = gauge!(
|
|
||||||
"tesla_charging_state",
|
|
||||||
vec![Label::new("state", String::from("other"))]
|
|
||||||
);
|
|
||||||
Self {
|
Self {
|
||||||
charging,
|
charging,
|
||||||
stopped,
|
stopped,
|
||||||
|
@ -178,58 +111,47 @@ impl ChargingStateGauges {
|
||||||
fn set(&mut self, state: ChargingState) {
|
fn set(&mut self, state: ChargingState) {
|
||||||
match state {
|
match state {
|
||||||
ChargingState::Charging => {
|
ChargingState::Charging => {
|
||||||
self.charging.set(1.);
|
self.charging.set(1);
|
||||||
self.stopped.set(0.);
|
self.stopped.set(0);
|
||||||
self.disconnected.set(0.);
|
self.disconnected.set(0);
|
||||||
self.other.set(0.);
|
self.other.set(0);
|
||||||
}
|
}
|
||||||
ChargingState::Stopped => {
|
ChargingState::Stopped => {
|
||||||
self.charging.set(0.);
|
self.charging.set(0);
|
||||||
self.stopped.set(1.);
|
self.stopped.set(1);
|
||||||
self.disconnected.set(0.);
|
self.disconnected.set(0);
|
||||||
self.other.set(0.);
|
self.other.set(0);
|
||||||
}
|
}
|
||||||
ChargingState::Disconnected => {
|
ChargingState::Disconnected => {
|
||||||
self.charging.set(0.);
|
self.charging.set(0);
|
||||||
self.stopped.set(0.);
|
self.stopped.set(0);
|
||||||
self.disconnected.set(1.);
|
self.disconnected.set(1);
|
||||||
self.other.set(0.);
|
self.other.set(0);
|
||||||
}
|
}
|
||||||
ChargingState::Other => {
|
ChargingState::Other => {
|
||||||
self.charging.set(0.);
|
self.charging.set(0);
|
||||||
self.stopped.set(0.);
|
self.stopped.set(0);
|
||||||
self.disconnected.set(0.);
|
self.disconnected.set(0);
|
||||||
self.other.set(1.);
|
self.other.set(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CabinOverheatProtectionGauges {
|
struct CabinOverheatProtectionGauges {
|
||||||
off: Gauge,
|
off: GenericGauge<AtomicI64>,
|
||||||
on: Gauge,
|
on: GenericGauge<AtomicI64>,
|
||||||
fan_only: Gauge,
|
fan_only: GenericGauge<AtomicI64>,
|
||||||
unknown: Gauge,
|
unknown: GenericGauge<AtomicI64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CabinOverheatProtectionGauges {
|
impl CabinOverheatProtectionGauges {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let off = gauge!(
|
let off = CABIN_OVERHEAT_PROTECTION.with_label_values(&["off"]);
|
||||||
"tesla_cabin_overheat_protection_state",
|
let on = CABIN_OVERHEAT_PROTECTION.with_label_values(&["on"]);
|
||||||
vec![Label::new("state", String::from("off"))]
|
let fan_only = CABIN_OVERHEAT_PROTECTION.with_label_values(&["fan_only"]);
|
||||||
);
|
let unknown = CABIN_OVERHEAT_PROTECTION.with_label_values(&["unknown"]);
|
||||||
let on = gauge!(
|
|
||||||
"tesla_cabin_overheat_protection_state",
|
|
||||||
vec![Label::new("state", String::from("on"))]
|
|
||||||
);
|
|
||||||
let fan_only = gauge!(
|
|
||||||
"tesla_cabin_overheat_protection_state",
|
|
||||||
vec![Label::new("state", String::from("fan_only"))]
|
|
||||||
);
|
|
||||||
let unknown = gauge!(
|
|
||||||
"tesla_cabin_overheat_protection_state",
|
|
||||||
vec![Label::new("state", String::from("unknown"))]
|
|
||||||
);
|
|
||||||
Self {
|
Self {
|
||||||
off,
|
off,
|
||||||
on,
|
on,
|
||||||
|
@ -241,53 +163,45 @@ impl CabinOverheatProtectionGauges {
|
||||||
fn set(&mut self, state: CabinOverheatProtection) {
|
fn set(&mut self, state: CabinOverheatProtection) {
|
||||||
match state {
|
match state {
|
||||||
CabinOverheatProtection::Off => {
|
CabinOverheatProtection::Off => {
|
||||||
self.off.set(1.);
|
self.off.set(1);
|
||||||
self.on.set(0.);
|
self.on.set(0);
|
||||||
self.fan_only.set(0.);
|
self.fan_only.set(0);
|
||||||
self.unknown.set(0.);
|
self.unknown.set(0);
|
||||||
}
|
}
|
||||||
CabinOverheatProtection::On => {
|
CabinOverheatProtection::On => {
|
||||||
self.off.set(0.);
|
self.off.set(0);
|
||||||
self.on.set(1.);
|
self.on.set(1);
|
||||||
self.fan_only.set(0.);
|
self.fan_only.set(0);
|
||||||
self.unknown.set(0.);
|
self.unknown.set(0);
|
||||||
}
|
}
|
||||||
CabinOverheatProtection::FanOnly => {
|
CabinOverheatProtection::FanOnly => {
|
||||||
self.off.set(0.);
|
self.off.set(0);
|
||||||
self.on.set(0.);
|
self.on.set(0);
|
||||||
self.fan_only.set(1.);
|
self.fan_only.set(1);
|
||||||
self.unknown.set(0.);
|
self.unknown.set(0);
|
||||||
}
|
}
|
||||||
CabinOverheatProtection::Unknown => {
|
CabinOverheatProtection::Unknown => {
|
||||||
self.off.set(0.);
|
self.off.set(0);
|
||||||
self.on.set(0.);
|
self.on.set(0);
|
||||||
self.fan_only.set(0.);
|
self.fan_only.set(0);
|
||||||
self.unknown.set(1.);
|
self.unknown.set(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HvacAutoRequestGauges {
|
struct HvacAutoRequestGauges {
|
||||||
override_g: Gauge,
|
override_g: GenericGauge<AtomicI64>,
|
||||||
on: Gauge,
|
on: GenericGauge<AtomicI64>,
|
||||||
unknown: Gauge,
|
unknown: GenericGauge<AtomicI64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HvacAutoRequestGauges {
|
impl HvacAutoRequestGauges {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let override_g = gauge!(
|
let override_g = HVAC_AUTO.with_label_values(&["override"]);
|
||||||
"tesla_hvac_auto_request",
|
let on = HVAC_AUTO.with_label_values(&["on"]);
|
||||||
vec![Label::new("state", String::from("override"))]
|
let unknown = HVAC_AUTO.with_label_values(&["unknown"]);
|
||||||
);
|
|
||||||
let on = gauge!(
|
|
||||||
"tesla_hvac_auto_request",
|
|
||||||
vec![Label::new("state", String::from("on"))]
|
|
||||||
);
|
|
||||||
let unknown = gauge!(
|
|
||||||
"tesla_hvac_auto_request",
|
|
||||||
vec![Label::new("state", String::from("unknown"))]
|
|
||||||
);
|
|
||||||
Self {
|
Self {
|
||||||
override_g,
|
override_g,
|
||||||
on,
|
on,
|
||||||
|
@ -298,19 +212,19 @@ impl HvacAutoRequestGauges {
|
||||||
fn set(&mut self, state: HvacAutoRequest) {
|
fn set(&mut self, state: HvacAutoRequest) {
|
||||||
match state {
|
match state {
|
||||||
HvacAutoRequest::Override => {
|
HvacAutoRequest::Override => {
|
||||||
self.override_g.set(1.);
|
self.override_g.set(1);
|
||||||
self.on.set(0.);
|
self.on.set(0);
|
||||||
self.unknown.set(0.);
|
self.unknown.set(0);
|
||||||
}
|
}
|
||||||
HvacAutoRequest::On => {
|
HvacAutoRequest::On => {
|
||||||
self.override_g.set(0.);
|
self.override_g.set(0);
|
||||||
self.on.set(1.);
|
self.on.set(1);
|
||||||
self.unknown.set(0.);
|
self.unknown.set(0);
|
||||||
}
|
}
|
||||||
HvacAutoRequest::Unknown => {
|
HvacAutoRequest::Unknown => {
|
||||||
self.override_g.set(0.);
|
self.override_g.set(0);
|
||||||
self.on.set(0.);
|
self.on.set(0);
|
||||||
self.unknown.set(1.);
|
self.unknown.set(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,8 +236,10 @@ pub struct TeslaInterface {
|
||||||
vehicle: Box<teslatte::vehicles::VehicleData>,
|
vehicle: Box<teslatte::vehicles::VehicleData>,
|
||||||
last_refresh: Instant,
|
last_refresh: Instant,
|
||||||
auth_path: PathBuf,
|
auth_path: PathBuf,
|
||||||
metrics: Metrics,
|
|
||||||
monitored_values: MonitoredValues,
|
monitored_values: MonitoredValues,
|
||||||
|
charging_state: ChargingStateGauges,
|
||||||
|
cabin_overheat_protection: CabinOverheatProtectionGauges,
|
||||||
|
hvac_auto: HvacAutoRequestGauges,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -366,16 +282,16 @@ impl TeslaInterface {
|
||||||
.next()
|
.next()
|
||||||
.ok_or(AuthLoadError::NoVehicles)?;
|
.ok_or(AuthLoadError::NoVehicles)?;
|
||||||
|
|
||||||
let metrics = Metrics::new();
|
|
||||||
|
|
||||||
let interface = Self {
|
let interface = Self {
|
||||||
state: Arc::new(RwLock::new(Default::default())),
|
state: Arc::new(RwLock::new(Default::default())),
|
||||||
api,
|
api,
|
||||||
last_refresh,
|
last_refresh,
|
||||||
auth_path,
|
auth_path,
|
||||||
vehicle,
|
vehicle,
|
||||||
metrics,
|
|
||||||
monitored_values: Default::default(),
|
monitored_values: Default::default(),
|
||||||
|
charging_state: ChargingStateGauges::new(),
|
||||||
|
cabin_overheat_protection: CabinOverheatProtectionGauges::new(),
|
||||||
|
hvac_auto: HvacAutoRequestGauges::new(),
|
||||||
};
|
};
|
||||||
interface.save_key()?;
|
interface.save_key()?;
|
||||||
|
|
||||||
|
@ -423,97 +339,65 @@ impl TeslaInterface {
|
||||||
async fn refresh_state(&mut self) {
|
async fn refresh_state(&mut self) {
|
||||||
match self.get_state().await {
|
match self.get_state().await {
|
||||||
Ok(new_state) => {
|
Ok(new_state) => {
|
||||||
self.metrics.tesla_online.set(1.);
|
TESLA_ONLINE.set(1);
|
||||||
let mut state = self
|
let mut state = self
|
||||||
.state
|
.state
|
||||||
.write()
|
.write()
|
||||||
.expect("Tesla API state handler panicked!!");
|
.expect("Tesla API state handler panicked!!");
|
||||||
|
|
||||||
if let Some(new_charge_state) = new_state.charge_state {
|
if let Some(new_charge_state) = new_state.charge_state {
|
||||||
self.metrics
|
BATTERY_LEVEL.set(new_charge_state.battery_level);
|
||||||
.battery_level
|
CHARGE_RATE.set(new_charge_state.charge_rate);
|
||||||
.set(new_charge_state.battery_level as f64);
|
CHARGE_REQUEST.set(new_charge_state.charge_current_request);
|
||||||
self.metrics.charge_rate.set(new_charge_state.charge_rate);
|
CHARGE_ENABLE_REQUEST.set(bi(new_charge_state.charge_enable_request));
|
||||||
self.metrics
|
CHARGER_CONNECTED.set(bi(new_charge_state.charger_connected));
|
||||||
.charge_request
|
self.charging_state.set(new_charge_state.charging_state);
|
||||||
.set(new_charge_state.charge_current_request as f64);
|
|
||||||
self.metrics
|
|
||||||
.charge_enable_request
|
|
||||||
.set(bf(new_charge_state.charge_enable_request));
|
|
||||||
self.metrics
|
|
||||||
.charger_connected
|
|
||||||
.set(bf(new_charge_state.charger_connected));
|
|
||||||
self.metrics
|
|
||||||
.charging_state
|
|
||||||
.set(new_charge_state.charging_state);
|
|
||||||
if let Some(v) = new_charge_state.charger_actual_current {
|
if let Some(v) = new_charge_state.charger_actual_current {
|
||||||
self.metrics.charger_actual_current.set(v as f64);
|
CHARGER_ACTUAL_CURRENT.set(v);
|
||||||
}
|
}
|
||||||
if let Some(v) = new_charge_state.charger_phases {
|
if let Some(v) = new_charge_state.charger_phases {
|
||||||
self.metrics.charger_phases.set(v as f64);
|
CHARGER_PHASES.set(v);
|
||||||
}
|
}
|
||||||
if let Some(v) = new_charge_state.charger_pilot_current {
|
if let Some(v) = new_charge_state.charger_pilot_current {
|
||||||
self.metrics.charger_pilot_current.set(v as f64);
|
CHARGER_PILOT_CURRENT.set(v);
|
||||||
}
|
}
|
||||||
if let Some(v) = new_charge_state.charger_power {
|
if let Some(v) = new_charge_state.charger_power {
|
||||||
self.metrics.charger_power.set(v as f64);
|
CHARGER_POWER.set(v);
|
||||||
}
|
}
|
||||||
if let Some(v) = new_charge_state.charger_voltage {
|
if let Some(v) = new_charge_state.charger_voltage {
|
||||||
self.metrics.charger_voltage.set(v as f64);
|
CHARGER_VOLTAGE.set(v);
|
||||||
}
|
}
|
||||||
state.charge_state = Some(new_charge_state);
|
state.charge_state = Some(new_charge_state);
|
||||||
}
|
}
|
||||||
if let Some(new_location_data) = new_state.location_data {
|
if let Some(new_location_data) = new_state.location_data {
|
||||||
self.metrics.home.set(bf(new_location_data.home));
|
HOME.set(bi(new_location_data.home));
|
||||||
state.location_data = Some(new_location_data);
|
state.location_data = Some(new_location_data);
|
||||||
}
|
}
|
||||||
if let Some(new_climate_state) = new_state.climate_state {
|
if let Some(new_climate_state) = new_state.climate_state {
|
||||||
self.metrics.inside_temp.set(new_climate_state.inside_temp);
|
INSIDE_TEMP.set(new_climate_state.inside_temp);
|
||||||
self.metrics
|
OUTSIDE_TEMP.set(new_climate_state.outside_temp);
|
||||||
.outside_temp
|
BATTERY_HEATER.set(bi(new_climate_state.battery_heater));
|
||||||
.set(new_climate_state.outside_temp);
|
CLIMATE_ON.set(bi(new_climate_state.climate_on));
|
||||||
self.metrics
|
PRECONDITIONING.set(bi(new_climate_state.preconditioning));
|
||||||
.battery_heater
|
REMOTE_HEATER_CONTROL_ENABLED
|
||||||
.set(bf(new_climate_state.battery_heater));
|
.set(bi(new_climate_state.remote_heater_control_enabled));
|
||||||
self.metrics
|
IS_AUTO_CONDITIONING_ON.set(bi(new_climate_state.is_auto_conditioning_on));
|
||||||
.climate_on
|
DRIVER_TEMP_SETTING.set(new_climate_state.driver_temp_setting);
|
||||||
.set(bf(new_climate_state.climate_on));
|
PASSENGER_TEMP_SETTING.set(new_climate_state.passenger_temp_setting);
|
||||||
self.metrics
|
self.cabin_overheat_protection
|
||||||
.preconditioning
|
|
||||||
.set(bf(new_climate_state.preconditioning));
|
|
||||||
self.metrics
|
|
||||||
.remote_heater_control_enabled
|
|
||||||
.set(bf(new_climate_state.remote_heater_control_enabled));
|
|
||||||
self.metrics
|
|
||||||
.is_auto_conditioning_on
|
|
||||||
.set(bf(new_climate_state.is_auto_conditioning_on));
|
|
||||||
self.metrics
|
|
||||||
.driver_temp_setting
|
|
||||||
.set(new_climate_state.driver_temp_setting);
|
|
||||||
self.metrics
|
|
||||||
.passenger_temp_setting
|
|
||||||
.set(new_climate_state.passenger_temp_setting);
|
|
||||||
self.metrics
|
|
||||||
.cabin_overheat_protection
|
|
||||||
.set(new_climate_state.cabin_overheat_protection);
|
.set(new_climate_state.cabin_overheat_protection);
|
||||||
self.metrics
|
self.hvac_auto.set(new_climate_state.hvac_auto_request);
|
||||||
.hvac_auto
|
|
||||||
.set(new_climate_state.hvac_auto_request);
|
|
||||||
|
|
||||||
state.climate_state = Some(new_climate_state);
|
state.climate_state = Some(new_climate_state);
|
||||||
}
|
}
|
||||||
if let Some(new_vehicle_state) = new_state.vehicle_state {
|
if let Some(new_vehicle_state) = new_state.vehicle_state {
|
||||||
self.metrics
|
SENTRY_MODE.set(obi(new_vehicle_state.sentry_mode));
|
||||||
.sentry_mode
|
SENTRY_MODE_AVAILABLE.set(obi(new_vehicle_state.sentry_mode_available));
|
||||||
.set(obf(new_vehicle_state.sentry_mode));
|
|
||||||
self.metrics
|
|
||||||
.sentry_mode_available
|
|
||||||
.set(obf(new_vehicle_state.sentry_mode_available));
|
|
||||||
state.vehicle_state = Some(new_vehicle_state);
|
state.vehicle_state = Some(new_vehicle_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.metrics.tesla_online.set(0.);
|
TESLA_ONLINE.set(0);
|
||||||
match e {
|
match e {
|
||||||
teslatte::error::TeslatteError::DecodeJsonError {
|
teslatte::error::TeslatteError::DecodeJsonError {
|
||||||
source,
|
source,
|
||||||
|
@ -616,14 +500,14 @@ impl TeslaInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bf(value: bool) -> f64 {
|
fn bi(value: bool) -> i64 {
|
||||||
if value {
|
if value {
|
||||||
1.0
|
1
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obf(value: Option<bool>) -> f64 {
|
fn obi(value: Option<bool>) -> i64 {
|
||||||
value.map_or(-1., bf)
|
value.map_or(-1, bi)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
pub const CHARGE_CONTROLLER_LABEL: &str = "charge_controller";
|
|
||||||
pub const PL_LABEL: &str = "pl_device";
|
|
||||||
pub const TRISTAR_LABEL: &str = "tristar_device";
|
|
||||||
|
|
||||||
pub const BATTERY_VOLTAGE: &str = "battery_voltage";
|
|
||||||
pub const TARGET_VOLTAGE: &str = "target_voltage";
|
|
||||||
pub const INPUT_CURRENT: &str = "input_current";
|
|
||||||
pub const CHARGE_STATE: &str = "charge_state";
|
|
||||||
pub const BATTERY_TEMP: &str = "battery_temp";
|
|
||||||
|
|
||||||
pub const PL_DUTY_CYCLE: &str = "pl_duty_cycle";
|
|
||||||
pub const PL_LOAD_CURRENT: &str = "pl_internal_load_current";
|
|
||||||
|
|
||||||
pub const TRISTAR_INPUT_VOLTAGE: &str = "tristar_input_voltage";
|
|
||||||
pub const TRISTAR_CHARGE_CURRENT: &str = "tristar_charge_current";
|
|
||||||
pub const TRISTAR_POWER_OUT: &str = "tristar_power_out";
|
|
||||||
pub const TRISTAR_POWER_IN: &str = "tristar_power_in";
|
|
||||||
pub const TRISTAR_MAX_ARRAY_POWER: &str = "tristar_max_array_power";
|
|
||||||
pub const TRISTAR_MAX_ARRAY_VOLTAGE: &str = "tristar_max_array_voltage";
|
|
||||||
pub const TRISTAR_OPEN_CIRCUIT_VOLTAGE: &str = "tristar_open_circuit_voltage";
|
|
70
src/charge_controllers/gauges.rs
Normal file
70
src/charge_controllers/gauges.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use super::{CHARGE_CONTROLLER_LABEL, PL_LABEL, TRISTAR_LABEL};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use prometheus::{register_gauge_vec, register_int_gauge_vec, GaugeVec, IntGaugeVec};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref BATTERY_VOLTAGE: GaugeVec = register_gauge_vec!(
|
||||||
|
"battery_voltage",
|
||||||
|
"Battery voltage",
|
||||||
|
&[CHARGE_CONTROLLER_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref TARGET_VOLTAGE: GaugeVec = register_gauge_vec!(
|
||||||
|
"target_voltage",
|
||||||
|
"Target voltage",
|
||||||
|
&[CHARGE_CONTROLLER_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref INPUT_CURRENT: GaugeVec = register_gauge_vec!(
|
||||||
|
"input_current",
|
||||||
|
"Internal charge current",
|
||||||
|
&[CHARGE_CONTROLLER_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref CHARGE_STATE: IntGaugeVec = register_int_gauge_vec!(
|
||||||
|
"charge_state",
|
||||||
|
"Regulator state",
|
||||||
|
&[CHARGE_CONTROLLER_LABEL, "state"]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref BATTERY_TEMP: GaugeVec = register_gauge_vec!(
|
||||||
|
"battery_temp",
|
||||||
|
"Battery temperature",
|
||||||
|
&[CHARGE_CONTROLLER_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref PL_DUTY_CYCLE: GaugeVec =
|
||||||
|
register_gauge_vec!("pl_duty_cycle", "Duty cycle", &[PL_LABEL]).unwrap();
|
||||||
|
pub static ref PL_LOAD_CURRENT: GaugeVec = register_gauge_vec!(
|
||||||
|
"pl_internal_load_current",
|
||||||
|
"Internal load current",
|
||||||
|
&[PL_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref TRISTAR_INPUT_VOLTAGE: GaugeVec =
|
||||||
|
register_gauge_vec!("tristar_input_voltage", "Input voltage", &[TRISTAR_LABEL]).unwrap();
|
||||||
|
pub static ref TRISTAR_CHARGE_CURRENT: GaugeVec =
|
||||||
|
register_gauge_vec!("tristar_charge_current", "Charge current", &[TRISTAR_LABEL]).unwrap();
|
||||||
|
pub static ref TRISTAR_POWER_OUT: GaugeVec =
|
||||||
|
register_gauge_vec!("tristar_power_out", "Power out", &[TRISTAR_LABEL]).unwrap();
|
||||||
|
pub static ref TRISTAR_POWER_IN: GaugeVec =
|
||||||
|
register_gauge_vec!("tristar_power_in", "Power in", &[TRISTAR_LABEL]).unwrap();
|
||||||
|
pub static ref TRISTAR_MAX_ARRAY_POWER: GaugeVec = register_gauge_vec!(
|
||||||
|
"tristar_max_array_power",
|
||||||
|
"Maximum array power",
|
||||||
|
&[TRISTAR_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref TRISTAR_MAX_ARRAY_VOLTAGE: GaugeVec = register_gauge_vec!(
|
||||||
|
"tristar_max_array_voltage",
|
||||||
|
"Maximum array voltage",
|
||||||
|
&[TRISTAR_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref TRISTAR_OPEN_CIRCUIT_VOLTAGE: GaugeVec = register_gauge_vec!(
|
||||||
|
"tristar_open_circuit_voltage",
|
||||||
|
"Open circuit voltage",
|
||||||
|
&[TRISTAR_LABEL]
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
|
@ -1,54 +1,7 @@
|
||||||
use std::sync::OnceLock;
|
pub mod gauges;
|
||||||
|
|
||||||
use metrics::{describe_gauge, Unit};
|
|
||||||
|
|
||||||
mod gauge_names;
|
|
||||||
pub mod pl;
|
pub mod pl;
|
||||||
pub mod tristar;
|
pub mod tristar;
|
||||||
|
|
||||||
static HAS_REGISTERED_SHARED: OnceLock<()> = OnceLock::new();
|
pub const CHARGE_CONTROLLER_LABEL: &str = "charge_controller";
|
||||||
static HAS_REGISTERED_PL: OnceLock<()> = OnceLock::new();
|
pub const PL_LABEL: &str = "pl_device";
|
||||||
static HAS_REGISTERED_TRISTAR: OnceLock<()> = OnceLock::new();
|
pub const TRISTAR_LABEL: &str = "tristar_device";
|
||||||
|
|
||||||
fn register_metrics() {
|
|
||||||
if HAS_REGISTERED_SHARED.get().is_none() {
|
|
||||||
describe_gauge!(gauge_names::BATTERY_VOLTAGE, "Battery voltage");
|
|
||||||
describe_gauge!(gauge_names::TARGET_VOLTAGE, "Target voltage");
|
|
||||||
describe_gauge!(gauge_names::INPUT_CURRENT, "Internal charge current");
|
|
||||||
describe_gauge!(gauge_names::CHARGE_STATE, "Regulator state");
|
|
||||||
describe_gauge!(gauge_names::BATTERY_TEMP, "Battery temperature");
|
|
||||||
|
|
||||||
HAS_REGISTERED_SHARED.get_or_init(|| ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_pl_metrics() {
|
|
||||||
register_metrics();
|
|
||||||
if HAS_REGISTERED_PL.get().is_none() {
|
|
||||||
describe_gauge!(gauge_names::PL_DUTY_CYCLE, Unit::Percent, "Duty cycle");
|
|
||||||
describe_gauge!(gauge_names::PL_LOAD_CURRENT, "Internal load current");
|
|
||||||
|
|
||||||
HAS_REGISTERED_PL.get_or_init(|| ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_tristar_metrics() {
|
|
||||||
register_metrics();
|
|
||||||
if HAS_REGISTERED_TRISTAR.get().is_none() {
|
|
||||||
describe_gauge!(gauge_names::TRISTAR_INPUT_VOLTAGE, "Input voltage");
|
|
||||||
describe_gauge!(gauge_names::TRISTAR_CHARGE_CURRENT, "Charge current");
|
|
||||||
describe_gauge!(gauge_names::TRISTAR_POWER_OUT, "Power out");
|
|
||||||
describe_gauge!(gauge_names::TRISTAR_POWER_IN, "Power in");
|
|
||||||
describe_gauge!(gauge_names::TRISTAR_MAX_ARRAY_POWER, "Maximum array power");
|
|
||||||
describe_gauge!(
|
|
||||||
gauge_names::TRISTAR_MAX_ARRAY_VOLTAGE,
|
|
||||||
"Maximum array voltage"
|
|
||||||
);
|
|
||||||
describe_gauge!(
|
|
||||||
gauge_names::TRISTAR_OPEN_CIRCUIT_VOLTAGE,
|
|
||||||
"Open circuit voltage"
|
|
||||||
);
|
|
||||||
|
|
||||||
HAS_REGISTERED_TRISTAR.get_or_init(|| ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,24 +5,18 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::Timelike;
|
use chrono::Timelike;
|
||||||
use metrics::{gauge, Gauge, Label};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serialport::SerialPort;
|
use serialport::SerialPort;
|
||||||
|
|
||||||
use crate::errors::{PliError, PrintErrors};
|
use crate::{
|
||||||
|
charge_controllers::gauges::*,
|
||||||
use super::{gauge_names, register_pl_metrics};
|
errors::{PliError, PrintErrors},
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Pli {
|
pub struct Pli {
|
||||||
pub state: Arc<RwLock<PlState>>,
|
pub state: Arc<RwLock<PlState>>,
|
||||||
|
port_name: String,
|
||||||
port: Box<dyn SerialPort>,
|
port: Box<dyn SerialPort>,
|
||||||
battery_voltage: Gauge,
|
|
||||||
target_voltage: Gauge,
|
|
||||||
duty_cycle: Gauge,
|
|
||||||
internal_charge_current: Gauge,
|
|
||||||
internal_load_current: Gauge,
|
|
||||||
battery_temp: Gauge,
|
|
||||||
regulator_gauges: RegulatorGauges,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||||
|
@ -62,77 +56,36 @@ impl Default for RegulatorState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegulatorGauges {
|
fn set_regulator_gauges(state: &RegulatorState, label: &str) {
|
||||||
boost: Gauge,
|
let boost = CHARGE_STATE.with_label_values(&[label, "boost"]);
|
||||||
equalise: Gauge,
|
let equalise = CHARGE_STATE.with_label_values(&[label, "equalise"]);
|
||||||
absorption: Gauge,
|
let absorption = CHARGE_STATE.with_label_values(&[label, "absorption"]);
|
||||||
float: Gauge,
|
let float = CHARGE_STATE.with_label_values(&[label, "float"]);
|
||||||
}
|
|
||||||
|
|
||||||
impl RegulatorGauges {
|
|
||||||
fn new(labels: Vec<Label>) -> Self {
|
|
||||||
let boost = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("boost"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let equalise = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("equalise"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let absorption = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("absorption"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let float = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[labels, vec![Label::new("state", String::from("float"))]].concat()
|
|
||||||
);
|
|
||||||
Self {
|
|
||||||
boost,
|
|
||||||
equalise,
|
|
||||||
absorption,
|
|
||||||
float,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, state: &RegulatorState) {
|
|
||||||
match state {
|
match state {
|
||||||
RegulatorState::Boost => {
|
RegulatorState::Boost => {
|
||||||
self.boost.set(1.);
|
boost.set(1);
|
||||||
self.equalise.set(0.);
|
equalise.set(0);
|
||||||
self.absorption.set(0.);
|
absorption.set(0);
|
||||||
self.float.set(0.);
|
float.set(0);
|
||||||
}
|
}
|
||||||
RegulatorState::Equalise => {
|
RegulatorState::Equalise => {
|
||||||
self.boost.set(0.);
|
boost.set(0);
|
||||||
self.equalise.set(1.);
|
equalise.set(1);
|
||||||
self.absorption.set(0.);
|
absorption.set(0);
|
||||||
self.float.set(0.);
|
float.set(0);
|
||||||
}
|
}
|
||||||
RegulatorState::Absorption => {
|
RegulatorState::Absorption => {
|
||||||
self.boost.set(0.);
|
boost.set(0);
|
||||||
self.equalise.set(0.);
|
equalise.set(0);
|
||||||
self.absorption.set(1.);
|
absorption.set(1);
|
||||||
self.float.set(0.);
|
float.set(0);
|
||||||
}
|
}
|
||||||
RegulatorState::Float => {
|
RegulatorState::Float => {
|
||||||
self.boost.set(0.);
|
boost.set(0);
|
||||||
self.equalise.set(0.);
|
equalise.set(0);
|
||||||
self.absorption.set(0.);
|
absorption.set(0);
|
||||||
self.float.set(1.);
|
float.set(1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,44 +107,35 @@ impl Pli {
|
||||||
.timeout(Duration::from_millis(timeout))
|
.timeout(Duration::from_millis(timeout))
|
||||||
.open()?;
|
.open()?;
|
||||||
|
|
||||||
register_pl_metrics();
|
|
||||||
|
|
||||||
let device_labels = vec![
|
|
||||||
Label::new(gauge_names::CHARGE_CONTROLLER_LABEL, serial_port.clone()),
|
|
||||||
Label::new(gauge_names::PL_LABEL, serial_port),
|
|
||||||
];
|
|
||||||
|
|
||||||
let battery_voltage = gauge!(gauge_names::BATTERY_VOLTAGE, device_labels.clone());
|
|
||||||
let target_voltage = gauge!(gauge_names::TARGET_VOLTAGE, device_labels.clone());
|
|
||||||
let duty_cycle = gauge!(gauge_names::PL_DUTY_CYCLE, device_labels.clone());
|
|
||||||
let internal_charge_current = gauge!(gauge_names::INPUT_CURRENT, device_labels.clone());
|
|
||||||
let internal_load_current = gauge!(gauge_names::PL_LOAD_CURRENT, device_labels.clone());
|
|
||||||
let battery_temp = gauge!(gauge_names::BATTERY_TEMP, device_labels.clone());
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
state: Arc::new(RwLock::new(Default::default())),
|
state: Arc::new(RwLock::new(Default::default())),
|
||||||
|
port_name: serial_port,
|
||||||
port,
|
port,
|
||||||
battery_voltage,
|
|
||||||
target_voltage,
|
|
||||||
duty_cycle,
|
|
||||||
internal_charge_current,
|
|
||||||
internal_load_current,
|
|
||||||
battery_temp,
|
|
||||||
regulator_gauges: RegulatorGauges::new(device_labels),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
if let Some(new_state) = self.read_state().some_or_print_with("reading pl state") {
|
if let Some(new_state) = self.read_state().some_or_print_with("reading pl state") {
|
||||||
self.battery_voltage.set(new_state.battery_voltage);
|
BATTERY_VOLTAGE
|
||||||
self.target_voltage.set(new_state.target_voltage);
|
.with_label_values(&[&self.port_name])
|
||||||
self.duty_cycle.set(new_state.duty_cycle);
|
.set(new_state.battery_voltage);
|
||||||
self.internal_charge_current
|
TARGET_VOLTAGE
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
|
.set(new_state.target_voltage);
|
||||||
|
PL_DUTY_CYCLE
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
|
.set(new_state.duty_cycle);
|
||||||
|
INPUT_CURRENT
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.internal_charge_current);
|
.set(new_state.internal_charge_current);
|
||||||
self.internal_load_current
|
PL_LOAD_CURRENT
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.internal_load_current);
|
.set(new_state.internal_load_current);
|
||||||
self.battery_temp.set(new_state.battery_temp);
|
BATTERY_TEMP
|
||||||
self.regulator_gauges.set(&new_state.regulator_state);
|
.with_label_values(&[&self.port_name])
|
||||||
|
.set(new_state.battery_temp);
|
||||||
|
|
||||||
|
set_regulator_gauges(&new_state.regulator_state, &self.port_name);
|
||||||
|
|
||||||
*self.state.write().expect("PLI state handler panicked!!") = new_state;
|
*self.state.write().expect("PLI state handler panicked!!") = new_state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use libmodbus_rs::{Modbus, ModbusClient, ModbusRTU};
|
use libmodbus_rs::{Modbus, ModbusClient, ModbusRTU};
|
||||||
use metrics::{gauge, Gauge, Label};
|
use prometheus::core::{AtomicI64, GenericGauge};
|
||||||
|
|
||||||
use crate::errors::TristarError;
|
use crate::{charge_controllers::gauges::*, errors::TristarError};
|
||||||
|
|
||||||
use super::{gauge_names, register_tristar_metrics};
|
|
||||||
|
|
||||||
const DEVICE_ID: u8 = 0x01;
|
const DEVICE_ID: u8 = 0x01;
|
||||||
const RAM_DATA_SIZE: u16 = 0x005B;
|
const RAM_DATA_SIZE: u16 = 0x005B;
|
||||||
|
@ -42,70 +40,10 @@ impl Scaling {
|
||||||
|
|
||||||
pub struct Tristar {
|
pub struct Tristar {
|
||||||
state: TristarState,
|
state: TristarState,
|
||||||
gauges: TristarGauges,
|
port_name: String,
|
||||||
modbus: Modbus,
|
modbus: Modbus,
|
||||||
data_in: [u16; RAM_ARRAY_SIZE],
|
data_in: [u16; RAM_ARRAY_SIZE],
|
||||||
}
|
charge_state_gauges: ChargeStateGauges,
|
||||||
|
|
||||||
pub struct TristarGauges {
|
|
||||||
battery_voltage: Gauge,
|
|
||||||
target_voltage: Gauge,
|
|
||||||
input_current: Gauge,
|
|
||||||
battery_temp: Gauge,
|
|
||||||
charge_state: ChargeStateGauges,
|
|
||||||
tristar_input_voltage: Gauge,
|
|
||||||
tristar_charge_current: Gauge,
|
|
||||||
tristar_power_out: Gauge,
|
|
||||||
tristar_power_in: Gauge,
|
|
||||||
tristar_max_array_power: Gauge,
|
|
||||||
tristar_max_array_voltage: Gauge,
|
|
||||||
tristar_open_circuit_voltage: Gauge,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TristarGauges {
|
|
||||||
fn new(serial_port: String) -> Self {
|
|
||||||
let device_labels = vec![
|
|
||||||
Label::new(gauge_names::CHARGE_CONTROLLER_LABEL, serial_port.clone()),
|
|
||||||
Label::new(gauge_names::TRISTAR_LABEL, serial_port),
|
|
||||||
];
|
|
||||||
|
|
||||||
let battery_voltage = gauge!(gauge_names::BATTERY_VOLTAGE, device_labels.clone());
|
|
||||||
let target_voltage = gauge!(gauge_names::TARGET_VOLTAGE, device_labels.clone());
|
|
||||||
let input_current = gauge!(gauge_names::INPUT_CURRENT, device_labels.clone());
|
|
||||||
let battery_temp = gauge!(gauge_names::BATTERY_TEMP, device_labels.clone());
|
|
||||||
let charge_state = ChargeStateGauges::new(device_labels.clone());
|
|
||||||
let tristar_input_voltage =
|
|
||||||
gauge!(gauge_names::TRISTAR_INPUT_VOLTAGE, device_labels.clone());
|
|
||||||
let tristar_charge_current =
|
|
||||||
gauge!(gauge_names::TRISTAR_CHARGE_CURRENT, device_labels.clone());
|
|
||||||
let tristar_power_out = gauge!(gauge_names::TRISTAR_POWER_OUT, device_labels.clone());
|
|
||||||
let tristar_power_in = gauge!(gauge_names::TRISTAR_POWER_IN, device_labels.clone());
|
|
||||||
let tristar_max_array_power =
|
|
||||||
gauge!(gauge_names::TRISTAR_MAX_ARRAY_POWER, device_labels.clone());
|
|
||||||
let tristar_max_array_voltage = gauge!(
|
|
||||||
gauge_names::TRISTAR_MAX_ARRAY_VOLTAGE,
|
|
||||||
device_labels.clone()
|
|
||||||
);
|
|
||||||
let tristar_open_circuit_voltage = gauge!(
|
|
||||||
gauge_names::TRISTAR_OPEN_CIRCUIT_VOLTAGE,
|
|
||||||
device_labels.clone()
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
battery_voltage,
|
|
||||||
target_voltage,
|
|
||||||
input_current,
|
|
||||||
battery_temp,
|
|
||||||
charge_state,
|
|
||||||
tristar_input_voltage,
|
|
||||||
tristar_charge_current,
|
|
||||||
tristar_power_out,
|
|
||||||
tristar_power_in,
|
|
||||||
tristar_max_array_power,
|
|
||||||
tristar_max_array_voltage,
|
|
||||||
tristar_open_circuit_voltage,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Copy)]
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
|
@ -183,109 +121,32 @@ impl From<u16> for ChargeState {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChargeStateGauges {
|
struct ChargeStateGauges {
|
||||||
start: Gauge,
|
start: GenericGauge<AtomicI64>,
|
||||||
night_check: Gauge,
|
night_check: GenericGauge<AtomicI64>,
|
||||||
disconnect: Gauge,
|
disconnect: GenericGauge<AtomicI64>,
|
||||||
night: Gauge,
|
night: GenericGauge<AtomicI64>,
|
||||||
fault: Gauge,
|
fault: GenericGauge<AtomicI64>,
|
||||||
mppt: Gauge,
|
mppt: GenericGauge<AtomicI64>,
|
||||||
absorption: Gauge,
|
absorption: GenericGauge<AtomicI64>,
|
||||||
float: Gauge,
|
float: GenericGauge<AtomicI64>,
|
||||||
equalize: Gauge,
|
equalize: GenericGauge<AtomicI64>,
|
||||||
slave: Gauge,
|
slave: GenericGauge<AtomicI64>,
|
||||||
unknown: Gauge,
|
unknown: GenericGauge<AtomicI64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChargeStateGauges {
|
impl ChargeStateGauges {
|
||||||
fn new(labels: Vec<Label>) -> Self {
|
fn new(label: &str) -> Self {
|
||||||
let start = gauge!(
|
let start = CHARGE_STATE.with_label_values(&[label, "start"]);
|
||||||
gauge_names::CHARGE_STATE,
|
let night_check = CHARGE_STATE.with_label_values(&[label, "night_check"]);
|
||||||
[
|
let disconnect = CHARGE_STATE.with_label_values(&[label, "disconnect"]);
|
||||||
labels.clone(),
|
let night = CHARGE_STATE.with_label_values(&[label, "night"]);
|
||||||
vec![Label::new("state", String::from("start"))]
|
let fault = CHARGE_STATE.with_label_values(&[label, "fault"]);
|
||||||
]
|
let mppt = CHARGE_STATE.with_label_values(&[label, "mppt"]);
|
||||||
.concat()
|
let absorption = CHARGE_STATE.with_label_values(&[label, "absorption"]);
|
||||||
);
|
let float = CHARGE_STATE.with_label_values(&[label, "float"]);
|
||||||
let night_check = gauge!(
|
let equalize = CHARGE_STATE.with_label_values(&[label, "equalize"]);
|
||||||
gauge_names::CHARGE_STATE,
|
let slave = CHARGE_STATE.with_label_values(&[label, "slave"]);
|
||||||
[
|
let unknown = CHARGE_STATE.with_label_values(&[label, "unknown"]);
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("night_check"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let disconnect = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("disconnect"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let night = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("night"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let fault = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("fault"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let mppt = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("mppt"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let absorption = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("absorption"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let float = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("float"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let equalize = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("equalize"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let slave = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("slave"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
let unknown = gauge!(
|
|
||||||
gauge_names::CHARGE_STATE,
|
|
||||||
[
|
|
||||||
labels.clone(),
|
|
||||||
vec![Label::new("state", String::from("unknown"))]
|
|
||||||
]
|
|
||||||
.concat()
|
|
||||||
);
|
|
||||||
Self {
|
Self {
|
||||||
start,
|
start,
|
||||||
night_check,
|
night_check,
|
||||||
|
@ -302,64 +163,64 @@ impl ChargeStateGauges {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zero_all(&mut self) {
|
fn zero_all(&mut self) {
|
||||||
self.start.set(0.);
|
self.start.set(0);
|
||||||
self.night_check.set(0.);
|
self.night_check.set(0);
|
||||||
self.disconnect.set(0.);
|
self.disconnect.set(0);
|
||||||
self.night.set(0.);
|
self.night.set(0);
|
||||||
self.fault.set(0.);
|
self.fault.set(0);
|
||||||
self.mppt.set(0.);
|
self.mppt.set(0);
|
||||||
self.absorption.set(0.);
|
self.absorption.set(0);
|
||||||
self.float.set(0.);
|
self.float.set(0);
|
||||||
self.equalize.set(0.);
|
self.equalize.set(0);
|
||||||
self.slave.set(0.);
|
self.slave.set(0);
|
||||||
self.unknown.set(0.);
|
self.unknown.set(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, state: ChargeState) {
|
fn set(&mut self, state: ChargeState) {
|
||||||
match state {
|
match state {
|
||||||
ChargeState::Start => {
|
ChargeState::Start => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.start.set(1.);
|
self.start.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::NightCheck => {
|
ChargeState::NightCheck => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.night_check.set(1.);
|
self.night_check.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Disconnect => {
|
ChargeState::Disconnect => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.disconnect.set(1.);
|
self.disconnect.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Night => {
|
ChargeState::Night => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.night.set(1.);
|
self.night.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Fault => {
|
ChargeState::Fault => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.fault.set(1.);
|
self.fault.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Mppt => {
|
ChargeState::Mppt => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.mppt.set(1.);
|
self.mppt.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Absorption => {
|
ChargeState::Absorption => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.absorption.set(1.);
|
self.absorption.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Float => {
|
ChargeState::Float => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.float.set(1.);
|
self.float.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Equalize => {
|
ChargeState::Equalize => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.equalize.set(1.);
|
self.equalize.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Slave => {
|
ChargeState::Slave => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.slave.set(1.);
|
self.slave.set(1);
|
||||||
}
|
}
|
||||||
ChargeState::Unknown => {
|
ChargeState::Unknown => {
|
||||||
self.zero_all();
|
self.zero_all();
|
||||||
self.unknown.set(1.);
|
self.unknown.set(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,12 +234,13 @@ impl Tristar {
|
||||||
let mut modbus = Modbus::new_rtu(&serial_port, baud_rate, parity, data_bit, stop_bit)?;
|
let mut modbus = Modbus::new_rtu(&serial_port, baud_rate, parity, data_bit, stop_bit)?;
|
||||||
modbus.set_slave(DEVICE_ID)?;
|
modbus.set_slave(DEVICE_ID)?;
|
||||||
modbus.connect()?;
|
modbus.connect()?;
|
||||||
register_tristar_metrics();
|
let charge_state_gauges = ChargeStateGauges::new(&serial_port);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
gauges: TristarGauges::new(serial_port.clone()),
|
port_name: serial_port,
|
||||||
modbus,
|
modbus,
|
||||||
data_in: [0; RAM_ARRAY_SIZE],
|
data_in: [0; RAM_ARRAY_SIZE],
|
||||||
|
charge_state_gauges,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,30 +249,41 @@ impl Tristar {
|
||||||
.get_data()
|
.get_data()
|
||||||
.map(|scaling| TristarState::from_ram(scaling, &self.data_in))
|
.map(|scaling| TristarState::from_ram(scaling, &self.data_in))
|
||||||
{
|
{
|
||||||
self.gauges.battery_voltage.set(new_state.battery_voltage);
|
BATTERY_VOLTAGE
|
||||||
self.gauges.target_voltage.set(new_state.target_voltage);
|
.with_label_values(&[&self.port_name])
|
||||||
self.gauges.input_current.set(new_state.input_current);
|
.set(new_state.battery_voltage);
|
||||||
self.gauges.battery_temp.set(new_state.battery_temp as f64);
|
TARGET_VOLTAGE
|
||||||
self.gauges.charge_state.set(new_state.charge_state);
|
.with_label_values(&[&self.port_name])
|
||||||
self.gauges
|
.set(new_state.target_voltage);
|
||||||
.tristar_input_voltage
|
INPUT_CURRENT
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
|
.set(new_state.input_current);
|
||||||
|
BATTERY_TEMP
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
|
.set(new_state.battery_temp.into());
|
||||||
|
TRISTAR_INPUT_VOLTAGE
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.tristar_input_voltage);
|
.set(new_state.tristar_input_voltage);
|
||||||
self.gauges
|
TRISTAR_CHARGE_CURRENT
|
||||||
.tristar_charge_current
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.tristar_charge_current);
|
.set(new_state.tristar_charge_current);
|
||||||
self.gauges
|
TRISTAR_POWER_OUT
|
||||||
.tristar_power_out
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.tristar_power_out);
|
.set(new_state.tristar_power_out);
|
||||||
self.gauges.tristar_power_in.set(new_state.tristar_power_in);
|
TRISTAR_POWER_IN
|
||||||
self.gauges
|
.with_label_values(&[&self.port_name])
|
||||||
.tristar_max_array_power
|
.set(new_state.tristar_power_in);
|
||||||
|
TRISTAR_MAX_ARRAY_POWER
|
||||||
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.tristar_max_array_power);
|
.set(new_state.tristar_max_array_power);
|
||||||
self.gauges
|
TRISTAR_MAX_ARRAY_VOLTAGE
|
||||||
.tristar_max_array_voltage
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.tristar_max_array_voltage);
|
.set(new_state.tristar_max_array_voltage);
|
||||||
self.gauges
|
TRISTAR_OPEN_CIRCUIT_VOLTAGE
|
||||||
.tristar_open_circuit_voltage
|
.with_label_values(&[&self.port_name])
|
||||||
.set(new_state.tristar_open_circuit_voltage);
|
.set(new_state.tristar_open_circuit_voltage);
|
||||||
|
|
||||||
|
self.charge_state_gauges.set(new_state.charge_state);
|
||||||
self.state = new_state;
|
self.state = new_state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ async fn main() {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let _recorder = metrics_prometheus::install();
|
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Commands::GenerateConfig => {
|
Commands::GenerateConfig => {
|
||||||
|
|
|
@ -129,7 +129,7 @@ async fn flash(state: &State<ServerState>, remote_addr: std::net::IpAddr) {
|
||||||
async fn disable_control(state: &State<ServerState>, remote_addr: std::net::IpAddr) {
|
async fn disable_control(state: &State<ServerState>, remote_addr: std::net::IpAddr) {
|
||||||
log::warn!("disabling control: {remote_addr:?}");
|
log::warn!("disabling control: {remote_addr:?}");
|
||||||
match state.tcrc_state.write() {
|
match state.tcrc_state.write() {
|
||||||
Ok(mut handle) => handle.control_enable = false,
|
Ok(mut handle) => handle.set_control_enable(false),
|
||||||
Err(e) => log::error!("Error disabling control: {e:?}"),
|
Err(e) => log::error!("Error disabling control: {e:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ async fn disable_control(state: &State<ServerState>, remote_addr: std::net::IpAd
|
||||||
async fn enable_control(state: &State<ServerState>, remote_addr: std::net::IpAddr) {
|
async fn enable_control(state: &State<ServerState>, remote_addr: std::net::IpAddr) {
|
||||||
log::warn!("enabling control: {remote_addr:?}");
|
log::warn!("enabling control: {remote_addr:?}");
|
||||||
match state.tcrc_state.write() {
|
match state.tcrc_state.write() {
|
||||||
Ok(mut handle) => handle.control_enable = true,
|
Ok(mut handle) => handle.set_control_enable(true),
|
||||||
Err(e) => log::error!("Error enabling control: {e:?}"),
|
Err(e) => log::error!("Error enabling control: {e:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use metrics::{describe_gauge, gauge, Gauge};
|
use lazy_static::lazy_static;
|
||||||
|
use prometheus::{register_gauge, register_int_gauge, Gauge, IntGauge};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -11,13 +12,34 @@ use crate::{
|
||||||
types::{CarState, ChargeState},
|
types::{CarState, ChargeState},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref CONTROL_ENABLE_GAUGE: IntGauge =
|
||||||
|
register_int_gauge!("tcrc_control_enable", "Enable Tesla charge rate control",).unwrap();
|
||||||
|
pub static ref PROPORTIONAL_GAUGE: Gauge = register_gauge!(
|
||||||
|
"tcrc_proportional",
|
||||||
|
"Proportional component of requested change to charge rate",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref DERIVATIVE_GAUGE: Gauge = register_gauge!(
|
||||||
|
"tcrc_derivative",
|
||||||
|
"Derivative component of requested change to charge rate",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref LOAD_GAUGE: Gauge = register_gauge!(
|
||||||
|
"tcrc_load",
|
||||||
|
"Fudge factor from internal load of requested change to charge rate",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
pub static ref CHANGE_REQUEST_GAUGE: Gauge =
|
||||||
|
register_gauge!("tcrc_change_request", "Requested change to charge rate",).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TeslaChargeRateController {
|
pub struct TeslaChargeRateController {
|
||||||
pub car_state: Arc<RwLock<CarState>>,
|
pub car_state: Arc<RwLock<CarState>>,
|
||||||
pub pl_state: Option<Arc<RwLock<PlState>>>,
|
pub pl_state: Option<Arc<RwLock<PlState>>>,
|
||||||
pub tcrc_state: Arc<RwLock<TcrcState>>,
|
pub tcrc_state: Arc<RwLock<TcrcState>>,
|
||||||
pid: PidLoop,
|
pid: PidLoop,
|
||||||
voltage_low: u64,
|
voltage_low: u64,
|
||||||
control_enable_gauge: Gauge,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -31,6 +53,13 @@ pub struct TcrcState {
|
||||||
pub control_enable: bool,
|
pub control_enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TcrcState {
|
||||||
|
pub fn set_control_enable(&mut self, to: bool) {
|
||||||
|
self.control_enable = to;
|
||||||
|
CONTROL_ENABLE_GAUGE.set(if to { 1 } else { 0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for TcrcState {
|
impl Default for TcrcState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -41,14 +70,12 @@ impl Default for TcrcState {
|
||||||
|
|
||||||
impl TeslaChargeRateController {
|
impl TeslaChargeRateController {
|
||||||
pub fn new(car_state: Arc<RwLock<CarState>>, pl_state: Option<Arc<RwLock<PlState>>>) -> Self {
|
pub fn new(car_state: Arc<RwLock<CarState>>, pl_state: Option<Arc<RwLock<PlState>>>) -> Self {
|
||||||
describe_gauge!("tcrc_control_enable", "Enable Tesla charge rate control");
|
|
||||||
Self {
|
Self {
|
||||||
car_state,
|
car_state,
|
||||||
pl_state,
|
pl_state,
|
||||||
tcrc_state: Default::default(),
|
tcrc_state: Default::default(),
|
||||||
pid: Default::default(),
|
pid: Default::default(),
|
||||||
voltage_low: 0,
|
voltage_low: 0,
|
||||||
control_enable_gauge: gauge!("tcrc_control_enable"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,15 +109,13 @@ impl TeslaChargeRateController {
|
||||||
self.tcrc_state
|
self.tcrc_state
|
||||||
.write()
|
.write()
|
||||||
.expect("failed to write to tcrc state")
|
.expect("failed to write to tcrc state")
|
||||||
.control_enable = false;
|
.set_control_enable(false);
|
||||||
self.control_enable_gauge.set(0.);
|
|
||||||
}
|
}
|
||||||
TcrcRequest::EnableAutomaticControl => {
|
TcrcRequest::EnableAutomaticControl => {
|
||||||
self.tcrc_state
|
self.tcrc_state
|
||||||
.write()
|
.write()
|
||||||
.expect("failed to write to tcrc state")
|
.expect("failed to write to tcrc state")
|
||||||
.control_enable = true;
|
.set_control_enable(true);
|
||||||
self.control_enable_gauge.set(1.);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,38 +123,11 @@ impl TeslaChargeRateController {
|
||||||
|
|
||||||
struct PidLoop {
|
struct PidLoop {
|
||||||
previous_error: f64,
|
previous_error: f64,
|
||||||
proportional_gauge: Gauge,
|
|
||||||
derivative_gauge: Gauge,
|
|
||||||
load_gauge: Gauge,
|
|
||||||
change_request_gauge: Gauge,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PidLoop {
|
impl Default for PidLoop {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
describe_gauge!(
|
Self { previous_error: 0. }
|
||||||
"tcrc_proportional",
|
|
||||||
"Proportional component of requested change to charge rate"
|
|
||||||
);
|
|
||||||
let proportional_gauge = gauge!("tcrc_proportional");
|
|
||||||
describe_gauge!(
|
|
||||||
"tcrc_proportional",
|
|
||||||
"Derivative component of requested change to charge rate"
|
|
||||||
);
|
|
||||||
let derivative_gauge = gauge!("tcrc_derivative");
|
|
||||||
describe_gauge!(
|
|
||||||
"tcrc_load",
|
|
||||||
"Fudge factor from internal load of requested change to charge rate"
|
|
||||||
);
|
|
||||||
let load_gauge = gauge!("tcrc_load");
|
|
||||||
describe_gauge!("tcrc_change_request", "Requested change to charge rate");
|
|
||||||
let change_request_gauge = gauge!("tcrc_change_request");
|
|
||||||
Self {
|
|
||||||
previous_error: 0.,
|
|
||||||
proportional_gauge,
|
|
||||||
derivative_gauge,
|
|
||||||
load_gauge,
|
|
||||||
change_request_gauge,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,10 +150,10 @@ impl PidLoop {
|
||||||
|
|
||||||
let offset = proportional_component + derivative_component + extra_offsets;
|
let offset = proportional_component + derivative_component + extra_offsets;
|
||||||
|
|
||||||
self.proportional_gauge.set(proportional_component);
|
PROPORTIONAL_GAUGE.set(proportional_component);
|
||||||
self.derivative_gauge.set(derivative_component);
|
DERIVATIVE_GAUGE.set(derivative_component);
|
||||||
self.load_gauge.set(extra_offsets);
|
LOAD_GAUGE.set(extra_offsets);
|
||||||
self.change_request_gauge.set(offset);
|
CHANGE_REQUEST_GAUGE.set(offset);
|
||||||
|
|
||||||
let new_target = offset + (charge_state.charge_amps as f64);
|
let new_target = offset + (charge_state.charge_amps as f64);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue