coapum_senml/lib.rs
1//! # CoAPum SenML - Sensor Measurement Lists for Rust
2//!
3//! A Rust implementation of [RFC 8428](https://tools.ietf.org/html/rfc8428) - Sensor Measurement Lists (SenML).
4//!
5//! SenML is a format for representing simple sensor measurements and device parameters
6//! in a structured way. This crate provides type-safe handling of SenML data with
7//! support for multiple serialization formats including JSON, CBOR, and XML.
8//!
9//! ## Features
10//!
11//! - **RFC 8428 Compliant**: Full support for SenML specification
12//! - **Multiple Formats**: JSON, CBOR, XML serialization support
13//! - **Type Safety**: Strongly typed sensor data with validation
14//! - **Normalization**: Convert SenML packs to resolved form
15//! - **Builder Pattern**: Ergonomic API for creating SenML data
16//! - **Time Series**: Specialized support for time-series sensor data
17//!
18//! ## Quick Start
19//!
20//! ```rust
21//! use coapum_senml::{SenMLPack, SenMLRecord, SenMLBuilder, Result};
22//!
23//! fn example() -> Result<()> {
24//! // Create a simple temperature reading
25//! let pack = SenMLBuilder::new()
26//! .base_name("urn:dev:sensor1")
27//! .base_unit("Cel")
28//! .add_value("temperature", 22.5)
29//! .build();
30//!
31//! // Serialize to JSON
32//! let json = pack.to_json()?;
33//! println!("{}", json);
34//! Ok(())
35//! }
36//! ```
37//!
38//! ## SenML Data Model
39//!
40//! SenML represents sensor data as an array of records, where each record can contain:
41//! - **Base fields**: Apply to multiple records (bn, bt, bu, bv, bs, bver)
42//! - **Record fields**: Individual measurements (n, u, v, vs, vb, vd, s, t, ut)
43//!
44//! Base fields reduce redundancy by providing default values that apply to
45//! subsequent records in the pack.
46
47pub mod builder;
48pub mod error;
49pub mod normalize;
50pub mod pack;
51pub mod record;
52
53#[cfg(feature = "validation")]
54pub mod validation;
55
56#[cfg(feature = "json")]
57pub mod json;
58
59#[cfg(feature = "cbor")]
60pub mod cbor;
61
62#[cfg(feature = "xml")]
63pub mod xml;
64
65// Re-export main types
66pub use builder::SenMLBuilder;
67pub use error::{Result, SenMLError};
68pub use normalize::{NormalizedPack, NormalizedRecord};
69pub use pack::SenMLPack;
70pub use record::{SenMLRecord, SenMLValue};
71
72#[cfg(feature = "validation")]
73pub use validation::Validate;
74
75/// SenML Content-Format identifiers for CoAP
76pub mod content_format {
77 /// application/senml+json
78 pub const SENML_JSON: u16 = 110;
79 /// application/sensml+json
80 pub const SENSML_JSON: u16 = 111;
81 /// application/senml+cbor
82 pub const SENML_CBOR: u16 = 112;
83 /// application/sensml+cbor
84 pub const SENSML_CBOR: u16 = 113;
85 /// application/senml-exi
86 pub const SENML_EXI: u16 = 114;
87 /// application/sensml-exi
88 pub const SENSML_EXI: u16 = 115;
89 /// application/senml+xml
90 pub const SENML_XML: u16 = 310;
91 /// application/sensml+xml
92 pub const SENSML_XML: u16 = 311;
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_basic_senml_creation() {
101 let pack = SenMLBuilder::new()
102 .base_name("urn:dev:sensor1")
103 .add_value("temperature", 22.5)
104 .build();
105
106 assert!(pack.records.len() == 2); // Base record + measurement record
107 // Check that base name was stored in the first record
108 assert_eq!(pack.records[0].n, Some("urn:dev:sensor1".to_string()));
109 // Check that measurement record exists
110 assert_eq!(pack.records[1].v, Some(22.5));
111 }
112}