├── Devices ├── Base.js ├── MiAirPurifier.js ├── MiAirPurifier2.js ├── MiAirPurifier2S.js └── MiAirPurifierPro.js ├── README.md ├── images ├── MiAirPurifier.jpg ├── MiAirPurifier2.jpg ├── MiAirPurifier2S.jpg ├── MiAirPurifierMAX.jpg └── MiAirPurifierPro.jpg ├── index.js └── package.json /Devices/Base.js: -------------------------------------------------------------------------------- 1 | // Base 2 | Base = function() { 3 | this.platform = null; 4 | } 5 | 6 | Base.prototype.init = function(platform, config) { 7 | this.platform = platform; 8 | this.config = config; 9 | } 10 | 11 | Base.prototype.obj2array = function(obj) { 12 | var array = []; 13 | for(var item in obj) { 14 | array.push(obj[item]); 15 | } 16 | return array; 17 | } -------------------------------------------------------------------------------- /Devices/MiAirPurifier.js: -------------------------------------------------------------------------------- 1 | require('./Base'); 2 | 3 | const inherits = require('util').inherits; 4 | const miio = require('miio'); 5 | 6 | var Accessory, PlatformAccessory, Service, Characteristic, UUIDGen; 7 | 8 | MiAirPurifier = function(platform, config) { 9 | this.init(platform, config); 10 | 11 | Accessory = platform.Accessory; 12 | PlatformAccessory = platform.PlatformAccessory; 13 | Service = platform.Service; 14 | Characteristic = platform.Characteristic; 15 | UUIDGen = platform.UUIDGen; 16 | 17 | this.device = new miio.Device({ 18 | address: this.config['ip'], 19 | token: this.config['token'] 20 | }); 21 | 22 | this.accessories = {}; 23 | if(!this.config['airPurifierDisable'] && this.config['airPurifierName'] && this.config['airPurifierName'] != "" && this.config['silentModeSwitchName'] && this.config['silentModeSwitchName'] != "") { 24 | this.accessories['airPurifierAccessory'] = new MiAirPurifierAirPurifierAccessory(this); 25 | } 26 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 27 | this.accessories['buzzerSwitchAccessory'] = new MiAirPurifierBuzzerSwitchAccessory(this); 28 | } 29 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 30 | this.accessories['ledBulbAccessory'] = new MiAirPurifierLEDBulbAccessory(this); 31 | } 32 | if(!this.config['airQualityDisable'] && this.config['airQualityName'] && this.config['airQualityName'] != "") { 33 | this.accessories['airQualityAccessory'] = new MiAirPurifierAirQualityAccessory(this); 34 | } 35 | var accessoriesArr = this.obj2array(this.accessories); 36 | 37 | this.platform.log.debug("[MiAirPurifierPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 38 | 39 | return accessoriesArr; 40 | } 41 | inherits(MiAirPurifier, Base); 42 | 43 | MiAirPurifierAirPurifierAccessory = function(dThis) { 44 | this.device = dThis.device; 45 | this.name = dThis.config['airPurifierName']; 46 | this.silentModeSwitchDisable = dThis.config['silentModeSwitchDisable']; 47 | this.silentModeSwitchName = dThis.config['silentModeSwitchName']; 48 | this.platform = dThis.platform; 49 | } 50 | 51 | MiAirPurifierAirPurifierAccessory.prototype.getServices = function() { 52 | var that = this; 53 | var services = []; 54 | 55 | var infoService = new Service.AccessoryInformation(); 56 | infoService 57 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 58 | .setCharacteristic(Characteristic.Model, "AirPurifier") 59 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 60 | services.push(infoService); 61 | 62 | var silentModeSwitch = new Service.Switch(this.silentModeSwitchName); 63 | var silentModeOnCharacteristic = silentModeSwitch.getCharacteristic(Characteristic.On); 64 | if(!this.silentModeSwitchDisable) { 65 | services.push(silentModeSwitch); 66 | } 67 | 68 | var airPurifierService = new Service.AirPurifier(this.name); 69 | var activeCharacteristic = airPurifierService.getCharacteristic(Characteristic.Active); 70 | var currentAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.CurrentAirPurifierState); 71 | var targetAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.TargetAirPurifierState); 72 | // var lockPhysicalControlsCharacteristic = airPurifierService.addCharacteristic(Characteristic.LockPhysicalControls); 73 | var rotationSpeedCharacteristic = airPurifierService.addCharacteristic(Characteristic.RotationSpeed); 74 | 75 | var pm25DensityCharacteristic = airPurifierService.addCharacteristic(Characteristic.PM2_5Density); 76 | var airQualityCharacteristic = airPurifierService.addCharacteristic(Characteristic.AirQuality); 77 | services.push(airPurifierService); 78 | 79 | silentModeOnCharacteristic 80 | .on('get', function(callback) { 81 | that.device.call("get_prop", ["mode"]).then(result => { 82 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - getOn: " + result); 83 | 84 | if(result[0] === "silent") { 85 | callback(null, true); 86 | } else { 87 | callback(null, false); 88 | } 89 | }).catch(function(err) { 90 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - getOn Error: " + err); 91 | callback(err); 92 | }); 93 | }.bind(this)) 94 | .on('set', function(value, callback) { 95 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - setOn: " + value); 96 | if(value) { 97 | that.device.call("set_mode", ["silent"]).then(result => { 98 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 99 | if(result[0] === "ok") { 100 | targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.AUTO); 101 | callback(null); 102 | 103 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 104 | activeCharacteristic.updateValue(Characteristic.Active.ACTIVE); 105 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 106 | } 107 | } else { 108 | callback(new Error(result[0])); 109 | } 110 | }).catch(function(err) { 111 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 112 | callback(err); 113 | }); 114 | } else { 115 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 116 | callback(null); 117 | } else { 118 | var nowModel = that.getModeByRotationSpeed(rotationSpeedCharacteristic.value); 119 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == value ? 'auto' : nowModel]).then(result => { 120 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 121 | if(result[0] === "ok") { 122 | callback(null); 123 | } else { 124 | callback(new Error(result[0])); 125 | } 126 | }).catch(function(err) { 127 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 128 | callback(err); 129 | }); 130 | } 131 | } 132 | }.bind(this)); 133 | 134 | activeCharacteristic 135 | .on('get', function(callback) { 136 | that.device.call("get_prop", ["mode"]).then(result => { 137 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - Active - getActive: " + result); 138 | 139 | if(result[0] === "idle") { 140 | callback(null, Characteristic.Active.INACTIVE); 141 | } else { 142 | callback(null, Characteristic.Active.ACTIVE); 143 | } 144 | }).catch(function(err) { 145 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - Active - getActive Error: " + err); 146 | callback(err); 147 | }); 148 | }.bind(this)) 149 | .on('set', function(value, callback) { 150 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - Active - setActive: " + value); 151 | that.device.call("set_mode", [value ? "auto" : "idle"]).then(result => { 152 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - Active - setActive Result: " + result); 153 | if(result[0] === "ok") { 154 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.IDLE); 155 | callback(null); 156 | if(value) { 157 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 158 | that.device.call("get_prop", ["mode"]).then(result => { 159 | if(result[0] === "silent") { 160 | silentModeOnCharacteristic.updateValue(true); 161 | } else { 162 | silentModeOnCharacteristic.updateValue(false); 163 | } 164 | }).catch(function(err) { 165 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]AirPurifier2AirPurifierAccessory - Active - setActive Error: " + err); 166 | callback(err); 167 | }); 168 | } else { 169 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.INACTIVE); 170 | silentModeOnCharacteristic.updateValue(false); 171 | } 172 | } else { 173 | callback(new Error(result[0])); 174 | } 175 | }).catch(function(err) { 176 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - Active - setActive Error: " + err); 177 | callback(err); 178 | }); 179 | }.bind(this)); 180 | 181 | currentAirPurifierStateCharacteristic 182 | .on('get', function(callback) { 183 | that.device.call("get_prop", ["mode"]).then(result => { 184 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState: " + result); 185 | 186 | if(result[0] === "idle") { 187 | callback(null, Characteristic.CurrentAirPurifierState.INACTIVE); 188 | } else { 189 | callback(null, Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 190 | } 191 | }).catch(function(err) { 192 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState Error: " + err); 193 | callback(err); 194 | }); 195 | }.bind(this)); 196 | /* 197 | lockPhysicalControlsCharacteristic 198 | .on('get', function(callback) { 199 | that.device.call("get_prop", ["child_lock"]).then(result => { 200 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 201 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 202 | }).catch(function(err) { 203 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 204 | callback(err); 205 | }); 206 | }.bind(this)) 207 | .on('set', function(value, callback) { 208 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 209 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 210 | if(result[0] === "ok") { 211 | callback(null); 212 | } else { 213 | callback(new Error(result[0])); 214 | } 215 | }).catch(function(err) { 216 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 217 | callback(err); 218 | }); 219 | }.bind(this)); 220 | */ 221 | targetAirPurifierStateCharacteristic 222 | .on('get', function(callback) { 223 | that.device.call("get_prop", ["mode"]).then(result => { 224 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + result); 225 | 226 | if(result[0] === "auto" || result[0] === "silent") { 227 | callback(null, Characteristic.TargetAirPurifierState.AUTO); 228 | } else { 229 | callback(null, Characteristic.TargetAirPurifierState.MANUAL); 230 | } 231 | }).catch(function(err) { 232 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + err); 233 | callback(err); 234 | }); 235 | }.bind(this)) 236 | .on('set', function(value, callback) { 237 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState: " + value); 238 | var nowModel = that.getModeByRotationSpeed(rotationSpeedCharacteristic.value); 239 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == value ? (silentModeOnCharacteristic.value ? "silent" : "auto") : nowModel]).then(result => { 240 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Result: " + result); 241 | if(result[0] === "ok") { 242 | callback(null); 243 | } else { 244 | callback(new Error(result[0])); 245 | } 246 | }).catch(function(err) { 247 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Error: " + err); 248 | callback(err); 249 | }); 250 | }.bind(this)); 251 | 252 | rotationSpeedCharacteristic 253 | .on('get', function(callback) { 254 | that.device.call("get_prop", ["mode"]).then(result => { 255 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - RotationSpeed - getRotationSpeed: " + result); 256 | if(result[0] === "low") { 257 | if(rotationSpeedCharacteristic.value > 0 && rotationSpeedCharacteristic.value <= 25) { 258 | callback(null, rotationSpeedCharacteristic.value); 259 | } else { 260 | callback(null, 25); 261 | } 262 | } else if(result[0] === "medium") { 263 | if(rotationSpeedCharacteristic.value > 25 && rotationSpeedCharacteristic.value <= 50) { 264 | callback(null, rotationSpeedCharacteristic.value); 265 | } else { 266 | callback(null, 50); 267 | } 268 | } else if(result[0] === "high") { 269 | if(rotationSpeedCharacteristic.value > 50 && rotationSpeedCharacteristic.value <= 75) { 270 | callback(null, rotationSpeedCharacteristic.value); 271 | } else { 272 | callback(null, 75); 273 | } 274 | } else if(result[0] === "strong") { 275 | if(rotationSpeedCharacteristic.value > 75 && rotationSpeedCharacteristic.value <= 100) { 276 | callback(null, rotationSpeedCharacteristic.value); 277 | } else { 278 | callback(null, 100); 279 | } 280 | } else { 281 | callback(null, 0); 282 | } 283 | }).catch(function(err) { 284 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - RotationSpeed - getRotationSpeed Error: " + err); 285 | callback(err); 286 | }); 287 | }.bind(this)) 288 | .on('set', function(value, callback) { 289 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - RotationSpeed - setRotationSpeed set: " + value); 290 | if(value == 0) { 291 | callback(null); 292 | } else { 293 | var nowModel = that.getModeByRotationSpeed(rotationSpeedCharacteristic.value); 294 | var valueModel = that.getModeByRotationSpeed(value); 295 | if(nowModel != valueModel) { 296 | that.device.call("set_mode", valueModel).then(result => { 297 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirPurifierAccessory - RotationSpeed - setRotationSpeed Result: " + result); 298 | if(result[0] === "ok") { 299 | callback(null); 300 | } else { 301 | callback(new Error(result[0])); 302 | } 303 | }).catch(function(err) { 304 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 305 | callback(err); 306 | }) 307 | } else { 308 | callback(null); 309 | } 310 | } 311 | }.bind(this)); 312 | 313 | pm25DensityCharacteristic 314 | .on('get', function(callback) { 315 | this.device.call("get_prop", ["aqi"]).then(result => { 316 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity: " + result); 317 | callback(null, result[0]); 318 | 319 | var airQualityValue = Characteristic.AirQuality.UNKNOWN; 320 | if(result[0] <= 50) { 321 | airQualityValue = Characteristic.AirQuality.EXCELLENT; 322 | } else if(result[0] > 50 && result[0] <= 100) { 323 | airQualityValue = Characteristic.AirQuality.GOOD; 324 | } else if(result[0] > 100 && result[0] <= 200) { 325 | airQualityValue = Characteristic.AirQuality.FAIR; 326 | } else if(result[0] > 200 && result[0] <= 300) { 327 | airQualityValue = Characteristic.AirQuality.INFERIOR; 328 | } else if(result[0] > 300) { 329 | airQualityValue = Characteristic.AirQuality.POOR; 330 | } else { 331 | airQualityValue = Characteristic.AirQuality.UNKNOWN; 332 | } 333 | airQualityCharacteristic.updateValue(airQualityValue); 334 | }).catch(function(err) { 335 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity Error: " + err); 336 | callback(err); 337 | }); 338 | }.bind(this)); 339 | 340 | // var filterMaintenanceService = new Service.FilterMaintenance(this.name); 341 | var filterChangeIndicationCharacteristic = airPurifierService.getCharacteristic(Characteristic.FilterChangeIndication); 342 | var filterLifeLevelCharacteristic = airPurifierService.addCharacteristic(Characteristic.FilterLifeLevel); 343 | 344 | filterChangeIndicationCharacteristic 345 | .on('get', function(callback) { 346 | that.device.call("get_prop", ["filter1_life"]).then(result => { 347 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication: " + result); 348 | callback(null, result[0] < 5 ? Characteristic.FilterChangeIndication.CHANGE_FILTER : Characteristic.FilterChangeIndication.FILTER_OK); 349 | }).catch(function(err) { 350 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication Error: " + err); 351 | callback(err); 352 | }); 353 | }.bind(this)); 354 | filterLifeLevelCharacteristic 355 | .on('get', function(callback) { 356 | that.device.call("get_prop", ["filter1_life"]).then(result => { 357 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel: " + result); 358 | callback(null, result[0]); 359 | }).catch(function(err) { 360 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel Error: " + err); 361 | callback(err); 362 | }); 363 | }.bind(this)); 364 | // services.push(filterMaintenanceService); 365 | 366 | return services; 367 | } 368 | 369 | MiAirPurifierAirPurifierAccessory.prototype.getModeByRotationSpeed = function(value) { 370 | if(value > 0 && value <= 25) { 371 | mode = 'low'; 372 | } else if(value > 25 && value <= 50) { 373 | mode = 'medium'; 374 | } else if(value > 50 && value <= 70) { 375 | mode = 'high'; 376 | } else if(value > 75 && value <= 100) { 377 | mode = 'strong'; 378 | } else { 379 | mode = 'low'; 380 | } 381 | } 382 | 383 | MiAirPurifierBuzzerSwitchAccessory = function(dThis) { 384 | this.device = dThis.device; 385 | this.name = dThis.config['buzzerSwitchName']; 386 | this.platform = dThis.platform; 387 | } 388 | 389 | MiAirPurifierBuzzerSwitchAccessory.prototype.getServices = function() { 390 | var services = []; 391 | 392 | var infoService = new Service.AccessoryInformation(); 393 | infoService 394 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 395 | .setCharacteristic(Characteristic.Model, "AirPurifier") 396 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 397 | services.push(infoService); 398 | 399 | var switchService = new Service.Switch(this.name); 400 | switchService 401 | .getCharacteristic(Characteristic.On) 402 | .on('get', this.getBuzzerState.bind(this)) 403 | .on('set', this.setBuzzerState.bind(this)); 404 | services.push(switchService); 405 | 406 | return services; 407 | } 408 | 409 | MiAirPurifierBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 410 | var that = this; 411 | this.device.call("get_prop", ["buzzer"]).then(result => { 412 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 413 | callback(null, result[0] === "on" ? 1 : 0); 414 | }).catch(function(err) { 415 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 416 | callback(err); 417 | }); 418 | } 419 | 420 | MiAirPurifierBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 421 | var that = this; 422 | that.device.call("set_buzzer", [value ? "on" : "off"]).then(result => { 423 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 424 | if(result[0] === "ok") { 425 | callback(null); 426 | } else { 427 | callback(new Error(result[0])); 428 | } 429 | }).catch(function(err) { 430 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 431 | callback(err); 432 | }); 433 | } 434 | 435 | MiAirPurifierLEDBulbAccessory = function(dThis) { 436 | this.device = dThis.device; 437 | this.name = dThis.config['ledBulbName']; 438 | this.platform = dThis.platform; 439 | } 440 | 441 | MiAirPurifierLEDBulbAccessory.prototype.getServices = function() { 442 | var that = this; 443 | var services = []; 444 | 445 | var infoService = new Service.AccessoryInformation(); 446 | infoService 447 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 448 | .setCharacteristic(Characteristic.Model, "AirPurifier") 449 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 450 | services.push(infoService); 451 | 452 | var switchLEDService = new Service.Lightbulb(this.name); 453 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 454 | 455 | onCharacteristic 456 | .on('get', function(callback) { 457 | this.device.call("get_prop", ["led"]).then(result => { 458 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]AirPurifierProLEDBulbAccessory - switchLED - getLEDPower: " + result); 459 | callback(null, result[0] === "on" ? true : false); 460 | }).catch(function(err) { 461 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]AirPurifierProLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 462 | callback(err); 463 | }); 464 | }.bind(this)) 465 | .on('set', function(value, callback) { 466 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]AirPurifierProLEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 467 | this.device.call("set_led", [value ? "on" : "off"]).then(result => { 468 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]AirPurifierProLEDBulbAccessory - switchLED - setLEDPower Result: " + result); 469 | if(result[0] === "ok") { 470 | callback(null); 471 | } else { 472 | callback(new Error(result[0])); 473 | } 474 | }).catch(function(err) { 475 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]AirPurifierProLEDBulbAccessory - switchLED - setLEDPower Error: " + err); 476 | callback(err); 477 | }); 478 | }.bind(this)); 479 | services.push(switchLEDService); 480 | 481 | return services; 482 | } 483 | 484 | MiAirPurifierAirQualityAccessory = function(dThis) { 485 | this.device = dThis.device; 486 | this.name = dThis.config['airQualityName']; 487 | this.platform = dThis.platform; 488 | } 489 | 490 | MiAirPurifierAirQualityAccessory.prototype.getServices = function() { 491 | var that = this; 492 | var services = []; 493 | 494 | var infoService = new Service.AccessoryInformation(); 495 | infoService 496 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 497 | .setCharacteristic(Characteristic.Model, "AirPurifier") 498 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 499 | services.push(infoService); 500 | 501 | var pmService = new Service.AirQualitySensor(this.name); 502 | var pm2_5Characteristic = pmService.addCharacteristic(Characteristic.PM2_5Density); 503 | pmService 504 | .getCharacteristic(Characteristic.AirQuality) 505 | .on('get', function(callback) { 506 | that.device.call("get_prop", ["aqi"]).then(result => { 507 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierAirQualityAccessory - AirQuality - getAirQuality: " + result); 508 | 509 | pm2_5Characteristic.updateValue(result[0]); 510 | 511 | if(result[0] <= 50) { 512 | callback(null, Characteristic.AirQuality.EXCELLENT); 513 | } else if(result[0] > 50 && result[0] <= 100) { 514 | callback(null, Characteristic.AirQuality.GOOD); 515 | } else if(result[0] > 100 && result[0] <= 200) { 516 | callback(null, Characteristic.AirQuality.FAIR); 517 | } else if(result[0] > 200 && result[0] <= 300) { 518 | callback(null, Characteristic.AirQuality.INFERIOR); 519 | } else if(result[0] > 300) { 520 | callback(null, Characteristic.AirQuality.POOR); 521 | } else { 522 | callback(null, Characteristic.AirQuality.UNKNOWN); 523 | } 524 | }).catch(function(err) { 525 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierAirQualityAccessory - AirQuality - getAirQuality Error: " + err); 526 | callback(err); 527 | }); 528 | }.bind(this)); 529 | services.push(pmService); 530 | 531 | return services; 532 | } -------------------------------------------------------------------------------- /Devices/MiAirPurifier2.js: -------------------------------------------------------------------------------- 1 | require('./Base'); 2 | 3 | const inherits = require('util').inherits; 4 | const miio = require('miio'); 5 | 6 | var Accessory, PlatformAccessory, Service, Characteristic, UUIDGen; 7 | 8 | MiAirPurifier2 = function(platform, config) { 9 | this.init(platform, config); 10 | 11 | Accessory = platform.Accessory; 12 | PlatformAccessory = platform.PlatformAccessory; 13 | Service = platform.Service; 14 | Characteristic = platform.Characteristic; 15 | UUIDGen = platform.UUIDGen; 16 | 17 | this.device = new miio.Device({ 18 | address: this.config['ip'], 19 | token: this.config['token'] 20 | }); 21 | 22 | this.accessories = {}; 23 | if(!this.config['airPurifierDisable'] && this.config['airPurifierName'] && this.config['airPurifierName'] != "" && this.config['silentModeSwitchName'] && this.config['silentModeSwitchName'] != "") { 24 | this.accessories['airPurifierAccessory'] = new MiAirPurifier2AirPurifierAccessory(this); 25 | } 26 | if(!this.config['temperatureDisable'] && this.config['temperatureName'] && this.config['temperatureName'] != "") { 27 | this.accessories['temperatureAccessory'] = new MiAirPurifier2TemperatureAccessory(this); 28 | } 29 | if(!this.config['humidityDisable'] && this.config['humidityName'] && this.config['humidityName'] != "") { 30 | this.accessories['humidityAccessory'] = new MiAirPurifier2HumidityAccessory(this); 31 | } 32 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 33 | this.accessories['buzzerSwitchAccessory'] = new MiAirPurifier2BuzzerSwitchAccessory(this); 34 | } 35 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 36 | this.accessories['ledBulbAccessory'] = new MiAirPurifier2LEDBulbAccessory(this); 37 | } 38 | if(!this.config['airQualityDisable'] && this.config['airQualityName'] && this.config['airQualityName'] != "") { 39 | this.accessories['airQualityAccessory'] = new MiAirPurifier2AirQualityAccessory(this); 40 | } 41 | var accessoriesArr = this.obj2array(this.accessories); 42 | 43 | this.platform.log.debug("[MiAirPurifierPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 44 | 45 | return accessoriesArr; 46 | } 47 | inherits(MiAirPurifier2, Base); 48 | 49 | MiAirPurifier2AirPurifierAccessory = function(dThis) { 50 | this.device = dThis.device; 51 | this.name = dThis.config['airPurifierName']; 52 | this.silentModeSwitchDisable = dThis.config['silentModeSwitchDisable']; 53 | this.silentModeSwitchName = dThis.config['silentModeSwitchName']; 54 | this.platform = dThis.platform; 55 | } 56 | 57 | MiAirPurifier2AirPurifierAccessory.prototype.getServices = function() { 58 | var that = this; 59 | var services = []; 60 | 61 | var infoService = new Service.AccessoryInformation(); 62 | infoService 63 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 64 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 65 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 66 | services.push(infoService); 67 | 68 | var silentModeSwitch = new Service.Switch(this.silentModeSwitchName); 69 | var silentModeOnCharacteristic = silentModeSwitch.getCharacteristic(Characteristic.On); 70 | if(!this.silentModeSwitchDisable) { 71 | services.push(silentModeSwitch); 72 | } 73 | 74 | var airPurifierService = new Service.AirPurifier(this.name); 75 | var activeCharacteristic = airPurifierService.getCharacteristic(Characteristic.Active); 76 | var currentAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.CurrentAirPurifierState); 77 | var targetAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.TargetAirPurifierState); 78 | var lockPhysicalControlsCharacteristic = airPurifierService.addCharacteristic(Characteristic.LockPhysicalControls); 79 | var rotationSpeedCharacteristic = airPurifierService.addCharacteristic(Characteristic.RotationSpeed); 80 | 81 | var currentTemperatureCharacteristic = airPurifierService.addCharacteristic(Characteristic.CurrentTemperature); 82 | var currentRelativeHumidityCharacteristic = airPurifierService.addCharacteristic(Characteristic.CurrentRelativeHumidity); 83 | var pm25DensityCharacteristic = airPurifierService.addCharacteristic(Characteristic.PM2_5Density); 84 | var airQualityCharacteristic = airPurifierService.addCharacteristic(Characteristic.AirQuality); 85 | services.push(airPurifierService); 86 | 87 | silentModeOnCharacteristic 88 | .on('get', function(callback) { 89 | that.device.call("get_prop", ["mode"]).then(result => { 90 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - getOn: " + result); 91 | 92 | if(result[0] === "silent") { 93 | callback(null, true); 94 | } else { 95 | callback(null, false); 96 | } 97 | }).catch(function(err) { 98 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - getOn Error: " + err); 99 | callback(err); 100 | }); 101 | }.bind(this)) 102 | .on('set', function(value, callback) { 103 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - setOn: " + value); 104 | if(value) { 105 | that.device.call("set_mode", ["silent"]).then(result => { 106 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 107 | if(result[0] === "ok") { 108 | targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.AUTO); 109 | callback(null); 110 | 111 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 112 | activeCharacteristic.updateValue(Characteristic.Active.ACTIVE); 113 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 114 | } 115 | } else { 116 | callback(new Error(result[0])); 117 | } 118 | }).catch(function(err) { 119 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 120 | callback(err); 121 | }); 122 | } else { 123 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 124 | callback(null); 125 | } else { 126 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == targetAirPurifierStateCharacteristic.value ? "auto" : "favorite"]).then(result => { 127 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 128 | if(result[0] === "ok") { 129 | callback(null); 130 | } else { 131 | callback(new Error(result[0])); 132 | } 133 | }).catch(function(err) { 134 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 135 | callback(err); 136 | }); 137 | } 138 | } 139 | }.bind(this)); 140 | 141 | activeCharacteristic 142 | .on('get', function(callback) { 143 | that.device.call("get_prop", ["mode"]).then(result => { 144 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Active - getActive: " + result); 145 | 146 | if(result[0] === "idle") { 147 | callback(null, Characteristic.Active.INACTIVE); 148 | } else { 149 | callback(null, Characteristic.Active.ACTIVE); 150 | } 151 | }).catch(function(err) { 152 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Active - getActive Error: " + err); 153 | callback(err); 154 | }); 155 | }.bind(this)) 156 | .on('set', function(value, callback) { 157 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Active - setActive: " + value); 158 | that.device.call("set_power", [value ? "on" : "off"]).then(result => { 159 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Active - setActive Result: " + result); 160 | if(result[0] === "ok") { 161 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.IDLE); 162 | callback(null); 163 | if(value) { 164 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 165 | that.device.call("get_prop", ["mode"]).then(result => { 166 | if(result[0] === "silent") { 167 | silentModeOnCharacteristic.updateValue(true); 168 | } else { 169 | silentModeOnCharacteristic.updateValue(false); 170 | } 171 | }).catch(function(err) { 172 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Active - setActive Error: " + err); 173 | callback(err); 174 | }); 175 | } else { 176 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.INACTIVE); 177 | silentModeOnCharacteristic.updateValue(false); 178 | } 179 | } else { 180 | callback(new Error(result[0])); 181 | } 182 | }).catch(function(err) { 183 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Active - setActive Error: " + err); 184 | callback(err); 185 | }); 186 | }.bind(this)); 187 | 188 | currentAirPurifierStateCharacteristic 189 | .on('get', function(callback) { 190 | that.device.call("get_prop", ["mode"]).then(result => { 191 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState: " + result); 192 | 193 | if(result[0] === "idle") { 194 | callback(null, Characteristic.CurrentAirPurifierState.INACTIVE); 195 | } else { 196 | callback(null, Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 197 | } 198 | }).catch(function(err) { 199 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState Error: " + err); 200 | callback(err); 201 | }); 202 | }.bind(this)); 203 | 204 | lockPhysicalControlsCharacteristic 205 | .on('get', function(callback) { 206 | that.device.call("get_prop", ["child_lock"]).then(result => { 207 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 208 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 209 | }).catch(function(err) { 210 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 211 | callback(err); 212 | }); 213 | }.bind(this)) 214 | .on('set', function(value, callback) { 215 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 216 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 217 | if(result[0] === "ok") { 218 | callback(null); 219 | } else { 220 | callback(new Error(result[0])); 221 | } 222 | }).catch(function(err) { 223 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 224 | callback(err); 225 | }); 226 | }.bind(this)); 227 | 228 | targetAirPurifierStateCharacteristic 229 | .on('get', function(callback) { 230 | that.device.call("get_prop", ["mode"]).then(result => { 231 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + result); 232 | 233 | if(result[0] === "favorite") { 234 | callback(null, Characteristic.TargetAirPurifierState.MANUAL); 235 | } else { 236 | callback(null, Characteristic.TargetAirPurifierState.AUTO); 237 | } 238 | }).catch(function(err) { 239 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + err); 240 | callback(err); 241 | }); 242 | }.bind(this)) 243 | .on('set', function(value, callback) { 244 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState: " + value); 245 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == value ? (silentModeOnCharacteristic.value ? "silent" : "auto") : "favorite"]).then(result => { 246 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Result: " + result); 247 | if(result[0] === "ok") { 248 | if(Characteristic.TargetAirPurifierState.AUTO == value) { 249 | callback(null); 250 | } else { 251 | that.device.call("get_prop", ["favorite_level"]).then(result => { 252 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + result); 253 | silentModeOnCharacteristic.updateValue(false); 254 | if(rotationSpeedCharacteristic.value <= result[0] * 10 && rotationSpeedCharacteristic.value > (result[0] - 1) * 10) { 255 | callback(null); 256 | } else { 257 | rotationSpeedCharacteristic.value = result[0] * 10; 258 | callback(null); 259 | } 260 | }).catch(function(err) { 261 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 262 | callback(err); 263 | }); 264 | } 265 | } else { 266 | callback(new Error(result[0])); 267 | } 268 | }).catch(function(err) { 269 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Error: " + err); 270 | callback(err); 271 | }); 272 | }.bind(this)); 273 | 274 | rotationSpeedCharacteristic 275 | .on('get', function(callback) { 276 | that.device.call("get_prop", ["favorite_level"]).then(result => { 277 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - RotationSpeed - getRotationSpeed: " + result); 278 | callback(null, result[0]); 279 | }).catch(function(err) { 280 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - RotationSpeed - getRotationSpeed Error: " + err); 281 | callback(err); 282 | }); 283 | }.bind(this)) 284 | .on('set', function(value, callback) { 285 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - RotationSpeed - setRotationSpeed set: " + value); 286 | if(value == 0) { 287 | callback(null); 288 | } else { 289 | that.device.call("set_level_favorite", [parseInt(value / 10) < 10 ? parseInt(value / 10) + 1 : 10]).then(result => { 290 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - RotationSpeed - setRotationSpeed Result: " + result); 291 | if(result[0] === "ok") { 292 | // that.device.call("set_mode", ["favorite"]).then(result => { 293 | // that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - RotationSpeed - setTargetAirPurifierState Result: " + result); 294 | // if(result[0] === "ok") { 295 | // targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.MANUAL); 296 | // silentModeOnCharacteristic.updateValue(false); 297 | callback(null); 298 | // } else { 299 | // callback(new Error(result[0])); 300 | // } 301 | // }).catch(function(err) { 302 | // that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - RotationSpeed - setTargetAirPurifierState Error: " + err); 303 | // callback(err); 304 | // }); 305 | } else { 306 | callback(new Error(result[0])); 307 | } 308 | }).catch(function(err) { 309 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 310 | callback(err); 311 | }) 312 | } 313 | }.bind(this)); 314 | 315 | currentTemperatureCharacteristic.on('get', function(callback) { 316 | this.device.call("get_prop", ["temp_dec"]).then(result => { 317 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Temperature - getTemperature: " + result); 318 | callback(null, result[0] / 10); 319 | }).catch(function(err) { 320 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Temperature - getTemperature Error: " + err); 321 | callback(err); 322 | }); 323 | }.bind(this)); 324 | 325 | currentRelativeHumidityCharacteristic 326 | .on('get', function(callback) { 327 | this.device.call("get_prop", ["humidity"]).then(result => { 328 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Humidity - getHumidity: " + result); 329 | callback(null, result[0]); 330 | }).catch(function(err) { 331 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Humidity - getHumidity Error: " + err); 332 | callback(err); 333 | }); 334 | }.bind(this)); 335 | 336 | pm25DensityCharacteristic 337 | .on('get', function(callback) { 338 | this.device.call("get_prop", ["aqi"]).then(result => { 339 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity: " + result); 340 | callback(null, result[0]); 341 | 342 | var airQualityValue = Characteristic.AirQuality.UNKNOWN; 343 | if(result[0] <= 50) { 344 | airQualityValue = Characteristic.AirQuality.EXCELLENT; 345 | } else if(result[0] > 50 && result[0] <= 100) { 346 | airQualityValue = Characteristic.AirQuality.GOOD; 347 | } else if(result[0] > 100 && result[0] <= 200) { 348 | airQualityValue = Characteristic.AirQuality.FAIR; 349 | } else if(result[0] > 200 && result[0] <= 300) { 350 | airQualityValue = Characteristic.AirQuality.INFERIOR; 351 | } else if(result[0] > 300) { 352 | airQualityValue = Characteristic.AirQuality.POOR; 353 | } else { 354 | airQualityValue = Characteristic.AirQuality.UNKNOWN; 355 | } 356 | airQualityCharacteristic.updateValue(airQualityValue); 357 | }).catch(function(err) { 358 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity Error: " + err); 359 | callback(err); 360 | }); 361 | }.bind(this)); 362 | 363 | // var filterMaintenanceService = new Service.FilterMaintenance(this.name); 364 | var filterChangeIndicationCharacteristic = airPurifierService.getCharacteristic(Characteristic.FilterChangeIndication); 365 | var filterLifeLevelCharacteristic = airPurifierService.addCharacteristic(Characteristic.FilterLifeLevel); 366 | 367 | filterChangeIndicationCharacteristic 368 | .on('get', function(callback) { 369 | that.device.call("get_prop", ["filter1_life"]).then(result => { 370 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication: " + result); 371 | callback(null, result[0] < 5 ? Characteristic.FilterChangeIndication.CHANGE_FILTER : Characteristic.FilterChangeIndication.FILTER_OK); 372 | }).catch(function(err) { 373 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication Error: " + err); 374 | callback(err); 375 | }); 376 | }.bind(this)); 377 | filterLifeLevelCharacteristic 378 | .on('get', function(callback) { 379 | that.device.call("get_prop", ["filter1_life"]).then(result => { 380 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel: " + result); 381 | callback(null, result[0]); 382 | }).catch(function(err) { 383 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel Error: " + err); 384 | callback(err); 385 | }); 386 | }.bind(this)); 387 | // services.push(filterMaintenanceService); 388 | 389 | return services; 390 | } 391 | 392 | MiAirPurifier2TemperatureAccessory = function(dThis) { 393 | this.device = dThis.device; 394 | this.name = dThis.config['temperatureName']; 395 | this.platform = dThis.platform; 396 | } 397 | 398 | MiAirPurifier2TemperatureAccessory.prototype.getServices = function() { 399 | var services = []; 400 | 401 | var infoService = new Service.AccessoryInformation(); 402 | infoService 403 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 404 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 405 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 406 | services.push(infoService); 407 | 408 | var temperatureService = new Service.TemperatureSensor(this.name); 409 | temperatureService 410 | .getCharacteristic(Characteristic.CurrentTemperature) 411 | .on('get', this.getTemperature.bind(this)) 412 | services.push(temperatureService); 413 | 414 | return services; 415 | } 416 | 417 | MiAirPurifier2TemperatureAccessory.prototype.getTemperature = function(callback) { 418 | var that = this; 419 | this.device.call("get_prop", ["temp_dec"]).then(result => { 420 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2TemperatureAccessory - Temperature - getTemperature: " + result); 421 | callback(null, result[0] / 10); 422 | }).catch(function(err) { 423 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2TemperatureAccessory - Temperature - getTemperature Error: " + err); 424 | callback(err); 425 | }); 426 | } 427 | 428 | MiAirPurifier2HumidityAccessory = function(dThis) { 429 | this.device = dThis.device; 430 | this.name = dThis.config['humidityName']; 431 | this.platform = dThis.platform; 432 | } 433 | 434 | MiAirPurifier2HumidityAccessory.prototype.getServices = function() { 435 | var services = []; 436 | 437 | var infoService = new Service.AccessoryInformation(); 438 | infoService 439 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 440 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 441 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 442 | services.push(infoService); 443 | 444 | var humidityService = new Service.HumiditySensor(this.name); 445 | humidityService 446 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 447 | .on('get', this.getHumidity.bind(this)) 448 | services.push(humidityService); 449 | 450 | return services; 451 | } 452 | 453 | MiAirPurifier2HumidityAccessory.prototype.getHumidity = function(callback) { 454 | var that = this; 455 | this.device.call("get_prop", ["humidity"]).then(result => { 456 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2HumidityAccessory - Humidity - getHumidity: " + result); 457 | callback(null, result[0]); 458 | }).catch(function(err) { 459 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2HumidityAccessory - Humidity - getHumidity Error: " + err); 460 | callback(err); 461 | }); 462 | } 463 | 464 | MiAirPurifier2BuzzerSwitchAccessory = function(dThis) { 465 | this.device = dThis.device; 466 | this.name = dThis.config['buzzerSwitchName']; 467 | this.platform = dThis.platform; 468 | } 469 | 470 | MiAirPurifier2BuzzerSwitchAccessory.prototype.getServices = function() { 471 | var services = []; 472 | 473 | var infoService = new Service.AccessoryInformation(); 474 | infoService 475 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 476 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 477 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 478 | services.push(infoService); 479 | 480 | var switchService = new Service.Switch(this.name); 481 | switchService 482 | .getCharacteristic(Characteristic.On) 483 | .on('get', this.getBuzzerState.bind(this)) 484 | .on('set', this.setBuzzerState.bind(this)); 485 | services.push(switchService); 486 | 487 | return services; 488 | } 489 | 490 | MiAirPurifier2BuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 491 | var that = this; 492 | this.device.call("get_prop", ["buzzer"]).then(result => { 493 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2BuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 494 | callback(null, result[0] === "on" ? 1 : 0); 495 | }).catch(function(err) { 496 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2BuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 497 | callback(err); 498 | }); 499 | } 500 | 501 | MiAirPurifier2BuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 502 | var that = this; 503 | that.device.call("set_buzzer", [value ? "on" : "off"]).then(result => { 504 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2BuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 505 | if(result[0] === "ok") { 506 | callback(null); 507 | } else { 508 | callback(new Error(result[0])); 509 | } 510 | }).catch(function(err) { 511 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2BuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 512 | callback(err); 513 | }); 514 | } 515 | 516 | MiAirPurifier2LEDBulbAccessory = function(dThis) { 517 | this.device = dThis.device; 518 | this.name = dThis.config['ledBulbName']; 519 | this.platform = dThis.platform; 520 | } 521 | 522 | MiAirPurifier2LEDBulbAccessory.prototype.getServices = function() { 523 | var that = this; 524 | var services = []; 525 | 526 | var infoService = new Service.AccessoryInformation(); 527 | infoService 528 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 529 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 530 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 531 | services.push(infoService); 532 | 533 | var switchLEDService = new Service.Lightbulb(this.name); 534 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 535 | var brightnessCharacteristic = switchLEDService.addCharacteristic(Characteristic.Brightness); 536 | 537 | onCharacteristic 538 | .on('get', function(callback) { 539 | this.device.call("get_prop", ["led_b"]).then(result => { 540 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2LEDBulbAccessory - switchLED - getLEDPower: " + result); 541 | callback(null, result[0] === 2 ? false : true); 542 | }).catch(function(err) { 543 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2LEDBulbAccessory - switchLED - getLEDPower Error: " + err); 544 | callback(err); 545 | }); 546 | }.bind(this)) 547 | .on('set', function(value, callback) { 548 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2LEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 549 | that.setLedB(value ? that.getLevelByBrightness(brightnessCharacteristic.value) : 2, callback); 550 | }.bind(this)); 551 | brightnessCharacteristic 552 | .on('get', function(callback) { 553 | this.device.call("get_prop", ["led_b"]).then(result => { 554 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2LEDBulbAccessory - switchLED - getLEDPower: " + result); 555 | if(result[0] == 0) { 556 | if(brightnessCharacteristic.value > 50 && brightnessCharacteristic.value <= 100) { 557 | callback(null, brightnessCharacteristic.value); 558 | } else { 559 | callback(null, 100); 560 | } 561 | } else if(result[0] == 1) { 562 | if(brightnessCharacteristic.value > 0 && brightnessCharacteristic.value <= 50) { 563 | callback(null, brightnessCharacteristic.value); 564 | } else { 565 | callback(null, 50); 566 | } 567 | } else if(result[0] == 2) { 568 | callback(null, 0); 569 | } 570 | }).catch(function(err) { 571 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2LEDBulbAccessory - switchLED - getLEDPower Error: " + err); 572 | callback(err); 573 | }); 574 | }.bind(this)); 575 | services.push(switchLEDService); 576 | 577 | return services; 578 | } 579 | 580 | MiAirPurifier2LEDBulbAccessory.prototype.setLedB = function(led_b, callback) { 581 | var that = this; 582 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2LEDBulbAccessory - switchLED - setLedB: " + led_b); 583 | this.device.call("set_led_b", [led_b]).then(result => { 584 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2LEDBulbAccessory - switchLED - setLEDBrightness Result: " + result); 585 | if(result[0] === "ok") { 586 | callback(null); 587 | } else { 588 | callback(new Error(result[0])); 589 | } 590 | }).catch(function(err) { 591 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2LEDBulbAccessory - switchLED - setLEDBrightness Error: " + err); 592 | callback(err); 593 | }); 594 | } 595 | 596 | MiAirPurifier2LEDBulbAccessory.prototype.getLevelByBrightness = function(brightness) { 597 | if(brightness == 0) { 598 | return 2; 599 | } else if(brightness > 0 && brightness <= 50) { 600 | return 1; 601 | } else if (brightness > 50 && brightness <= 100) { 602 | return 0; 603 | } 604 | } 605 | 606 | MiAirPurifier2AirQualityAccessory = function(dThis) { 607 | this.device = dThis.device; 608 | this.name = dThis.config['airQualityName']; 609 | this.platform = dThis.platform; 610 | } 611 | 612 | MiAirPurifier2AirQualityAccessory.prototype.getServices = function() { 613 | var that = this; 614 | var services = []; 615 | 616 | var infoService = new Service.AccessoryInformation(); 617 | infoService 618 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 619 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 620 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 621 | services.push(infoService); 622 | 623 | var pmService = new Service.AirQualitySensor(this.name); 624 | var pm2_5Characteristic = pmService.addCharacteristic(Characteristic.PM2_5Density); 625 | pmService 626 | .getCharacteristic(Characteristic.AirQuality) 627 | .on('get', function(callback) { 628 | that.device.call("get_prop", ["aqi"]).then(result => { 629 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirQualityAccessory - AirQuality - getAirQuality: " + result); 630 | 631 | pm2_5Characteristic.updateValue(result[0]); 632 | 633 | if(result[0] <= 50) { 634 | callback(null, Characteristic.AirQuality.EXCELLENT); 635 | } else if(result[0] > 50 && result[0] <= 100) { 636 | callback(null, Characteristic.AirQuality.GOOD); 637 | } else if(result[0] > 100 && result[0] <= 200) { 638 | callback(null, Characteristic.AirQuality.FAIR); 639 | } else if(result[0] > 200 && result[0] <= 300) { 640 | callback(null, Characteristic.AirQuality.INFERIOR); 641 | } else if(result[0] > 300) { 642 | callback(null, Characteristic.AirQuality.POOR); 643 | } else { 644 | callback(null, Characteristic.AirQuality.UNKNOWN); 645 | } 646 | }).catch(function(err) { 647 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirQualityAccessory - AirQuality - getAirQuality Error: " + err); 648 | callback(err); 649 | }); 650 | }.bind(this)); 651 | services.push(pmService); 652 | 653 | return services; 654 | } -------------------------------------------------------------------------------- /Devices/MiAirPurifier2S.js: -------------------------------------------------------------------------------- 1 | require('./Base'); 2 | 3 | const inherits = require('util').inherits; 4 | const miio = require('miio'); 5 | 6 | var Accessory, PlatformAccessory, Service, Characteristic, UUIDGen; 7 | 8 | MiAirPurifier2S = function(platform, config) { 9 | this.init(platform, config); 10 | 11 | Accessory = platform.Accessory; 12 | PlatformAccessory = platform.PlatformAccessory; 13 | Service = platform.Service; 14 | Characteristic = platform.Characteristic; 15 | UUIDGen = platform.UUIDGen; 16 | 17 | this.device = new miio.Device({ 18 | address: this.config['ip'], 19 | token: this.config['token'] 20 | }); 21 | 22 | this.accessories = {}; 23 | if(!this.config['airPurifierDisable'] && this.config['airPurifierName'] && this.config['airPurifierName'] != "" && this.config['silentModeSwitchName'] && this.config['silentModeSwitchName'] != "") { 24 | this.accessories['airPurifierAccessory'] = new MiAirPurifier2SAirPurifierAccessory(this); 25 | } 26 | if(!this.config['temperatureDisable'] && this.config['temperatureName'] && this.config['temperatureName'] != "") { 27 | this.accessories['temperatureAccessory'] = new MiAirPurifier2STemperatureAccessory(this); 28 | } 29 | if(!this.config['humidityDisable'] && this.config['humidityName'] && this.config['humidityName'] != "") { 30 | this.accessories['humidityAccessory'] = new MiAirPurifier2SHumidityAccessory(this); 31 | } 32 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 33 | this.accessories['buzzerSwitchAccessory'] = new MiAirPurifier2SBuzzerSwitchAccessory(this); 34 | } 35 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 36 | this.accessories['ledBulbAccessory'] = new MiAirPurifier2SLEDBulbAccessory(this); 37 | } 38 | if(!this.config['airQualityDisable'] && this.config['airQualityName'] && this.config['airQualityName'] != "") { 39 | this.accessories['airQualityAccessory'] = new MiAirPurifier2SAirQualityAccessory(this); 40 | } 41 | var accessoriesArr = this.obj2array(this.accessories); 42 | 43 | this.platform.log.debug("[MiAirPurifierPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 44 | 45 | return accessoriesArr; 46 | } 47 | inherits(MiAirPurifier2S, Base); 48 | 49 | MiAirPurifier2SAirPurifierAccessory = function(dThis) { 50 | this.device = dThis.device; 51 | this.name = dThis.config['airPurifierName']; 52 | this.silentModeSwitchDisable = dThis.config['silentModeSwitchDisable']; 53 | this.silentModeSwitchName = dThis.config['silentModeSwitchName']; 54 | this.platform = dThis.platform; 55 | this.frm = [0,5,10,15,20,25,30,40,50,60,70,80,90,95,100]; 56 | } 57 | 58 | MiAirPurifier2SAirPurifierAccessory.prototype.getServices = function() { 59 | var that = this; 60 | var services = []; 61 | 62 | var infoService = new Service.AccessoryInformation(); 63 | infoService 64 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 65 | .setCharacteristic(Characteristic.Model, "AirPurifier2S") 66 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 67 | services.push(infoService); 68 | 69 | var silentModeSwitch = new Service.Switch(this.silentModeSwitchName); 70 | var silentModeOnCharacteristic = silentModeSwitch.getCharacteristic(Characteristic.On); 71 | if(!this.silentModeSwitchDisable) { 72 | services.push(silentModeSwitch); 73 | } 74 | 75 | var airPurifierService = new Service.AirPurifier(this.name); 76 | var activeCharacteristic = airPurifierService.getCharacteristic(Characteristic.Active); 77 | var currentAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.CurrentAirPurifierState); 78 | var targetAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.TargetAirPurifierState); 79 | var lockPhysicalControlsCharacteristic = airPurifierService.addCharacteristic(Characteristic.LockPhysicalControls); 80 | var rotationSpeedCharacteristic = airPurifierService.addCharacteristic(Characteristic.RotationSpeed); 81 | 82 | var currentTemperatureCharacteristic = airPurifierService.addCharacteristic(Characteristic.CurrentTemperature); 83 | var currentRelativeHumidityCharacteristic = airPurifierService.addCharacteristic(Characteristic.CurrentRelativeHumidity); 84 | var pm25DensityCharacteristic = airPurifierService.addCharacteristic(Characteristic.PM2_5Density); 85 | var airQualityCharacteristic = airPurifierService.addCharacteristic(Characteristic.AirQuality); 86 | services.push(airPurifierService); 87 | 88 | silentModeOnCharacteristic 89 | .on('get', function(callback) { 90 | that.device.call("get_prop", ["mode"]).then(result => { 91 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - getOn: " + result); 92 | 93 | if(result[0] === "silent") { 94 | callback(null, true); 95 | } else { 96 | callback(null, false); 97 | } 98 | }).catch(function(err) { 99 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - getOn Error: " + err); 100 | callback(err); 101 | }); 102 | }.bind(this)) 103 | .on('set', function(value, callback) { 104 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - setOn: " + value); 105 | if(value) { 106 | that.device.call("set_mode", ["silent"]).then(result => { 107 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 108 | if(result[0] === "ok") { 109 | targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.AUTO); 110 | callback(null); 111 | 112 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 113 | activeCharacteristic.updateValue(Characteristic.Active.ACTIVE); 114 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 115 | } 116 | } else { 117 | callback(new Error(result[0])); 118 | } 119 | }).catch(function(err) { 120 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 121 | callback(err); 122 | }); 123 | } else { 124 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 125 | callback(null); 126 | } else { 127 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == targetAirPurifierStateCharacteristic.value ? "auto" : "favorite"]).then(result => { 128 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 129 | if(result[0] === "ok") { 130 | callback(null); 131 | } else { 132 | callback(new Error(result[0])); 133 | } 134 | }).catch(function(err) { 135 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 136 | callback(err); 137 | }); 138 | } 139 | } 140 | }.bind(this)); 141 | 142 | activeCharacteristic 143 | .on('get', function(callback) { 144 | that.device.call("get_prop", ["power"]).then(result => { 145 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - Active - getActive: " + result); 146 | 147 | if(result[0] === "off") { 148 | callback(null, Characteristic.Active.INACTIVE); 149 | } else { 150 | callback(null, Characteristic.Active.ACTIVE); 151 | } 152 | }).catch(function(err) { 153 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - Active - getActive Error: " + err); 154 | callback(err); 155 | }); 156 | }.bind(this)) 157 | .on('set', function(value, callback) { 158 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - Active - setActive: " + value); 159 | that.device.call("set_power", [value ? "on" : "off"]).then(result => { 160 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - Active - setActive Result: " + result); 161 | if(result[0] === "ok") { 162 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.IDLE); 163 | callback(null); 164 | if(value) { 165 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 166 | that.device.call("get_prop", ["mode"]).then(result => { 167 | if(result[0] === "silent") { 168 | silentModeOnCharacteristic.updateValue(true); 169 | } else { 170 | silentModeOnCharacteristic.updateValue(false); 171 | } 172 | }).catch(function(err) { 173 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]AirPurifier2AirPurifierAccessory - Active - setActive Error: " + err); 174 | callback(err); 175 | }); 176 | } else { 177 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.INACTIVE); 178 | silentModeOnCharacteristic.updateValue(false); 179 | } 180 | } else { 181 | callback(new Error(result[0])); 182 | } 183 | }).catch(function(err) { 184 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - Active - setActive Error: " + err); 185 | callback(err); 186 | }); 187 | }.bind(this)); 188 | 189 | currentAirPurifierStateCharacteristic 190 | .on('get', function(callback) { 191 | that.device.call("get_prop", ["power"]).then(result => { 192 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState: " + result); 193 | 194 | if(result[0] === "off") { 195 | callback(null, Characteristic.CurrentAirPurifierState.INACTIVE); 196 | } else { 197 | callback(null, Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 198 | } 199 | }).catch(function(err) { 200 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState Error: " + err); 201 | callback(err); 202 | }); 203 | }.bind(this)); 204 | 205 | lockPhysicalControlsCharacteristic 206 | .on('get', function(callback) { 207 | that.device.call("get_prop", ["child_lock"]).then(result => { 208 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 209 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 210 | }).catch(function(err) { 211 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 212 | callback(err); 213 | }); 214 | }.bind(this)) 215 | .on('set', function(value, callback) { 216 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 217 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 218 | if(result[0] === "ok") { 219 | callback(null); 220 | } else { 221 | callback(new Error(result[0])); 222 | } 223 | }).catch(function(err) { 224 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 225 | callback(err); 226 | }); 227 | }.bind(this)); 228 | 229 | targetAirPurifierStateCharacteristic 230 | .on('get', function(callback) { 231 | that.device.call("get_prop", ["mode"]).then(result => { 232 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + result); 233 | 234 | if(result[0] === "favorite") { 235 | callback(null, Characteristic.TargetAirPurifierState.MANUAL); 236 | } else { 237 | callback(null, Characteristic.TargetAirPurifierState.AUTO); 238 | } 239 | }).catch(function(err) { 240 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + err); 241 | callback(err); 242 | }); 243 | }.bind(this)) 244 | .on('set', function(value, callback) { 245 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState: " + value); 246 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == value ? (silentModeOnCharacteristic.value ? "silent" : "auto") : "favorite"]).then(result => { 247 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Result: " + result); 248 | if(result[0] === "ok") { 249 | if(Characteristic.TargetAirPurifierState.AUTO == value) { 250 | callback(null); 251 | } else { 252 | that.device.call("get_prop", ["favorite_level"]).then(result => { 253 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + result); 254 | silentModeOnCharacteristic.updateValue(false); 255 | if(rotationSpeedCharacteristic.value <= result[0] * 10 && rotationSpeedCharacteristic.value > (result[0] - 1) * 10) { 256 | callback(null); 257 | } else { 258 | rotationSpeedCharacteristic.value = result[0] * 10; 259 | callback(null); 260 | } 261 | }).catch(function(err) { 262 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 263 | callback(err); 264 | }); 265 | } 266 | } else { 267 | callback(new Error(result[0])); 268 | } 269 | }).catch(function(err) { 270 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Error: " + err); 271 | callback(err); 272 | }); 273 | }.bind(this)); 274 | 275 | rotationSpeedCharacteristic 276 | .on('get', function(callback) { 277 | that.device.call("get_prop", ["favorite_level"]).then(result => { 278 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - RotationSpeed - getRotationSpeed: " + result); 279 | callback(null, that.getRotationSpeedByFavoriteLevel(parseInt(result[0]), rotationSpeedCharacteristic.value)); 280 | }).catch(function(err) { 281 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - RotationSpeed - getRotationSpeed Error: " + err); 282 | callback(err); 283 | }); 284 | }.bind(this)) 285 | .on('set', function(value, callback) { 286 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - RotationSpeed - setRotationSpeed set: " + value); 287 | if(value == 0) { 288 | callback(null); 289 | } else { 290 | that.device.call("set_level_favorite", [that.getFavoriteLevelByRotationSpeed(value)]).then(result => { 291 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - RotationSpeed - setRotationSpeed Result: " + result); 292 | if(result[0] === "ok") { 293 | // that.device.call("set_mode", ["favorite"]).then(result => { 294 | // that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirPurifierAccessory - RotationSpeed - setTargetAirPurifierState Result: " + result); 295 | // if(result[0] === "ok") { 296 | // targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.MANUAL); 297 | // silentModeOnCharacteristic.updateValue(false); 298 | callback(null); 299 | // } else { 300 | // callback(new Error(result[0])); 301 | // } 302 | // }).catch(function(err) { 303 | // that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - RotationSpeed - setTargetAirPurifierState Error: " + err); 304 | // callback(err); 305 | // }); 306 | } else { 307 | callback(new Error(result[0])); 308 | } 309 | }).catch(function(err) { 310 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 311 | callback(err); 312 | }) 313 | } 314 | }.bind(this)); 315 | 316 | currentTemperatureCharacteristic.on('get', function(callback) { 317 | this.device.call("get_prop", ["temp_dec"]).then(result => { 318 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Temperature - getTemperature: " + result); 319 | callback(null, result[0] / 10); 320 | }).catch(function(err) { 321 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Temperature - getTemperature Error: " + err); 322 | callback(err); 323 | }); 324 | }.bind(this)); 325 | 326 | currentRelativeHumidityCharacteristic 327 | .on('get', function(callback) { 328 | this.device.call("get_prop", ["humidity"]).then(result => { 329 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Humidity - getHumidity: " + result); 330 | callback(null, result[0]); 331 | }).catch(function(err) { 332 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Humidity - getHumidity Error: " + err); 333 | callback(err); 334 | }); 335 | }.bind(this)); 336 | 337 | pm25DensityCharacteristic 338 | .on('get', function(callback) { 339 | this.device.call("get_prop", ["aqi"]).then(result => { 340 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity: " + result); 341 | callback(null, result[0]); 342 | 343 | var airQualityValue = Characteristic.AirQuality.UNKNOWN; 344 | if(result[0] <= 50) { 345 | airQualityValue = Characteristic.AirQuality.EXCELLENT; 346 | } else if(result[0] > 50 && result[0] <= 100) { 347 | airQualityValue = Characteristic.AirQuality.GOOD; 348 | } else if(result[0] > 100 && result[0] <= 200) { 349 | airQualityValue = Characteristic.AirQuality.FAIR; 350 | } else if(result[0] > 200 && result[0] <= 300) { 351 | airQualityValue = Characteristic.AirQuality.INFERIOR; 352 | } else if(result[0] > 300) { 353 | airQualityValue = Characteristic.AirQuality.POOR; 354 | } else { 355 | airQualityValue = Characteristic.AirQuality.UNKNOWN; 356 | } 357 | airQualityCharacteristic.updateValue(airQualityValue); 358 | }).catch(function(err) { 359 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity Error: " + err); 360 | callback(err); 361 | }); 362 | }.bind(this)); 363 | 364 | // var filterMaintenanceService = new Service.FilterMaintenance(this.name); 365 | var filterChangeIndicationCharacteristic = airPurifierService.getCharacteristic(Characteristic.FilterChangeIndication); 366 | var filterLifeLevelCharacteristic = airPurifierService.addCharacteristic(Characteristic.FilterLifeLevel); 367 | 368 | filterChangeIndicationCharacteristic 369 | .on('get', function(callback) { 370 | that.device.call("get_prop", ["filter1_life"]).then(result => { 371 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication: " + result); 372 | callback(null, result[0] < 5 ? Characteristic.FilterChangeIndication.CHANGE_FILTER : Characteristic.FilterChangeIndication.FILTER_OK); 373 | }).catch(function(err) { 374 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication Error: " + err); 375 | callback(err); 376 | }); 377 | }.bind(this)); 378 | filterLifeLevelCharacteristic 379 | .on('get', function(callback) { 380 | that.device.call("get_prop", ["filter1_life"]).then(result => { 381 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel: " + result); 382 | callback(null, result[0]); 383 | }).catch(function(err) { 384 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel Error: " + err); 385 | callback(err); 386 | }); 387 | }.bind(this)); 388 | // services.push(filterMaintenanceService); 389 | 390 | return services; 391 | } 392 | 393 | MiAirPurifier2SAirPurifierAccessory.prototype.getFavoriteLevelByRotationSpeed = function(rotationSpeed) { 394 | if(this.frm.length < 2) { 395 | return 1; 396 | } 397 | 398 | for(var i = 1; i< this.frm.length; i++) { 399 | if(rotationSpeed > this.frm[i-1] && rotationSpeed <= this.frm[i]) { 400 | return i; 401 | } 402 | } 403 | 404 | return 1; 405 | } 406 | 407 | MiAirPurifier2SAirPurifierAccessory.prototype.getRotationSpeedByFavoriteLevel = function(favoriteLevel, rotationSpeed) { 408 | if(this.frm.length < 2) { 409 | return 1; 410 | } 411 | 412 | if(rotationSpeed > this.frm[favoriteLevel-1] && rotationSpeed <= this.frm[favoriteLevel]) { 413 | return rotationSpeed; 414 | } else { 415 | return this.frm[favoriteLevel]; 416 | } 417 | 418 | } 419 | 420 | MiAirPurifier2STemperatureAccessory = function(dThis) { 421 | this.device = dThis.device; 422 | this.name = dThis.config['temperatureName']; 423 | this.platform = dThis.platform; 424 | } 425 | 426 | MiAirPurifier2STemperatureAccessory.prototype.getServices = function() { 427 | var services = []; 428 | 429 | var infoService = new Service.AccessoryInformation(); 430 | infoService 431 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 432 | .setCharacteristic(Characteristic.Model, "AirPurifier2S") 433 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 434 | services.push(infoService); 435 | 436 | var temperatureService = new Service.TemperatureSensor(this.name); 437 | temperatureService 438 | .getCharacteristic(Characteristic.CurrentTemperature) 439 | .on('get', this.getTemperature.bind(this)) 440 | services.push(temperatureService); 441 | 442 | return services; 443 | } 444 | 445 | MiAirPurifier2STemperatureAccessory.prototype.getTemperature = function(callback) { 446 | var that = this; 447 | this.device.call("get_prop", ["temp_dec"]).then(result => { 448 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2STemperatureAccessory - Temperature - getTemperature: " + result); 449 | callback(null, result[0] / 10); 450 | }).catch(function(err) { 451 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2STemperatureAccessory - Temperature - getTemperature Error: " + err); 452 | callback(err); 453 | }); 454 | } 455 | 456 | MiAirPurifier2SHumidityAccessory = function(dThis) { 457 | this.device = dThis.device; 458 | this.name = dThis.config['humidityName']; 459 | this.platform = dThis.platform; 460 | } 461 | 462 | MiAirPurifier2SHumidityAccessory.prototype.getServices = function() { 463 | var services = []; 464 | 465 | var infoService = new Service.AccessoryInformation(); 466 | infoService 467 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 468 | .setCharacteristic(Characteristic.Model, "AirPurifier2S") 469 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 470 | services.push(infoService); 471 | 472 | var humidityService = new Service.HumiditySensor(this.name); 473 | humidityService 474 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 475 | .on('get', this.getHumidity.bind(this)) 476 | services.push(humidityService); 477 | 478 | return services; 479 | } 480 | 481 | MiAirPurifier2SHumidityAccessory.prototype.getHumidity = function(callback) { 482 | var that = this; 483 | this.device.call("get_prop", ["humidity"]).then(result => { 484 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SHumidityAccessory - Humidity - getHumidity: " + result); 485 | callback(null, result[0]); 486 | }).catch(function(err) { 487 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SHumidityAccessory - Humidity - getHumidity Error: " + err); 488 | callback(err); 489 | }); 490 | } 491 | 492 | MiAirPurifier2SBuzzerSwitchAccessory = function(dThis) { 493 | this.device = dThis.device; 494 | this.name = dThis.config['buzzerSwitchName']; 495 | this.platform = dThis.platform; 496 | } 497 | 498 | MiAirPurifier2SBuzzerSwitchAccessory.prototype.getServices = function() { 499 | var services = []; 500 | 501 | var infoService = new Service.AccessoryInformation(); 502 | infoService 503 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 504 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 505 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 506 | services.push(infoService); 507 | 508 | var switchService = new Service.Switch(this.name); 509 | switchService 510 | .getCharacteristic(Characteristic.On) 511 | .on('get', this.getBuzzerState.bind(this)) 512 | .on('set', this.setBuzzerState.bind(this)); 513 | services.push(switchService); 514 | 515 | return services; 516 | } 517 | 518 | MiAirPurifier2SBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 519 | var that = this; 520 | this.device.call("get_prop", ["volume"]).then(result => { 521 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SBuzzerSwitchAccessory - Mute - getBuzzerState: " + result); 522 | callback(null, result[0] === "on" ? true : false); 523 | }).catch(function(err) { 524 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SBuzzerSwitchAccessory - Mute - getBuzzerState Error: " + err); 525 | callback(err); 526 | }); 527 | } 528 | 529 | MiAirPurifier2SBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 530 | var that = this; 531 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SBuzzerSwitchAccessory - Mute - setBuzzerState: " + value); 532 | that.device.call("set_buzzer", [value ? "on" : "off"]).then(result => { 533 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SBuzzerSwitchAccessory - Mute - setBuzzerState Result: " + result); 534 | if(result[0] === "ok") { 535 | callback(null); 536 | } else { 537 | callback(new Error(result[0])); 538 | } 539 | }).catch(function(err) { 540 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SBuzzerSwitchAccessory - Mute - setBuzzerState Error: " + err); 541 | callback(err); 542 | }); 543 | } 544 | 545 | MiAirPurifier2SLEDBulbAccessory = function(dThis) { 546 | this.device = dThis.device; 547 | this.name = dThis.config['ledBulbName']; 548 | this.platform = dThis.platform; 549 | } 550 | 551 | MiAirPurifier2SLEDBulbAccessory.prototype.getServices = function() { 552 | var that = this; 553 | var services = []; 554 | 555 | var infoService = new Service.AccessoryInformation(); 556 | infoService 557 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 558 | .setCharacteristic(Characteristic.Model, "AirPurifier2S") 559 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 560 | services.push(infoService); 561 | 562 | var switchLEDService = new Service.Lightbulb(this.name); 563 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 564 | 565 | onCharacteristic 566 | .on('get', function(callback) { 567 | this.device.call("get_prop", ["led"]).then(result => { 568 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SLEDBulbAccessory - switchLED - getLEDPower: " + result); 569 | callback(null, result[0] === "on" ? true : false); 570 | }).catch(function(err) { 571 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 572 | callback(err); 573 | }); 574 | }.bind(this)) 575 | .on('set', function(value, callback) { 576 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SLEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 577 | this.device.call("set_led", [value ? "on" : "off"]).then(result => { 578 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SLEDBulbAccessory - switchLED - setLEDPower Result: " + result); 579 | if(result[0] === "ok") { 580 | callback(null); 581 | } else { 582 | callback(new Error(result[0])); 583 | } 584 | }).catch(function(err) { 585 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SLEDBulbAccessory - switchLED - setLEDPower Error: " + err); 586 | callback(err); 587 | }); 588 | }.bind(this)); 589 | services.push(switchLEDService); 590 | 591 | return services; 592 | } 593 | 594 | MiAirPurifier2SAirQualityAccessory = function(dThis) { 595 | this.device = dThis.device; 596 | this.name = dThis.config['airQualityName']; 597 | this.platform = dThis.platform; 598 | } 599 | 600 | MiAirPurifier2SAirQualityAccessory.prototype.getServices = function() { 601 | var that = this; 602 | var services = []; 603 | 604 | var infoService = new Service.AccessoryInformation(); 605 | infoService 606 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 607 | .setCharacteristic(Characteristic.Model, "AirPurifier2S") 608 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 609 | services.push(infoService); 610 | 611 | var pmService = new Service.AirQualitySensor(this.name); 612 | var pm2_5Characteristic = pmService.addCharacteristic(Characteristic.PM2_5Density); 613 | pmService 614 | .getCharacteristic(Characteristic.AirQuality) 615 | .on('get', function(callback) { 616 | that.device.call("get_prop", ["aqi"]).then(result => { 617 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2SAirQualityAccessory - AirQuality - getAirQuality: " + result); 618 | 619 | pm2_5Characteristic.updateValue(result[0]); 620 | 621 | if(result[0] <= 50) { 622 | callback(null, Characteristic.AirQuality.EXCELLENT); 623 | } else if(result[0] > 50 && result[0] <= 100) { 624 | callback(null, Characteristic.AirQuality.GOOD); 625 | } else if(result[0] > 100 && result[0] <= 200) { 626 | callback(null, Characteristic.AirQuality.FAIR); 627 | } else if(result[0] > 200 && result[0] <= 300) { 628 | callback(null, Characteristic.AirQuality.INFERIOR); 629 | } else if(result[0] > 300) { 630 | callback(null, Characteristic.AirQuality.POOR); 631 | } else { 632 | callback(null, Characteristic.AirQuality.UNKNOWN); 633 | } 634 | }).catch(function(err) { 635 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2SAirQualityAccessory - AirQuality - getAirQuality Error: " + err); 636 | callback(err); 637 | }); 638 | }.bind(this)); 639 | services.push(pmService); 640 | 641 | return services; 642 | } -------------------------------------------------------------------------------- /Devices/MiAirPurifierPro.js: -------------------------------------------------------------------------------- 1 | require('./Base'); 2 | 3 | const inherits = require('util').inherits; 4 | const miio = require('miio'); 5 | 6 | var Accessory, PlatformAccessory, Service, Characteristic, UUIDGen; 7 | 8 | MiAirPurifierPro = function(platform, config) { 9 | this.init(platform, config); 10 | 11 | Accessory = platform.Accessory; 12 | PlatformAccessory = platform.PlatformAccessory; 13 | Service = platform.Service; 14 | Characteristic = platform.Characteristic; 15 | UUIDGen = platform.UUIDGen; 16 | 17 | this.device = new miio.Device({ 18 | address: this.config['ip'], 19 | token: this.config['token'] 20 | }); 21 | 22 | this.accessories = {}; 23 | if(!this.config['airPurifierDisable'] && this.config['airPurifierName'] && this.config['airPurifierName'] != "" && this.config['silentModeSwitchName'] && this.config['silentModeSwitchName'] != "") { 24 | this.accessories['airPurifierAccessory'] = new MiAirPurifierProAirPurifierAccessory(this); 25 | } 26 | if(!this.config['temperatureDisable'] && this.config['temperatureName'] && this.config['temperatureName'] != "") { 27 | this.accessories['temperatureAccessory'] = new MiAirPurifierProTemperatureAccessory(this); 28 | } 29 | if(!this.config['humidityDisable'] && this.config['humidityName'] && this.config['humidityName'] != "") { 30 | this.accessories['humidityAccessory'] = new MiAirPurifierProHumidityAccessory(this); 31 | } 32 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 33 | // this.accessories['buzzerSpeakerAccessory'] = new MiAirPurifierProBuzzerSpeakerAccessory(this); 34 | this.accessories['buzzerSwitchAccessory'] = new MiAirPurifierProBuzzerSwitchAccessory(this); 35 | } 36 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 37 | this.accessories['ledBulbAccessory'] = new MiAirPurifierProLEDBulbAccessory(this); 38 | } 39 | if(!this.config['airQualityDisable'] && this.config['airQualityName'] && this.config['airQualityName'] != "") { 40 | this.accessories['airQualityAccessory'] = new MiAirPurifierProAirQualityAccessory(this); 41 | } 42 | var accessoriesArr = this.obj2array(this.accessories); 43 | 44 | this.platform.log.debug("[MiAirPurifierPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 45 | 46 | return accessoriesArr; 47 | } 48 | inherits(MiAirPurifierPro, Base); 49 | 50 | MiAirPurifierProAirPurifierAccessory = function(dThis) { 51 | this.device = dThis.device; 52 | this.name = dThis.config['airPurifierName']; 53 | this.silentModeSwitchDisable = dThis.config['silentModeSwitchDisable']; 54 | this.silentModeSwitchName = dThis.config['silentModeSwitchName']; 55 | this.platform = dThis.platform; 56 | } 57 | 58 | MiAirPurifierProAirPurifierAccessory.prototype.getServices = function() { 59 | var that = this; 60 | var services = []; 61 | 62 | var infoService = new Service.AccessoryInformation(); 63 | infoService 64 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 65 | .setCharacteristic(Characteristic.Model, "AirPurifierPro") 66 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 67 | services.push(infoService); 68 | 69 | var silentModeSwitch = new Service.Switch(this.silentModeSwitchName); 70 | var silentModeOnCharacteristic = silentModeSwitch.getCharacteristic(Characteristic.On); 71 | if(!this.silentModeSwitchDisable) { 72 | services.push(silentModeSwitch); 73 | } 74 | 75 | var airPurifierService = new Service.AirPurifier(this.name); 76 | var activeCharacteristic = airPurifierService.getCharacteristic(Characteristic.Active); 77 | var currentAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.CurrentAirPurifierState); 78 | var targetAirPurifierStateCharacteristic = airPurifierService.getCharacteristic(Characteristic.TargetAirPurifierState); 79 | var lockPhysicalControlsCharacteristic = airPurifierService.addCharacteristic(Characteristic.LockPhysicalControls); 80 | var rotationSpeedCharacteristic = airPurifierService.addCharacteristic(Characteristic.RotationSpeed); 81 | 82 | var currentTemperatureCharacteristic = airPurifierService.addCharacteristic(Characteristic.CurrentTemperature); 83 | var currentRelativeHumidityCharacteristic = airPurifierService.addCharacteristic(Characteristic.CurrentRelativeHumidity); 84 | var pm25DensityCharacteristic = airPurifierService.addCharacteristic(Characteristic.PM2_5Density); 85 | var airQualityCharacteristic = airPurifierService.addCharacteristic(Characteristic.AirQuality); 86 | services.push(airPurifierService); 87 | 88 | silentModeOnCharacteristic 89 | .on('get', function(callback) { 90 | that.device.call("get_prop", ["mode"]).then(result => { 91 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - getOn: " + result); 92 | 93 | if(result[0] === "silent") { 94 | callback(null, true); 95 | } else { 96 | callback(null, false); 97 | } 98 | }).catch(function(err) { 99 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - getOn Error: " + err); 100 | callback(err); 101 | }); 102 | }.bind(this)) 103 | .on('set', function(value, callback) { 104 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - setOn: " + value); 105 | if(value) { 106 | that.device.call("set_mode", ["silent"]).then(result => { 107 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 108 | if(result[0] === "ok") { 109 | targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.AUTO); 110 | callback(null); 111 | 112 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 113 | activeCharacteristic.updateValue(Characteristic.Active.ACTIVE); 114 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 115 | } 116 | } else { 117 | callback(new Error(result[0])); 118 | } 119 | }).catch(function(err) { 120 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 121 | callback(err); 122 | }); 123 | } else { 124 | if(Characteristic.Active.INACTIVE == activeCharacteristic.value) { 125 | callback(null); 126 | } else { 127 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == targetAirPurifierStateCharacteristic.value ? "auto" : "favorite"]).then(result => { 128 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - setOn Result: " + result); 129 | if(result[0] === "ok") { 130 | callback(null); 131 | } else { 132 | callback(new Error(result[0])); 133 | } 134 | }).catch(function(err) { 135 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - SilentModeSwitch - setOn Error: " + err); 136 | callback(err); 137 | }); 138 | } 139 | } 140 | }.bind(this)); 141 | 142 | activeCharacteristic 143 | .on('get', function(callback) { 144 | that.device.call("get_prop", ["power"]).then(result => { 145 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - Active - getActive: " + result); 146 | 147 | if(result[0] === "off") { 148 | callback(null, Characteristic.Active.INACTIVE); 149 | } else { 150 | callback(null, Characteristic.Active.ACTIVE); 151 | } 152 | }).catch(function(err) { 153 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - Active - getActive Error: " + err); 154 | callback(err); 155 | }); 156 | }.bind(this)) 157 | .on('set', function(value, callback) { 158 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - Active - setActive: " + value); 159 | that.device.call("set_power", [value ? "on" : "off"]).then(result => { 160 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - Active - setActive Result: " + result); 161 | if(result[0] === "ok") { 162 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.IDLE); 163 | callback(null); 164 | if(value) { 165 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 166 | that.device.call("get_prop", ["mode"]).then(result => { 167 | if(result[0] === "silent") { 168 | silentModeOnCharacteristic.updateValue(true); 169 | } else { 170 | silentModeOnCharacteristic.updateValue(false); 171 | } 172 | }).catch(function(err) { 173 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]AirPurifier2AirPurifierAccessory - Active - setActive Error: " + err); 174 | callback(err); 175 | }); 176 | } else { 177 | currentAirPurifierStateCharacteristic.updateValue(Characteristic.CurrentAirPurifierState.INACTIVE); 178 | silentModeOnCharacteristic.updateValue(false); 179 | } 180 | } else { 181 | callback(new Error(result[0])); 182 | } 183 | }).catch(function(err) { 184 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - Active - setActive Error: " + err); 185 | callback(err); 186 | }); 187 | }.bind(this)); 188 | 189 | currentAirPurifierStateCharacteristic 190 | .on('get', function(callback) { 191 | that.device.call("get_prop", ["power"]).then(result => { 192 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState: " + result); 193 | 194 | if(result[0] === "off") { 195 | callback(null, Characteristic.CurrentAirPurifierState.INACTIVE); 196 | } else { 197 | callback(null, Characteristic.CurrentAirPurifierState.PURIFYING_AIR); 198 | } 199 | }).catch(function(err) { 200 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - CurrentAirPurifierState - getCurrentAirPurifierState Error: " + err); 201 | callback(err); 202 | }); 203 | }.bind(this)); 204 | 205 | lockPhysicalControlsCharacteristic 206 | .on('get', function(callback) { 207 | that.device.call("get_prop", ["child_lock"]).then(result => { 208 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 209 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 210 | }).catch(function(err) { 211 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 212 | callback(err); 213 | }); 214 | }.bind(this)) 215 | .on('set', function(value, callback) { 216 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 217 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 218 | if(result[0] === "ok") { 219 | callback(null); 220 | } else { 221 | callback(new Error(result[0])); 222 | } 223 | }).catch(function(err) { 224 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 225 | callback(err); 226 | }); 227 | }.bind(this)); 228 | 229 | targetAirPurifierStateCharacteristic 230 | .on('get', function(callback) { 231 | that.device.call("get_prop", ["mode"]).then(result => { 232 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + result); 233 | 234 | if(result[0] === "favorite") { 235 | callback(null, Characteristic.TargetAirPurifierState.MANUAL); 236 | } else { 237 | callback(null, Characteristic.TargetAirPurifierState.AUTO); 238 | } 239 | }).catch(function(err) { 240 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - getTargetAirPurifierState: " + err); 241 | callback(err); 242 | }); 243 | }.bind(this)) 244 | .on('set', function(value, callback) { 245 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState: " + value); 246 | that.device.call("set_mode", [Characteristic.TargetAirPurifierState.AUTO == value ? (silentModeOnCharacteristic.value ? "silent" : "auto") : "favorite"]).then(result => { 247 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Result: " + result); 248 | if(result[0] === "ok") { 249 | if(Characteristic.TargetAirPurifierState.AUTO == value) { 250 | callback(null); 251 | } else { 252 | that.device.call("get_prop", ["favorite_level"]).then(result => { 253 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + result); 254 | silentModeOnCharacteristic.updateValue(false); 255 | if(rotationSpeedCharacteristic.value <= result[0] * 10 && rotationSpeedCharacteristic.value > (result[0] - 1) * 10) { 256 | callback(null); 257 | } else { 258 | rotationSpeedCharacteristic.value = result[0] * 10; 259 | callback(null); 260 | } 261 | }).catch(function(err) { 262 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 263 | callback(err); 264 | }); 265 | } 266 | } else { 267 | callback(new Error(result[0])); 268 | } 269 | }).catch(function(err) { 270 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - setTargetAirPurifierState Error: " + err); 271 | callback(err); 272 | }); 273 | }.bind(this)); 274 | 275 | rotationSpeedCharacteristic 276 | .on('get', function(callback) { 277 | that.device.call("get_prop", ["favorite_level"]).then(result => { 278 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - RotationSpeed - getRotationSpeed: " + result); 279 | callback(null, result[0]); 280 | }).catch(function(err) { 281 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - RotationSpeed - getRotationSpeed Error: " + err); 282 | callback(err); 283 | }); 284 | }.bind(this)) 285 | .on('set', function(value, callback) { 286 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - RotationSpeed - setRotationSpeed set: " + value); 287 | if(value == 0) { 288 | callback(null); 289 | } else { 290 | that.device.call("set_level_favorite", [parseInt(value / 10) < 10 ? parseInt(value / 10) + 1 : 10]).then(result => { 291 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - RotationSpeed - setRotationSpeed Result: " + result); 292 | if(result[0] === "ok") { 293 | // that.device.call("set_mode", ["favorite"]).then(result => { 294 | // that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirPurifierAccessory - RotationSpeed - setTargetAirPurifierState Result: " + result); 295 | // if(result[0] === "ok") { 296 | // targetAirPurifierStateCharacteristic.updateValue(Characteristic.TargetAirPurifierState.MANUAL); 297 | // silentModeOnCharacteristic.updateValue(false); 298 | callback(null); 299 | // } else { 300 | // callback(new Error(result[0])); 301 | // } 302 | // }).catch(function(err) { 303 | // that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - RotationSpeed - setTargetAirPurifierState Error: " + err); 304 | // callback(err); 305 | // }); 306 | } else { 307 | callback(new Error(result[0])); 308 | } 309 | }).catch(function(err) { 310 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirPurifierAccessory - TargetAirPurifierState - getRotationSpeed: " + err); 311 | callback(err); 312 | }) 313 | } 314 | }.bind(this)); 315 | 316 | currentTemperatureCharacteristic.on('get', function(callback) { 317 | this.device.call("get_prop", ["temp_dec"]).then(result => { 318 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Temperature - getTemperature: " + result); 319 | callback(null, result[0] / 10); 320 | }).catch(function(err) { 321 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Temperature - getTemperature Error: " + err); 322 | callback(err); 323 | }); 324 | }.bind(this)); 325 | 326 | currentRelativeHumidityCharacteristic 327 | .on('get', function(callback) { 328 | this.device.call("get_prop", ["humidity"]).then(result => { 329 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - Humidity - getHumidity: " + result); 330 | callback(null, result[0]); 331 | }).catch(function(err) { 332 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - Humidity - getHumidity Error: " + err); 333 | callback(err); 334 | }); 335 | }.bind(this)); 336 | 337 | pm25DensityCharacteristic 338 | .on('get', function(callback) { 339 | this.device.call("get_prop", ["aqi"]).then(result => { 340 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity: " + result); 341 | callback(null, result[0]); 342 | 343 | var airQualityValue = Characteristic.AirQuality.UNKNOWN; 344 | if(result[0] <= 50) { 345 | airQualityValue = Characteristic.AirQuality.EXCELLENT; 346 | } else if(result[0] > 50 && result[0] <= 100) { 347 | airQualityValue = Characteristic.AirQuality.GOOD; 348 | } else if(result[0] > 100 && result[0] <= 200) { 349 | airQualityValue = Characteristic.AirQuality.FAIR; 350 | } else if(result[0] > 200 && result[0] <= 300) { 351 | airQualityValue = Characteristic.AirQuality.INFERIOR; 352 | } else if(result[0] > 300) { 353 | airQualityValue = Characteristic.AirQuality.POOR; 354 | } else { 355 | airQualityValue = Characteristic.AirQuality.UNKNOWN; 356 | } 357 | airQualityCharacteristic.updateValue(airQualityValue); 358 | }).catch(function(err) { 359 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - aqi - getHumidity Error: " + err); 360 | callback(err); 361 | }); 362 | }.bind(this)); 363 | 364 | // var filterMaintenanceService = new Service.FilterMaintenance(this.name); 365 | var filterChangeIndicationCharacteristic = airPurifierService.getCharacteristic(Characteristic.FilterChangeIndication); 366 | var filterLifeLevelCharacteristic = airPurifierService.addCharacteristic(Characteristic.FilterLifeLevel); 367 | 368 | filterChangeIndicationCharacteristic 369 | .on('get', function(callback) { 370 | that.device.call("get_prop", ["filter1_life"]).then(result => { 371 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication: " + result); 372 | callback(null, result[0] < 5 ? Characteristic.FilterChangeIndication.CHANGE_FILTER : Characteristic.FilterChangeIndication.FILTER_OK); 373 | }).catch(function(err) { 374 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterChangeIndication - getFilterChangeIndication Error: " + err); 375 | callback(err); 376 | }); 377 | }.bind(this)); 378 | filterLifeLevelCharacteristic 379 | .on('get', function(callback) { 380 | that.device.call("get_prop", ["filter1_life"]).then(result => { 381 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel: " + result); 382 | callback(null, result[0]); 383 | }).catch(function(err) { 384 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifier2AirPurifierAccessory - FilterLifeLevel - getFilterLifeLevel Error: " + err); 385 | callback(err); 386 | }); 387 | }.bind(this)); 388 | // services.push(filterMaintenanceService); 389 | 390 | return services; 391 | } 392 | 393 | MiAirPurifierProTemperatureAccessory = function(dThis) { 394 | this.device = dThis.device; 395 | this.name = dThis.config['temperatureName']; 396 | this.platform = dThis.platform; 397 | } 398 | 399 | MiAirPurifierProTemperatureAccessory.prototype.getServices = function() { 400 | var services = []; 401 | 402 | var infoService = new Service.AccessoryInformation(); 403 | infoService 404 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 405 | .setCharacteristic(Characteristic.Model, "AirPurifierPro") 406 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 407 | services.push(infoService); 408 | 409 | var temperatureService = new Service.TemperatureSensor(this.name); 410 | temperatureService 411 | .getCharacteristic(Characteristic.CurrentTemperature) 412 | .on('get', this.getTemperature.bind(this)) 413 | services.push(temperatureService); 414 | 415 | return services; 416 | } 417 | 418 | MiAirPurifierProTemperatureAccessory.prototype.getTemperature = function(callback) { 419 | var that = this; 420 | this.device.call("get_prop", ["temp_dec"]).then(result => { 421 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProTemperatureAccessory - Temperature - getTemperature: " + result); 422 | callback(null, result[0] / 10); 423 | }).catch(function(err) { 424 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProTemperatureAccessory - Temperature - getTemperature Error: " + err); 425 | callback(err); 426 | }); 427 | } 428 | 429 | MiAirPurifierProHumidityAccessory = function(dThis) { 430 | this.device = dThis.device; 431 | this.name = dThis.config['humidityName']; 432 | this.platform = dThis.platform; 433 | } 434 | 435 | MiAirPurifierProHumidityAccessory.prototype.getServices = function() { 436 | var services = []; 437 | 438 | var infoService = new Service.AccessoryInformation(); 439 | infoService 440 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 441 | .setCharacteristic(Characteristic.Model, "AirPurifierPro") 442 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 443 | services.push(infoService); 444 | 445 | var humidityService = new Service.HumiditySensor(this.name); 446 | humidityService 447 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 448 | .on('get', this.getHumidity.bind(this)) 449 | services.push(humidityService); 450 | 451 | return services; 452 | } 453 | 454 | MiAirPurifierProHumidityAccessory.prototype.getHumidity = function(callback) { 455 | var that = this; 456 | this.device.call("get_prop", ["humidity"]).then(result => { 457 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProHumidityAccessory - Humidity - getHumidity: " + result); 458 | callback(null, result[0]); 459 | }).catch(function(err) { 460 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProHumidityAccessory - Humidity - getHumidity Error: " + err); 461 | callback(err); 462 | }); 463 | } 464 | /* 465 | MiAirPurifierProBuzzerSpeakerAccessory = function(dThis) { 466 | this.device = dThis.device; 467 | this.name = dThis.config['buzzerSpeakerName']; 468 | this.platform = dThis.platform; 469 | } 470 | 471 | MiAirPurifierProBuzzerSpeakerAccessory.prototype.getServices = function() { 472 | var that = this; 473 | var services = []; 474 | 475 | var infoService = new Service.AccessoryInformation(); 476 | infoService 477 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 478 | .setCharacteristic(Characteristic.Model, "AirPurifierPro") 479 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 480 | services.push(infoService); 481 | 482 | var speakerService = new Service.Speaker(this.name); 483 | var muteCharacteristic = speakerService.getCharacteristic(Characteristic.Mute); 484 | var volumeCharacteristic = speakerService.addCharacteristic(Characteristic.Volume); 485 | 486 | muteCharacteristic 487 | .on('get', function(callback) { 488 | this.device.call("get_prop", ["volume"]).then(result => { 489 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Mute - getBuzzerState: " + result); 490 | callback(null, result[0] == 0 ? false : true); 491 | }).catch(function(err) { 492 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProBuzzerSpeakerAccessory - Mute - getBuzzerState Error: " + err); 493 | callback(err); 494 | }); 495 | }.bind(this)) 496 | .on('set', function(value, callback) { 497 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Mute - setBuzzerState: " + value); 498 | that.device.call("set_volume", [value ? "on" : 0]).then(result => { 499 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Mute - setBuzzerState Result: " + result); 500 | if(result[0] === "ok") { 501 | callback(null); 502 | } else { 503 | callback(new Error(result[0])); 504 | } 505 | }).catch(function(err) { 506 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProBuzzerSpeakerAccessory - Mute - setBuzzerState Error: " + err); 507 | callback(err); 508 | }); 509 | }.bind(this)); 510 | 511 | volumeCharacteristic 512 | .on('get', function(callback) { 513 | this.device.call("get_prop", ["volume"]).then(result => { 514 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Volume - getVolume: " + result); 515 | callback(null, result[0]); 516 | }).catch(function(err) { 517 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProBuzzerSpeakerAccessory - Volume - getVolume Error: " + err); 518 | callback(err); 519 | }); 520 | }.bind(this)) 521 | .on('set', function(value, callback) { 522 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Volume - setVolume: " + value); 523 | that.device.call("set_volume", [value ? "on" : 0]).then(result => { 524 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Volume - setVolume Result: " + result); 525 | if(result[0] === "ok") { 526 | callback(null); 527 | } else { 528 | callback(new Error(result[0])); 529 | } 530 | }).catch(function(err) { 531 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProBuzzerSpeakerAccessory - Volume - setVolume Error: " + err); 532 | callback(err); 533 | }); 534 | }.bind(this)); 535 | services.push(speakerService); 536 | 537 | return services; 538 | } 539 | */ 540 | 541 | MiAirPurifierProBuzzerSwitchAccessory = function(dThis) { 542 | this.device = dThis.device; 543 | this.name = dThis.config['buzzerSwitchName']; 544 | this.platform = dThis.platform; 545 | } 546 | 547 | MiAirPurifierProBuzzerSwitchAccessory.prototype.getServices = function() { 548 | var services = []; 549 | 550 | var infoService = new Service.AccessoryInformation(); 551 | infoService 552 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 553 | .setCharacteristic(Characteristic.Model, "AirPurifier2") 554 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 555 | services.push(infoService); 556 | 557 | var switchService = new Service.Switch(this.name); 558 | switchService 559 | .getCharacteristic(Characteristic.On) 560 | .on('get', this.getBuzzerState.bind(this)) 561 | .on('set', this.setBuzzerState.bind(this)); 562 | services.push(switchService); 563 | 564 | return services; 565 | } 566 | 567 | MiAirPurifierProBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 568 | var that = this; 569 | this.device.call("get_prop", ["volume"]).then(result => { 570 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Mute - getBuzzerState: " + result); 571 | callback(null, result[0] == 0 ? false : true); 572 | }).catch(function(err) { 573 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProBuzzerSpeakerAccessory - Mute - getBuzzerState Error: " + err); 574 | callback(err); 575 | }); 576 | } 577 | 578 | MiAirPurifierProBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 579 | var that = this; 580 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Mute - setBuzzerState: " + value); 581 | that.device.call("set_volume", [value ? 100 : 0]).then(result => { 582 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProBuzzerSpeakerAccessory - Mute - setBuzzerState Result: " + result); 583 | if(result[0] === "ok") { 584 | callback(null); 585 | } else { 586 | callback(new Error(result[0])); 587 | } 588 | }).catch(function(err) { 589 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProBuzzerSpeakerAccessory - Mute - setBuzzerState Error: " + err); 590 | callback(err); 591 | }); 592 | } 593 | 594 | MiAirPurifierProLEDBulbAccessory = function(dThis) { 595 | this.device = dThis.device; 596 | this.name = dThis.config['ledBulbName']; 597 | this.platform = dThis.platform; 598 | } 599 | 600 | MiAirPurifierProLEDBulbAccessory.prototype.getServices = function() { 601 | var that = this; 602 | var services = []; 603 | 604 | var infoService = new Service.AccessoryInformation(); 605 | infoService 606 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 607 | .setCharacteristic(Characteristic.Model, "AirPurifierPro") 608 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 609 | services.push(infoService); 610 | 611 | var switchLEDService = new Service.Lightbulb(this.name); 612 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 613 | 614 | onCharacteristic 615 | .on('get', function(callback) { 616 | this.device.call("get_prop", ["led"]).then(result => { 617 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProLEDBulbAccessory - switchLED - getLEDPower: " + result); 618 | callback(null, result[0] === "on" ? true : false); 619 | }).catch(function(err) { 620 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 621 | callback(err); 622 | }); 623 | }.bind(this)) 624 | .on('set', function(value, callback) { 625 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProLEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 626 | this.device.call("set_led", [value ? "on" : "off"]).then(result => { 627 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProLEDBulbAccessory - switchLED - setLEDPower Result: " + result); 628 | if(result[0] === "ok") { 629 | callback(null); 630 | } else { 631 | callback(new Error(result[0])); 632 | } 633 | }).catch(function(err) { 634 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProLEDBulbAccessory - switchLED - setLEDPower Error: " + err); 635 | callback(err); 636 | }); 637 | }.bind(this)); 638 | services.push(switchLEDService); 639 | 640 | return services; 641 | } 642 | 643 | MiAirPurifierProAirQualityAccessory = function(dThis) { 644 | this.device = dThis.device; 645 | this.name = dThis.config['airQualityName']; 646 | this.platform = dThis.platform; 647 | } 648 | 649 | MiAirPurifierProAirQualityAccessory.prototype.getServices = function() { 650 | var that = this; 651 | var services = []; 652 | 653 | var infoService = new Service.AccessoryInformation(); 654 | infoService 655 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 656 | .setCharacteristic(Characteristic.Model, "AirPurifierPro") 657 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 658 | services.push(infoService); 659 | 660 | var pmService = new Service.AirQualitySensor(this.name); 661 | var pm2_5Characteristic = pmService.addCharacteristic(Characteristic.PM2_5Density); 662 | pmService 663 | .getCharacteristic(Characteristic.AirQuality) 664 | .on('get', function(callback) { 665 | that.device.call("get_prop", ["aqi"]).then(result => { 666 | that.platform.log.debug("[MiAirPurifierPlatform][DEBUG]MiAirPurifierProAirQualityAccessory - AirQuality - getAirQuality: " + result); 667 | 668 | pm2_5Characteristic.updateValue(result[0]); 669 | 670 | if(result[0] <= 50) { 671 | callback(null, Characteristic.AirQuality.EXCELLENT); 672 | } else if(result[0] > 50 && result[0] <= 100) { 673 | callback(null, Characteristic.AirQuality.GOOD); 674 | } else if(result[0] > 100 && result[0] <= 200) { 675 | callback(null, Characteristic.AirQuality.FAIR); 676 | } else if(result[0] > 200 && result[0] <= 300) { 677 | callback(null, Characteristic.AirQuality.INFERIOR); 678 | } else if(result[0] > 300) { 679 | callback(null, Characteristic.AirQuality.POOR); 680 | } else { 681 | callback(null, Characteristic.AirQuality.UNKNOWN); 682 | } 683 | }).catch(function(err) { 684 | that.platform.log.error("[MiAirPurifierPlatform][ERROR]MiAirPurifierProAirQualityAccessory - AirQuality - getAirQuality Error: " + err); 685 | callback(err); 686 | }); 687 | }.bind(this)); 688 | services.push(pmService); 689 | 690 | return services; 691 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # homebridge-mi-airpurifier 2 | [![npm version](https://badge.fury.io/js/homebridge-mi-airpurifier.svg)](https://badge.fury.io/js/homebridge-mi-airpurifier) 3 | 4 | XiaoMi air purifier plugins for HomeBridge. 5 | Thanks for [nfarina](https://github.com/nfarina)(the author of [homebridge](https://github.com/nfarina/homebridge)), [OpenMiHome](https://github.com/OpenMiHome/mihome-binary-protocol), [aholstenson](https://github.com/aholstenson)(the author of [miio](https://github.com/aholstenson/miio)), [licuhui](https://github.com/licuhui), [superszy](https://github.com/superszy), all other developer and testers. 6 | 7 | **Note: I have only a part of these devices, so some devices don't have tested. If you find bugs, please submit them to [issues](https://github.com/YinHangCode/homebridge-mi-airpurifier/issues) or [QQ Group: 107927710](//shang.qq.com/wpa/qunwpa?idkey=8b9566598f40dd68412065ada24184ef72c6bddaa11525ca26c4e1536a8f2a3d).** 8 | 9 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/master/images/MiAirPurifier.jpg) 10 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/master/images/MiAirPurifier2.jpg) 11 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/master/images/MiAirPurifierPro.jpg) 12 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/master/images/MiAirPurifier2S.jpg) 13 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/master/images/MiAirPurifierMAX.jpg) 14 | 15 | ## Supported Devices 16 | 1.MiAirPurifier(小米空气净化器) 17 | 2.MiAirPurifier2(小米空气净化器2) 18 | 3.MiAirPurifierPro(小米空气净化器Pro) 19 | 4.MiAirPurifier2S(小米空气净化器2S) 20 | 5.MiAirPurifierMAX(米家空气净化器MAX) ---- coming soon 21 | 22 | ## Pre-Requirements 23 | 1.Make sure your IOS version is ios11 or later. 24 | 25 | ## Installation 26 | 1. Install HomeBridge, please follow it's [README](https://github.com/nfarina/homebridge/blob/master/README.md). 27 | If you are using Raspberry Pi, please read [Running-HomeBridge-on-a-Raspberry-Pi](https://github.com/nfarina/homebridge/wiki/Running-HomeBridge-on-a-Raspberry-Pi). 28 | 2. Make sure you can see HomeBridge in your iOS devices, if not, please go back to step 1. 29 | 3. Install packages. 30 | ``` 31 | npm install -g homebridge-mi-airpurifier 32 | ``` 33 | 34 | ## Configuration 35 | ``` 36 | "platforms": [{ 37 | "platform": "MiAirPurifierPlatform", 38 | "deviceCfgs": [{ 39 | "type": "MiAirPurifier", 40 | "ip": "192.168.88.xx", 41 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 42 | "airPurifierDisable": false, 43 | "airPurifierName": "MiAirPurifier", 44 | "silentModeSwitchDisable": false, 45 | "silentModeSwitchName": "MiAirPurifier Silent Mode Switch", 46 | "buzzerSwitchDisable": true, 47 | "buzzerSwitchName": "MiAirPurifier Buzzer Switch", 48 | "ledBulbDisable": true, 49 | "ledBulbName": "MiAirPurifier LED Switch", 50 | "airQualityDisable": false, 51 | "airQualityName": "MiAirPurifier AirQuality" 52 | }, { 53 | "type": "MiAirPurifier2", 54 | "ip": "192.168.88.xx", 55 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 56 | "airPurifierDisable": false, 57 | "airPurifierName": "MiAirPurifier2", 58 | "silentModeSwitchDisable": false, 59 | "silentModeSwitchName": "MiAirPurifier2 Silent Mode Switch", 60 | "temperatureDisable": false, 61 | "temperatureName": "MiAirPurifier2 Temperature", 62 | "humidityDisable": false, 63 | "humidityName": "MiAirPurifier2 Humidity", 64 | "buzzerSwitchDisable": true, 65 | "buzzerSwitchName": "MiAirPurifier2 Buzzer Switch", 66 | "ledBulbDisable": true, 67 | "ledBulbName": "MiAirPurifier2 LED Switch", 68 | "airQualityDisable": false, 69 | "airQualityName": "MiAirPurifier2 AirQuality" 70 | }, { 71 | "type": "MiAirPurifierPro", 72 | "ip": "192.168.88.xx", 73 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 74 | "airPurifierDisable": false, 75 | "airPurifierName": "MiAirPurifierPro", 76 | "silentModeSwitchDisable": false, 77 | "silentModeSwitchName": "MiAirPurifierPro Silent Mode Switch", 78 | "temperatureDisable": false, 79 | "temperatureName": "MiAirPurifierPro Temperature", 80 | "humidityDisable": false, 81 | "humidityName": "MiAirPurifierPro Humidity", 82 | "buzzerSwitchDisable": true, 83 | "buzzerSwitchName": "MiAirPurifierPro Buzzer Switch", 84 | "ledBulbDisable": true, 85 | "ledBulbName": "MiAirPurifierPro LED Switch", 86 | "airQualityDisable": false, 87 | "airQualityName": "MiAirPurifierPro AirQuality" 88 | }, { 89 | "type": "MiAirPurifier2S", 90 | "ip": "192.168.88.xx", 91 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 92 | "airPurifierDisable": false, 93 | "airPurifierName": "MiAirPurifier2S", 94 | "silentModeSwitchDisable": false, 95 | "silentModeSwitchName": "MiAirPurifier2S Silent Mode Switch", 96 | "temperatureDisable": false, 97 | "temperatureName": "MiAirPurifier2S Temperature", 98 | "humidityDisable": false, 99 | "humidityName": "MiAirPurifier2S Humidity", 100 | "buzzerSwitchDisable": true, 101 | "buzzerSwitchName": "MiAirPurifier2S Buzzer Switch", 102 | "ledBulbDisable": true, 103 | "ledBulbName": "MiAirPurifier2S LED Switch", 104 | "airQualityDisable": false, 105 | "airQualityName": "MiAirPurifier2S AirQuality" 106 | }] 107 | }] 108 | ``` 109 | 110 | ## Get token 111 | ### Get token by miio2.db 112 | setup MiJia(MiHome) app in your android device or android virtual machine. 113 | open MiJia(MiHome) app and login your account. 114 | refresh device list and make sure device display in the device list. 115 | get miio2.db(path: /data/data/com.xiaomi.smarthome/databases/miio2.db) file from your android device or android virtual machine. 116 | open website [[Get MiIo Tokens By DataBase File](http://miio2.yinhh.com/)], upload miio2.db file and submit. 117 | ### Get token by network 118 | Open command prompt or terminal. Run following command: 119 | ``` 120 | miio --discover 121 | ``` 122 | Wait until you get output similar to this: 123 | ``` 124 | Device ID: xxxxxxxx 125 | Model info: Unknown 126 | Address: 192.168.88.xx 127 | Token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx via auto-token 128 | Support: Unknown 129 | ``` 130 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is token. 131 | If token is "???", then reset device and connect device created Wi-Fi hotspot. 132 | Run following command: 133 | ``` 134 | miio --discover --sync 135 | ``` 136 | Wait until you get output. 137 | For more information about token, please refer to [OpenMiHome](https://github.com/OpenMiHome/mihome-binary-protocol) and [miio](https://github.com/aholstenson/miio). 138 | 139 | ## Version Logs 140 | ### 0.1.3 (2018-07-11) 141 | 1.add MiAirPurifier, MiAirPurifier2, MiAirPurifier2S, MiAirPurifierPro FilterLife feature. 142 | ### 0.1.2 (2018-02-10) 143 | 1.update 'package.json'. 144 | ### 0.1.1 (2018-01-21) 145 | 1.remove feature of turn to manual mode when set rotation speed, because of it will affect HomeKit automation. 146 | ### 0.1.0 (2017-11-16) 147 | 1.support for XiaoMi AirPurifier2S. 148 | 2.modify class name, reduce the probability of conflicts due to the same class name and other plugins. 149 | ### 0.0.9 (2017-10-28) 150 | 1.fixed bug that XiaoMi AirPurifierPro power status display inaccurate. 151 | ### 0.0.8 (2017-10-12) 152 | 1.fixed bug that XiaoMi AirPurifier can not work. 153 | ### 0.0.7 (2017-10-01) 154 | 1.fixed bug that linkage issues between silent mode switch accessory and air purifier accessory. 155 | ### 0.0.6 (2017-09-22) 156 | 1.fixed bug that silent mode switch accessory don't display. 157 | 2.fixed bug that XiaoMi AirPurifierPro led light accessory display brightness. 158 | ### 0.0.5 (2017-09-21) 159 | 1.fixed bug that XiaoMi AirPurifier and XiaoMi AirPurifierPro air purifier accessory don't display. 160 | ### 0.0.4 (2017-09-11) 161 | 1.optimized code. 162 | ### 0.0.3 (2017-09-10) 163 | 1.fixed bug that air purifier accessory disable when set "silentModeSwitchDisable" value is true. 164 | ### 0.0.2 (2017-09-09) 165 | 1.fixed bug that can not startup. 166 | 2.add setting silent mode switch disable feature. 167 | 3.optimized code. 168 | ### 0.0.1 (2017-09-09) 169 | 1.support for XiaoMi AirPurifier. 170 | 2.support for XiaoMi AirPurifier2. 171 | 3.support for XiaoMi AirPurifierPro. 172 | -------------------------------------------------------------------------------- /images/MiAirPurifier.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/deeaca0a7f08ee10e3c0ea56194f735ce60e8735/images/MiAirPurifier.jpg -------------------------------------------------------------------------------- /images/MiAirPurifier2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/deeaca0a7f08ee10e3c0ea56194f735ce60e8735/images/MiAirPurifier2.jpg -------------------------------------------------------------------------------- /images/MiAirPurifier2S.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/deeaca0a7f08ee10e3c0ea56194f735ce60e8735/images/MiAirPurifier2S.jpg -------------------------------------------------------------------------------- /images/MiAirPurifierMAX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/deeaca0a7f08ee10e3c0ea56194f735ce60e8735/images/MiAirPurifierMAX.jpg -------------------------------------------------------------------------------- /images/MiAirPurifierPro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-airpurifier/deeaca0a7f08ee10e3c0ea56194f735ce60e8735/images/MiAirPurifierPro.jpg -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./Devices/MiAirPurifier2'); 2 | require('./Devices/MiAirPurifier'); 3 | require('./Devices/MiAirPurifierPro'); 4 | require('./Devices/MiAirPurifier2S'); 5 | 6 | var fs = require('fs'); 7 | var packageFile = require("./package.json"); 8 | var PlatformAccessory, Accessory, Service, Characteristic, UUIDGen; 9 | 10 | module.exports = function(homebridge) { 11 | if(!isConfig(homebridge.user.configPath(), "platforms", "MiAirPurifierPlatform")) { 12 | return; 13 | } 14 | 15 | PlatformAccessory = homebridge.platformAccessory; 16 | Accessory = homebridge.hap.Accessory; 17 | Service = homebridge.hap.Service; 18 | Characteristic = homebridge.hap.Characteristic; 19 | UUIDGen = homebridge.hap.uuid; 20 | 21 | homebridge.registerPlatform('homebridge-mi-airpurifier', 'MiAirPurifierPlatform', MiAirPurifierPlatform, true); 22 | } 23 | 24 | function isConfig(configFile, type, name) { 25 | var config = JSON.parse(fs.readFileSync(configFile)); 26 | if("accessories" === type) { 27 | var accessories = config.accessories; 28 | for(var i in accessories) { 29 | if(accessories[i]['accessory'] === name) { 30 | return true; 31 | } 32 | } 33 | } else if("platforms" === type) { 34 | var platforms = config.platforms; 35 | for(var i in platforms) { 36 | if(platforms[i]['platform'] === name) { 37 | return true; 38 | } 39 | } 40 | } else { 41 | } 42 | 43 | return false; 44 | } 45 | 46 | function MiAirPurifierPlatform(log, config, api) { 47 | if(null == config) { 48 | return; 49 | } 50 | 51 | this.Accessory = Accessory; 52 | this.PlatformAccessory = PlatformAccessory; 53 | this.Service = Service; 54 | this.Characteristic = Characteristic; 55 | this.UUIDGen = UUIDGen; 56 | 57 | this.log = log; 58 | this.config = config; 59 | 60 | if (api) { 61 | this.api = api; 62 | } 63 | 64 | this.log.info("[MiAirPurifierPlatform][INFO]*******************************************************************"); 65 | this.log.info("[MiAirPurifierPlatform][INFO] MiAirPurifierPlatform v%s By YinHang", packageFile.version); 66 | this.log.info("[MiAirPurifierPlatform][INFO] GitHub: https://github.com/YinHangCode/homebridge-mi-airpurifier "); 67 | this.log.info("[MiAirPurifierPlatform][INFO] QQ Group: 107927710 "); 68 | this.log.info("[MiAirPurifierPlatform][INFO]*******************************************************************"); 69 | this.log.info("[MiAirPurifierPlatform][INFO]start success..."); 70 | } 71 | 72 | MiAirPurifierPlatform.prototype = { 73 | accessories: function(callback) { 74 | var myAccessories = []; 75 | 76 | var deviceCfgs = this.config['deviceCfgs']; 77 | if(deviceCfgs instanceof Array) { 78 | for (var i = 0; i < deviceCfgs.length; i++) { 79 | var deviceCfg = deviceCfgs[i]; 80 | if(null == deviceCfg['type'] || "" == deviceCfg['type']) { 81 | continue; 82 | } 83 | if(null == deviceCfg['token'] || "" == deviceCfg['token'] || null == deviceCfg['ip'] || "" == deviceCfg['ip']) { 84 | continue; 85 | } 86 | 87 | if (deviceCfg['type'] == "MiAirPurifier") { 88 | new MiAirPurifier(this, deviceCfg).forEach(function(accessory, index, arr){ 89 | myAccessories.push(accessory); 90 | }); 91 | } else if (deviceCfg['type'] == "MiAirPurifier2") { 92 | new MiAirPurifier2(this, deviceCfg).forEach(function(accessory, index, arr){ 93 | myAccessories.push(accessory); 94 | }); 95 | } else if (deviceCfg['type'] == "MiAirPurifierPro") { 96 | new MiAirPurifierPro(this, deviceCfg).forEach(function(accessory, index, arr){ 97 | myAccessories.push(accessory); 98 | }); 99 | } else if (deviceCfg['type'] == "MiAirPurifier2S") { 100 | new MiAirPurifier2S(this, deviceCfg).forEach(function(accessory, index, arr){ 101 | myAccessories.push(accessory); 102 | }); 103 | } else { 104 | } 105 | } 106 | this.log.info("[MiAirPurifierPlatform][INFO]device size: " + deviceCfgs.length + ", accessories size: " + myAccessories.length); 107 | } 108 | 109 | callback(myAccessories); 110 | } 111 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "homebridge-mi-airpurifier", 3 | "version": "0.1.3", 4 | "description": "XiaoMi air purifier plugins for HomeBridge(https://github.com/nfarina/homebridge).", 5 | "keywords": [ 6 | "homebridge-plugin", 7 | "xiaomi", 8 | "mi", 9 | "airpurifier" 10 | ], 11 | "author": "YinHang", 12 | "homepage": "https://github.com/YinHangCode/homebridge-mi-airpurifier", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/YinHangCode/homebridge-mi-airpurifier" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/YinHangCode/homebridge-mi-airpurifier/issues" 19 | }, 20 | "engines": { 21 | "node": ">=7.0.0", 22 | "homebridge": ">=0.4.1" 23 | }, 24 | "dependencies": { 25 | "miio": "0.14.1" 26 | } 27 | } --------------------------------------------------------------------------------