homebridge-dreo-db94
Version:
Homebridge Plugin for Dreo Smart Devices
322 lines • 17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FanAccessory = void 0;
const BaseAccessory_1 = require("./BaseAccessory");
/**
* Platform Accessory
* An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types.
*/
class FanAccessory extends BaseAccessory_1.BaseAccessory {
constructor(platform, accessory, state) {
// Call base class constructor
super(platform, accessory);
this.state = state;
// Cached copy of latest fan states
this.currState = {
on: false,
powerCMD: 'none',
speed: 1,
swing: false,
swingCMD: 'none',
autoMode: false,
lockPhysicalControls: false,
maxSpeed: 1,
temperature: 0,
lightOn: false,
brightness: 100,
};
// Initialize fan values
// Get max fan speed from Dreo API
this.currState.maxSpeed =
accessory.context.device.controlsConf.control.find((params) => params.type === 'Speed').items[1].text;
// Load current state from Dreo API
this.currState.speed =
(state.windlevel.state * 100) / this.currState.maxSpeed;
// Some fans use different commands to toggle power, determine which one should be used
if (state.fanon !== undefined) {
this.currState.powerCMD = 'fanon';
this.currState.on = state.fanon.state;
}
else {
this.currState.powerCMD = 'poweron';
this.currState.on = state.poweron.state;
}
// Get the Fanv2 service if it exists, otherwise create a new Fanv2 service
// You can create multiple services for each accessory
this.service =
this.accessory.getService(this.platform.Service.Fanv2) ||
this.accessory.addService(this.platform.Service.Fanv2);
// Set the service name, this is what is displayed as the default name on the Home app
// In this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.deviceName);
// Each service must implement at-minimum the "required characteristics" for the given service type
// See https://developers.homebridge.io/#/service/Fanv2
// Register handlers for the Active Characteristic
this.service
.getCharacteristic(this.platform.Characteristic.Active)
.onSet(this.setActive.bind(this))
.onGet(this.getActive.bind(this));
// Register handlers for the RotationSpeed Characteristic
this.service
.getCharacteristic(this.platform.Characteristic.RotationSpeed)
.setProps({
// Setting minStep defines fan speed steps in HomeKit
minStep: 100 / this.currState.maxSpeed,
})
.onSet(this.setRotationSpeed.bind(this))
.onGet(this.getRotationSpeed.bind(this));
// Check whether fan supports oscillation
// Some fans use different commands to toggle oscillation, determine which one should be used
const swing = accessory.context.device.controlsConf.control.find((params) => params.type === 'Oscillation');
if (swing !== undefined) {
this.currState.swingCMD = swing.cmd;
}
if (this.currState.swingCMD !== 'none') {
// Register handlers for Swing Mode (oscillation)
this.service
.getCharacteristic(this.platform.Characteristic.SwingMode)
.onSet(this.setSwingMode.bind(this))
.onGet(this.getSwingMode.bind(this));
this.currState.swing = state[this.currState.swingCMD].state;
}
// Check if mode control is supported
if (state.mode !== undefined) {
// Register handlers for Target Fan State
this.service
.getCharacteristic(this.platform.Characteristic.TargetFanState)
.onSet(this.setMode.bind(this))
.onGet(this.getMode.bind(this));
this.currState.autoMode = this.convertModeToBoolean(state.mode.state);
}
// Check if child lock is supported
if (state.childlockon !== undefined) {
// Register handlers for Lock Physical Controls
this.service
.getCharacteristic(this.platform.Characteristic.LockPhysicalControls)
.onSet(this.setLockPhysicalControls.bind(this))
.onGet(this.getLockPhysicalControls.bind(this));
this.currState.lockPhysicalControls = Boolean(state.childlockon.state);
}
const shouldHideTemperatureSensor = this.platform.config.hideTemperatureSensor || false; // default to false if not defined
// If temperature is defined and we are not hiding the sensor
if (state.temperature !== undefined && !shouldHideTemperatureSensor) {
this.currState.temperature = this.correctedTemperature(state.temperature.state);
// Check if the Temperature Sensor service already exists, if not create a new one
this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor);
if (!this.temperatureService) {
this.temperatureService = this.accessory.addService(this.platform.Service.TemperatureSensor, 'Temperature Sensor');
}
// Bind the get handler for temperature to this service
this.temperatureService
.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
.onGet(this.getTemperature.bind(this));
}
else {
const existingTemperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor);
if (existingTemperatureService) {
platform.log.debug('Hiding Temperature Sensor');
this.accessory.removeService(existingTemperatureService);
}
}
if (state.lighton !== undefined && state.brightness !== undefined) {
this.currState.lightOn = state.lighton.state;
this.currState.brightness = state.brightness.state;
// Initialize Lightbulb service
this.lightService =
this.accessory.getService(this.platform.Service.Lightbulb) ||
this.accessory.addService(this.platform.Service.Lightbulb);
this.lightService.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.deviceName + ' Light');
this.lightService
.getCharacteristic(this.platform.Characteristic.On)
.onSet(this.setLightOn.bind(this))
.onGet(this.getLightOn.bind(this));
this.lightService
.getCharacteristic(this.platform.Characteristic.Brightness)
.onSet(this.setBrightness.bind(this))
.onGet(this.getBrightness.bind(this));
}
// Update values from Dreo app
platform.webHelper.addEventListener('message', (message) => {
const data = JSON.parse(message.data);
// Check if message applies to this device
if (data.devicesn === accessory.context.device.sn) {
platform.log.debug('Incoming %s', message.data);
// Check if we need to update fan state in homekit
if (data.method === 'control-report' ||
data.method === 'control-reply' ||
data.method === 'report') {
Object.keys(data.reported).forEach((key) => {
var _a, _b;
switch (key) {
case 'poweron':
this.currState.on = data.reported.poweron;
this.service
.getCharacteristic(this.platform.Characteristic.Active)
.updateValue(this.currState.on);
this.platform.log.debug('Fan power:', data.reported.poweron);
break;
case 'fanon':
this.currState.on = data.reported.fanon;
this.service
.getCharacteristic(this.platform.Characteristic.Active)
.updateValue(this.currState.on);
this.platform.log.debug('Fan power:', data.reported.fanon);
break;
case 'windlevel':
this.currState.speed =
(data.reported.windlevel * 100) / this.currState.maxSpeed;
this.service
.getCharacteristic(this.platform.Characteristic.RotationSpeed)
.updateValue(this.currState.speed);
this.platform.log.debug('Fan speed:', data.reported.windlevel);
break;
case 'shakehorizon':
this.currState.swing = data.reported.shakehorizon;
this.service
.getCharacteristic(this.platform.Characteristic.SwingMode)
.updateValue(this.currState.swing);
this.platform.log.debug('Oscillation mode:', data.reported.shakehorizon);
break;
case 'hoscon':
this.currState.swing = data.reported.hoscon;
this.service
.getCharacteristic(this.platform.Characteristic.SwingMode)
.updateValue(this.currState.swing);
this.platform.log.debug('Oscillation mode:', data.reported.hoscon);
break;
case 'oscmode':
this.currState.swing = Boolean(data.reported.oscmode);
this.service
.getCharacteristic(this.platform.Characteristic.SwingMode)
.updateValue(this.currState.swing);
this.platform.log.debug('Oscillation mode:', data.reported.oscmode);
break;
case 'mode':
this.currState.autoMode = this.convertModeToBoolean(data.reported.mode);
this.service
.getCharacteristic(this.platform.Characteristic.TargetFanState)
.updateValue(this.currState.autoMode);
this.platform.log.debug('Fan mode:', data.reported.mode);
break;
case 'childlockon':
this.currState.lockPhysicalControls = Boolean(data.reported.childlockon);
this.service
.getCharacteristic(this.platform.Characteristic.LockPhysicalControls)
.updateValue(this.currState.lockPhysicalControls);
this.platform.log.debug('Child lock:', data.reported.childlockon);
break;
case 'temperature':
if (this.temperatureService !== undefined &&
!shouldHideTemperatureSensor) {
this.currState.temperature = this.correctedTemperature(data.reported.temperature);
this.temperatureService
.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
.updateValue(this.currState.temperature);
}
this.platform.log.debug('Temperature:', data.reported.temperature);
break;
case 'lighton':
this.currState.lightOn = data.reported.lighton;
(_a = this.lightService) === null || _a === void 0 ? void 0 : _a.getCharacteristic(this.platform.Characteristic.On).updateValue(this.currState.lightOn);
this.platform.log.debug('Light on:', data.reported.lighton);
break;
case 'brightness':
this.currState.brightness = data.reported.brightness;
(_b = this.lightService) === null || _b === void 0 ? void 0 : _b.getCharacteristic(this.platform.Characteristic.Brightness).updateValue(this.currState.brightness);
this.platform.log.debug('Brightness:', data.reported.brightness);
break;
default:
platform.log.debug('Unknown command received:', Object.keys(data.reported)[0]);
}
});
}
}
});
}
// Handle requests to set the "Active" characteristic
setActive(value) {
this.platform.log.debug('Triggered SET Active:', value);
// Check state to prevent duplicate requests
if (this.currState.on !== Boolean(value)) {
// Send to Dreo server via websocket
this.platform.webHelper.control(this.sn, {
[this.currState.powerCMD]: Boolean(value),
});
}
}
// Handle requests to get the current value of the "Active" characteristic
getActive() {
return this.currState.on;
}
// Handle requests to set the fan speed
async setRotationSpeed(value) {
// Rotation speed needs to be scaled from HomeKit's percentage value (Dreo app uses whole numbers, ex. 1-6)
const converted = Math.round((value * this.currState.maxSpeed) / 100);
// Avoid setting speed to 0 (illegal value)
if (converted !== 0) {
this.platform.log.debug('Setting fan speed:', converted);
// Setting power state to true ensures the fan is actually on
this.platform.webHelper.control(this.sn, {
[this.currState.powerCMD]: true,
windlevel: converted,
});
}
}
async getRotationSpeed() {
return this.currState.speed;
}
// Turn oscillation on/off
async setSwingMode(value) {
this.platform.webHelper.control(this.sn, {
[this.currState.swingCMD]: this.currState.swingCMD === 'oscmode' ? Number(value) : Boolean(value),
});
}
async getSwingMode() {
return this.currState.swing;
}
// Set fan mode
async setMode(value) {
this.platform.webHelper.control(this.sn, {
mode: value === this.platform.Characteristic.TargetFanState.AUTO ? 4 : 1,
});
}
async getMode() {
return this.currState.autoMode;
}
// Turn child lock on/off
async setLockPhysicalControls(value) {
this.platform.webHelper.control(this.sn, { childlockon: Number(value) });
}
getLockPhysicalControls() {
return this.currState.lockPhysicalControls;
}
async getTemperature() {
return this.currState.temperature;
}
correctedTemperature(temperatureFromDreo) {
const offset = this.platform.config.temperatureOffset || 0; // default to 0 if not defined
// Dreo response is always Fahrenheit - convert to Celsius which is what HomeKit expects
return ((temperatureFromDreo + offset - 32) * 5) / 9;
}
convertModeToBoolean(value) {
// Show all non-automatic modes as "Manual"
return value === 4;
}
setLightOn(value) {
this.platform.log.debug('Triggered SET Light On:', value);
this.platform.webHelper.control(this.sn, { lighton: Boolean(value) });
}
getLightOn() {
return this.currState.lightOn;
}
setBrightness(value) {
this.platform.log.debug('Triggered SET Brightness:', value);
this.platform.webHelper.control(this.sn, { brightness: value });
}
getBrightness() {
return this.currState.brightness;
}
}
exports.FanAccessory = FanAccessory;
//# sourceMappingURL=FanAccessory.js.map