UNPKG

homebridge-freeathome-local-api

Version:

Control your free@home setup using the local API provided by your System Access Point

446 lines (434 loc) 15 kB
import { Channel, Device } from "freeathome-local-api-client"; import { Characteristic, CharacteristicValue, PlatformAccessory, Service, WithUUID, } from "homebridge"; import { FreeAtHomeContext } from "../src/freeAtHomeContext.js"; import { ShutterActuatorAccessory } from "../src/shutterActuatorAccessory.js"; import { EmptyGuid } from "../src/util.js"; import { createPlatformAccessory, MockFreeAtHomeHomebridgePlatform, } from "./platform.mock.js"; describe("Shutter Accessory", () => { let channel: Channel; let device: Device; let platform: MockFreeAtHomeHomebridgePlatform; let platformAccessory: PlatformAccessory<FreeAtHomeContext>; beforeEach(() => { channel = {}; device = {}; platform = new MockFreeAtHomeHomebridgePlatform(); platformAccessory = createPlatformAccessory("Shutter Accessory"); platformAccessory.context = { channel: channel, channelId: "ch1234", device: device, deviceSerial: "ABB7xxxxxxxx", }; }); afterEach(() => { platform.resetLoggerCalls(); }); it("should be created with default state", async () => { const accessory = new ShutterActuatorAccessory(platform, platformAccessory); expect(accessory).toBeTruthy(); const instance = accessory as unknown as { service: Service; }; const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(0); expect(await characteristicTp.handleGetRequest()).toBe(0); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.STOPPED ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); }); it("should be created with opening state", async () => { channel.inputs = { idp0002: { value: "75", }, }; channel.outputs = { odp0000: { value: "2", }, odp0001: { value: "50", }, odp0003: { value: "1", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); expect(accessory).toBeTruthy(); const instance = accessory as unknown as { service: Service; }; const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(50); expect(await characteristicTp.handleGetRequest()).toBe(25); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.INCREASING ); expect(await characteristicObs.handleGetRequest()).toBeTrue(); }); it("should be created with closing state", async () => { channel.inputs = { idp0002: { value: "25", }, }; channel.outputs = { odp0000: { value: "3", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); expect(accessory).toBeTruthy(); const instance = accessory as unknown as { service: Service; }; const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(50); expect(await characteristicTp.handleGetRequest()).toBe(75); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.DECREASING ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); }); it("should be created with stopped state", async () => { channel.inputs = { idp0002: { value: "50", }, }; channel.outputs = { odp0000: { value: "0", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); expect(accessory).toBeTruthy(); const instance = accessory as unknown as { service: Service; }; const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(50); expect(await characteristicTp.handleGetRequest()).toBe(50); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.STOPPED ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); }); it("should not handle a request to set TargetPosition characteristic if the value has not changed", async () => { channel.inputs = { idp0002: { value: "50", }, }; channel.outputs = { odp0000: { value: "0", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); expect(accessory).toBeTruthy(); const instance = accessory as unknown as { service: Service; }; const characteristic = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); expect(await characteristic.handleGetRequest()).toBe(50); const spy = spyOn(accessory.platform.sysap, "setDatapoint"); await characteristic.handleSetRequest(50); expect(spy).not.toHaveBeenCalled(); }); it("should handle request to set TargetPosition characteristic if the value has changed", async () => { channel.inputs = { idp0002: { value: "50", }, }; channel.outputs = { odp0000: { value: "0", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); expect(accessory).toBeTruthy(); const instance = accessory as unknown as { service: Service; }; const characteristic = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); expect(await characteristic.handleGetRequest()).toBe(50); const spy = spyOn(accessory.platform.sysap, "setDatapoint"); await characteristic.handleSetRequest(70); expect(spy).toHaveBeenCalledWith( EmptyGuid, "ABB7xxxxxxxx", "ch1234", "idp0002", "30" ); // eslint-disable-next-line @typescript-eslint/unbound-method expect(platform.log.info).toHaveBeenCalledWith( "Shutter Accessory (Shutter Actuator ABB7xxxxxxxx (ch1234)) set characteristic TargetPosition -> 70" ); }); it("should ignore update if datapoint is unknown", async () => { const accessory = new ShutterActuatorAccessory(platform, platformAccessory); const instance = accessory as unknown as { service: Service; doUpdateDatapoint: ( acccessoryDisplayType: string, service: Service, characteristic: WithUUID<new () => Characteristic>, characteristicValue: CharacteristicValue ) => void; }; const spy = spyOn(instance, "doUpdateDatapoint"); const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(0); expect(await characteristicTp.handleGetRequest()).toBe(0); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.STOPPED ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); accessory.updateDatapoint("test", ""); expect(spy).not.toHaveBeenCalled(); }); it("should process update to position state datapoint", async () => { channel.outputs = { odp0000: { value: "0", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); const instance = accessory as unknown as { service: Service; doUpdateDatapoint: ( acccessoryDisplayType: string, service: Service, characteristic: WithUUID<new () => Characteristic>, characteristicValue: CharacteristicValue ) => void; }; const spy = spyOn(instance, "doUpdateDatapoint"); const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(50); expect(await characteristicTp.handleGetRequest()).toBe(50); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.STOPPED ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); accessory.updateDatapoint("odp0000", "2"); expect(spy).toHaveBeenCalledWith( "Shutter Actuator", instance.service, accessory.platform.Characteristic.PositionState, accessory.platform.Characteristic.PositionState.INCREASING ); }); it("should process update to current position datapoint", async () => { channel.outputs = { odp0000: { value: "0", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); const instance = accessory as unknown as { service: Service; doUpdateDatapoint: ( acccessoryDisplayType: string, service: Service, characteristic: WithUUID<new () => Characteristic>, characteristicValue: CharacteristicValue ) => void; }; const spy = spyOn(instance, "doUpdateDatapoint"); const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(50); expect(await characteristicTp.handleGetRequest()).toBe(50); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.STOPPED ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); accessory.updateDatapoint("odp0001", "25"); expect(spy).toHaveBeenCalledWith( "Shutter Actuator", instance.service, accessory.platform.Characteristic.CurrentPosition, 75 ); }); it("should process update to obstruction datapoint", async () => { channel.outputs = { odp0000: { value: "0", }, odp0001: { value: "50", }, odp0003: { value: "0", }, }; const accessory = new ShutterActuatorAccessory(platform, platformAccessory); const instance = accessory as unknown as { service: Service; doUpdateDatapoint: ( acccessoryDisplayType: string, service: Service, characteristic: WithUUID<new () => Characteristic>, characteristicValue: CharacteristicValue ) => void; }; const spy = spyOn(instance, "doUpdateDatapoint"); const characteristicCp = instance.service.getCharacteristic( accessory.platform.Characteristic.CurrentPosition ); const characteristicTp = instance.service.getCharacteristic( accessory.platform.Characteristic.TargetPosition ); const characteristicPs = instance.service.getCharacteristic( accessory.platform.Characteristic.PositionState ); const characteristicObs = instance.service.getCharacteristic( accessory.platform.Characteristic.ObstructionDetected ); expect(await characteristicCp.handleGetRequest()).toBe(50); expect(await characteristicTp.handleGetRequest()).toBe(50); expect(await characteristicPs.handleGetRequest()).toBe( accessory.platform.Characteristic.PositionState.STOPPED ); expect(await characteristicObs.handleGetRequest()).toBeFalse(); accessory.updateDatapoint("odp0003", "1"); expect(spy).toHaveBeenCalledWith( "Shutter Actuator", instance.service, accessory.platform.Characteristic.ObstructionDetected, true ); }); });