diff options
Diffstat (limited to 'src/accessory.ts')
| -rw-r--r-- | src/accessory.ts | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/accessory.ts b/src/accessory.ts new file mode 100644 index 0000000..a3bd051 --- /dev/null +++ b/src/accessory.ts @@ -0,0 +1,170 @@ +import type { Service, PlatformAccessory, CharacteristicValue } from 'homebridge'; +import type { Device } from './device.js'; + +import { Platform } from './platform.js'; +import { WindLevel } from './device.js'; + +export class Accessory { + private service: Service; + + constructor( + private readonly platform: Platform, + private readonly accessory: PlatformAccessory, + private readonly device: Device, + ) { + this.accessory.getService(this.platform.Service.AccessoryInformation)! + .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Xiaomi') + .setCharacteristic(this.platform.Characteristic.Model, 'xiaomi.aircondition.ma2') + .setCharacteristic(this.platform.Characteristic.SerialNumber, this.device.deviceId().toString()); + + this.service = this.accessory.getService(this.platform.Service.HeaterCooler) + || this.accessory.addService(this.platform.Service.HeaterCooler); + + this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessory.context.config.name); + + this.service.getCharacteristic(this.platform.Characteristic.Active) + .onSet(this.setActive.bind(this)) + .onGet(this.getActive.bind(this)); + + this.service.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState) + .onGet(this.getCurrentHeaterCoolerState.bind(this)); + + this.service.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState) + .onSet(this.setTargetHeaterCoolerState.bind(this)) + .onGet(this.getTargetHeaterCoolerState.bind(this)); + + this.service.getCharacteristic(this.platform.Characteristic.CurrentTemperature) + .onGet(this.getCurrentTemperature.bind(this)); + + this.service.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature) + .onSet(this.setTargetTemperature.bind(this)) + .onGet(this.getTargetTemperature.bind(this)) + .setProps({ + minValue: 16, + maxValue: 31, + minStep: 0.5, + }); + + this.service.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature) + .onSet(this.setTargetTemperature.bind(this)) + .onGet(this.getTargetTemperature.bind(this)) + .setProps({ + minValue: 16, + maxValue: 31, + minStep: 0.5, + }); + + this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed) + .onSet(this.setRotationSpeed.bind(this)) + .onGet(this.getRotationSpeed.bind(this)); + + this.service.getCharacteristic(this.platform.Characteristic.SwingMode) + .onSet(this.setSwingMode.bind(this)) + .onGet(this.getSwingMode.bind(this)); + + this.polling(); + } + + async polling() { + await this.device.refresh(); + this.platform.log.debug('Polling state from device: ', this.device.getRawState()); + setTimeout(this.polling.bind(this), 60000); + } + + async setActive(value: CharacteristicValue) { + if (value === this.platform.Characteristic.Active.ACTIVE) { + await this.device.turnOn(); + + return; + } + + await this.device.turnOff(); + } + + async getActive(): Promise<CharacteristicValue> { + return this.device.isOn() + ? this.platform.Characteristic.Active.ACTIVE + : this.platform.Characteristic.Active.INACTIVE; + } + + async getCurrentHeaterCoolerState(): Promise<CharacteristicValue> { + if (this.device.isOff()) { + return this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE; + } + + if (this.device.isCooling()) { + return this.device.temperature() > this.device.targetTemperature() + ? this.platform.Characteristic.CurrentHeaterCoolerState.COOLING + : this.platform.Characteristic.CurrentHeaterCoolerState.IDLE; + } + + if (this.device.isHeating()) { + return this.device.temperature() < this.device.targetTemperature() + ? this.platform.Characteristic.CurrentHeaterCoolerState.HEATING + : this.platform.Characteristic.CurrentHeaterCoolerState.IDLE; + } + + return this.platform.Characteristic.CurrentHeaterCoolerState.COOLING; + } + + async setTargetHeaterCoolerState(value: CharacteristicValue) { + switch (value) { + case this.platform.Characteristic.TargetHeaterCoolerState.HEAT: + await this.device.heating(); + break; + case this.platform.Characteristic.TargetHeaterCoolerState.COOL: + await this.device.cooling(); + break; + default: + await this.device.auto(); + break; + } + } + + async getTargetHeaterCoolerState(): Promise<CharacteristicValue> { + if (this.device.isCooling()) { + return this.platform.Characteristic.TargetHeaterCoolerState.COOL; + } + + if (this.device.isHeating()) { + return this.platform.Characteristic.TargetHeaterCoolerState.HEAT; + } + + return this.platform.Characteristic.TargetHeaterCoolerState.AUTO; + } + + getCurrentTemperature(): CharacteristicValue { + return this.device.temperature(); + } + + async setTargetTemperature(value: CharacteristicValue) { + await this.device.temperatureSetTo(value as number); + } + + getTargetTemperature(): CharacteristicValue { + return this.device.targetTemperature(); + } + + async setRotationSpeed(value: CharacteristicValue) { + const level = Math.ceil(value as number / 100 * WindLevel.Level7); + await this.device.windLevelSetTo(level); + } + + getRotationSpeed(): CharacteristicValue { + const level = this.device.windLevel(); + const speed = level * Math.ceil(100 / WindLevel.Level7); + return speed > 100 ? 100 : speed; + } + + async setSwingMode(value: CharacteristicValue) { + if (value === this.platform.Characteristic.SwingMode.SWING_ENABLED) { + await this.device.startSwinging(); + } else { + await this.device.stopSwinging(); + } + } + + getSwingMode() { + return this.device.swinging(); + } +} |
