# Zigbee2mqtt types This is an auto generated lib containing concrete types that can easily deserialise any json MQTT payloads from zigbee2mqtt. ## How to use To speed up compile time all structs are behind feature flags, these are split into vendors e.g. if you are using a sensor by xiaomi then you will need to add the xiaomi feature to your Cargo.toml like `zigbee2mqtt-types = {features = ["xiaomi"]}` Example of using [a door contact sensor](https://www.zigbee2mqtt.io/devices/MCCGQ11LM.html) (note: debug is also a feature) add `zigbee2mqtt-types = {features = ["debug", "xiaomi"]}` to Cargo.toml dependencies ```rust use zigbee2mqtt_types::xiaomi::ZigbeeMccgq11lm; #[test] fn contact_sensor_mccgq11lm() { //https://www.zigbee2mqtt.io/devices/MCCGQ11LM.html let json = serde_json::json!({ "voltage": 2995, "battery": 97, "device_temperature": 19, "power_outage_count": 6, "linkquality": 247, "contact": false, }) .to_string(); let parsed: ZigbeeMccgq11lm = match serde_json::from_str(&json) { Ok(contact) => contact, Err(err) => { println!("{:?}", err); assert!(false); } }; assert_eq!(2995, parsed.voltage); assert_eq!(97, parsed.battery); assert_eq!(19, parsed.device_temperature); assert_eq!(6, parsed.power_outage_count); assert_eq!(247, parsed.linkquality); assert_eq!(false, parsed.contact); } ``` Zigbee2MQTT has two [additional options](https://www.zigbee2mqtt.io/guide/configuration/mqtt.html#mqtt-behaviour) that add data to the JSON, 1) elapsed, 2) last_seen. There is a feature flag to also convert these to their static types (**Note**: Atm I am converting timestamps to String, I didn't want to way into converting the string into a real time struct I'm sorry. PR welcome, but I fear devils are awaiting) 1) Elapsed can be enabled with feature = `elapsed` and it gets converted to a `elapsed: u64` 2) Last_seen can be iso_8601(local and utc) or epoch. Note: A parse error will be thrown if these features are enabled but the field is not present in the json - For either of the iso use feature = `last_seen_iso_8601` and it gets converted to a `last_seen: String` - For epoch use feature = `last_seen_epoch` and it gets converted to a `last_seen: u64` - **Note**: last_seen features are mutually exclusive as they both resolve to the same struct field just with different types, this does break Rust convention but I see no real use case that both would be enabled. If you have one please open an issue and I can look at a way to make it not mutually exclusive These features manifest like so ```rust use zigbee2mqtt_types::xiaomi::ZigbeeMccgq11lm; #[test] fn contact_sensor_mccgq11lm_last_seen_iso_8601_elapsed() { //https://www.zigbee2mqtt.io/devices/MCCGQ11LM.html let json = serde_json::json!({ "voltage": 2995, "battery": 97, "device_temperature": 19, "last_seen": "2022_10_20T11:55:07.199z", // zigbee2mqtt last_seen setting in ISO_8601 mode "power_outage_count": 6, "linkquality": 247, "contact": false, "elapsed": 2547593 // zigbee2mqtt elapsed setting true }) .to_string(); let parsed: ZigbeeMccgq11lm = match serde_json::from_str(&json) { Ok(contact) => contact, Err(err) => { println!("{:?}", err); // with last_seen or elapsed feature flags turned on a parse errr will be thrown if not present in the json assert!(false); } }; assert_eq!("2022_10_20T11:55:07.199z", parsed.last_seen); // last_seen parsed to a string assert_eq!(2547593, parsed.elapsed); // elapsed parsed to a u64 assert_eq!(2995, parsed.voltage); assert_eq!(97, parsed.battery); assert_eq!(19, parsed.device_temperature); assert_eq!(6, parsed.power_outage_count); assert_eq!(247, parsed.linkquality); assert_eq!(false, parsed.contact); } ``` ## Some gotchas ### Model/Vendor names 1 gotcha is all not all model/vendor names strings conform to Rusts struct/package naming convention, so I needed todo some transformation to them. Models roughly remove all invalid chars and have Zigbee infront of them. Vendors have an `_` in place of any invalid chars example of changes to models ```txt "ZS057-D0Z" = "ZigbeeZs057Dd0z" "BF 265" = "ZigbeeBf265" "5110.40" = "Zigbee5110F40" "MEAZON_BIZY_PLUG" = "ZigbeeMeazonUbizyUplug" ``` example of changes to vendors ```txt "Eaton/Halo LED" = "eaton_halo_led" "Custom devices (DiY)" = "custom_devices__diy_" "Villeroy & Boch" = "villeroy___boch" "J.XUAN" = "j_xuan" // the bellow is just removing non ascii chars I would personally prefer to swap them for similar ascii but for now I will _ "Müller Licht" = "m_ller_licht" "Sinopé" = "sinop_" ``` Model function that does conversion is [here](https://gitlab.com/seam345/zigbee2mqtt-types/-/blob/2966e202ede466085392acbeea77c647c508dd36/src/bin/generate.rs#L214) Vendor function that does conversion is [here](https://gitlab.com/seam345/zigbee2mqtt-types/-/blob/2966e202ede466085392acbeea77c647c508dd36/src/bin/generate.rs#L77) ### Composite values I currently don't parse object values so color on the philips light in mqtt it is `"color": {"hue":25,"saturation":95,"x":0.5267,"y":0.4133}`, in short anything with a `{` in the value is not parsed. This will be fixed in a future update I just wanted to reduce scope ## Why While creating a recent project I found myself being lazy with how I was defining my structs to consume MQTT payloads and given they are already defined in Zigbee2MQTT I went looking for a way to generate them programmatically. ## Contributions All development should be in the top level generator binary as [zigbee-herdsman](https://github.com/Koenkk/zigbee-herdsman-converters.git) updates too frequently to maintain human updating of this lib. Atm I don't have this generating wit CI but at some point I plan to that to keep this up to date with [zigbee-herdsman](https://github.com/Koenkk/zigbee-herdsman-converters.git) ## Future goals - [ ] improve lib documentation - [ ] some sort of type extension to allow last seen to be correctly parsed - [ ] add get set methods Up to date issues can be seen here https://gitlab.com/seam345/zigbee2mqtt-types/-/issues