Skip to content

Commit

Permalink
feat(entities): add debounce edge options
Browse files Browse the repository at this point in the history
Closes #329
  • Loading branch information
mKeRix committed Dec 6, 2020
1 parent 396289c commit d5b92cf
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 7 deletions.
6 changes: 6 additions & 0 deletions config/test.yml
Expand Up @@ -8,6 +8,12 @@ entities:
debounce:
wait: 0.75
maxWait: 2
leading_debounced_entity:
debounce:
wait: 0.75
maxWait: 2
leading: true
trailing: false
rolling_average_entity:
rollingAverage:
window: 60
Expand Down
14 changes: 8 additions & 6 deletions docs/guide/entities.md
Expand Up @@ -21,12 +21,14 @@ Behaviors may be set per entity ID, with the ID being the key and an object with

#### Debounce

Debouncing is especially helpful for sensors that jump states quickly in an incorrect manner. This could for example be the case for some GPIO sensors or thermopiles.

| Name | Type | Default | Description |
| --------- | ------ | ------- | ------------------------------------------------------------ |
| `wait` | Number | | Number of seconds to wait after the last time the state was updated before publishing it to integrations. |
| `maxWait` | Number | | Maximum number of seconds that a state update may be delayed. If left undefined there will be no limit. |
Debouncing is especially helpful for sensors that jump states quickly in an incorrect manner. This could for example be the case for some GPIO sensors or thermopiles. This behavior is based on the [Lodash debounce implementation](https://lodash.com/docs/#debounce) and the options will therefore behave the same.

| Name | Type | Default | Description |
| ---------- | ------- | ------- | ------------------------------------------------------------ |
| `wait` | Number | | Number of seconds to wait after the last time the state was updated before publishing it to integrations. |
| `maxWait` | Number | | Maximum number of seconds that a state update may be delayed. If left undefined there will be no limit. |
| `leading` | Boolean | `false` | Invoke the update on the leading edge of the timeout. |
| `trailing` | Boolean | `true` | Invoke the update on the trailing edge of the timeout. |

::: details Example Config

Expand Down
6 changes: 5 additions & 1 deletion src/entities/debounce.proxy.ts
Expand Up @@ -11,7 +11,11 @@ export class DebounceProxyHandler implements ProxyHandler<Entity> {
target.state = value;
},
config.wait * 1000,
{ maxWait: config.maxWait * 1000 }
{
maxWait: config.maxWait * 1000,
leading: config.leading ?? false,
trailing: config.trailing ?? true,
}
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/entities/entities.config.ts
Expand Up @@ -10,6 +10,8 @@ export class EntityBehavior {
export class DebounceOptions {
wait?: number;
maxWait?: number;
leading: boolean;
trailing?: boolean;
}

export class RollingAverageOptions {
Expand Down
26 changes: 26 additions & 0 deletions src/entities/entities.service.spec.ts
Expand Up @@ -159,6 +159,32 @@ describe('EntitiesService', () => {
);
});

it('should debounce state updates on leading edge if configured', () => {
jest.useFakeTimers('modern');
const spy = jest.spyOn(emitter, 'emit');

const entityProxy = service.add(
new Sensor('leading_debounced_entity', 'Debounce Test')
);
spy.mockClear();

entityProxy.state = 42;
entityProxy.state = 1337;

expect(entityProxy.state).toBe(42);

jest.runAllTimers();

expect(entityProxy.state).toBe(42);
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(
'stateUpdate',
'leading_debounced_entity',
42,
false
);
});

it('should calculate rolling average for non-number states if configured', () => {
jest.useFakeTimers('modern');
const spy = jest.spyOn(emitter, 'emit');
Expand Down

0 comments on commit d5b92cf

Please sign in to comment.