Skip to content

Latest commit

 

History

History
186 lines (142 loc) · 5.68 KB

ADD_NEW_SENSOR.md

File metadata and controls

186 lines (142 loc) · 5.68 KB

Add support for a new sensor

Every part will have an example with a new "Toto" sensor.

Sensor type

File => src/app/states/devices/abstract-device.ts

Each sensor need to have a corresponding enum, which string value needs to be unique. It is used to identify the sensor type when passing a sensor object to any service in the application.

For BLE sensors, the value needs to be a sub-string of the name advertised by the device.

example

export enum DeviceType {
  Mock = 'Mock',
  OGKit = 'OG-KIT1',
  AtomTag = 'AtomTag',
  SafeCast = 'bGeigieBLE',
  PocketGeiger = 'Pocket Geiger Type 6',
  Toto = 'toto'
}

Sensor class

File => src/app/states/devices/<connection-type>/device-<sensor-type>.ts

This class will represent this sensor type and all its parameters and characteristics.

They can either be statically set (all sensors of this type all will have the same values) or dynamically computed (the constructor receives the advertising BLE datas).

Some inherited values from base class like hitsAccuracyThreshold can also be overridden in the sensor class.

example

For a BLE sensor the file would be src/app/states/devices/ble/device-toto.ts

import { ApparatusSensorType, DeviceType } from '@app/states/devices/abstract-device';
import { AbstractBLEDevice, RawBLEDevice } from '@app/states/devices/abstract-ble-device';

export class DeviceToto extends AbstractBLEDevice {
  readonly deviceType = DeviceType.Toto;
  apparatusSensorType = ApparatusSensorType.Geiger;
  apparatusTubeType = 'TotoTube';
  hitsPeriod = 1000;

  constructor(rawDevice: RawBLEDevice) {
    super(rawDevice);
    this.apparatusVersion = rawDevice.name;
    this.apparatusId = rawDevice.id;
  }
}

Sensor instantiation

After creating the sensor class, you need to tell where and when it should be instantiated.

BLE device

File => src/app/states/ble/ble-devices.service.ts

You need to edit the file around line 25 like this:

private devices = [DeviceType.OGKit, DeviceType.AtomTag, DeviceType.SafeCast, DeviceType.Toto];

USB device

File => src/app/states/usb/usb-devices.service.ts

You need to edit the file around line 19 like this:

private devices = [DeviceType.PocketGeiger, DeviceType.Toto];

Sensor service

File => src/app/states/devices/<connection-type>/device-<sensor-type>.service.ts

The sensor need a service to handle the communication between the application and the physical device.

Once you've implemented this service, you need to attach it to the global devices service so it can be used automatically throughout the application.

Example

For a BLE sensor the file would be src/app/states/devices/ble/device-toto.service.ts

import { Injectable } from '@angular/core';
import { Store } from '@ngxs/store';
import { Observable, of } from 'rxjs';
import { bufferCount, filter, map, tap } from 'rxjs/operators';
import { Step } from '@app/states/measures/measures/measure';
import { AbstractBLEDeviceService } from '@app/states/devices/ble/abstract-ble-device.service';
import { DeviceSafeCast } from '@app/states/devices/ble/device-safe-cast';

@Injectable({
  providedIn: 'root'
})
export class DeviceTotoService extends AbstractBLEDeviceService<DeviceToto> {
  protected service = 'ef080d8c-c3be-41ff-bd3f-05a5f4795d7f';
  protected receiveCharacteristic = 'a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b';

  constructor(protected store: Store) {
    super(store, ble);
  }

  protected convertHitsNumberPerSec(hitsNumberPerSec: number): number {
    return (hitsNumberPerSec * 60) / 334;
  }

  getDeviceInfo(device: DeviceToto): Observable<Partial<DeviceToto>> {
    return of({});
  }

  saveDeviceParams(device: DeviceToto): Observable<any> {
    return of(null);
  }

  startMeasureScan(device: DeviceToto, stopSignal: Observable<any>): Observable<Step> {
    stopSignal.subscribe(() => this.stopReceiveData(device));
    let readingBufferSequence = false;
    return this.startReceiveData(device).pipe(
      filter((buffer: ArrayBuffer) => {
        const dataView = new DataView(buffer);
        return dataView.getUint8(0) === 36 || readingBufferSequence;
      }),
      tap(() => (readingBufferSequence = true)),
      bufferCount(18),
      tap(() => (readingBufferSequence = false)),
      map(dataView => this.decodeDataPackage(dataView))
    );
  }

  protected decodeDataPackage(dataView: DataView): Step {
    const data = dataView.buffer
      .map(buffer => this.textDecoder.decode(buffer))
      .join('')
      .split(',');
    return {
      ts: Date.now(),
      hitsNumber: Number(data[4])
    };
  }

  buildDevice(rawBLEDevice: RawBLEDevice): DeviceToto | null {
    if (rawBLEDevice.name.includes(DeviceType.Toto)) {
      return new DeviceToto(rawBLEDevice);
    }
    return null;
  }
}

Around line 20 in src/app/states/devices/devices.services.ts

constructor(
    private actions$: Actions,
    private toastController: ToastController,
    private translateService: TranslateService,
    private deviceMockService: DeviceMockService,
    private deviceOGKitService: DeviceOGKitService,
    private deviceAtomTagService: DeviceAtomTagService,
    private deviceSafeCastService: DeviceSafeCastService,
    private devicePocketGeigerService: DevicePocketGeigerService,
    private deviceTotoService: DeviceTotoService
  ) {
    this.services = {
      [DeviceType.Mock]: this.deviceMockService,
      [DeviceType.OGKit]: this.deviceOGKitService,
      [DeviceType.AtomTag]: this.deviceAtomTagService,
      [DeviceType.SafeCast]: this.deviceSafeCastService,
      [DeviceType.PocketGeiger]: this.devicePocketGeigerService,
      [DeviceType.Toto]: this.deviceTotoService
    };
    /** irrelevant stuff **/
  }