Skip to content

Commit

Permalink
feat(gpio): add option to configure switches
Browse files Browse the repository at this point in the history
  • Loading branch information
mKeRix committed Apr 5, 2020
1 parent 51b985f commit 9d8b7c4
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 1 deletion.
3 changes: 3 additions & 0 deletions config/test.yml
Expand Up @@ -9,6 +9,9 @@ gpio:
- name: Radar
pin: 24
deviceClass: motion
switches:
- name: Test Switch
pin: 17
shell:
sensors:
- name: Simple Test
Expand Down
12 changes: 12 additions & 0 deletions docs/integrations/gpio.md
Expand Up @@ -49,6 +49,7 @@ services:
| Name | Type | Default | Description |
| --------------- | -------------------------------------- | ------- | -------------------------------------- |
| `binarySensors` | [GPIO Binary Sensors](#binary-sensors) | | Array of binary sensor configurations. |
| `switches` | [GPIO Switches](#switches) | | Array of switch configurations. |

### Binary Sensors

Expand All @@ -58,6 +59,14 @@ services:
| `pin` | Number | | Number of the GPIO pin that should be tracked. |
| `deviceClass` | String | | Home Assistant [device class](https://www.home-assistant.io/integrations/binary_sensor/#device-class) that the sensor should be shown as. |

### Switches

| Name | Type | Default | Description |
| ------ | ------ | ------- | ------------------------------------------------------------ |
| `name` | String | | Friendly name for this sensor. |
| `pin` | Number | | Number of the GPIO pin that should be used as output. |
| `icon` | String | | Icon to display for the switch in the Home Assistant frontend. |

::: details Example Config

```yaml
Expand All @@ -69,6 +78,9 @@ gpio:
- name: Bedroom Motion Sensor
pin: 17
deviceClass: motion
switches:
- name: LED
pin: 18
```

:::
Expand Down
7 changes: 7 additions & 0 deletions src/integrations/gpio/gpio.config.ts
Expand Up @@ -2,10 +2,17 @@ import { BinarySensorDeviceClass } from '../home-assistant/binary-sensor-config'

export class GpioConfig {
binarySensors: GpioBinarySensorOptions[] = [];
switches: GpioSwitchOptions[] = [];
}

class GpioBinarySensorOptions {
name: string;
pin: number;
deviceClass?: BinarySensorDeviceClass;
}

class GpioSwitchOptions {
name: string;
pin: number;
icon?: string;
}
13 changes: 12 additions & 1 deletion src/integrations/gpio/gpio.service.spec.ts
Expand Up @@ -8,6 +8,7 @@ import { BinarySensorConfig } from '../home-assistant/binary-sensor-config';
import { Gpio } from 'onoff';
import { mocked } from 'ts-jest/utils';
import { ClusterService } from '../../cluster/cluster.service';
import { GpioSwitch } from './gpio.switch';

jest.mock('onoff');

Expand Down Expand Up @@ -43,7 +44,7 @@ describe('GpioService', () => {
it('should register entities on bootstrap', () => {
service.onApplicationBootstrap();

expect(entitiesService.add).toHaveBeenCalledTimes(2);
expect(entitiesService.add).toHaveBeenCalledTimes(3);
expect(entitiesService.add).toHaveBeenCalledWith(
new BinarySensor('gpio-pir-sensor', 'PIR Sensor'),
expect.any(Array)
Expand All @@ -52,6 +53,10 @@ describe('GpioService', () => {
new BinarySensor('gpio-radar', 'Radar'),
expect.any(Array)
);
expect(entitiesService.add).toHaveBeenCalledWith(
new GpioSwitch('gpio-test-switch', 'Test Switch', expect.any(Gpio)),
expect.any(Array)
);
});

it('should pass on entity customizations', () => {
Expand All @@ -65,6 +70,12 @@ describe('GpioService', () => {
});
});

it('should export the switches as output pins', () => {
service.onApplicationBootstrap();

expect(mockGpio).toHaveBeenCalledWith(17, 'out');
});

it('should export the binary sensors as input pins', () => {
service.onApplicationBootstrap();

Expand Down
39 changes: 39 additions & 0 deletions src/integrations/gpio/gpio.service.ts
Expand Up @@ -15,6 +15,9 @@ import {
BinarySensorConfig,
BinarySensorDeviceClass
} from '../home-assistant/binary-sensor-config';
import { SwitchConfig } from '../home-assistant/switch-config';
import { GpioSwitch } from './gpio.switch';
import { Switch } from '../../entities/switch';

@Injectable()
export class GpioService
Expand Down Expand Up @@ -42,6 +45,14 @@ export class GpioService
binarySensor.deviceClass
);
});

this.config.switches.forEach(switchOptions => {
this.createSwitch(
switchOptions.name,
switchOptions.pin,
switchOptions.icon
);
});
}

/**
Expand Down Expand Up @@ -95,4 +106,32 @@ export class GpioService

return binarySensor;
}

/**
* Creates a new switch that controls a GPIO output.
*
* @param name - Friendly name of the switch
* @param pin - GPIO pin to output to
* @param icon - Icon to use
* @returns Registered switch
*/
protected createSwitch(name: string, pin: number, icon?: string): Switch {
const id = makeId(`gpio ${name}`);
const customizations: Array<EntityCustomization<any>> = [
{
for: SwitchConfig,
overrides: {
icon
}
}
];

const gpio = new Gpio(pin, 'out');
this.gpios.push(gpio);

return this.entitiesService.add(
new GpioSwitch(id, name, gpio),
customizations
) as Switch;
}
}
28 changes: 28 additions & 0 deletions src/integrations/gpio/gpio.switch.spec.ts
@@ -0,0 +1,28 @@
import { Gpio } from 'onoff';
import { GpioSwitch } from './gpio.switch';

jest.mock('onoff');

describe('GpioSwitch', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should write 1 to the GPIO pin when turned on', async () => {
const pin = new Gpio(17, 'out');
const gpioSwitch = new GpioSwitch('test', 'Test', pin);

await gpioSwitch.turnOn();
expect(pin.write).toHaveBeenCalledWith(1);
expect(gpioSwitch.state).toBeTruthy();
});

it('should write 0 to the GPIO pin when turned off', async () => {
const pin = new Gpio(17, 'out');
const gpioSwitch = new GpioSwitch('test', 'Test', pin);

await gpioSwitch.turnOff();
expect(pin.write).toHaveBeenCalledWith(0);
expect(gpioSwitch.state).toBeFalsy();
});
});
21 changes: 21 additions & 0 deletions src/integrations/gpio/gpio.switch.ts
@@ -0,0 +1,21 @@
import { Switch } from '../../entities/switch';
import { Gpio } from 'onoff';

export class GpioSwitch extends Switch {
private gpio: Gpio;

constructor(id: string, name: string, gpio: Gpio) {
super(id, name, false);
this.gpio = gpio;
}

async turnOn(): Promise<void> {
await this.gpio.write(1);
super.turnOn();
}

async turnOff(): Promise<void> {
await this.gpio.write(0);
super.turnOff();
}
}

0 comments on commit 9d8b7c4

Please sign in to comment.