diff --git a/src/lib/Characteristic.spec.ts b/src/lib/Characteristic.spec.ts index 8c26ac0b5..7a1b4b483 100644 --- a/src/lib/Characteristic.spec.ts +++ b/src/lib/Characteristic.spec.ts @@ -1094,6 +1094,35 @@ describe("Characteristic", () => { expect(mock).toBeCalledTimes(0); }); + it("should validate Formats.FLOAT with precision with minimum steps", () => { + const steps = (100 / 6); + const characteristic = createCharacteristicWithProps({ + format: Formats.FLOAT, + perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE], + minValue: 0, + maxValue: 100, + minStep: steps, + }); + + characteristic.setValue(steps); + expect(characteristic.value).toEqual(steps); + + characteristic.setValue(steps * 2); + expect(characteristic.value).toEqual(steps * 2); + + characteristic.setValue(steps * 3); + expect(characteristic.value).toEqual(steps * 3); + + characteristic.setValue(steps * 4); + expect(characteristic.value).toEqual(steps * 4); + + characteristic.setValue(steps * 5); + expect(characteristic.value).toEqual(steps * 5); + + characteristic.setValue(steps * 6); + expect(characteristic.value).toEqual(steps * 6); + }); + it("should allow negative floats in range for Formats.FLOAT", () => { const characteristic = createCharacteristicWithProps({ format: Formats.FLOAT, diff --git a/src/lib/Characteristic.ts b/src/lib/Characteristic.ts index 630269cf5..08b82795a 100644 --- a/src/lib/Characteristic.ts +++ b/src/lib/Characteristic.ts @@ -2071,8 +2071,9 @@ export class Characteristic extends EventEmitter { if (stepValue === 1) { value = Math.round(value); } else if (stepValue > 1) { + const eps = 1; // stable constant for floating point precision value = Math.round(value); - value = value - (value % stepValue); + value = value - ((value + eps) % stepValue) + eps; } // for stepValue < 1 rounding is done only when formatting the response. We can't store the "perfect" .step anyways }