tesla-charge-controller/charge-controller-supervisor/src/controller.rs

161 lines
4.4 KiB
Rust
Raw Normal View History

2024-12-28 20:39:07 +11:00
pub struct Controller {
name: String,
interval: std::time::Duration,
inner: ControllerInner,
data: std::sync::Arc<tokio::sync::RwLock<CommonData>>,
voltage_rx: Option<tokio::sync::mpsc::UnboundedReceiver<VoltageCommand>>,
voltage_tx: Option<MultiTx>,
2024-12-28 20:39:07 +11:00
}
#[derive(Default, serde::Serialize, Clone)]
pub struct CommonData {
pub battery_voltage: f64,
pub target_voltage: f64,
pub battery_temp: f64,
}
#[derive(Clone, Copy, Debug)]
pub enum VoltageCommand {
Set(f64),
}
2024-12-28 20:39:07 +11:00
impl Controller {
pub fn new(
config: crate::config::ChargeControllerConfig,
) -> eyre::Result<(
Self,
Option<tokio::sync::mpsc::UnboundedSender<VoltageCommand>>,
)> {
2024-12-28 20:39:07 +11:00
let inner = match config.variant {
crate::config::ChargeControllerVariant::Tristar => ControllerInner::Tristar(
2024-12-28 21:09:19 +11:00
crate::tristar::Tristar::new(&config.serial_port, &config.name, config.baud_rate)?,
2024-12-28 20:39:07 +11:00
),
crate::config::ChargeControllerVariant::Pl {
timeout_milliseconds,
} => ControllerInner::Pl(crate::pl::Pli::new(
2024-12-28 21:09:19 +11:00
&config.serial_port,
&config.name,
2024-12-28 20:39:07 +11:00
config.baud_rate,
timeout_milliseconds,
)?),
};
let data = CommonData::default();
let data = std::sync::Arc::new(tokio::sync::RwLock::new(data));
let (voltage_tx, voltage_rx) = if config.follow_primary {
let (a, b) = tokio::sync::mpsc::unbounded_channel();
(Some(a), Some(b))
} else {
(None, None)
};
Ok((
Self {
name: config.name,
interval: std::time::Duration::from_secs(config.watch_interval_seconds),
inner,
data,
voltage_rx,
voltage_tx: None,
},
voltage_tx,
))
2024-12-28 20:39:07 +11:00
}
pub fn get_data_ptr(&self) -> std::sync::Arc<tokio::sync::RwLock<CommonData>> {
self.data.clone()
}
pub async fn refresh(&mut self) -> eyre::Result<()> {
let data = self.inner.refresh().await?;
if let Some(tx) = self.voltage_tx.as_mut() {
log::debug!(
"tristar {}: primary: sending target voltage {}",
self.name,
data.target_voltage
);
tx.send_to_all(VoltageCommand::Set(data.target_voltage));
}
2024-12-28 20:39:07 +11:00
*self.data.write().await = data;
Ok(())
}
pub fn timeout_interval(&self) -> std::time::Duration {
self.interval
}
pub fn name(&self) -> &str {
&self.name
}
pub fn set_tx_to_secondary(
&mut self,
tx: Vec<tokio::sync::mpsc::UnboundedSender<VoltageCommand>>,
) {
2024-12-30 15:16:04 +11:00
assert!(
self.voltage_rx.is_none(),
"trying to set {} as primary when it is also a secondary!",
self.name
);
2024-12-30 15:16:04 +11:00
self.voltage_tx = Some(MultiTx(tx));
}
pub fn get_rx(&mut self) -> Option<&mut tokio::sync::mpsc::UnboundedReceiver<VoltageCommand>> {
self.voltage_rx.as_mut()
}
pub async fn process_command(&mut self, command: VoltageCommand) -> eyre::Result<()> {
match command {
VoltageCommand::Set(target_voltage) => {
self.inner.set_target_voltage(target_voltage).await
}
}
}
}
struct MultiTx(Vec<tokio::sync::mpsc::UnboundedSender<VoltageCommand>>);
impl MultiTx {
fn send_to_all(&mut self, command: VoltageCommand) {
2024-12-30 15:16:04 +11:00
for sender in &mut self.0 {
if let Err(e) = sender.send(command) {
log::error!("failed to send command {command:?}: {e:?}");
}
}
}
2024-12-28 20:39:07 +11:00
}
pub enum ControllerInner {
Pl(crate::pl::Pli),
Tristar(crate::tristar::Tristar),
}
impl ControllerInner {
pub async fn refresh(&mut self) -> eyre::Result<CommonData> {
match self {
ControllerInner::Pl(pli) => {
2024-12-28 22:39:15 +11:00
let pl_data = pli.refresh().await?;
2024-12-28 20:39:07 +11:00
Ok(pl_data)
}
ControllerInner::Tristar(tristar) => {
let tristar_data = tristar.refresh().await?;
Ok(tristar_data)
}
}
}
pub async fn set_target_voltage(&mut self, target_voltage: f64) -> eyre::Result<()> {
match self {
ControllerInner::Pl(_) => todo!(),
ControllerInner::Tristar(tristar) => tristar.set_target_voltage(target_voltage).await,
}
}
2024-12-28 20:39:07 +11:00
}