Skip to content

Commit e26c074

Browse files
committed
fixed float and interger range rounding beheviour according to homie
conventions specification
1 parent bca266f commit e26c074

File tree

3 files changed

+31
-9
lines changed

3 files changed

+31
-9
lines changed

src/value.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl fmt::Display for Homie5ValueConversionError {
5757
write!(f, "Integer '{}' is out of allowed range: {}", value, range)
5858
}
5959
Homie5ValueConversionError::FloatOutOfRange(value, range) => {
60-
write!(f, "Flaot '{}' is out of allowed range: {}", value, range)
60+
write!(f, "Float '{}' is out of allowed range: {}", value, range)
6161
}
6262
Homie5ValueConversionError::InvalidDateTimeFormat(value) => {
6363
write!(f, "'{}' is not a valid date/time value", value)
@@ -188,7 +188,7 @@ impl Display for HomieColorValue {
188188
impl FromStr for HomieColorValue {
189189
type Err = Homie5ValueConversionError;
190190
fn from_str(s: &str) -> Result<Self, Self::Err> {
191-
let mut tokens = str::split(s, ',');
191+
let mut tokens = s.split(',');
192192
match tokens.next() {
193193
Some("rgb") => {
194194
if let (Some(Ok(r)), Some(Ok(g)), Some(Ok(b))) = (
@@ -620,12 +620,13 @@ impl HomieValue {
620620
let HomiePropertyFormat::FloatRange(range) = &property_desc.format else {
621621
return Ok(value);
622622
};
623-
// Use the minimum, max, or current value as base (in that priority order)
623+
624+
// Use min as base, if not present, use max, otherwise use the current value
624625
let base = range.min.or(range.max).unwrap_or(value);
625626

626-
// Calculate the rounded value based on the step
627+
// Adjust rounding logic: floor((x + 0.5)) to always round up
627628
let rounded = match range.step {
628-
Some(s) if s > 0.0 => ((value - base) / s).round() * s + base,
629+
Some(s) if s > 0.0 => ((value - base) / s + 0.5).floor() * s + base,
629630
_ => value,
630631
};
631632

@@ -642,12 +643,12 @@ impl HomieValue {
642643
return Ok(value);
643644
};
644645

645-
// Use the minimum or maximum as the base, or use the current value
646+
// Use min as base, if not present, use max, otherwise use the current value
646647
let base = range.min.or(range.max).unwrap_or(value);
647648

648-
// Calculate the rounded value based on the step
649+
// Adjust rounding logic: floor((x + 0.5)) to always round up
649650
let rounded = match range.step {
650-
Some(s) if s > 0 => ((value - base) as f64 / s as f64).round() as i64 * s + base,
651+
Some(s) if s > 0 => ((value - base) as f64 / s as f64 + 0.5).floor() as i64 * s + base,
651652
_ => value,
652653
};
653654

tests/common/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub enum HomieTest {
7777
PropertyDescription(HomieTestDefinition<serde_yaml::Value, Option<()>, Option<()>>),
7878
PropertyValue(HomieTestDefinition<HomiePropertyDescription, String, Option<()>>),
7979
PropertyValueInteger(HomieTestDefinition<HomiePropertyDescription, String, Option<i64>>),
80+
PropertyValueFloat(HomieTestDefinition<HomiePropertyDescription, String, Option<f64>>),
8081
HomieID(HomieTestDefinition<Option<()>, String, Option<()>>),
8182
}
8283

@@ -88,13 +89,15 @@ impl HomieTest {
8889
HomieTest::PropertyValue(homie_test_definition) => &homie_test_definition.description,
8990
HomieTest::PropertyValueInteger(homie_test_definition) => &homie_test_definition.description,
9091
HomieTest::HomieID(homie_test_definition) => &homie_test_definition.description,
92+
HomieTest::PropertyValueFloat(homie_test_definition) => &homie_test_definition.description,
9193
}
9294
}
9395
pub fn valid(&self) -> bool {
9496
match self {
9597
HomieTest::PropertyDescription(homie_test_definition) => homie_test_definition.valid,
9698
HomieTest::PropertyValue(homie_test_definition) => homie_test_definition.valid,
9799
HomieTest::PropertyValueInteger(homie_test_definition) => homie_test_definition.valid,
100+
HomieTest::PropertyValueFloat(homie_test_definition) => homie_test_definition.valid,
98101
HomieTest::HomieID(homie_test_definition) => homie_test_definition.valid,
99102
}
100103
}

tests/homie_value.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ fn test_homie_integer_value_from_file() {
3939
assert!(result.is_ok(), "{:?}", result);
4040
}
4141

42+
#[test]
43+
fn test_homie_float_value_from_file() {
44+
let result = run_homietests("homie5/values/float.yml", |test_definition| {
45+
if let HomieTest::PropertyValueFloat(test) = test_definition {
46+
let Ok(homie_value) = HomieValue::parse(&test.input_data, &test.definition) else {
47+
return Ok(false);
48+
};
49+
let HomieValue::Float(value) = homie_value else {
50+
return Err(anyhow::anyhow!("Invalid Testdefinition in test file"));
51+
};
52+
Ok(Some(value) == test.output_data)
53+
} else {
54+
Err(anyhow::anyhow!("Invalid Testdefinition in test file"))
55+
}
56+
});
57+
58+
assert!(result.is_ok(), "{:?}", result);
59+
}
4260
#[test]
4361
fn test_homie_color_value_display_rgb() {
4462
let color = HomieColorValue::RGB(255, 100, 50);
@@ -284,7 +302,7 @@ fn test_integer_value_with_max_only_range() {
284302
assert_eq!(HomieValue::parse("8", &desc).unwrap(), HomieValue::Integer(8));
285303

286304
// Value rounded to nearest step
287-
assert_eq!(HomieValue::parse("9", &desc).unwrap(), HomieValue::Integer(8));
305+
assert_eq!(HomieValue::parse("9", &desc).unwrap(), HomieValue::Integer(10));
288306

289307
// Value too high (out of range)
290308
assert!(HomieValue::parse("21", &desc).is_err());

0 commit comments

Comments
 (0)