Method Signature
pub async fn get_weather(&mut self, plant_id: &str) -> Result<serde_json::Value>
Description
Retrieves weather and environmental data for the specified plant location. This includes information from environmental monitoring devices such as temperature sensors, irradiance meters, and other weather monitoring equipment installed at the plant site. This method automatically handles authentication by checking the current session and re-authenticating if necessary.
Parameters
The unique identifier of the plant. This ID can be obtained from the get_plants() method.
Return Type
Returns Result<serde_json::Value> where:
- Success:
serde_json::Value - JSON object containing weather and environmental data
- Error:
GrowattError - See error cases below
Response Structure
The response is returned as a raw serde_json::Value because the structure may vary depending on the environmental devices installed at the plant. Common fields include:
Container object for the environment listArray of environmental monitoring devices and their readingsSerial number of the environmental monitoring device
Type of environmental device (e.g., “ENV”, “WEATHER”)
Current temperature in degrees Celsius (if available)
Solar irradiance in W/m² (if available)
Wind speed in m/s (if available)
Relative humidity percentage (if available)
Code Examples
Basic Usage
use growatt_api::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
// Login first
client.login("username", "password").await?;
// Get weather data
let weather = client.get_weather("1234567").await?;
// Print the raw JSON response
println!("Weather data: {}", serde_json::to_string_pretty(&weather)?);
Ok(())
}
use growatt_api::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("username", "password").await?;
let weather = client.get_weather("1234567").await?;
// Extract environmental data
if let Some(obj) = weather.get("obj") {
if let Some(datas) = obj.get("datas").and_then(|d| d.as_array()) {
for device in datas {
if let Some(sn) = device.get("deviceSn").and_then(|s| s.as_str()) {
println!("\nDevice: {}", sn);
}
if let Some(temp) = device.get("temperature").and_then(|t| t.as_f64()) {
println!(" Temperature: {:.1}°C", temp);
}
if let Some(irr) = device.get("irradiance").and_then(|i| i.as_f64()) {
println!(" Irradiance: {:.1} W/m²", irr);
}
if let Some(humid) = device.get("humidity").and_then(|h| h.as_f64()) {
println!(" Humidity: {:.1}%", humid);
}
}
}
}
Ok(())
}
Check Weather for All Plants
use growatt_api::Growatt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("username", "password").await?;
// Get all plants
let plants = client.get_plants().await?;
// Check weather for each plant
for plant in plants.0.iter() {
println!("\n=== {} ===", plant.plant_name);
match client.get_weather(&plant.plant_id).await {
Ok(weather) => {
// Process weather data
if let Some(obj) = weather.get("obj") {
if let Some(datas) = obj.get("datas").and_then(|d| d.as_array()) {
if datas.is_empty() {
println!("No environmental devices found");
} else {
println!("Environmental devices: {}", datas.len());
}
}
}
}
Err(e) => {
eprintln!("Error fetching weather: {}", e);
}
}
}
Ok(())
}
Create Custom Weather Struct
use growatt_api::Growatt;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct EnvironmentalDevice {
#[serde(rename = "deviceSn")]
device_sn: Option<String>,
temperature: Option<f64>,
irradiance: Option<f64>,
humidity: Option<f64>,
#[serde(rename = "windSpeed")]
wind_speed: Option<f64>,
}
#[derive(Debug, Deserialize)]
struct WeatherResponse {
obj: Option<WeatherObj>,
}
#[derive(Debug, Deserialize)]
struct WeatherObj {
datas: Option<Vec<EnvironmentalDevice>>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("username", "password").await?;
let weather_json = client.get_weather("1234567").await?;
// Deserialize into custom struct
let weather: WeatherResponse = serde_json::from_value(weather_json)?;
if let Some(obj) = weather.obj {
if let Some(devices) = obj.datas {
for device in devices {
println!("Device: {:?}", device.device_sn);
println!(" Temp: {:?}°C", device.temperature);
println!(" Irradiance: {:?} W/m²", device.irradiance);
}
}
}
Ok(())
}
Monitoring Loop with Weather Data
use growatt_api::Growatt;
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Growatt::new();
client.login("username", "password").await?;
let plant_id = "1234567";
loop {
// Get plant data and weather simultaneously
let plant_data = client.get_plant(plant_id).await?;
let weather = client.get_weather(plant_id).await?;
println!("\n[{}]", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"));
if let Some(power) = plant_data.current_power {
println!("Power: {:.2} W", power);
}
if let Some(obj) = weather.get("obj") {
if let Some(datas) = obj.get("datas").and_then(|d| d.as_array()) {
for device in datas {
if let Some(temp) = device.get("temperature").and_then(|t| t.as_f64()) {
println!("Temperature: {:.1}°C", temp);
}
if let Some(irr) = device.get("irradiance").and_then(|i| i.as_f64()) {
println!("Irradiance: {:.1} W/m²", irr);
}
}
}
}
sleep(Duration::from_secs(300)).await; // 5 minutes
}
}
Error Cases
The method may return the following errors:
GrowattError::NotLoggedIn
Thrown when the session is invalid and no credentials are stored for automatic re-authentication.
GrowattError::NotLoggedIn
Solution: Call login() with valid credentials before calling this method.
GrowattError::InvalidResponse
Thrown when the API returns an empty response or null data.
GrowattError::InvalidResponse("Empty response. Please ensure you are logged in.")
Common causes:
- Invalid plant ID
- Session expired during the request
- Plant does not have any environmental monitoring devices installed
- Plant does not exist or is not accessible to the authenticated user
GrowattError::RequestError
Thrown when the HTTP request fails due to network issues or server problems.
GrowattError::RequestError(reqwest::Error)
Common causes:
- Network connectivity issues
- Growatt server is down or unreachable
- Request timeout
GrowattError::JsonError
Thrown when the response cannot be parsed as valid JSON.
GrowattError::JsonError(serde_json::Error)
Common causes:
- Corrupted response data
- Server returned non-JSON content
Implementation Details
API Endpoint
POST {base_url}/device/getEnvList
Default base URL: https://server.growatt.com
Request Parameters
The method sends a form-encoded POST request with:
plantId: The plant identifier
currPage: Set to “1” (pagination support)
The API response structure varies based on the environmental devices installed. A typical response:
{
"obj": {
"datas": [
{
"deviceSn": "ENV12345",
"deviceType": "ENV",
"temperature": 25.5,
"irradiance": 850.0,
"humidity": 65.0,
"windSpeed": 3.2
}
],
"count": 1
}
}
If no environmental devices are installed, the response may be:
{
"obj": {
"datas": [],
"count": 0
}
}
Authentication
This method automatically calls check_login() before making the API request, which:
- Checks if the current session is valid
- Re-authenticates using stored credentials if the session expired
- Returns
NotLoggedIn error if no credentials are available
Why serde_json::Value?
The method returns serde_json::Value instead of a strongly-typed struct because:
- Environmental device configurations vary significantly between installations
- The API may return different field sets based on device capabilities
- This provides maximum flexibility for parsing device-specific data
- Users can deserialize into custom structs that match their specific equipment