Skip to content

Commit

Permalink
feat(Bulb): add Bulb#blink method (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
plasticrake authored Nov 7, 2023
1 parent 2f192da commit a8dd13d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
48 changes: 47 additions & 1 deletion src/bulb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Device, { isBulbSysinfo } from '../device';
import type { CommonSysinfo, DeviceConstructorOptions } from '../device';
import Cloud from '../shared/cloud';
import Emeter, { RealtimeNormalized } from '../shared/emeter';
import Lighting, { LightState } from './lighting';
import Lighting, { LightState, LightStateInput } from './lighting';
import Schedule from './schedule';
import Time from '../shared/time';

Expand Down Expand Up @@ -435,6 +435,52 @@ class Bulb extends Device {
return !powerState;
}

/**
* Blink Bulb.
*
* Sends `system.lighting.set_light_state` command alternating on at full brightness and off number of `times` at `rate`,
* then sets the light state to its pre-blink state.
* @throws {@link ResponseError}
*/
async blink(
times = 5,
rate = 1000,
sendOptions?: SendOptions,
): Promise<boolean> {
const delay = (t: number): Promise<void> => {
return new Promise((resolve) => {
setTimeout(resolve, t);
});
};

const origLightState = await this.lighting.getLightState(sendOptions);
let lastBlink: number;

let isBlinkOn = false;
for (let i = 0; i < times * 2; i += 1) {
isBlinkOn = !isBlinkOn;
lastBlink = Date.now();

const lightState: LightStateInput = isBlinkOn
? { on_off: 1, brightness: 100 }
: { on_off: 0 };

// eslint-disable-next-line no-await-in-loop
await this.lighting.setLightState(lightState, sendOptions);

const timeToWait = rate / 2 - (Date.now() - lastBlink);
if (timeToWait > 0) {
// eslint-disable-next-line no-await-in-loop
await delay(timeToWait);
}
}
const currLightState = await this.lighting.getLightState(sendOptions);
if (currLightState !== origLightState) {
await this.lighting.setLightState(origLightState, sendOptions);
}
return true;
}

private emitEvents(): void {
if (!this.emitEventsEnabled) {
return;
Expand Down
28 changes: 27 additions & 1 deletion test/bulb/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from 'assert';
import sinon from 'sinon';

import type { Bulb } from '../../src';
import type { Bulb, LightStateInput } from '../../src';
import { AnyDevice } from '../../src/client';

import { config, expect, retry, testDevices } from '../setup';
Expand Down Expand Up @@ -206,6 +206,32 @@ describe('Bulb', function () {
expect(spyPowerUpdate).to.be.calledThrice;
});
});

describe('#blink()', function () {
it('should blink Bulb', async function () {
expect(await bulb.blink(2, 100)).to.be.true;
});

(
[
{ on_off: 0 },
{ on_off: 1 },
{ on_off: 1, brightness: 50 },
{ on_off: 1, brightness: 75 },
] as LightStateInput[]
).forEach((lightState) => {
it(`should restore the previous lightstate after blink: ${JSON.stringify(
lightState,
)}`, async function () {
await bulb.lighting.setLightState(lightState);

const preLightState = await bulb.lighting.getLightState();
expect(await bulb.blink(2, 100)).to.be.true;
const postLightState = await bulb.lighting.getLightState();
expect(postLightState).to.eql(preLightState);
});
});
});
});
});
});
Expand Down

0 comments on commit a8dd13d

Please sign in to comment.