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 abstracted via traits making it runtime agnostic
- Supports Modbus TCP and RTU (via tokio-modbus).
-
tokio-modbusis optional. Custom transports can implement the client trait directly. - Implements "Device Information Model Discovery" as defined in the SunSpec specification.
- Compile-time model selection via Cargo features
- 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.
- Supports nested and repeating groups.
- Unknown or unsupported models are reported during discovery.
Features
| Feature | Description | Extra dependencies | Default |
|---|---|---|---|
tokio |
Enable tokio-based timeouts | tokio, tokio/time |
yes |
tokio-modbus |
Enable tokio-modbus support |
tokio-modbus, tokio |
yes |
serde |
Enable serde support |
serde, bitflags/serde |
yes |
all-models |
Enable all generated models | model1, model2, ... |
yes |
model<X> |
Enable generated model X |
none | yes |
If you only need a small subset of models, disable default features and opt in to the features and specific models you need:
[]
= { = "...", = false, = ["tokio-modbus", "model1", "model103"] }
Examples
The examples directory in the code repository contains the unabridged code.
examples/readme: minimal end-to-end example used in this READMEexamples/model103: reading a common inverter model from a deviceexamples/model712: reading a model with nested and repeating groups
Example code for accessing data from a three phase inverter using the model 103
use ;
use Parser;
use Itertools;
use ;
use sleep;
use connect;
async
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.
-
Full support for nested and repeating groups.
How do I reduce compile times or binary size?
- Disable default features and enable only the features you need.
- This is is useful if you interact only with a small number of models.
Do I have to use tokio-modbus?
- No.
tokio-modbusis just the bundled transport adapter. - You can provide your own transport by implementing the async client trait and
constructing an
AsyncClientwith it. - The separate
tokiofeature only controls tokio-based timeout handling.
What happens if a device exposes models this crate does not know?
- Discovery still succeeds.
- Known models are stored in
device.models. - Unknown model ids, addresses, and lengths are returned in
device.unknown_models.
Can I scan for all slave IDs on a bus?
- Yes.
AsyncClient::devices()probes slave ids0..=255and returns every device that responds with a valid SunSpec header. - If you already know the slave id, use
AsyncClient::device(slave_id)instead.
How do discovery addresses and timeouts work?
- The default discovery addresses are
[40000, 0, 50000]. - That order avoids unnecessary timeouts on devices that do not behave well at
address
0. - You can override discovery addresses and read/write timeouts via
Config.
How are large models handled?
- Models larger than the Modbus single-request limit are read in chunks and then decoded as one typed model value.
- Nested groups and repeating groups are handled by the generated model code.
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.