Skip to content

Commit aa059dd

Browse files
committed
Add SolisCloud PV monitoring widget (#940)
* Add SolisCloud PV monitoring widget Integrates the SolisCloud API to show current solar power output on the main dashboard view. Backend fetches station data with HMAC-SHA1 auth and caches it for 5 minutes. Frontend adds a compact SolisBox as a 4th column alongside the temperature boxes, auto-refreshing every 5 minutes. * Tweak trend style * Fix test
1 parent ce45341 commit aa059dd

16 files changed

Lines changed: 776 additions & 26 deletions

File tree

‎backend/.env.example‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ HUE_ROOM_TYPES='{}'
1818
# Sensor history
1919
# HCC_DB_PATH=hcc.db
2020
# HCC_HISTORY_RETENTION_DAYS=90
21+
22+
# SolisCloud PV monitoring
23+
SOLIS_KEY_ID=
24+
SOLIS_KEY_SECRET=
25+
SOLIS_STATION_ID=
26+
# SOLIS_BASE_URL=https://www.soliscloud.com:13333

‎backend/Cargo.lock‎

Lines changed: 106 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎backend/Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ rusqlite = { version = "0.34", features = ["bundled"] }
2424
chrono = { version = "0.4", features = ["serde"] }
2525
quick-xml = "0.39"
2626
sun = "0.3"
27+
hmac = "0.13.0"
28+
sha1 = "0.11.0"
29+
md5 = "0.8.0"
30+
base64 = "0.22.1"
2731

2832
[dev-dependencies]
2933
wiremock = "0.6"

‎backend/src/lib.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod cache;
22
pub mod hue;
33
pub mod settings;
4+
pub mod solis;
45
pub mod storage;
56
pub mod weather;
67

@@ -23,6 +24,7 @@ pub struct AppState {
2324
pub hue_cache: Cache<hue::models::HueResponse>,
2425
pub tomorrow_cache: Cache<serde_json::Value>,
2526
pub weather_cache: Cache<weather::models::WeatherResponse>,
27+
pub solis_cache: Cache<solis::models::SolisWidgetData>,
2628
pub hue_events_tx: broadcast::Sender<hue::events::HueLiveEvent>,
2729
pub storage: storage::Storage,
2830
}
@@ -36,6 +38,7 @@ pub struct AppState {
3638
hue::handlers::events_sse,
3739
hue::handlers::pair,
3840
hue::handlers::toggle_group,
41+
solis::handlers::get_data,
3942
status,
4043
sensor_history,
4144
),
@@ -48,6 +51,7 @@ pub struct AppState {
4851
hue::events::HueLiveEvent,
4952
hue::handlers::PairRequest,
5053
hue::handlers::PairResponse,
54+
solis::models::SolisWidgetData,
5155
StatusResponse,
5256
storage::SensorReading,
5357
))
@@ -179,6 +183,10 @@ pub fn create_app(
179183
"/toggleGroup/{id}",
180184
web::post().to(hue::handlers::toggle_group),
181185
),
186+
)
187+
.service(
188+
web::scope("/solis")
189+
.route("", web::get().to(solis::handlers::get_data)),
182190
),
183191
)
184192
.service(SwaggerUi::new("/docs/{_:.*}").url("/api-doc/openapi.json", openapi))
@@ -221,6 +229,7 @@ pub fn create_test_app_state_with(settings: Settings) -> Arc<AppState> {
221229
hue_cache: Cache::new(std::time::Duration::from_secs(3)),
222230
tomorrow_cache: Cache::new(std::time::Duration::from_secs(3600)),
223231
weather_cache: Cache::new(std::time::Duration::from_secs(3600)),
232+
solis_cache: Cache::new(std::time::Duration::from_secs(300)),
224233
hue_events_tx,
225234
storage,
226235
})
@@ -258,6 +267,7 @@ pub async fn run_server() -> std::io::Result<()> {
258267
hue_cache: Cache::new(std::time::Duration::from_secs(3)),
259268
tomorrow_cache: Cache::new(std::time::Duration::from_secs(3600)),
260269
weather_cache: Cache::new(std::time::Duration::from_secs(3600)),
270+
solis_cache: Cache::new(std::time::Duration::from_secs(300)),
261271
hue_events_tx: hue_events_tx.clone(),
262272
storage,
263273
});

‎backend/src/settings.rs‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ pub struct Settings {
1111
pub static_dir: String,
1212
pub port: u16,
1313
pub history_retention_days: u32,
14+
pub solis_key_id: String,
15+
pub solis_key_secret: String,
16+
pub solis_station_id: String,
17+
pub solis_base_url: String,
1418
}
1519

1620
impl Settings {
@@ -26,6 +30,10 @@ impl Settings {
2630
static_dir: "./dist".into(),
2731
port: 3000,
2832
history_retention_days: 0,
33+
solis_key_id: String::new(),
34+
solis_key_secret: String::new(),
35+
solis_station_id: String::new(),
36+
solis_base_url: "https://www.soliscloud.com:13333".into(),
2937
}
3038
}
3139

@@ -53,6 +61,11 @@ impl Settings {
5361
.ok()
5462
.and_then(|d| d.parse().ok())
5563
.unwrap_or(0),
64+
solis_key_id: env::var("SOLIS_KEY_ID").unwrap_or_default(),
65+
solis_key_secret: env::var("SOLIS_KEY_SECRET").unwrap_or_default(),
66+
solis_station_id: env::var("SOLIS_STATION_ID").unwrap_or_default(),
67+
solis_base_url: env::var("SOLIS_BASE_URL")
68+
.unwrap_or_else(|_| "https://www.soliscloud.com:13333".into()),
5669
}
5770
}
5871
}

0 commit comments

Comments
 (0)