summaryrefslogtreecommitdiff
path: root/src/accessory.ts
diff options
context:
space:
mode:
authorZhineng Li <[email protected]>2026-03-29 06:53:53 +0800
committerZhineng Li <[email protected]>2026-03-29 06:53:53 +0800
commit256f19558f8ed5747c15c85f7e401835787504eb (patch)
tree1d879482c4945bd2b5d6fd94e60d831f6023d33c /src/accessory.ts
downloadhomebridge-xiaomi-aircondition-ma2-256f19558f8ed5747c15c85f7e401835787504eb.tar.gz
homebridge-xiaomi-aircondition-ma2-256f19558f8ed5747c15c85f7e401835787504eb.zip
first commit
Diffstat (limited to 'src/accessory.ts')
-rw-r--r--src/accessory.ts170
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();
+ }
+}