Skip to content

Commit

Permalink
feat(grid-eye): add heatmap camera entity
Browse files Browse the repository at this point in the history
  • Loading branch information
mKeRix committed May 31, 2020
1 parent aee7f09 commit ac52e76
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 3 deletions.
19 changes: 16 additions & 3 deletions docs/integrations/grid-eye.md
Expand Up @@ -65,11 +65,20 @@ When placing your sensor you need to consider a few factors to get reliable resu

## Settings

| Name | Type | Default | Description |
| ---------------- | ------------------- | ------- | ------------------------------------------------------------ |
| `busNumber` | Number | `1` | I<sup>2</sup>C bus number of your machine that the sensor is connected to. |
| `address` | Number | `0x69` | I<sup>2</sup>C address of the D6T sensor that you want to use. |
| `deltaThreshold` | Number | `2` | Minimum temperature difference between average and single temperature pixel in &deg;C for it to be considered as human presence. Increase if you are seeing false positives, decrease if you are seeing false negatives. |
| `heatmap` | [Heatmap](#heatmap) | | A number of options for configuring the heatmap output. |

### Heatmap

| Name | Type | Default | Description |
| ---------------- | ------ | ------- | ------------------------------------------------------------ |
| `busNumber` | Number | `1` | I<sup>2</sup>C bus number of your machine that the sensor is connected to. |
| `address` | Number | `0x69` | I<sup>2</sup>C address of the D6T sensor that you want to use. |
| `deltaThreshold` | Number | `2` | Minimum temperature difference between average and single temperature pixel in &deg;C for it to be considered as human presence. Increase if you are seeing false positives, decrease if you are seeing false negatives. |
| `minTemperature` | Number | `16` | Temperature that will be considered the lower bound for the color scale in &deg;C. |
| `maxTemperature` | Number | `30` | Temperature that will be considered the upper bound for the color scale in &deg;C. |
| `rotation` | Number | `0` | The amount of degrees that the heatmap output image should be rotated. Only `0`, `90`, `180` or `270` are supported as values. |

::: details Example Config

Expand All @@ -79,6 +88,10 @@ global:
- gridEye
gridEye:
deltaThreshold: 2
heatmap:
minTemperature: 16
maxTemperature: 30
rotation: 180
```

:::
Expand Down
3 changes: 3 additions & 0 deletions src/integrations/grid-eye/grid-eye.config.ts
@@ -1,5 +1,8 @@
import { HeatmapOptions } from '../thermopile/thermopile-occupancy.config';

export class GridEyeConfig {
busNumber = 1;
address = 0x69;
deltaThreshold = 2;
heatmap = new HeatmapOptions();
}
29 changes: 29 additions & 0 deletions src/integrations/grid-eye/grid-eye.service.spec.ts
Expand Up @@ -24,6 +24,7 @@ jest.mock(
},
{ virtual: true }
);
jest.mock('canvas', () => undefined, { virtual: true });

describe('GridEyeService', () => {
let service: GridEyeService;
Expand Down Expand Up @@ -73,6 +74,18 @@ describe('GridEyeService', () => {
);
});

it('should register a new camera on bootstrap if available', async () => {
jest.spyOn(service, 'isHeatmapAvailable').mockReturnValue(true);
await service.onApplicationBootstrap();

expect(entitiesService.add).toHaveBeenCalledWith(
expect.objectContaining({
id: 'grideye_heatmap',
name: 'GridEYE Heatmap',
})
);
});

it('should close the i2c bus on shutdown', async () => {
await service.onApplicationBootstrap();
await service.onApplicationShutdown();
Expand All @@ -99,6 +112,22 @@ describe('GridEyeService', () => {
});
});

it('should update the camera entity with the generated heatmap', async () => {
jest.spyOn(service, 'isHeatmapAvailable').mockReturnValue(true);
entitiesService.add.mockImplementation((entity) => entity);
jest.spyOn(service, 'getCoordinates').mockResolvedValue([
[1, 2],
[8, 6],
]);

const imageData = new Buffer('abc');
jest.spyOn(service, 'generateHeatmap').mockResolvedValue(imageData);

await service.onApplicationBootstrap();
await service.updateState();
expect(entitiesService.add.mock.calls[1][0].state).toBe(imageData);
});

it('should get the temperatures of all 64 pixels', async () => {
const temperatureSpy = jest
.spyOn(service, 'getPixelTemperature')
Expand Down
28 changes: 28 additions & 0 deletions src/integrations/grid-eye/grid-eye.service.ts
Expand Up @@ -15,6 +15,7 @@ import { GridEyeConfig } from './grid-eye.config';
import { ConfigService } from '../../config/config.service';
import { SensorConfig } from '../home-assistant/sensor-config';
import { EntityCustomization } from '../../entities/entity-customization.interface';
import { Camera } from '../../entities/camera';

const TEMPERATURE_REGISTER_START = 0x80;
const FRAMERATE_REGISTER = 0x02;
Expand All @@ -26,6 +27,7 @@ export class GridEyeService extends ThermopileOccupancyService
private readonly logger: Logger;
private i2cBus: PromisifiedBus;
private sensor: Entity;
private camera: Camera;

constructor(
private readonly entitiesService: EntitiesService,
Expand All @@ -45,6 +47,14 @@ export class GridEyeService extends ThermopileOccupancyService
this.setRegister(FRAMERATE_REGISTER, 1); // set framerate to 1 FPS -> less noise

this.sensor = this.createSensor();

if (this.isHeatmapAvailable()) {
this.camera = this.createHeatmapCamera();
} else {
this.logger.warn(
'Heatmap is unavailable due to the canvas dependency not being installed'
);
}
}

/**
Expand All @@ -68,6 +78,13 @@ export class GridEyeService extends ThermopileOccupancyService

this.sensor.state = coordinates.length;
this.sensor.attributes.coordinates = coordinates;

if (this.camera != undefined) {
this.camera.state = await this.generateHeatmap(
temperatures,
this.config.heatmap
);
}
}

/**
Expand Down Expand Up @@ -165,4 +182,15 @@ export class GridEyeService extends ThermopileOccupancyService
customizations
) as Sensor;
}

/**
* Creates and registers a new heatmap camera entity.
*
* @returns Registered camera
*/
protected createHeatmapCamera(): Camera {
return this.entitiesService.add(
new Camera('grideye_heatmap', 'GridEYE Heatmap')
) as Camera;
}
}

0 comments on commit ac52e76

Please sign in to comment.