Overview
The Growatt API provides comprehensive energy statistics across different time periods: daily, monthly, yearly, and total lifetime energy. This guide shows you how to retrieve and work with these statistics.Prerequisites
Before retrieving energy statistics, you’ll need:- A plant ID (from
get_plants()) - A MIX device serial number (from
get_mix_ids())
All energy statistics methods require authentication. The SDK handles session management automatically.
Getting MIX Device IDs
First, retrieve the MIX device IDs for your plant:use growatt::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("your_username", "your_password").await?;
let plant_id = "your_plant_id";
// Get MIX device IDs
let mix_ids = client.get_mix_ids(plant_id).await?;
println!("MIX devices: {}", mix_ids);
client.logout().await?;
Ok(())
}
Daily Energy Statistics
Retrieve hourly energy data for a specific day:use growatt::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("your_username", "your_password").await?;
let plant_id = "your_plant_id";
let mix_sn = "your_mix_serial_number";
let date = "2025-04-26"; // Format: YYYY-MM-DD
// Get daily energy statistics
let daily_stats = client.get_energy_stats_daily(date, plant_id, mix_sn).await?;
println!("Daily statistics: {}", daily_stats);
client.logout().await?;
Ok(())
}
Date Format
The date parameter must be inYYYY-MM-DD format:
// Using today's date
let today = chrono::Local::now().format("%Y-%m-%d").to_string();
let daily_stats = client.get_energy_stats_daily(&today, plant_id, mix_sn).await?;
// Using a specific date
let date = "2025-04-26";
let daily_stats = client.get_energy_stats_daily(date, plant_id, mix_sn).await?;
Monthly Energy Statistics
Retrieve daily energy data for a specific month:use growatt::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("your_username", "your_password").await?;
let plant_id = "your_plant_id";
let mix_sn = "your_mix_serial_number";
let date = "2025-04"; // Format: YYYY-MM
// Get monthly energy statistics
let monthly_stats = client.get_energy_stats_monthly(date, plant_id, mix_sn).await?;
println!("Monthly statistics: {}", monthly_stats);
client.logout().await?;
Ok(())
}
Date Format
The date parameter must be inYYYY-MM format:
// Using current month
let current_month = chrono::Local::now().format("%Y-%m").to_string();
let monthly_stats = client.get_energy_stats_monthly(¤t_month, plant_id, mix_sn).await?;
// Using a specific month
let date = "2025-04";
let monthly_stats = client.get_energy_stats_monthly(date, plant_id, mix_sn).await?;
Yearly Energy Statistics
Retrieve monthly energy data for a specific year:use growatt::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("your_username", "your_password").await?;
let plant_id = "your_plant_id";
let mix_sn = "your_mix_serial_number";
let year = "2025"; // Format: YYYY
// Get yearly energy statistics
let yearly_stats = client.get_energy_stats_yearly(year, plant_id, mix_sn).await?;
println!("Yearly statistics: {}", yearly_stats);
client.logout().await?;
Ok(())
}
Year Format
// Using current year
let current_year = chrono::Local::now().format("%Y").to_string();
let yearly_stats = client.get_energy_stats_yearly(¤t_year, plant_id, mix_sn).await?;
// Using a specific year
let year = "2025";
let yearly_stats = client.get_energy_stats_yearly(year, plant_id, mix_sn).await?;
Total Energy Statistics
Retrieve yearly energy data for the plant’s entire lifetime:use growatt::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("your_username", "your_password").await?;
let plant_id = "your_plant_id";
let mix_sn = "your_mix_serial_number";
let year = "2025"; // Format: YYYY
// Get total energy statistics
let total_stats = client.get_energy_stats_total(year, plant_id, mix_sn).await?;
println!("Total statistics: {}", total_stats);
client.logout().await?;
Ok(())
}
The year parameter in
get_energy_stats_total() determines the starting year for the historical data.Complete Energy Statistics Example
Here’s a comprehensive example showing how to retrieve all types of energy statistics:use growatt::Growatt;
use chrono::Local;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
// Login
client.login("your_username", "your_password").await?;
println!("Login successful!");
// Get plants
let plants = client.get_plants().await?;
if plants.0.is_empty() {
println!("No plants found");
return Ok(());
}
let plant_id = &plants.0[0].plant_id;
println!("Using plant: {}", plant_id);
// Get MIX device IDs
let mix_ids = client.get_mix_ids(plant_id).await?;
// Extract the first MIX serial number
// Note: You'll need to parse the JSON response based on actual structure
let mix_sn = "your_mix_serial_number"; // Extract from mix_ids
// Current date components
let now = Local::now();
let today = now.format("%Y-%m-%d").to_string();
let this_month = now.format("%Y-%m").to_string();
let this_year = now.format("%Y").to_string();
// Get daily energy statistics
println!("\nFetching daily statistics for {}...", today);
match client.get_energy_stats_daily(&today, plant_id, mix_sn).await {
Ok(stats) => println!("Daily stats: {}", stats),
Err(e) => eprintln!("Error fetching daily stats: {}", e),
}
// Get monthly energy statistics
println!("\nFetching monthly statistics for {}...", this_month);
match client.get_energy_stats_monthly(&this_month, plant_id, mix_sn).await {
Ok(stats) => println!("Monthly stats: {}", stats),
Err(e) => eprintln!("Error fetching monthly stats: {}", e),
}
// Get yearly energy statistics
println!("\nFetching yearly statistics for {}...", this_year);
match client.get_energy_stats_yearly(&this_year, plant_id, mix_sn).await {
Ok(stats) => println!("Yearly stats: {}", stats),
Err(e) => eprintln!("Error fetching yearly stats: {}", e),
}
// Get total energy statistics
println!("\nFetching total energy statistics...");
match client.get_energy_stats_total(&this_year, plant_id, mix_sn).await {
Ok(stats) => println!("Total stats: {}", stats),
Err(e) => eprintln!("Error fetching total stats: {}", e),
}
// Logout
client.logout().await?;
println!("\nSuccessfully logged out");
Ok(())
}
Battery Statistics
Retrieve weekly battery charge/discharge statistics:use growatt::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("your_username", "your_password").await?;
let plant_id = "your_plant_id";
let mix_sn = "your_mix_serial_number";
// Get weekly battery statistics
let battery_stats = client.get_weekly_battery_stats(plant_id, mix_sn).await?;
println!("Battery statistics: {}", battery_stats);
client.logout().await?;
Ok(())
}
Working with JSON Responses
All energy statistics methods returnserde_json::Value. Here’s how to parse the data:
use serde_json::Value;
let daily_stats = client.get_energy_stats_daily("2025-04-26", plant_id, mix_sn).await?;
// Access specific fields
if let Some(obj) = daily_stats.as_object() {
// Parse based on actual API response structure
if let Some(data) = obj.get("data") {
println!("Energy data: {}", data);
}
}
// Convert to a custom struct
#[derive(Debug, serde::Deserialize)]
struct EnergyData {
// Define fields based on actual API response
energy: Option<f64>,
power: Option<f64>,
}
if let Ok(energy_data) = serde_json::from_value::<EnergyData>(daily_stats) {
println!("Parsed energy data: {:?}", energy_data);
}
Best Practices
Cache MIX serial numbers: Retrieve MIX IDs once and cache them to avoid repeated API calls:
let mix_ids = client.get_mix_ids(plant_id).await?;
// Parse and cache the serial numbers
let mix_serial_numbers: Vec<String> = parse_mix_ids(&mix_ids);
// Use cached values for statistics
for mix_sn in &mix_serial_numbers {
let stats = client.get_energy_stats_daily(&today, plant_id, mix_sn).await?;
// Process stats
}
Use appropriate time granularity: Choose the right statistics method based on your needs:
- Daily: For hourly monitoring and detailed analysis
- Monthly: For daily trends within a month
- Yearly: For monthly trends and yearly comparisons
- Total: For lifetime historical data
Handle rate limits: If fetching statistics for multiple devices, add delays between requests:
use tokio::time::{sleep, Duration};
for mix_sn in mix_serial_numbers {
let stats = client.get_energy_stats_daily(&today, plant_id, &mix_sn).await?;
process_stats(stats);
// Small delay to avoid rate limiting
sleep(Duration::from_millis(500)).await;
}
Validate date formats: Always validate date parameters before making API calls:
use chrono::NaiveDate;
fn validate_and_fetch_daily(
client: &mut Growatt,
date_str: &str,
plant_id: &str,
mix_sn: &str,
) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
// Validate date format
NaiveDate::parse_from_str(date_str, "%Y-%m-%d")?;
// Fetch statistics
let stats = client.get_energy_stats_daily(date_str, plant_id, mix_sn).await?;
Ok(stats)
}
Error Handling
Properly handle errors when fetching energy statistics:use growatt::GrowattError;
match client.get_energy_stats_daily(&date, plant_id, mix_sn).await {
Ok(stats) => {
println!("Successfully retrieved statistics");
process_statistics(stats);
}
Err(GrowattError::InvalidResponse(msg)) => {
eprintln!("Invalid response (may indicate no data for this period): {}", msg);
}
Err(GrowattError::NotLoggedIn) => {
eprintln!("Session expired, re-authenticating...");
client.login(username, password).await?;
}
Err(e) => {
eprintln!("Error fetching statistics: {}", e);
}
}
API Methods Reference
All energy statistics methods follow this pattern:// Daily statistics (hourly data points)
pub async fn get_energy_stats_daily(
&mut self,
date: &str, // Format: "YYYY-MM-DD"
plant_id: &str,
mix_sn: &str
) -> Result<serde_json::Value>
// Monthly statistics (daily data points)
pub async fn get_energy_stats_monthly(
&mut self,
date: &str, // Format: "YYYY-MM"
plant_id: &str,
mix_sn: &str
) -> Result<serde_json::Value>
// Yearly statistics (monthly data points)
pub async fn get_energy_stats_yearly(
&mut self,
year: &str, // Format: "YYYY"
plant_id: &str,
mix_sn: &str
) -> Result<serde_json::Value>
// Total statistics (yearly data points)
pub async fn get_energy_stats_total(
&mut self,
year: &str, // Format: "YYYY"
plant_id: &str,
mix_sn: &str
) -> Result<serde_json::Value>
// Battery statistics (weekly data)
pub async fn get_weekly_battery_stats(
&mut self,
plant_id: &str,
mix_sn: &str
) -> Result<serde_json::Value>