Expand description
§SunSpec Rust Implementation
This Rust crate contains code for accessing SunSpec compliant devices in a safe and convenient way.
§Highlights
- Pure Rust library
- No unsafe code
- Panic free
- All communication is done via tokio-modbus without wrapping it in some kind of abstraction layer.
-
Supports Modbus TCP and RTU (via
tokio-modbus
). - Implements “Device Information Model Discovery” as defined in the SunSpec specification.
- Fully typed models generated from the JSON files contained in the SunSpec models repository
- Fully typed enums
- Fully typed bitfields
- Fully documented. Even the generated models.
- Reading of complete models in a single request.
Nested and repeating groups are not supported, yet.
§Features
Feature | Description | Extra dependencies | Default |
---|---|---|---|
tokio | Enable tokio_modbus support | tokio-modbus | yes |
§Examples
The examples
directory in the code repository contains the unabridged code.
§Example code for accessing data from a three phase inverter using the model 103
ⓘ
use std::{error::Error, net::SocketAddr, time::Duration};
use clap::Parser;
use itertools::Itertools;
use sunspec::tokio_modbus::{discover_models, read_model};
use tokio::time::sleep;
use tokio_modbus::{client::tcp::connect_slave, Slave};
#[derive(Parser)]
struct Args {
addr: SocketAddr,
device_id: u8,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
let mut ctx = connect_slave(args.addr, Slave(args.device_id)).await?;
let models = discover_models(&mut ctx).await?.models;
let m1 = read_model(&mut ctx, &models.m1).await?;
println!("Manufacturer: {}", m1.mn);
println!("Model: {}", m1.md);
println!("Version: {}", m1.vr.as_deref().unwrap_or("(unspecified)"));
println!("Serial Number: {}", m1.sn);
println!(
"Supported models: {}",
models
.supported_model_ids()
.iter()
.map(|id| id.to_string())
.join(", ")
);
loop {
let m103 = read_model(&mut ctx, &models.m103).await?;
let w = m103.w as f32 * 10f32.powf(m103.w_sf.into());
let wh = m103.wh as f32 * 10f32.powf(m103.wh_sf.into());
println!("{:12.3} kWh {:9.3} kW", wh / 1000.0, w / 1000.0,);
sleep(Duration::from_secs(1)).await;
}
}
§FAQ
How does this crate differ from crates like tokio-sunspec
, sunspec-models
, sunspec_rs
?
-
This crate generates all code using Rust code via the official SunSpec models repository with a code generator that was written in Rust, too.
-
All generated models are plain Rust structs. A single Modbus call can return the complete data for a model rather than having to fetch points individually.
-
All public types are documented. Even the generated models.
§License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Re-exports§
pub use models::Models;
Modules§
- This module contains all the genererated SunSpec models.
- This module contains the actual communication methods via
tokio-modbus
.
Structs§
- The result of a SunSpec model discovery.
- This structure is used to store the address of models after a successful model discovery.
- Definition of a point
- For every discovered but unknown model to this library this structure is returned.
Enums§
- This error is returned if there was an error decoding the value of a given point.
- This error is returned when an error occurs during model discovery.
- This error is returned if there was an error loading the requested model.
- This error is returned if there was an error while reading data from a point.
- This error is returned if there was an error while writing data to a point.
Constants§
- “SunS” identifier used when performing the model discovery.
Traits§
- This trait marks points with a fixed size. All non-string values are actually fixed size.
- Every model implements this trait which contains methods for accessing
- This trait contains all the conversion methods needed for working with points of the SunSpec models.