Skip to main content

energy_api/
lib.rs

1#![deny(unsafe_code)]
2#![deny(missing_docs)]
3//! # energy-api
4//!
5//! Rust client and server bindings for the German energy market API-Webdienste
6//! (MaKo — Marktkommunikation).
7//!
8//! ## Module layout
9//!
10//! ```text
11//! energy_api
12//! ├── models/       OpenAPI/AsyncAPI types shared by all APIs
13//! ├── transport/    HTTP + mTLS builder, JWS sign/verify
14//! ├── directory/    Verzeichnisdienst — REST client, WebSocket client, server
15//! ├── client/       Electricity API clients  (feature = "client")
16//! │   ├── control_measures   NB/LF and MSB send calls
17//! │   └── malo_ident         LF and NB callback calls
18//! └── server/       Electricity API servers  (feature = "server")
19//!     ├── control_measures   MSB and NB/LF receive handlers + axum router
20//!     ├── malo_ident         NB and LF receive handlers + axum router
21//!     └── wim_order          MSB receive handler (iMS Anmeldung) + NB callbacks
22//! ```
23//!
24//! ## Feature flags
25//!
26//! | Feature     | Enables                                                  |
27//! |-------------|----------------------------------------------------------|
28//! | `client`    | HTTP clients for all APIs (reqwest + rustls)             |
29//! | `server`    | Axum router factories for server implementations         |
30//! | `websocket` | WebSocket subscription client (tokio-tungstenite)        |
31//! | `crypto`    | JWS ECDSA-SHA256 sign/verify for directory records (p256)|
32//!
33//! ## Quick start
34//!
35//! ### Look up an endpoint via the directory
36//!
37//! ```no_run
38//! # #[cfg(feature = "client")]
39//! # async fn example() -> Result<(), energy_api::Error> {
40//! use energy_api::directory::DirectoryServiceClient;
41//! use url::Url;
42//!
43//! let base = Url::parse("https://verzeichnisdienst.example.de/")?;
44//! let client = DirectoryServiceClient::new_insecure(base)?;
45//! let (record, _cert, _sig) = client
46//!     .get_record("1234567890723", "controlMeasuresV1", 1)
47//!     .await?;
48//! println!("{}", record.url);
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! ### Send a grid control command
54//!
55//! ```no_run
56//! # #[cfg(feature = "client")]
57//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
58//! use energy_api::client::ControlMeasuresClient;
59//! use energy_api::models::electricity::{
60//!     CommandControl, LocationId, NeloId, MaximumPowerValue,
61//! };
62//! use url::Url;
63//! use uuid::Uuid;
64//!
65//! let client = ControlMeasuresClient::new(
66//!     Url::parse("https://msb.example.de/")?,
67//!     reqwest::Client::new(),
68//! );
69//! client.send_konfiguration(
70//!     Uuid::new_v4(),
71//!     "2025-06-01T10:00:00.000Z",
72//!     // `NeloId::new` validates the ASCII-Verfahren check digit.
73//!     &LocationId::NetworkLocation(NeloId::new("E1234848431")?),
74//!     &CommandControl {
75//!         maximum_power_value: MaximumPowerValue("10.5".into()),
76//!         execution_time_from: "2025-06-01T10:00:00Z".into(),
77//!         execution_time_until: None,
78//!     },
79//!     None,
80//! ).await?;
81//! # Ok(())
82//! # }
83//! ```
84
85#![allow(clippy::too_many_arguments)]
86#![allow(clippy::large_enum_variant)]
87
88pub mod directory;
89pub mod error;
90pub mod models;
91pub mod spec_version;
92pub mod transport;
93
94#[cfg(feature = "client")]
95pub mod client;
96
97#[cfg(feature = "server")]
98pub mod server;
99
100pub use error::Error;