Skip to main content

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:
  1. A plant ID (from get_plants())
  2. 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 in YYYY-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 in YYYY-MM format:
// Using current month
let current_month = chrono::Local::now().format("%Y-%m").to_string();
let monthly_stats = client.get_energy_stats_monthly(&current_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(&current_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 return serde_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>

Build docs developers (and LLMs) love