From 88144693a88e6a5d4b56279136aabfc9a9f3ffe3 Mon Sep 17 00:00:00 2001
From: Alex Janka <alex@alexjanka.com>
Date: Fri, 10 Jan 2025 11:38:10 +1100
Subject: [PATCH] ccs: get full controller state via web

---
 .../src/controller.rs                         |  1 +
 charge-controller-supervisor/src/web.rs       | 32 +++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/charge-controller-supervisor/src/controller.rs b/charge-controller-supervisor/src/controller.rs
index c8563c7..106c84a 100644
--- a/charge-controller-supervisor/src/controller.rs
+++ b/charge-controller-supervisor/src/controller.rs
@@ -18,6 +18,7 @@ pub struct CommonData {
 }
 
 #[derive(serde::Serialize, Clone)]
+#[serde(tag = "model")]
 pub enum ControllerState {
     Pl(pl::PlState),
     Tristar(tristar::TristarState),
diff --git a/charge-controller-supervisor/src/web.rs b/charge-controller-supervisor/src/web.rs
index 3a3a9a6..57d55f5 100644
--- a/charge-controller-supervisor/src/web.rs
+++ b/charge-controller-supervisor/src/web.rs
@@ -52,8 +52,10 @@ pub fn rocket(state: ServerState) -> rocket::Rocket<rocket::Build> {
                 metrics,
                 interfaces,
                 all_interfaces,
+                all_interfaces_full,
                 primary_interface,
                 interface,
+                interface_full,
                 get_control,
                 enable_control,
                 disable_control
@@ -96,6 +98,22 @@ async fn all_interfaces(
     Json(data)
 }
 
+#[get("/interfaces/data/full")]
+async fn all_interfaces_full(
+    state: &State<ServerState>,
+) -> Json<Vec<(String, crate::controller::ControllerState)>> {
+    let mut data = Vec::new();
+
+    for (k, v) in &state.map {
+        let v = v.read().await;
+        if let Some(v) = v.as_ref() {
+            data.push((k.clone(), v.clone()));
+        }
+    }
+
+    Json(data)
+}
+
 #[get("/interface/<name>")]
 async fn interface(
     name: &str,
@@ -110,6 +128,20 @@ async fn interface(
     Ok(Json(data.as_ref().ok_or(ServerError::NoData)?.common()))
 }
 
+#[get("/interface/<name>/full")]
+async fn interface_full(
+    name: &str,
+    state: &State<ServerState>,
+) -> Result<Json<crate::controller::ControllerState>, ServerError> {
+    let data = state
+        .map
+        .get(name)
+        .ok_or(ServerError::NotFound)?
+        .read()
+        .await;
+    Ok(Json(data.as_ref().ok_or(ServerError::NoData)?.clone()))
+}
+
 #[get("/metrics")]
 fn metrics() -> Result<String, ServerError> {
     Ok(