diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/package.json b/package.json index 8d690a0..081696b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "main": "dist/index.js", "scripts": { "lint": "eslint src/**", + "lint:fix": "eslint --fix src/**", "watch": "npm run build && npm link && nodemon", "build": "rimraf ./dist && tsc", "prepublishOnly": "npm run lint && npm run build" diff --git a/src/Pressure.ts b/src/Pressure.ts index 1b38217..5016ba0 100644 --- a/src/Pressure.ts +++ b/src/Pressure.ts @@ -1,19 +1,19 @@ -import {Characteristic, Formats, Perms, Service} from 'homebridge' +import {Characteristic, Formats, Perms, Service} from 'homebridge'; export class Pressure extends Characteristic { static readonly UUID: string = '2B411C00-E2E2-4B21-A665-7F079E525304'; constructor() { - super('kPA', Pressure.UUID); - this.setProps({ - format: Formats.FLOAT, - maxValue: 100000, - minValue: 0, - minStep: 0.001, - perms: [Perms.PAIRED_READ, Perms.NOTIFY] - }); - this.value = this.getDefaultValue(); + super('kPA', Pressure.UUID); + this.setProps({ + format: Formats.FLOAT, + maxValue: 100000, + minValue: 0, + minStep: 0.001, + perms: [Perms.PAIRED_READ, Perms.NOTIFY], + }); + this.value = this.getDefaultValue(); } } @@ -21,8 +21,8 @@ export class PressureSensor extends Service { static readonly UUID: string = '2B411C00-E2E2-4B21-A665-7F079E525404'; constructor() { - super('Pressure', PressureSensor.UUID); + super('Pressure', PressureSensor.UUID); - this.addCharacteristic(Pressure); + this.addCharacteristic(Pressure); } } diff --git a/src/index.ts b/src/index.ts index 3f7eb19..68a9f7a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,11 +2,11 @@ import type { API } from 'homebridge'; import { PLATFORM_NAME } from './settings'; import { FlairPlatform } from './platform'; -import "reflect-metadata"; +import 'reflect-metadata'; /** * This method registers the platform with Homebridge */ export = (api: API) => { - api.registerPlatform(PLATFORM_NAME, FlairPlatform); + api.registerPlatform(PLATFORM_NAME, FlairPlatform); } diff --git a/src/platform.ts b/src/platform.ts index 8e3c723..bfd332d 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -5,11 +5,11 @@ import {PLATFORM_NAME, PLUGIN_NAME} from './settings'; import {FlairPuckPlatformAccessory} from './puckPlatformAccessory'; import {FlairVentPlatformAccessory} from './ventPlatformAccessory'; import {FlairRoomPlatformAccessory} from './roomPlatformAccessory'; -import Client from "flair-api-ts/lib/client"; -import {Puck, Vent, Room, Structure, FlairMode, StructureHeatCoolMode} from "flair-api-ts/lib/client/models"; -import {Model} from "flair-api-ts/lib/client/models/model"; -import {plainToClass} from "class-transformer"; -import {getRandomIntInclusive} from "./utils"; +import Client from 'flair-api-ts/lib/client'; +import {Puck, Vent, Room, Structure, FlairMode, StructureHeatCoolMode} from 'flair-api-ts/lib/client/models'; +import {Model} from 'flair-api-ts/lib/client/models/model'; +import {plainToClass} from 'class-transformer'; +import {getRandomIntInclusive} from './utils'; /** * HomebridgePlatform @@ -35,86 +35,86 @@ export class FlairPlatform implements DynamicPlatformPlugin { public readonly config: PlatformConfig, public readonly api: API, ) { - this.log.debug('Finished initializing platform:', this.config.name); - - if (!this.validConfig()) { - throw('The Flair config is no valid.'); - } - - this.client = new Client(this.config.clientId, this.config.clientSecret, this.config.username, this.config.password); - - // When this event is fired it means Homebridge has restored all cached accessories from disk. - // Dynamic Platform plugins should only register new accessories after this event was fired, - // in order to ensure they weren't added to homebridge already. This event can also be used - // to start discovery of new accessories. - this.api.on(APIEvent.DID_FINISH_LAUNCHING, async () => { - log.debug('Executed didFinishLaunching callback'); - // run the method to discover / register your devices as accessories - await this.discoverDevices(); - - setInterval(async () => { - await this.getNewStructureReadings() - }, (this.config.pollInterval+ getRandomIntInclusive(1,20)) * 1000); - }); + this.log.debug('Finished initializing platform:', this.config.name); + + if (!this.validConfig()) { + throw('The Flair config is no valid.'); + } + + this.client = new Client(this.config.clientId, this.config.clientSecret, this.config.username, this.config.password); + + // When this event is fired it means Homebridge has restored all cached accessories from disk. + // Dynamic Platform plugins should only register new accessories after this event was fired, + // in order to ensure they weren't added to homebridge already. This event can also be used + // to start discovery of new accessories. + this.api.on(APIEvent.DID_FINISH_LAUNCHING, async () => { + log.debug('Executed didFinishLaunching callback'); + // run the method to discover / register your devices as accessories + await this.discoverDevices(); + + setInterval(async () => { + await this.getNewStructureReadings(); + }, (this.config.pollInterval+ getRandomIntInclusive(1,20)) * 1000); + }); } private validConfig() { - if (!this.config.clientId) { - this.log.error('You need to enter a Flair Client Id') - return false; - } - - if (!this.config.clientSecret) { - this.log.error('You need to enter a Flair Client Id') - return false; - } - - if (!this.config.username) { - this.log.error('You need to enter your flair username') - return false; - } - - if (!this.config.password) { - this.log.error('You need to enter your flair password') - return false; - } - - return true; + if (!this.config.clientId) { + this.log.error('You need to enter a Flair Client Id'); + return false; + } + + if (!this.config.clientSecret) { + this.log.error('You need to enter a Flair Client Id'); + return false; + } + + if (!this.config.username) { + this.log.error('You need to enter your flair username'); + return false; + } + + if (!this.config.password) { + this.log.error('You need to enter your flair password'); + return false; + } + + return true; } private async getNewStructureReadings() { - try { - let structure = await this.client.getStructure(await this.getStructure()); - this.updateStructureFromStructureReading(structure); - } catch (e) { - this.log.error(e); - } + try { + const structure = await this.client.getStructure(await this.getStructure()); + this.updateStructureFromStructureReading(structure); + } catch (e) { + this.log.error(e); + } } private updateStructureFromStructureReading(structure: Structure) { - this.structure = structure; - for (const room of this.rooms) { - if (room) { - room.updateFromStructure(this.structure); - } + this.structure = structure; + for (const room of this.rooms) { + if (room) { + room.updateFromStructure(this.structure); } - return this.structure; + } + return this.structure; } public async setStructureMode(mode: FlairMode, heatingCoolingMode: StructureHeatCoolMode): Promise { - let structure = await this.client.setStructureMode(await this.getStructure(), mode); - structure = await this.client.setStructureHeatingCoolMode(structure, heatingCoolingMode); + let structure = await this.client.setStructureMode(await this.getStructure(), mode); + structure = await this.client.setStructureHeatingCoolMode(structure, heatingCoolingMode); - return this.updateStructureFromStructureReading(structure); + return this.updateStructureFromStructureReading(structure); } private async getStructure(): Promise { - if (this.structure) { - return this.structure!; - } - this.structure = await this.client.getPrimaryStructure(); + if (this.structure) { return this.structure!; + } + this.structure = await this.client.getPrimaryStructure(); + return this.structure!; } /** @@ -122,27 +122,26 @@ export class FlairPlatform implements DynamicPlatformPlugin { * It should be used to setup event handlers for characteristics and update respective values. */ configureAccessory(accessory: PlatformAccessory) { - this.log.info('Restoring accessory from cache:', accessory.displayName); - - if (accessory.context.type == Puck.type) { - this.log.info('Restoring puck from cache:', accessory.displayName); - accessory.context.device = plainToClass(Puck, accessory.context.device) - new FlairPuckPlatformAccessory(this, accessory, this.client); - } else if (accessory.context.type == Vent.type) { - this.log.info('Restoring vent from cache:', accessory.displayName); - accessory.context.device = plainToClass(Vent, accessory.context.device) - new FlairVentPlatformAccessory(this, accessory, this.client); - } else if (accessory.context.type == Room.type) { - this.log.info('Restoring room from cache:', accessory.displayName); - accessory.context.device = plainToClass(Room, accessory.context.device) - let self = this; - this.getStructure().then((structure: Structure) => { - self.rooms.push(new FlairRoomPlatformAccessory(self, accessory, this.client, structure)); - }) - } + this.log.info('Restoring accessory from cache:', accessory.displayName); + + if (accessory.context.type === Puck.type) { + this.log.info('Restoring puck from cache:', accessory.displayName); + accessory.context.device = plainToClass(Puck, accessory.context.device); + new FlairPuckPlatformAccessory(this, accessory, this.client); + } else if (accessory.context.type === Vent.type) { + this.log.info('Restoring vent from cache:', accessory.displayName); + accessory.context.device = plainToClass(Vent, accessory.context.device); + new FlairVentPlatformAccessory(this, accessory, this.client); + } else if (accessory.context.type === Room.type) { + this.log.info('Restoring room from cache:', accessory.displayName); + accessory.context.device = plainToClass(Room, accessory.context.device); + this.getStructure().then((structure: Structure) => { + this.rooms.push(new FlairRoomPlatformAccessory(this, accessory, this.client, structure)); + }); + } - // add the restored accessory to the accessories cache so we can track if it has already been registered - this.accessories.push(accessory); + // add the restored accessory to the accessories cache so we can track if it has already been registered + this.accessories.push(accessory); } /** @@ -151,86 +150,85 @@ export class FlairPlatform implements DynamicPlatformPlugin { * must not be registered again to prevent "duplicate UUID" errors. */ async discoverDevices() { - let currentUUIDs: string[] = []; - let uuids: [string[], string[], string[]] = await Promise.all([ - this.addDevices(await this.client.getPucks()), - this.addDevices(await this.client.getVents()), - this.addDevices((await this.client.getRooms()).filter((value: Room) => { - return value.pucksInactive === 'Active' - }) as [Room]) - ]); - - currentUUIDs = currentUUIDs.concat(uuids[0], uuids[1], uuids[2]) - - - //Loop over the current uuid's and if they don't exist then remove them. - for (const accessory of this.accessories) { - if (!currentUUIDs.find(uuid => uuid === accessory.UUID)) { - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - delete this.accessories[this.accessories.indexOf(accessory, 0)]; - this.log.debug('Removing not found device:', accessory.displayName) - } + let currentUUIDs: string[] = []; + const uuids: [string[], string[], string[]] = await Promise.all([ + this.addDevices(await this.client.getPucks()), + this.addDevices(await this.client.getVents()), + this.addDevices((await this.client.getRooms()).filter((value: Room) => { + return value.pucksInactive === 'Active'; + }) as [Room]), + ]); + + currentUUIDs = currentUUIDs.concat(uuids[0], uuids[1], uuids[2]); + + + //Loop over the current uuid's and if they don't exist then remove them. + for (const accessory of this.accessories) { + if (!currentUUIDs.find(uuid => uuid === accessory.UUID)) { + this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); + delete this.accessories[this.accessories.indexOf(accessory, 0)]; + this.log.debug('Removing not found device:', accessory.displayName); } + } } async addDevices(devices: [Model]): Promise { - const currentUUIDs: string[] = []; - - // loop over the discovered devices and register each one if it has not already been registered - for (const device of devices) { - - // generate a unique id for the accessory this should be generated from - // something globally unique, but constant, for example, the device serial - // number or MAC address - const uuid = this.api.hap.uuid.generate(device.id!); - currentUUIDs.push(uuid); - - // check that the device has not already been registered by checking the - // cached devices we stored in the `configureAccessory` method above - if (!this.accessories.find(accessory => accessory.UUID === uuid)) { - - // create a new accessory - const accessory = new this.api.platformAccessory(device.name!, uuid); - - // store a copy of the device object in the `accessory.context` - // the `context` property can be used to store any data about the accessory you may need - accessory.context.device = device; - - - // create the accessory handler - // this is imported from `puckPlatformAccessory.ts` - if (device instanceof Puck) { - accessory.context.type = Puck.type; - new FlairPuckPlatformAccessory(this, accessory, this.client); - } else if (device instanceof Vent) { - accessory.context.type = Vent.type; - new FlairVentPlatformAccessory(this, accessory, this.client); - } else if (device instanceof Room) { - accessory.context.type = Room.type; - let self = this; - this.getStructure().then((structure: Structure) => { - self.rooms.push(new FlairRoomPlatformAccessory(self, accessory, this.client, structure)); - }) - } else { - continue; - } - this.log.info(`Registering new ${accessory.context.type}`, device.name!); - - // link the accessory to your platform - this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - - // push into accessory cache - this.accessories.push(accessory); - - // it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.: - // this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - } else { - this.log.debug('Discovered accessory already exists:', device.name!) - } + const currentUUIDs: string[] = []; + + // loop over the discovered devices and register each one if it has not already been registered + for (const device of devices) { + + // generate a unique id for the accessory this should be generated from + // something globally unique, but constant, for example, the device serial + // number or MAC address + const uuid = this.api.hap.uuid.generate(device.id!); + currentUUIDs.push(uuid); + + // check that the device has not already been registered by checking the + // cached devices we stored in the `configureAccessory` method above + if (!this.accessories.find(accessory => accessory.UUID === uuid)) { + + // create a new accessory + const accessory = new this.api.platformAccessory(device.name!, uuid); + + // store a copy of the device object in the `accessory.context` + // the `context` property can be used to store any data about the accessory you may need + accessory.context.device = device; + + + // create the accessory handler + // this is imported from `puckPlatformAccessory.ts` + if (device instanceof Puck) { + accessory.context.type = Puck.type; + new FlairPuckPlatformAccessory(this, accessory, this.client); + } else if (device instanceof Vent) { + accessory.context.type = Vent.type; + new FlairVentPlatformAccessory(this, accessory, this.client); + } else if (device instanceof Room) { + accessory.context.type = Room.type; + this.getStructure().then((structure: Structure) => { + this.rooms.push(new FlairRoomPlatformAccessory(this, accessory, this.client, structure)); + }); + } else { + continue; + } + this.log.info(`Registering new ${accessory.context.type}`, device.name!); + + // link the accessory to your platform + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); + + // push into accessory cache + this.accessories.push(accessory); + + // it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.: + // this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); + } else { + this.log.debug('Discovered accessory already exists:', device.name!); } + } - return currentUUIDs + return currentUUIDs; } } diff --git a/src/puckPlatformAccessory.ts b/src/puckPlatformAccessory.ts index 3da39d3..6b8a1f5 100644 --- a/src/puckPlatformAccessory.ts +++ b/src/puckPlatformAccessory.ts @@ -1,17 +1,13 @@ -import {CharacteristicEventTypes} from 'homebridge'; import type { - Service, - PlatformAccessory, - CharacteristicValue, - CharacteristicSetCallback, - CharacteristicGetCallback + Service, + PlatformAccessory, } from 'homebridge'; import {FlairPlatform} from './platform'; -import {Puck, Vent} from "flair-api-ts/lib/client/models"; -import Client from "flair-api-ts/lib/client"; -import {Pressure, PressureSensor} from "./Pressure"; -import {getRandomIntInclusive} from "./utils"; +import {Puck} from 'flair-api-ts/lib/client/models'; +import Client from 'flair-api-ts/lib/client'; +import {Pressure, PressureSensor} from './Pressure'; +import {getRandomIntInclusive} from './utils'; /** * Platform Accessory @@ -31,66 +27,72 @@ export class FlairPuckPlatformAccessory { constructor( private readonly platform: FlairPlatform, private readonly accessory: PlatformAccessory, - client: Client + client: Client, ) { - this.puck = this.accessory.context.device; - this.client = client; - - // set accessory information - this.accessoryInformationService = this.accessory.getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Flair') - .setCharacteristic(this.platform.Characteristic.Model, 'Puck') - .setCharacteristic(this.platform.Characteristic.SerialNumber, this.puck.displayNumber); - - // you can create multiple services for each accessory - this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor) ?? this.accessory.addService(this.platform.Service.TemperatureSensor); - this.temperatureService.setPrimaryService(true); - this.temperatureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); - this.temperatureService.setCharacteristic(this.platform.Characteristic.CurrentTemperature, this.puck.currentTemperatureC) - - this.humidityService = this.accessory.getService(this.platform.Service.HumiditySensor) ?? this.accessory.addService(this.platform.Service.HumiditySensor); - this.humidityService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); - this.humidityService.setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.puck.currentHumidity) - this.temperatureService.addLinkedService(this.humidityService); - - //Add our custom pressure sensor - this.pressureService = this.accessory.getService(PressureSensor) ?? this.accessory.addService(PressureSensor); - this.pressureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); - this.pressureService.setCharacteristic(Pressure, this.puck.currentRoomPressure); - this.temperatureService.addLinkedService(this.pressureService); - - setInterval(async () => { - await this.getNewPuckReadings() - }, (platform.config.pollInterval + getRandomIntInclusive(1, 20)) * 1000); - this.getNewPuckReadings(); + this.puck = this.accessory.context.device; + this.client = client; + + // set accessory information + this.accessoryInformationService = this.accessory.getService(this.platform.Service.AccessoryInformation)! + .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Flair') + .setCharacteristic(this.platform.Characteristic.Model, 'Puck') + .setCharacteristic(this.platform.Characteristic.SerialNumber, this.puck.displayNumber); + + // you can create multiple services for each accessory + this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor) + ?? this.accessory.addService(this.platform.Service.TemperatureSensor); + this.temperatureService.setPrimaryService(true); + this.temperatureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); + this.temperatureService.setCharacteristic( + this.platform.Characteristic.CurrentTemperature, + this.puck.currentTemperatureC, + ); + + this.humidityService = this.accessory.getService(this.platform.Service.HumiditySensor) + ?? this.accessory.addService(this.platform.Service.HumiditySensor); + this.humidityService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); + this.humidityService.setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.puck.currentHumidity); + this.temperatureService.addLinkedService(this.humidityService); + + //Add our custom pressure sensor + this.pressureService = this.accessory.getService(PressureSensor) + ?? this.accessory.addService(PressureSensor); + this.pressureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); + this.pressureService.setCharacteristic(Pressure, this.puck.currentRoomPressure); + this.temperatureService.addLinkedService(this.pressureService); + + setInterval(async () => { + await this.getNewPuckReadings(); + }, (platform.config.pollInterval + getRandomIntInclusive(1, 20)) * 1000); + this.getNewPuckReadings(); } async getNewPuckReadings(): Promise { - try { - let puck = await this.client.getPuckReading(this.puck) - this.updatePuckReadingsFromPuck(puck) - return puck; - } catch (e) { - this.platform.log.error(e); - } - - return this.puck + try { + const puck = await this.client.getPuckReading(this.puck); + this.updatePuckReadingsFromPuck(puck); + return puck; + } catch (e) { + this.platform.log.error(e); + } + + return this.puck; } updatePuckReadingsFromPuck(puck: Puck) { - this.accessory.context.device = puck; - this.puck = puck; + this.accessory.context.device = puck; + this.puck = puck; - // push the new value to HomeKit - this.temperatureService.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.puck.currentTemperatureC); - this.humidityService.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.puck.currentHumidity); - this.pressureService.updateCharacteristic(Pressure, this.puck.currentRoomPressure); + // push the new value to HomeKit + this.temperatureService.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.puck.currentTemperatureC); + this.humidityService.updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.puck.currentHumidity); + this.pressureService.updateCharacteristic(Pressure, this.puck.currentRoomPressure); - this.accessory.getService(this.platform.Service.AccessoryInformation)! - .updateCharacteristic(this.platform.Characteristic.FirmwareRevision, this.puck.firmwareVersionS) + this.accessory.getService(this.platform.Service.AccessoryInformation)! + .updateCharacteristic(this.platform.Characteristic.FirmwareRevision, this.puck.firmwareVersionS); - this.platform.log.debug(`Pushed updated current temperature state for ${this.puck.name!} to HomeKit:`, this.puck.currentTemperatureC); + this.platform.log.debug(`Pushed updated current temperature state for ${this.puck.name!} to HomeKit:`, this.puck.currentTemperatureC); } } diff --git a/src/roomPlatformAccessory.ts b/src/roomPlatformAccessory.ts index 1658a58..d2e05b3 100644 --- a/src/roomPlatformAccessory.ts +++ b/src/roomPlatformAccessory.ts @@ -1,15 +1,15 @@ import type {PlatformAccessory, Service} from 'homebridge'; import { - CharacteristicEventTypes, - CharacteristicGetCallback, - CharacteristicSetCallback, - CharacteristicValue + CharacteristicEventTypes, + CharacteristicGetCallback, + CharacteristicSetCallback, + CharacteristicValue, } from 'homebridge'; import {FlairPlatform} from './platform'; -import Client from "flair-api-ts/lib/client"; -import {FlairMode, Room, Structure, StructureHeatCoolMode} from "flair-api-ts/lib/client/models"; -import {getRandomIntInclusive} from "./utils"; +import Client from 'flair-api-ts/lib/client'; +import {FlairMode, Room, Structure, StructureHeatCoolMode} from 'flair-api-ts/lib/client/models'; +import {getRandomIntInclusive} from './utils'; /** * Platform Accessory @@ -29,157 +29,175 @@ export class FlairRoomPlatformAccessory { private readonly platform: FlairPlatform, private readonly accessory: PlatformAccessory, client: Client, - structure: Structure + structure: Structure, ) { - this.room = this.accessory.context.device; - this.client = client; - this.structure = structure; - - // set accessory information - this.accessoryInformationService = this.accessory.getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Flair') - .setCharacteristic(this.platform.Characteristic.Model, 'Room') - .setCharacteristic(this.platform.Characteristic.SerialNumber, this.room.id!); - - this.thermostatService = this.accessory.getService(this.platform.Service.Thermostat) ?? this.accessory.addService(this.platform.Service.Thermostat); - this.thermostatService.setPrimaryService(true); - this.thermostatService - .setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name) - .setCharacteristic(this.platform.Characteristic.CurrentTemperature, this.room.currentTemperatureC!) - .setCharacteristic(this.platform.Characteristic.TargetTemperature, this.room.setPointC!) - .setCharacteristic(this.platform.Characteristic.TargetHeatingCoolingState, this.getTargetHeatingCoolingStateFromStructure(this.structure)!) - .setCharacteristic(this.platform.Characteristic.CurrentHeatingCoolingState, this.getCurrentHeatingCoolingStateFromStructure(this.structure)!) - .setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.room.currentHumidity!) - - this.thermostatService.getCharacteristic(this.platform.Characteristic.TargetTemperature) - .on(CharacteristicEventTypes.SET, this.setTargetTemperature.bind(this)) - .on(CharacteristicEventTypes.GET, this.getTargetTemperature.bind(this)) - - this.thermostatService.getCharacteristic(this.platform.Characteristic.TargetHeatingCoolingState) - .on(CharacteristicEventTypes.SET, this.setTargetHeatingCoolingState.bind(this)) - // .on(CharacteristicEventTypes.GET, this.getTargetTemperature.bind(this)) - - setInterval(async () => { - await this.getNewRoomReadings() - }, (platform.config.pollInterval+ getRandomIntInclusive(1,20)) * 1000); - this.getNewRoomReadings(); + this.room = this.accessory.context.device; + this.client = client; + this.structure = structure; + + // set accessory information + this.accessoryInformationService = this.accessory.getService(this.platform.Service.AccessoryInformation)! + .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Flair') + .setCharacteristic(this.platform.Characteristic.Model, 'Room') + .setCharacteristic(this.platform.Characteristic.SerialNumber, this.room.id!); + + this.thermostatService = this.accessory.getService(this.platform.Service.Thermostat) + ?? this.accessory.addService(this.platform.Service.Thermostat); + this.thermostatService.setPrimaryService(true); + this.thermostatService + .setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name) + .setCharacteristic(this.platform.Characteristic.CurrentTemperature, this.room.currentTemperatureC!) + .setCharacteristic(this.platform.Characteristic.TargetTemperature, this.room.setPointC!) + .setCharacteristic( + this.platform.Characteristic.TargetHeatingCoolingState, + this.getTargetHeatingCoolingStateFromStructure(this.structure)!, + ) + .setCharacteristic( + this.platform.Characteristic.CurrentHeatingCoolingState, + this.getCurrentHeatingCoolingStateFromStructure(this.structure)!, + ) + .setCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.room.currentHumidity!); + + this.thermostatService.getCharacteristic(this.platform.Characteristic.TargetTemperature) + .on(CharacteristicEventTypes.SET, this.setTargetTemperature.bind(this)) + .on(CharacteristicEventTypes.GET, this.getTargetTemperature.bind(this)); + + this.thermostatService.getCharacteristic(this.platform.Characteristic.TargetHeatingCoolingState) + .on(CharacteristicEventTypes.SET, this.setTargetHeatingCoolingState.bind(this)); + // .on(CharacteristicEventTypes.GET, this.getTargetTemperature.bind(this)) + + setInterval(async () => { + await this.getNewRoomReadings(); + }, (platform.config.pollInterval+ getRandomIntInclusive(1,20)) * 1000); + this.getNewRoomReadings(); } setTargetHeatingCoolingState(value: CharacteristicValue, callback: CharacteristicSetCallback) { - if (value == this.platform.Characteristic.TargetHeatingCoolingState.OFF) { - this.platform.setStructureMode(FlairMode.MANUAL, StructureHeatCoolMode.COOL).then((structure: Structure) => { - callback(null, value); - this.updateFromStructure(structure); - }) - } else if(value == this.platform.Characteristic.TargetHeatingCoolingState.COOL) { - this.platform.setStructureMode(FlairMode.AUTO, StructureHeatCoolMode.COOL).then((structure: Structure) => { - callback(null, value); - this.updateFromStructure(structure); - }) - } else if(value == this.platform.Characteristic.TargetHeatingCoolingState.HEAT) { - this.platform.setStructureMode(FlairMode.AUTO, StructureHeatCoolMode.HEAT).then((structure: Structure) => { - callback(null, value); - this.updateFromStructure(structure); - }) - } else if(value == this.platform.Characteristic.TargetHeatingCoolingState.AUTO) { - this.platform.setStructureMode(FlairMode.AUTO, StructureHeatCoolMode.COOL).then((structure: Structure) => { - callback(null, this.platform.Characteristic.TargetHeatingCoolingState.AUTO); - this.updateFromStructure(structure); - }) - } + if (value === this.platform.Characteristic.TargetHeatingCoolingState.OFF) { + this.platform.setStructureMode(FlairMode.MANUAL, StructureHeatCoolMode.COOL).then((structure: Structure) => { + callback(null, value); + this.updateFromStructure(structure); + }); + } else if(value === this.platform.Characteristic.TargetHeatingCoolingState.COOL) { + this.platform.setStructureMode(FlairMode.AUTO, StructureHeatCoolMode.COOL).then((structure: Structure) => { + callback(null, value); + this.updateFromStructure(structure); + }); + } else if(value === this.platform.Characteristic.TargetHeatingCoolingState.HEAT) { + this.platform.setStructureMode(FlairMode.AUTO, StructureHeatCoolMode.HEAT).then((structure: Structure) => { + callback(null, value); + this.updateFromStructure(structure); + }); + } else if(value === this.platform.Characteristic.TargetHeatingCoolingState.AUTO) { + this.platform.setStructureMode(FlairMode.AUTO, StructureHeatCoolMode.COOL).then((structure: Structure) => { + callback(null, this.platform.Characteristic.TargetHeatingCoolingState.AUTO); + this.updateFromStructure(structure); + }); + } } setTargetTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { - let self = this; - this.client.setRoomSetPoint(this.room, value as number).then(function (room: Room) { - self.updateRoomReadingsFromRoom(room) - self.platform.log.debug('Set Characteristic Temperature -> ', value); - // you must call the callback function - callback(null, room.setPointC); - }) + this.client.setRoomSetPoint(this.room, value as number).then((room: Room) => { + this.updateRoomReadingsFromRoom(room); + this.platform.log.debug('Set Characteristic Temperature -> ', value); + // you must call the callback function + callback(null, room.setPointC); + }); } getTargetTemperature(callback: CharacteristicGetCallback) { - this.getNewRoomReadings().then(function (room: Room) { - callback(null, room.setPointC) - }) + this.getNewRoomReadings().then((room: Room) => { + callback(null, room.setPointC); + }); } async getNewRoomReadings(): Promise { - try { - let room = await this.client.getRoom(this.room) - this.updateRoomReadingsFromRoom(room) - return room; - } catch (e) { - this.platform.log.error(e); - } - - return this.room + try { + const room = await this.client.getRoom(this.room); + this.updateRoomReadingsFromRoom(room); + return room; + } catch (e) { + this.platform.log.error(e); + } + + return this.room; } public updateFromStructure(structure: Structure) { - this.structure = structure; - - // push the new value to HomeKit - this.thermostatService - .updateCharacteristic(this.platform.Characteristic.TargetHeatingCoolingState, this.getTargetHeatingCoolingStateFromStructure(this.structure)!) - .updateCharacteristic(this.platform.Characteristic.CurrentHeatingCoolingState, this.getCurrentHeatingCoolingStateFromStructure(this.structure)!) - - this.platform.log.debug(`Pushed updated current structure state for ${this.room.name!} to HomeKit:`, this.structure.structureHeatCoolMode!); + this.structure = structure; + + // push the new value to HomeKit + this.thermostatService + .updateCharacteristic( + this.platform.Characteristic.TargetHeatingCoolingState, + this.getTargetHeatingCoolingStateFromStructure(this.structure)!, + ) + .updateCharacteristic( + this.platform.Characteristic.CurrentHeatingCoolingState, + this.getCurrentHeatingCoolingStateFromStructure(this.structure)!, + ); + + this.platform.log.debug( + `Pushed updated current structure state for ${this.room.name!} to HomeKit:`, + this.structure.structureHeatCoolMode!, + ); } updateRoomReadingsFromRoom(room: Room) { - this.accessory.context.device = room; - this.room = room; - - // push the new value to HomeKit - this.thermostatService - .updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.room.currentTemperatureC!) - .updateCharacteristic(this.platform.Characteristic.TargetTemperature, this.room.setPointC!) - .updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.room.currentHumidity!) - this.platform.log.debug(`Pushed updated current temperature state for ${this.room.name!} to HomeKit:`, this.room.currentTemperatureC!); + this.accessory.context.device = room; + this.room = room; + + // push the new value to HomeKit + this.thermostatService + .updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.room.currentTemperatureC!) + .updateCharacteristic(this.platform.Characteristic.TargetTemperature, this.room.setPointC!) + .updateCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity, this.room.currentHumidity!); + this.platform.log.debug( + `Pushed updated current temperature state for ${this.room.name!} to HomeKit:`, + this.room.currentTemperatureC!, + ); } private getCurrentHeatingCoolingStateFromStructure(structure: Structure) { - if (structure.mode === FlairMode.MANUAL) { - return this.platform.Characteristic.CurrentHeatingCoolingState.OFF - } + if (structure.mode === FlairMode.MANUAL) { + return this.platform.Characteristic.CurrentHeatingCoolingState.OFF; + } - if (structure.structureHeatCoolMode === StructureHeatCoolMode.COOL) { - return this.platform.Characteristic.CurrentHeatingCoolingState.COOL; - } + if (structure.structureHeatCoolMode === StructureHeatCoolMode.COOL) { + return this.platform.Characteristic.CurrentHeatingCoolingState.COOL; + } - if (structure.structureHeatCoolMode === StructureHeatCoolMode.HEAT) { - return this.platform.Characteristic.CurrentHeatingCoolingState.HEAT; - } + if (structure.structureHeatCoolMode === StructureHeatCoolMode.HEAT) { + return this.platform.Characteristic.CurrentHeatingCoolingState.HEAT; + } - if (structure.structureHeatCoolMode === StructureHeatCoolMode.AUTO) { - return this.platform.Characteristic.CurrentHeatingCoolingState.COOL; - } + if (structure.structureHeatCoolMode === StructureHeatCoolMode.AUTO) { + return this.platform.Characteristic.CurrentHeatingCoolingState.COOL; + } } private getTargetHeatingCoolingStateFromStructure(structure: Structure) { - if (structure.mode === FlairMode.MANUAL) { - return this.platform.Characteristic.TargetHeatingCoolingState.OFF - } + if (structure.mode === FlairMode.MANUAL) { + return this.platform.Characteristic.TargetHeatingCoolingState.OFF; + } - if (structure.structureHeatCoolMode === StructureHeatCoolMode.COOL) { - return this.platform.Characteristic.TargetHeatingCoolingState.COOL; - } + if (structure.structureHeatCoolMode === StructureHeatCoolMode.COOL) { + return this.platform.Characteristic.TargetHeatingCoolingState.COOL; + } - if (structure.structureHeatCoolMode === StructureHeatCoolMode.HEAT) { - return this.platform.Characteristic.TargetHeatingCoolingState.HEAT; - } + if (structure.structureHeatCoolMode === StructureHeatCoolMode.HEAT) { + return this.platform.Characteristic.TargetHeatingCoolingState.HEAT; + } - if (structure.structureHeatCoolMode === StructureHeatCoolMode.AUTO) { - return this.platform.Characteristic.TargetHeatingCoolingState.AUTO; - } + if (structure.structureHeatCoolMode === StructureHeatCoolMode.AUTO) { + return this.platform.Characteristic.TargetHeatingCoolingState.AUTO; + } } } diff --git a/src/utils.ts b/src/utils.ts index e8fb91e..6a99750 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ export function getRandomIntInclusive(min: number, max: number) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive } diff --git a/src/ventPlatformAccessory.ts b/src/ventPlatformAccessory.ts index a6d4a29..0e446aa 100644 --- a/src/ventPlatformAccessory.ts +++ b/src/ventPlatformAccessory.ts @@ -1,16 +1,16 @@ import type { - CharacteristicGetCallback, - CharacteristicSetCallback, - CharacteristicValue, - PlatformAccessory, - Service + CharacteristicGetCallback, + CharacteristicSetCallback, + CharacteristicValue, + PlatformAccessory, + Service, } from 'homebridge'; import {CharacteristicEventTypes} from 'homebridge'; import {FlairPlatform} from './platform'; -import Client from "flair-api-ts/lib/client"; -import {Vent} from "flair-api-ts/lib/client/models"; -import {Pressure, PressureSensor} from "./Pressure"; -import {getRandomIntInclusive} from "./utils"; +import Client from 'flair-api-ts/lib/client'; +import {Vent} from 'flair-api-ts/lib/client/models'; +import {Pressure, PressureSensor} from './Pressure'; +import {getRandomIntInclusive} from './utils'; /** * Platform Accessory @@ -29,47 +29,55 @@ export class FlairVentPlatformAccessory { constructor( private readonly platform: FlairPlatform, private readonly accessory: PlatformAccessory, - client: Client + client: Client, ) { - this.vent = this.accessory.context.device; - this.client = client; - - // set accessory information - this.accessoryInformationService = this.accessory.getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Flair') - .setCharacteristic(this.platform.Characteristic.Model, 'Vent') - .setCharacteristic(this.platform.Characteristic.SerialNumber, this.vent.id!); - - // We fake a vent as a window covering. - this.windowService = this.accessory.getService(this.platform.Service.WindowCovering) ?? this.accessory.addService(this.platform.Service.WindowCovering); - this.windowService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); - this.windowService.setPrimaryService(true) - - //Add our temperature sensor - this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor) ?? this.accessory.addService(this.platform.Service.TemperatureSensor); - this.temperatureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); - this.temperatureService.setCharacteristic(this.platform.Characteristic.CurrentTemperature, this.vent.ductTemperatureC); - this.windowService.addLinkedService(this.temperatureService); - - //Add our custom pressure sensor - this.pressureService = this.accessory.getService(PressureSensor) ?? this.accessory.addService(PressureSensor); - this.pressureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); - this.pressureService.setCharacteristic(Pressure, this.vent.ductPressure); - this.windowService.addLinkedService(this.pressureService); - - this.windowService.setCharacteristic(this.platform.Characteristic.TargetPosition, this.vent.percentOpen) - this.windowService.setCharacteristic(this.platform.Characteristic.CurrentPosition, this.vent.percentOpen) - this.windowService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED) - this.windowService.getCharacteristic(this.platform.Characteristic.TargetPosition) - .on(CharacteristicEventTypes.SET, this.setTargetPosition.bind(this)) - .on(CharacteristicEventTypes.GET, this.getTargetPosition.bind(this)) - - - - setInterval(async () => { - await this.getNewVentReadings() - }, (platform.config.pollInterval+ getRandomIntInclusive(1,20)) * 1000); - this.getNewVentReadings() + this.vent = this.accessory.context.device; + this.client = client; + + // set accessory information + this.accessoryInformationService = this.accessory.getService(this.platform.Service.AccessoryInformation)! + .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Flair') + .setCharacteristic(this.platform.Characteristic.Model, 'Vent') + .setCharacteristic(this.platform.Characteristic.SerialNumber, this.vent.id!); + + // We fake a vent as a window covering. + this.windowService = this.accessory.getService(this.platform.Service.WindowCovering) + ?? this.accessory.addService(this.platform.Service.WindowCovering); + this.windowService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); + this.windowService.setPrimaryService(true); + + //Add our temperature sensor + this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor) + ?? this.accessory.addService(this.platform.Service.TemperatureSensor); + this.temperatureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); + this.temperatureService.setCharacteristic( + this.platform.Characteristic.CurrentTemperature, + this.vent.ductTemperatureC, + ); + this.windowService.addLinkedService(this.temperatureService); + + //Add our custom pressure sensor + this.pressureService = this.accessory.getService(PressureSensor) ?? this.accessory.addService(PressureSensor); + this.pressureService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.name); + this.pressureService.setCharacteristic(Pressure, this.vent.ductPressure); + this.windowService.addLinkedService(this.pressureService); + + this.windowService.setCharacteristic(this.platform.Characteristic.TargetPosition, this.vent.percentOpen); + this.windowService.setCharacteristic(this.platform.Characteristic.CurrentPosition, this.vent.percentOpen); + this.windowService.setCharacteristic( + this.platform.Characteristic.PositionState, + this.platform.Characteristic.PositionState.STOPPED, + ); + this.windowService.getCharacteristic(this.platform.Characteristic.TargetPosition) + .on(CharacteristicEventTypes.SET, this.setTargetPosition.bind(this)) + .on(CharacteristicEventTypes.GET, this.getTargetPosition.bind(this)); + + + + setInterval(async () => { + await this.getNewVentReadings(); + }, (platform.config.pollInterval+ getRandomIntInclusive(1,20)) * 1000); + this.getNewVentReadings(); } /** @@ -77,53 +85,61 @@ export class FlairVentPlatformAccessory { // * These are sent when the user changes the state of an accessory, for example, changing the Brightness // */ setTargetPosition(value: CharacteristicValue, callback: CharacteristicSetCallback) { - let self = this; - this.client.setVentPercentOpen(this.vent, value as number).then(function (vent: Vent) { - self.updateVentReadingsFromVent(vent) - self.platform.log.debug('Set Characteristic Percent Open -> ', value); - // you must call the callback function - callback(null, vent.percentOpen); - }) + this.client.setVentPercentOpen(this.vent, value as number).then((vent: Vent) => { + this.updateVentReadingsFromVent(vent); + this.platform.log.debug('Set Characteristic Percent Open -> ', value); + // you must call the callback function + callback(null, vent.percentOpen); + }); } getTargetPosition(callback: CharacteristicGetCallback) { - this.getNewVentReadings().then(function (vent: Vent) { - callback(null, vent.percentOpen) - }) + this.getNewVentReadings().then((vent: Vent) => { + callback(null, vent.percentOpen); + }); } async getNewVentReadings(): Promise { - try { - let vent = await this.client.getVentReading(this.vent) - this.updateVentReadingsFromVent(vent) - return vent; - } catch (e) { - this.platform.log.error(e); - } - - return this.vent + try { + const vent = await this.client.getVentReading(this.vent); + this.updateVentReadingsFromVent(vent); + return vent; + } catch (e) { + this.platform.log.error(e); + } + + return this.vent; } updateVentReadingsFromVent(vent: Vent) { - this.accessory.context.device = vent; - this.vent = vent; - - this.temperatureService.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.vent.ductTemperatureC); - - this.pressureService.updateCharacteristic(Pressure, this.vent.ductPressure); - - this.windowService.updateCharacteristic(this.platform.Characteristic.TargetPosition, this.vent.percentOpen); - this.windowService.updateCharacteristic(this.platform.Characteristic.CurrentPosition, this.vent.percentOpen); - this.windowService.updateCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED) - - this.accessoryInformationService.updateCharacteristic(this.platform.Characteristic.FirmwareRevision, this.vent.firmwareVersionS) - - this.platform.log.debug(`Pushed updated state for vent: ${this.vent.name!} to HomeKit`, { - open: this.vent.percentOpen, - pressure: this.vent.ductPressure, - temperature: this.vent.ductTemperatureC - }); + this.accessory.context.device = vent; + this.vent = vent; + + this.temperatureService.updateCharacteristic( + this.platform.Characteristic.CurrentTemperature, + this.vent.ductTemperatureC, + ); + + this.pressureService.updateCharacteristic(Pressure, this.vent.ductPressure); + + this.windowService.updateCharacteristic(this.platform.Characteristic.TargetPosition, this.vent.percentOpen); + this.windowService.updateCharacteristic(this.platform.Characteristic.CurrentPosition, this.vent.percentOpen); + this.windowService.updateCharacteristic( + this.platform.Characteristic.PositionState, + this.platform.Characteristic.PositionState.STOPPED, + ); + + this.accessoryInformationService.updateCharacteristic( + this.platform.Characteristic.FirmwareRevision, + this.vent.firmwareVersionS, + ); + + this.platform.log.debug(`Pushed updated state for vent: ${this.vent.name!} to HomeKit`, { + open: this.vent.percentOpen, + pressure: this.vent.ductPressure, + temperature: this.vent.ductTemperatureC, + }); } }