1use bytes::Buf;
10
11use crate::error::{Error, Result};
12use aranet_types::{CurrentReading, DeviceType, Status};
13
14#[derive(Debug, Clone)]
22pub struct ExtendedReading {
23 pub reading: CurrentReading,
25 pub radiation_duration: Option<u64>,
27}
28
29pub fn parse_aranet4_reading(data: &[u8]) -> Result<CurrentReading> {
41 CurrentReading::from_bytes(data).map_err(|e| Error::InvalidData(e.to_string()))
42}
43
44pub fn parse_aranet2_reading(data: &[u8]) -> Result<CurrentReading> {
53 if data.len() < 7 {
54 return Err(Error::InvalidData(format!(
55 "Aranet2 reading requires 7 bytes, got {}",
56 data.len()
57 )));
58 }
59
60 let mut buf = data;
61 let temp_raw = buf.get_u16_le();
62 let humidity = buf.get_u8();
63 let battery = buf.get_u8();
64 let status = Status::from(buf.get_u8());
65 let interval = buf.get_u16_le();
66
67 Ok(CurrentReading {
68 co2: 0, temperature: temp_raw as f32 / 20.0,
70 pressure: 0.0, humidity,
72 battery,
73 status,
74 interval,
75 age: 0,
76 captured_at: None,
77 radon: None,
78 radiation_rate: None,
79 radiation_total: None,
80 radon_avg_24h: None,
81 radon_avg_7d: None,
82 radon_avg_30d: None,
83 })
84}
85
86pub fn parse_aranet_radon_reading(data: &[u8]) -> Result<ExtendedReading> {
90 if data.len() < 15 {
91 return Err(Error::InvalidData(format!(
92 "Aranet Radon reading requires 15 bytes, got {}",
93 data.len()
94 )));
95 }
96
97 let mut buf = data;
98
99 let co2 = buf.get_u16_le();
101 let temp_raw = buf.get_u16_le();
102 let pressure_raw = buf.get_u16_le();
103 let humidity = buf.get_u8();
104 let battery = buf.get_u8();
105 let status = Status::from(buf.get_u8());
106 let interval = buf.get_u16_le();
107 let age = buf.get_u16_le();
108
109 let radon = buf.get_u16_le() as u32;
111
112 let reading = CurrentReading {
113 co2,
114 temperature: temp_raw as f32 / 20.0,
115 pressure: pressure_raw as f32 / 10.0,
116 humidity,
117 battery,
118 status,
119 interval,
120 age,
121 captured_at: None,
122 radon: Some(radon),
123 radiation_rate: None,
124 radiation_total: None,
125 radon_avg_24h: None,
126 radon_avg_7d: None,
127 radon_avg_30d: None,
128 };
129
130 Ok(ExtendedReading {
131 reading,
132 radiation_duration: None,
133 })
134}
135
136pub fn parse_aranet_radon_gatt(data: &[u8]) -> Result<CurrentReading> {
158 if data.len() < 18 {
159 return Err(Error::InvalidData(format!(
160 "Aranet Radon GATT reading requires at least 18 bytes, got {}",
161 data.len()
162 )));
163 }
164
165 let mut buf = data;
166
167 let _device_type = buf.get_u16_le(); let interval = buf.get_u16_le();
170 let age = buf.get_u16_le();
171 let battery = buf.get_u8();
172
173 let temp_raw = buf.get_u16_le();
175 let pressure_raw = buf.get_u16_le();
176 let humidity_raw = buf.get_u16_le();
177 let radon = buf.get_u32_le();
178 let status = if buf.has_remaining() {
179 Status::from(buf.get_u8())
180 } else {
181 Status::Green
182 };
183
184 let (radon_avg_24h, radon_avg_7d, radon_avg_30d) = if buf.remaining() >= 24 {
188 let _time_24h = buf.get_u32_le();
189 let avg_24h_raw = buf.get_u32_le();
190 let _time_7d = buf.get_u32_le();
191 let avg_7d_raw = buf.get_u32_le();
192 let _time_30d = buf.get_u32_le();
193 let avg_30d_raw = buf.get_u32_le();
194
195 let avg_24h = if avg_24h_raw >= 0xff00_0000 {
197 None
198 } else {
199 Some(avg_24h_raw)
200 };
201 let avg_7d = if avg_7d_raw >= 0xff00_0000 {
202 None
203 } else {
204 Some(avg_7d_raw)
205 };
206 let avg_30d = if avg_30d_raw >= 0xff00_0000 {
207 None
208 } else {
209 Some(avg_30d_raw)
210 };
211
212 (avg_24h, avg_7d, avg_30d)
213 } else {
214 (None, None, None)
215 };
216
217 Ok(CurrentReading {
218 co2: 0,
219 temperature: temp_raw as f32 / 20.0,
220 pressure: pressure_raw as f32 / 10.0,
221 humidity: (humidity_raw / 10).min(255) as u8, battery,
223 status,
224 interval,
225 age,
226 captured_at: None,
227 radon: Some(radon),
228 radiation_rate: None,
229 radiation_total: None,
230 radon_avg_24h,
231 radon_avg_7d,
232 radon_avg_30d,
233 })
234}
235
236pub fn parse_aranet_radiation_gatt(data: &[u8]) -> Result<ExtendedReading> {
248 if data.len() < 28 {
249 return Err(Error::InvalidData(format!(
250 "Aranet Radiation GATT reading requires at least 28 bytes, got {}",
251 data.len()
252 )));
253 }
254
255 let mut buf = data;
256
257 buf.advance(2);
259
260 let interval = buf.get_u16_le();
261 let age = buf.get_u16_le();
262 let battery = buf.get_u8();
263
264 let dose_rate_nsv = buf.get_u32_le();
266 let dose_rate_usv = dose_rate_nsv as f32 / 1000.0;
267
268 let total_dose_nsv = buf.get_u64_le();
270 let total_dose_msv = total_dose_nsv as f64 / 1_000_000.0;
271
272 let duration = buf.get_u64_le();
274
275 let status = if buf.has_remaining() {
276 Status::from(buf.get_u8())
277 } else {
278 Status::Green
279 };
280
281 let reading = CurrentReading {
282 co2: 0,
283 temperature: 0.0,
284 pressure: 0.0,
285 humidity: 0,
286 battery,
287 status,
288 interval,
289 age,
290 captured_at: None,
291 radon: None,
292 radiation_rate: Some(dose_rate_usv),
293 radiation_total: Some(total_dose_msv),
294 radon_avg_24h: None,
295 radon_avg_7d: None,
296 radon_avg_30d: None,
297 };
298
299 Ok(ExtendedReading {
300 reading,
301 radiation_duration: Some(duration),
302 })
303}
304
305pub fn parse_reading_for_device(data: &[u8], device_type: DeviceType) -> Result<CurrentReading> {
307 match device_type {
308 DeviceType::Aranet4 => parse_aranet4_reading(data),
309 DeviceType::Aranet2 => parse_aranet2_reading(data),
310 DeviceType::AranetRadon => parse_aranet_radon_reading(data).map(|ext| ext.reading),
311 DeviceType::AranetRadiation => parse_aranet_radiation_gatt(data).map(|ext| ext.reading),
312 _ => parse_aranet4_reading(data),
314 }
315}
316
317pub fn parse_extended_reading(data: &[u8], device_type: DeviceType) -> Result<ExtendedReading> {
319 match device_type {
320 DeviceType::Aranet4 => {
321 let reading = parse_aranet4_reading(data)?;
322 Ok(ExtendedReading {
323 reading,
324 radiation_duration: None,
325 })
326 }
327 DeviceType::Aranet2 => {
328 let reading = parse_aranet2_reading(data)?;
329 Ok(ExtendedReading {
330 reading,
331 radiation_duration: None,
332 })
333 }
334 DeviceType::AranetRadon => parse_aranet_radon_reading(data),
335 DeviceType::AranetRadiation => parse_aranet_radiation_gatt(data),
336 _ => {
338 let reading = parse_aranet4_reading(data)?;
339 Ok(ExtendedReading {
340 reading,
341 radiation_duration: None,
342 })
343 }
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350
351 #[test]
354 fn test_parse_aranet2_reading() {
355 let data: [u8; 7] = [
361 0xC2, 0x01, 55, 90, 1, 0x2C, 0x01, ];
367
368 let reading = parse_aranet2_reading(&data).unwrap();
369 assert_eq!(reading.co2, 0);
370 assert!((reading.temperature - 22.5).abs() < 0.01);
371 assert_eq!(reading.humidity, 55);
372 assert_eq!(reading.battery, 90);
373 assert_eq!(reading.status, Status::Green);
374 assert_eq!(reading.interval, 300);
375 }
376
377 #[test]
378 fn test_parse_aranet2_reading_all_status_values() {
379 for (status_byte, expected_status) in [
381 (0, Status::Error),
382 (1, Status::Green),
383 (2, Status::Yellow),
384 (3, Status::Red),
385 (4, Status::Error), ] {
387 let data: [u8; 7] = [
388 0xC2,
389 0x01, 55,
391 90,
392 status_byte,
393 0x2C,
394 0x01,
395 ];
396
397 let reading = parse_aranet2_reading(&data).unwrap();
398 assert_eq!(reading.status, expected_status);
399 }
400 }
401
402 #[test]
403 fn test_parse_aranet2_reading_insufficient_bytes() {
404 let data: [u8; 5] = [0xC2, 0x01, 55, 90, 1]; let result = parse_aranet2_reading(&data);
407 assert!(result.is_err());
408
409 let err = result.unwrap_err();
410 assert!(err.to_string().contains("requires 7 bytes"));
411 assert!(err.to_string().contains("got 5"));
412 }
413
414 #[test]
415 fn test_parse_aranet2_reading_edge_values() {
416 let data: [u8; 7] = [
418 0x00, 0x00, 0, 0, 0, 0x00, 0x00, ];
424
425 let reading = parse_aranet2_reading(&data).unwrap();
426 assert_eq!(reading.co2, 0);
427 assert!((reading.temperature - 0.0).abs() < 0.01);
428 assert_eq!(reading.humidity, 0);
429 assert_eq!(reading.battery, 0);
430 assert_eq!(reading.status, Status::Error);
431 assert_eq!(reading.interval, 0);
432 }
433
434 #[test]
435 fn test_parse_aranet2_reading_max_values() {
436 let data: [u8; 7] = [
437 0xFF, 0xFF, 255, 100, 3, 0xFF, 0xFF, ];
443
444 let reading = parse_aranet2_reading(&data).unwrap();
445 assert!((reading.temperature - 3276.75).abs() < 0.01); assert_eq!(reading.humidity, 255);
447 assert_eq!(reading.battery, 100);
448 assert_eq!(reading.status, Status::Red);
449 assert_eq!(reading.interval, 65535);
450 }
451
452 #[test]
455 fn test_parse_aranet4_reading() {
456 let data: [u8; 13] = [
458 0x20, 0x03, 0xC2, 0x01, 0x94, 0x27, 45, 85, 1, 0x2C, 0x01, 0x78, 0x00, ];
467
468 let reading = parse_aranet4_reading(&data).unwrap();
469 assert_eq!(reading.co2, 800);
470 assert!((reading.temperature - 22.5).abs() < 0.01);
471 assert!((reading.pressure - 1013.2).abs() < 0.1);
472 assert_eq!(reading.humidity, 45);
473 assert_eq!(reading.battery, 85);
474 assert_eq!(reading.status, Status::Green);
475 assert_eq!(reading.interval, 300);
476 assert_eq!(reading.age, 120);
477 }
478
479 #[test]
480 fn test_parse_aranet4_reading_high_co2() {
481 let data: [u8; 13] = [
483 0xD0, 0x07, 0x90, 0x01, 0x88, 0x27, 60, 75, 3, 0x3C, 0x00, 0x1E, 0x00, ];
492
493 let reading = parse_aranet4_reading(&data).unwrap();
494 assert_eq!(reading.co2, 2000);
495 assert_eq!(reading.status, Status::Red);
496 }
497
498 #[test]
499 fn test_parse_aranet4_reading_insufficient_bytes() {
500 let data: [u8; 10] = [0; 10];
501
502 let result = parse_aranet4_reading(&data);
503 assert!(result.is_err());
504
505 let err = result.unwrap_err();
506 assert!(err.to_string().contains("expected 13"));
508 assert!(err.to_string().contains("got 10"));
509 }
510
511 #[test]
514 fn test_parse_aranet_radon_reading() {
515 let data: [u8; 15] = [
517 0x00, 0x00, 0xC2, 0x01, 0x94, 0x27, 50, 80, 1, 0x2C, 0x01, 0x3C, 0x00, 0x64, 0x00, ];
527
528 let result = parse_aranet_radon_reading(&data).unwrap();
529 assert_eq!(result.reading.radon, Some(100));
530 assert!(result.reading.radiation_rate.is_none());
531 assert!((result.reading.temperature - 22.5).abs() < 0.01);
532 assert_eq!(result.reading.humidity, 50);
533 }
534
535 #[test]
536 fn test_parse_aranet_radon_reading_high_radon() {
537 let mut data: [u8; 15] = [0; 15];
538 data[13] = 0xF4;
540 data[14] = 0x01; let result = parse_aranet_radon_reading(&data).unwrap();
543 assert_eq!(result.reading.radon, Some(500));
544 }
545
546 #[test]
547 fn test_parse_aranet_radon_reading_insufficient_bytes() {
548 let data: [u8; 12] = [0; 12];
549
550 let result = parse_aranet_radon_reading(&data);
551 assert!(result.is_err());
552 assert!(
553 result
554 .unwrap_err()
555 .to_string()
556 .contains("requires 15 bytes")
557 );
558 }
559
560 #[test]
563 fn test_parse_aranet_radon_gatt() {
564 let mut data: [u8; 18] = [0; 18];
566 data[0] = 0x03;
568 data[1] = 0x00;
569 data[2] = 0x58;
571 data[3] = 0x02;
572 data[4] = 0x78;
574 data[5] = 0x00;
575 data[6] = 85;
577 data[7] = 0xC2;
579 data[8] = 0x01;
580 data[9] = 0x94;
582 data[10] = 0x27;
583 data[11] = 0xC2;
585 data[12] = 0x01;
586 data[13] = 0x64;
588 data[14] = 0x00;
589 data[15] = 0x00;
590 data[16] = 0x00;
591 data[17] = 1;
593
594 let reading = parse_aranet_radon_gatt(&data).unwrap();
595 assert_eq!(reading.battery, 85);
596 assert!((reading.temperature - 22.5).abs() < 0.01);
597 assert_eq!(reading.radon, Some(100)); assert_eq!(reading.co2, 0); assert_eq!(reading.status, Status::Green);
600 assert_eq!(reading.interval, 600);
601 assert_eq!(reading.age, 120);
602 }
603
604 #[test]
605 fn test_parse_aranet_radon_gatt_insufficient_bytes() {
606 let data: [u8; 15] = [0; 15];
607
608 let result = parse_aranet_radon_gatt(&data);
609 assert!(result.is_err());
610 assert!(
611 result
612 .unwrap_err()
613 .to_string()
614 .contains("at least 18 bytes")
615 );
616 }
617
618 #[test]
619 fn test_parse_aranet_radon_gatt_high_radon() {
620 let mut data: [u8; 18] = [0; 18];
622 data[0] = 0x03; data[13] = 0xA0;
626 data[14] = 0x86;
627 data[15] = 0x01;
628 data[16] = 0x00; let reading = parse_aranet_radon_gatt(&data).unwrap();
631 assert_eq!(reading.radon, Some(100000)); }
633
634 #[test]
637 fn test_parse_reading_for_device_aranet4() {
638 let data: [u8; 13] = [
639 0x20, 0x03, 0xC2, 0x01, 0x94, 0x27, 45, 85, 1, 0x2C, 0x01, 0x78, 0x00, ];
646
647 let reading = parse_reading_for_device(&data, DeviceType::Aranet4).unwrap();
648 assert_eq!(reading.co2, 800);
649 }
650
651 #[test]
652 fn test_parse_reading_for_device_aranet2() {
653 let data: [u8; 7] = [0xC2, 0x01, 55, 90, 1, 0x2C, 0x01];
654
655 let reading = parse_reading_for_device(&data, DeviceType::Aranet2).unwrap();
656 assert_eq!(reading.co2, 0); assert!((reading.temperature - 22.5).abs() < 0.01);
658 }
659
660 #[test]
663 fn test_extended_reading_with_radon() {
664 let reading = CurrentReading {
665 co2: 0,
666 temperature: 22.5,
667 pressure: 1013.2,
668 humidity: 50,
669 battery: 80,
670 status: Status::Green,
671 interval: 300,
672 age: 60,
673 captured_at: None,
674 radon: Some(150),
675 radiation_rate: None,
676 radiation_total: None,
677 radon_avg_24h: None,
678 radon_avg_7d: None,
679 radon_avg_30d: None,
680 };
681
682 let extended = ExtendedReading {
683 reading,
684 radiation_duration: None,
685 };
686
687 assert_eq!(extended.reading.radon, Some(150));
688 assert!(extended.reading.radiation_rate.is_none());
689 assert!((extended.reading.temperature - 22.5).abs() < 0.01);
690 }
691
692 #[test]
693 fn test_extended_reading_with_radiation() {
694 let reading = CurrentReading {
695 co2: 0,
696 temperature: 20.0,
697 pressure: 1000.0,
698 humidity: 45,
699 battery: 90,
700 status: Status::Green,
701 interval: 60,
702 age: 30,
703 captured_at: None,
704 radon: None,
705 radiation_rate: Some(0.15),
706 radiation_total: Some(0.001),
707 radon_avg_24h: None,
708 radon_avg_7d: None,
709 radon_avg_30d: None,
710 };
711
712 let extended = ExtendedReading {
713 reading,
714 radiation_duration: Some(3600),
715 };
716
717 assert!(extended.reading.radon.is_none());
718 assert!((extended.reading.radiation_rate.unwrap() - 0.15).abs() < 0.001);
719 assert_eq!(extended.radiation_duration, Some(3600));
720 }
721
722 #[test]
723 fn test_extended_reading_debug() {
724 let reading = CurrentReading {
725 co2: 800,
726 temperature: 22.5,
727 pressure: 1013.2,
728 humidity: 50,
729 battery: 80,
730 status: Status::Green,
731 interval: 300,
732 age: 60,
733 captured_at: None,
734 radon: Some(100),
735 radiation_rate: None,
736 radiation_total: None,
737 radon_avg_24h: None,
738 radon_avg_7d: None,
739 radon_avg_30d: None,
740 };
741
742 let extended = ExtendedReading {
743 reading,
744 radiation_duration: None,
745 };
746
747 let debug_str = format!("{:?}", extended);
748 assert!(debug_str.contains("radon"));
749 assert!(debug_str.contains("100"));
750 }
751
752 #[test]
753 fn test_extended_reading_clone() {
754 let reading = CurrentReading {
755 co2: 800,
756 temperature: 22.5,
757 pressure: 1013.2,
758 humidity: 50,
759 battery: 80,
760 status: Status::Green,
761 interval: 300,
762 age: 60,
763 captured_at: None,
764 radon: Some(100),
765 radiation_rate: Some(0.1),
766 radiation_total: Some(0.001),
767 radon_avg_24h: None,
768 radon_avg_7d: None,
769 radon_avg_30d: None,
770 };
771
772 let extended = ExtendedReading {
773 reading,
774 radiation_duration: Some(3600),
775 };
776
777 let cloned = extended.clone();
778 assert_eq!(cloned.reading.radon, extended.reading.radon);
779 assert_eq!(
780 cloned.reading.radiation_rate,
781 extended.reading.radiation_rate
782 );
783 assert_eq!(cloned.reading.co2, extended.reading.co2);
784 assert_eq!(cloned.radiation_duration, extended.radiation_duration);
785 }
786
787 #[test]
788 fn test_parse_aranet_radiation_gatt() {
789 let data = [
791 0x00, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x5A, 0xE8, 0x03, 0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x10, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ];
801
802 let result = parse_aranet_radiation_gatt(&data).unwrap();
803 assert_eq!(result.reading.interval, 60);
804 assert_eq!(result.reading.age, 30);
805 assert_eq!(result.reading.battery, 90);
806 assert!((result.reading.radiation_rate.unwrap() - 1.0).abs() < 0.001);
807 assert!((result.reading.radiation_total.unwrap() - 1.0).abs() < 0.001);
808 assert_eq!(result.radiation_duration, Some(3600));
809 assert_eq!(result.reading.status, Status::Green);
810 assert!(result.reading.radon.is_none());
811 }
812
813 #[test]
814 fn test_parse_aranet_radiation_gatt_insufficient_bytes() {
815 let data = [0x00; 20]; let result = parse_aranet_radiation_gatt(&data);
817 assert!(result.is_err());
818 let err = result.unwrap_err();
819 assert!(err.to_string().contains("28 bytes"));
820 }
821
822 #[test]
823 fn test_parse_aranet_radiation_gatt_high_values() {
824 let data = [
826 0x00, 0x00, 0x2C, 0x01, 0x0A, 0x00, 0x64, 0x10, 0x27, 0x00, 0x00, 0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00,
832 0x00, 0x80, 0x51, 0x01, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x02, ];
837
838 let result = parse_aranet_radiation_gatt(&data).unwrap();
839 assert_eq!(result.reading.interval, 300);
840 assert!((result.reading.radiation_rate.unwrap() - 10.0).abs() < 0.001);
841 assert!((result.reading.radiation_total.unwrap() - 100.0).abs() < 0.001);
842 assert_eq!(result.radiation_duration, Some(86400));
843 assert_eq!(result.reading.status, Status::Yellow);
844 }
845}
846
847#[cfg(test)]
873mod proptests {
874 use super::*;
875 use proptest::prelude::*;
876
877 proptest! {
878 #[test]
880 fn parse_aranet4_never_panics(data: Vec<u8>) {
881 let _ = parse_aranet4_reading(&data);
882 }
883
884 #[test]
885 fn parse_aranet2_never_panics(data: Vec<u8>) {
886 let _ = parse_aranet2_reading(&data);
887 }
888
889 #[test]
890 fn parse_aranet_radon_never_panics(data: Vec<u8>) {
891 let _ = parse_aranet_radon_reading(&data);
892 }
893
894 #[test]
895 fn parse_aranet_radon_gatt_never_panics(data: Vec<u8>) {
896 let _ = parse_aranet_radon_gatt(&data);
897 }
898
899 #[test]
900 fn parse_aranet_radiation_gatt_never_panics(data: Vec<u8>) {
901 let _ = parse_aranet_radiation_gatt(&data);
902 }
903
904 #[test]
906 fn parse_reading_for_device_never_panics(
907 data: Vec<u8>,
908 device_type_byte in 0xF1u8..=0xF4u8,
909 ) {
910 if let Ok(device_type) = DeviceType::try_from(device_type_byte) {
911 let _ = parse_reading_for_device(&data, device_type);
912 }
913 }
914
915 #[test]
917 fn aranet4_valid_bytes_parse_correctly(
918 co2 in 0u16..10000u16,
919 temp_raw in 0u16..2000u16,
920 pressure_raw in 8000u16..12000u16,
921 humidity in 0u8..100u8,
922 battery in 0u8..100u8,
923 status_byte in 0u8..4u8,
924 interval in 60u16..3600u16,
925 age in 0u16..3600u16,
926 ) {
927 let mut data = [0u8; 13];
928 data[0..2].copy_from_slice(&co2.to_le_bytes());
929 data[2..4].copy_from_slice(&temp_raw.to_le_bytes());
930 data[4..6].copy_from_slice(&pressure_raw.to_le_bytes());
931 data[6] = humidity;
932 data[7] = battery;
933 data[8] = status_byte;
934 data[9..11].copy_from_slice(&interval.to_le_bytes());
935 data[11..13].copy_from_slice(&age.to_le_bytes());
936
937 let result = parse_aranet4_reading(&data);
938 prop_assert!(result.is_ok());
939
940 let reading = result.unwrap();
941 prop_assert_eq!(reading.co2, co2);
942 prop_assert_eq!(reading.humidity, humidity);
943 prop_assert_eq!(reading.battery, battery);
944 prop_assert_eq!(reading.interval, interval);
945 prop_assert_eq!(reading.age, age);
946 }
947
948 #[test]
950 fn aranet2_valid_bytes_parse_correctly(
951 temp_raw in 0u16..2000u16,
952 humidity in 0u8..100u8,
953 battery in 0u8..100u8,
954 status_byte in 0u8..4u8,
955 interval in 60u16..3600u16,
956 ) {
957 let mut data = [0u8; 7];
958 data[0..2].copy_from_slice(&temp_raw.to_le_bytes());
959 data[2] = humidity;
960 data[3] = battery;
961 data[4] = status_byte;
962 data[5..7].copy_from_slice(&interval.to_le_bytes());
963
964 let result = parse_aranet2_reading(&data);
965 prop_assert!(result.is_ok());
966
967 let reading = result.unwrap();
968 prop_assert_eq!(reading.co2, 0); prop_assert_eq!(reading.humidity, humidity);
970 prop_assert_eq!(reading.battery, battery);
971 }
972 }
973}