├── Devices ├── Base.js ├── DmakerFan.js ├── DmakerFanP5c.js ├── MiDCVariableFrequencyFan.js ├── ZhiMiDCVariableFrequencyFan.js └── ZhiMiNaturalWindFan.js ├── README.md ├── images ├── DmakerFan.jpg ├── MiDCVariableFrequencyFan.jpg ├── ZhiMiDCVariableFrequencyFan.jpg └── ZhiMiNaturalWindFan.jpg ├── index.js ├── package.json └── utils └── Utils.js /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/DmakerFan.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 | DmakerFan = 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['fanDisable'] && this.config['fanName'] && this.config['fanName'] != "") { 24 | this.accessories['fanAccessory'] = new DmakerFanAccessory(this); 25 | } 26 | 27 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 28 | this.accessories['ledBulbAccessory'] = new DmakerFanLEDBulbAccessory(this); 29 | } 30 | 31 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 32 | this.accessories['buzzerSwitchAccessory'] = new DmakerFanBuzzerSwitchAccessory(this); 33 | } 34 | 35 | var accessoriesArr = this.obj2array(this.accessories); 36 | 37 | this.platform.log.debug("[MiFanPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 38 | 39 | return accessoriesArr; 40 | } 41 | inherits(DmakerFan, Base); 42 | 43 | DmakerFanAccessory = function(dThis) { 44 | this.device = dThis.device; 45 | this.name = dThis.config['fanName']; 46 | this.platform = dThis.platform; 47 | } 48 | 49 | DmakerFanAccessory.prototype.getServices = function() { 50 | var that = this; 51 | var services = []; 52 | 53 | var infoService = new Service.AccessoryInformation(); 54 | infoService 55 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 56 | .setCharacteristic(Characteristic.Model, "DmakerFan") 57 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 58 | services.push(infoService); 59 | 60 | var fanService = new Service.Fanv2(this.name); 61 | var activeCharacteristic = fanService.getCharacteristic(Characteristic.Active); 62 | var lockPhysicalControlsCharacteristic = fanService.addCharacteristic(Characteristic.LockPhysicalControls); 63 | var swingModeControlsCharacteristic = fanService.addCharacteristic(Characteristic.SwingMode); 64 | var rotationSpeedCharacteristic = fanService.addCharacteristic(Characteristic.RotationSpeed); 65 | var rotationDirectionCharacteristic = fanService.addCharacteristic(Characteristic.RotationDirection); 66 | 67 | activeCharacteristic 68 | .on('get', function(callback) { 69 | that.device.call("get_prop", ["all"]).then(result => { 70 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - Active - getActive: " + result); 71 | if (result[0] === true) { 72 | callback(null, Characteristic.Active.ACTIVE); 73 | } else { 74 | callback(null, Characteristic.Active.INACTIVE); 75 | } 76 | }).catch(function(err) { 77 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - Active - getActive Error: " + err); 78 | callback(err); 79 | }); 80 | }.bind(this)) 81 | .on('set', function(value, callback) { 82 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - Active - setActive: " + value); 83 | that.device.call("s_power", [value ? "true" : "false"]).then(result => { 84 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - Active - setActive Result: " + result); 85 | if(result[0] === "ok") { 86 | callback(null); 87 | 88 | } else { 89 | callback(new Error(result[0])); 90 | } 91 | }).catch(function(err) { 92 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - Active - setActive Error: " + err); 93 | callback(err); 94 | }); 95 | }.bind(this)); 96 | 97 | lockPhysicalControlsCharacteristic 98 | .on('get', function(callback) { 99 | that.device.call("get_prop", ["all"]).then(result => { 100 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 101 | if (result[8] === true) { 102 | callback(null, Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED); 103 | } else { 104 | callback(null, Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 105 | } 106 | }).catch(function(err) { 107 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 108 | callback(err); 109 | }); 110 | }.bind(this)) 111 | .on('set', function(value, callback) { 112 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - LockPhysicalControls - setLockPhysicalControls: " + value); 113 | that.device.call("s_lock", [value ? "true" : "false"]).then(result => { 114 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 115 | if(result[0] === "ok") { 116 | callback(null); 117 | 118 | } else { 119 | callback(new Error(result[0])); 120 | } 121 | }).catch(function(err) { 122 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 123 | callback(err); 124 | }); 125 | }.bind(this)); 126 | 127 | // angle_enable 128 | swingModeControlsCharacteristic 129 | .on('get', function(callback) { 130 | that.device.call("get_prop", ["all"]).then(result => { 131 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - SwingMode - getSwingModeControls: " + result); 132 | if (result[3] === true) { 133 | callback(null, Characteristic.SwingMode.SWING_ENABLED); 134 | } else { 135 | callback(null, Characteristic.SwingMode.SWING_DISABLED); 136 | } 137 | }).catch(function(err) { 138 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - SwingMode - getSwingModeControls Error: " + err); 139 | callback(err); 140 | }); 141 | }.bind(this)) 142 | .on('set', function(value, callback) { 143 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - SwingMode - setSwingModeControls: " + value); 144 | that.device.call("s_roll", [value ? "true" : "false"]).then(result => { 145 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - SwingMode - setSwingModeControls Result: " + result); 146 | if(result[0] === "ok") { 147 | callback(null); 148 | } else { 149 | callback(new Error(result[0])); 150 | } 151 | }).catch(function(err) { 152 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - SwingMode - setSwingModeControls Error: " + err); 153 | callback(err); 154 | }); 155 | }.bind(this)); 156 | 157 | 158 | rotationSpeedCharacteristic 159 | .on('get', function(callback) { 160 | that.device.call("get_prop", ["all"]).then(result => { 161 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - RotationSpeed - getRotationSpeed: " + result); 162 | callback(null, result[2]); 163 | }).catch(function(err) { 164 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - RotationSpeed - getRotationSpeed Error: " + err); 165 | callback(err); 166 | }); 167 | }.bind(this)) 168 | .on('set', function(value, callback) { 169 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - RotationSpeed - setRotationSpeed: " + value); 170 | that.device.call("s_speed", [value]).then(result => { 171 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 172 | if(result[0] === "ok") { 173 | callback(null); 174 | } else { 175 | callback(new Error(result[0])); 176 | } 177 | }).catch(function(err) { 178 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 179 | callback(err); 180 | }); 181 | }.bind(this)); 182 | 183 | rotationDirectionCharacteristic 184 | .on('get', function(callback) { 185 | that.device.call("get_prop", ["all"]).then(result => { 186 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - RotationDirection - getRotationDirection: " + result); 187 | if (result[1] === "normal") { 188 | callback(null, Characteristic.RotationDirection.CLOCKWISE); 189 | } else { 190 | callback(null, Characteristic.RotationDirection.COUNTER_CLOCKWISE); 191 | } 192 | }).catch(function(err) { 193 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - RotationDirection - getRotationDirection Error: " + err); 194 | callback(err); 195 | }); 196 | }.bind(this)) 197 | .on('set', function(value, callback) { 198 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - RotationDirection - setRotationDirection: " + value); 199 | that.device.call("s_mode", [value ? "normal" : "nature"]).then(result => { 200 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanAccessory - RotationDirection - setRotationDirection Result: " + result); 201 | if(result[0] === "ok") { 202 | callback(null); 203 | } else { 204 | callback(new Error(result[0])); 205 | } 206 | }).catch(function(err) { 207 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanAccessory - RotationDirection - setRotationDirection Error: " + err); 208 | callback(err); 209 | }); 210 | }.bind(this)); 211 | 212 | services.push(fanService); 213 | 214 | return services; 215 | } 216 | 217 | DmakerFanLEDBulbAccessory = function(dThis) { 218 | this.device = dThis.device; 219 | this.name = dThis.config['ledBulbName']; 220 | this.platform = dThis.platform; 221 | } 222 | 223 | DmakerFanLEDBulbAccessory.prototype.getServices = function() { 224 | var services = []; 225 | 226 | var infoService = new Service.AccessoryInformation(); 227 | infoService 228 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 229 | .setCharacteristic(Characteristic.Model, "DmakerFan") 230 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 231 | services.push(infoService); 232 | 233 | var switchService = new Service.Switch(this.name); 234 | switchService 235 | .getCharacteristic(Characteristic.On) 236 | .on('get', this.getLEDBulbState.bind(this)) 237 | .on('set', this.setLEDBulbState.bind(this)); 238 | services.push(switchService); 239 | 240 | return services; 241 | } 242 | 243 | DmakerFanLEDBulbAccessory.prototype.getLEDBulbState = function(callback) { 244 | var that = this; 245 | this.device.call("get_prop", ["all"]).then(result => { 246 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanLEDBulbAccessory - ledBulb - getLEDBulbState: " + result); 247 | if (result[6] === true) { 248 | callback(null, true); 249 | } else { 250 | callback(null, false); 251 | } 252 | }).catch(function(err) { 253 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanLEDBulbAccessory - ledBulb - getLEDBulbState Error: " + err); 254 | callback(err); 255 | }); 256 | } 257 | 258 | DmakerFanLEDBulbAccessory.prototype.setLEDBulbState = function(value, callback) { 259 | var that = this; 260 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanLEDBulbAccessory - ledBulb - setLEDBulbState: " + value); 261 | that.device.call("s_light", [value ? "true" : "false"]).then(result => { 262 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanLEDBulbAccessory - ledBulb - setLEDBulbState Result: " + result); 263 | if(result[0] === "ok") { 264 | callback(null); 265 | } else { 266 | callback(new Error(result[0])); 267 | } 268 | }).catch(function(err) { 269 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanLEDBulbAccessory - ledBulb - setLEDBulbState Error: " + err); 270 | callback(err); 271 | }); 272 | } 273 | 274 | DmakerFanBuzzerSwitchAccessory = function(dThis) { 275 | this.device = dThis.device; 276 | this.name = dThis.config['buzzerSwitchName']; 277 | this.platform = dThis.platform; 278 | } 279 | 280 | DmakerFanBuzzerSwitchAccessory.prototype.getServices = function() { 281 | var services = []; 282 | 283 | var infoService = new Service.AccessoryInformation(); 284 | infoService 285 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 286 | .setCharacteristic(Characteristic.Model, "DmakerFan") 287 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 288 | services.push(infoService); 289 | 290 | var switchService = new Service.Switch(this.name); 291 | switchService 292 | .getCharacteristic(Characteristic.On) 293 | .on('get', this.getBuzzerState.bind(this)) 294 | .on('set', this.setBuzzerState.bind(this)); 295 | services.push(switchService); 296 | 297 | return services; 298 | } 299 | 300 | DmakerFanBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 301 | var that = this; 302 | this.device.call("get_prop", ["all"]).then(result => { 303 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 304 | if (result[7] === true) { 305 | callback(null, true); 306 | } else { 307 | callback(null, false); 308 | } 309 | }).catch(function(err) { 310 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 311 | callback(err); 312 | }); 313 | } 314 | 315 | DmakerFanBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 316 | var that = this; 317 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState: " + value); 318 | that.device.call("s_sound", [value ? "true" : "false"]).then(result => { 319 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 320 | if(result[0] === "ok") { 321 | callback(null); 322 | } else { 323 | callback(new Error(result[0])); 324 | } 325 | }).catch(function(err) { 326 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 327 | callback(err); 328 | }); 329 | } 330 | 331 | -------------------------------------------------------------------------------- /Devices/DmakerFanP5c.js: -------------------------------------------------------------------------------- 1 | require('./Base'); 2 | const {buildCommandArgs,isSuccess} = require('../utils/Utils') 3 | const inherits = require('util').inherits; 4 | const miio = require('miio'); 5 | 6 | let Accessory, PlatformAccessory, Service, Characteristic, UUIDGen, deviceId; 7 | 8 | let buildArgs = function (siid, piid, value) { 9 | const args = buildCommandArgs(deviceId, siid, piid, value); 10 | this.platform.log.debug("[MiFanPlatform][DEBUG]command args: ",args); 11 | return args 12 | }; 13 | DmakerFanP5c = function (platform, config) { 14 | this.init(platform, config); 15 | Accessory = platform.Accessory; 16 | PlatformAccessory = platform.PlatformAccessory; 17 | Service = platform.Service; 18 | Characteristic = platform.Characteristic; 19 | UUIDGen = platform.UUIDGen; 20 | 21 | this.device = new miio.Device({ 22 | address: this.config['ip'], 23 | token: this.config['token'] 24 | }); 25 | 26 | this.accessories = {}; 27 | if (!this.config['fanDisable'] && this.config['fanName'] && this.config['fanName'] != "") { 28 | this.accessories['fanAccessory'] = new DmakerFanP5cAccessory(this); 29 | } 30 | if (this.config['deviceId'] && this.config['deviceId'] != "") { 31 | console.log('+++++++++++++deviceId初始化成功+++++++++++') 32 | deviceId = this.config['deviceId'] 33 | } 34 | 35 | if (!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 36 | this.accessories['ledBulbAccessory'] = new DmakerFanP5cLEDBulbAccessory(this); 37 | } 38 | 39 | if (!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 40 | this.accessories['buzzerSwitchAccessory'] = new DmakerFanP5cBuzzerSwitchAccessory(this); 41 | } 42 | 43 | var accessoriesArr = this.obj2array(this.accessories); 44 | 45 | this.platform.log.debug("[MiFanPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 46 | 47 | return accessoriesArr; 48 | } 49 | inherits(DmakerFanP5c, Base); 50 | 51 | DmakerFanP5cAccessory = function (dThis) { 52 | this.device = dThis.device; 53 | this.name = dThis.config['fanName']; 54 | this.platform = dThis.platform; 55 | } 56 | 57 | DmakerFanP5cAccessory.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, "DmakerFanP5c") 65 | .setCharacteristic(Characteristic.SerialNumber, "9527"); 66 | services.push(infoService); 67 | 68 | var fanService = new Service.Fanv2(this.name); 69 | var activeCharacteristic = fanService.getCharacteristic(Characteristic.Active); 70 | var lockPhysicalControlsCharacteristic = fanService.addCharacteristic(Characteristic.LockPhysicalControls); 71 | var swingModeControlsCharacteristic = fanService.addCharacteristic(Characteristic.SwingMode); 72 | var rotationSpeedCharacteristic = fanService.addCharacteristic(Characteristic.RotationSpeed); 73 | var rotationDirectionCharacteristic = fanService.addCharacteristic(Characteristic.RotationDirection); 74 | 75 | activeCharacteristic 76 | .on('get', function (callback) { 77 | const args = buildArgs(2, 1); 78 | that.device.call("get_properties", args).then(result => { 79 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - Active - getActive: " + result); 80 | if (result[0].code === 0 && result[0].value === true) { 81 | callback(null, Characteristic.Active.ACTIVE); 82 | } else { 83 | callback(null, Characteristic.Active.INACTIVE); 84 | } 85 | }).catch(function (err) { 86 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - Active - getActive Error: " + err); 87 | callback(err); 88 | }); 89 | }.bind(this)) 90 | .on('set', function (value, callback) { 91 | const args = buildArgs(2, 1, value); 92 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - Active - setActive: " + value); 93 | that.device.call("set_properties", args).then(result => { 94 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - Active - setActive Result: " + result); 95 | if (isSuccess(result)) { 96 | callback(null); 97 | } else { 98 | callback(new Error(result[0])); 99 | } 100 | }).catch(function (err) { 101 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - Active - setActive Error: " + err); 102 | callback(err); 103 | }); 104 | }.bind(this)); 105 | 106 | lockPhysicalControlsCharacteristic 107 | .on('get', function (callback) { 108 | const args = buildArgs(7, 1); 109 | that.device.call("get_properties", args).then(result => { 110 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 111 | if (result[0].value === true) { 112 | callback(null, Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED); 113 | } else { 114 | callback(null, Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 115 | } 116 | }).catch(function (err) { 117 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 118 | callback(err); 119 | }); 120 | }.bind(this)) 121 | .on('set', function (value, callback) { 122 | const args = buildArgs(7, 1, value); 123 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - LockPhysicalControls - setLockPhysicalControls: " + value); 124 | that.device.call("set_properties", args).then(result => { 125 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 126 | if (isSuccess(result)) { 127 | callback(null); 128 | } else { 129 | callback(new Error(result[0])); 130 | } 131 | }).catch(function (err) { 132 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 133 | callback(err); 134 | }); 135 | }.bind(this)); 136 | 137 | // angle_enable 138 | swingModeControlsCharacteristic 139 | .on('get', function (callback) { 140 | const args = buildArgs(2, 4); 141 | that.device.call("get_properties", args).then(result => { 142 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - SwingMode - getSwingModeControls: " + result); 143 | if (result[0].code === 0 && result[0].value === true) { 144 | callback(null, Characteristic.SwingMode.SWING_ENABLED); 145 | } else { 146 | callback(null, Characteristic.SwingMode.SWING_DISABLED); 147 | } 148 | }).catch(function (err) { 149 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - SwingMode - getSwingModeControls Error: " + err); 150 | callback(err); 151 | }); 152 | }.bind(this)) 153 | .on('set', function (value, callback) { 154 | const args = buildArgs(2, 4, value); 155 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - SwingMode - setSwingModeControls: " + value); 156 | that.device.call("set_properties", args).then(result => { 157 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - SwingMode - setSwingModeControls Result: " + result); 158 | if (isSuccess(result)) { 159 | callback(null); 160 | } else { 161 | callback(new Error(result[0])); 162 | } 163 | }).catch(function (err) { 164 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - SwingMode - setSwingModeControls Error: " + err); 165 | callback(err); 166 | }); 167 | }.bind(this)); 168 | 169 | 170 | rotationSpeedCharacteristic 171 | .on('get', function (callback) { 172 | const args = buildArgs(8, 1); 173 | that.device.call("get_properties", args).then(result => { 174 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - RotationSpeed - getRotationSpeed: " + result); 175 | callback(null, result[0].value); 176 | }).catch(function (err) { 177 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - RotationSpeed - getRotationSpeed Error: " + err); 178 | callback(err); 179 | }); 180 | }.bind(this)) 181 | .on('set', function (value, callback) { 182 | const args = buildArgs(8, 1, value); 183 | 184 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - RotationSpeed - setRotationSpeed: " + value); 185 | that.device.call("set_properties", args).then(result => { 186 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - RotationSpeed - setRotationSpeed Result: " + result); 187 | if (isSuccess(result)) { 188 | callback(null); 189 | } else { 190 | callback(new Error(result[0])); 191 | } 192 | }).catch(function (err) { 193 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - RotationSpeed - setRotationSpeed Error: " + err); 194 | callback(err); 195 | }); 196 | }.bind(this)); 197 | 198 | rotationDirectionCharacteristic 199 | .on('get', function (callback) { 200 | const args = buildArgs(2, 3); 201 | that.device.call("get_properties", args).then(result => { 202 | const args = buildArgs(2, 3); 203 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - RotationDirection - getRotationDirection: " + result); 204 | if (result[0].value === 0) { 205 | callback(null, Characteristic.RotationDirection.CLOCKWISE); 206 | } else { 207 | callback(null, Characteristic.RotationDirection.COUNTER_CLOCKWISE); 208 | } 209 | }).catch(function (err) { 210 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - RotationDirection - getRotationDirection Error: " + err); 211 | callback(err); 212 | }); 213 | }.bind(this)) 214 | .on('set', function (value, callback) { 215 | const args = buildArgs(2, 3, value); 216 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - RotationDirection - setRotationDirection: " + value); 217 | that.device.call("set_properties", args).then(result => { 218 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanP5cAccessory - RotationDirection - setRotationDirection Result: " + result); 219 | if (isSuccess(result)) { 220 | callback(null); 221 | } else { 222 | callback(new Error(result[0])); 223 | } 224 | }).catch(function (err) { 225 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanP5cAccessory - RotationDirection - setRotationDirection Error: " + err); 226 | callback(err); 227 | }); 228 | }.bind(this)); 229 | 230 | services.push(fanService); 231 | 232 | return services; 233 | } 234 | 235 | DmakerFanP5cLEDBulbAccessory = function (dThis) { 236 | this.device = dThis.device; 237 | this.name = dThis.config['ledBulbName']; 238 | this.platform = dThis.platform; 239 | } 240 | 241 | DmakerFanP5cLEDBulbAccessory.prototype.getServices = function () { 242 | var services = []; 243 | 244 | var infoService = new Service.AccessoryInformation(); 245 | infoService 246 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 247 | .setCharacteristic(Characteristic.Model, "DmakerFanP5c") 248 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 249 | services.push(infoService); 250 | 251 | var switchService = new Service.Switch(this.name); 252 | switchService 253 | .getCharacteristic(Characteristic.On) 254 | .on('get', this.getLEDBulbState.bind(this)) 255 | .on('set', this.setLEDBulbState.bind(this)); 256 | services.push(switchService); 257 | 258 | return services; 259 | } 260 | 261 | DmakerFanP5cLEDBulbAccessory.prototype.getLEDBulbState = function (callback) { 262 | var that = this; 263 | const args = buildArgs(4, 1); 264 | this.device.call("get_properties", args).then(result => { 265 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanLEDBulbAccessory - ledBulb - getLEDBulbState: " + result); 266 | if (result[0].value === true) { 267 | callback(null, true); 268 | } else { 269 | callback(null, false); 270 | } 271 | }).catch(function (err) { 272 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanLEDBulbAccessory - ledBulb - getLEDBulbState Error: " + err); 273 | callback(err); 274 | }); 275 | } 276 | 277 | DmakerFanP5cLEDBulbAccessory.prototype.setLEDBulbState = function (value, callback) { 278 | var that = this; 279 | const args = buildArgs(4, 1, value); 280 | 281 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanLEDBulbAccessory - ledBulb - setLEDBulbState: " + value); 282 | that.device.call("set_properties", args).then(result => { 283 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanLEDBulbAccessory - ledBulb - setLEDBulbState Result: " + result); 284 | if (isSuccess(result)) { 285 | callback(null); 286 | } else { 287 | callback(new Error(result[0])); 288 | } 289 | }).catch(function (err) { 290 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanLEDBulbAccessory - ledBulb - setLEDBulbState Error: " + err); 291 | callback(err); 292 | }); 293 | } 294 | 295 | DmakerFanP5cBuzzerSwitchAccessory = function (dThis) { 296 | this.device = dThis.device; 297 | this.name = dThis.config['buzzerSwitchName']; 298 | this.platform = dThis.platform; 299 | } 300 | 301 | DmakerFanP5cBuzzerSwitchAccessory.prototype.getServices = function () { 302 | var services = []; 303 | var infoService = new Service.AccessoryInformation(); 304 | infoService 305 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 306 | .setCharacteristic(Characteristic.Model, "DmakerFanP5c") 307 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 308 | services.push(infoService); 309 | 310 | var switchService = new Service.Switch(this.name); 311 | switchService 312 | .getCharacteristic(Characteristic.On) 313 | .on('get', this.getBuzzerState.bind(this)) 314 | .on('set', this.setBuzzerState.bind(this)); 315 | services.push(switchService); 316 | 317 | return services; 318 | } 319 | 320 | DmakerFanP5cBuzzerSwitchAccessory.prototype.getBuzzerState = function (callback) { 321 | var that = this; 322 | const args = buildArgs(5, 1); 323 | 324 | this.device.call("get_properties", ["all"]).then(result => { 325 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 326 | if (result[0].value === true) { 327 | callback(null, true); 328 | } else { 329 | callback(null, false); 330 | } 331 | }).catch(function (err) { 332 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 333 | callback(err); 334 | }); 335 | } 336 | 337 | DmakerFanP5cBuzzerSwitchAccessory.prototype.setBuzzerState = function (value, callback) { 338 | var that = this; 339 | const args = buildArgs(5, 1, value); 340 | 341 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState: " + value); 342 | that.device.call("set_properties", args).then(result => { 343 | that.platform.log.debug("[MiFanPlatform][DEBUG]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 344 | if (isSuccess()) { 345 | callback(null); 346 | } else { 347 | callback(new Error(result[0])); 348 | } 349 | }).catch(function (err) { 350 | that.platform.log.error("[MiFanPlatform][ERROR]DmakerFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 351 | callback(err); 352 | }); 353 | } 354 | 355 | -------------------------------------------------------------------------------- /Devices/MiDCVariableFrequencyFan.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 | MiDCVariableFrequencyFan = 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['fanDisable'] && this.config['fanName'] && this.config['fanName'] != "") { 24 | this.accessories['fanAccessory'] = new MiDCVFFanFanAccessory(this); 25 | } 26 | if(!this.config['temperatureDisable'] && this.config['temperatureName'] && this.config['temperatureName'] != "") { 27 | this.accessories['temperatureAccessory'] = new MiDCVFFanTemperatureAccessory(this); 28 | } 29 | if(!this.config['humidityDisable'] && this.config['humidityName'] && this.config['humidityName'] != "") { 30 | this.accessories['humidityAccessory'] = new MiDCVFFanHumidityAccessory(this); 31 | } 32 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 33 | this.accessories['buzzerSwitchAccessory'] = new MiDCVFFanBuzzerSwitchAccessory(this); 34 | } 35 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 36 | this.accessories['ledBulbAccessory'] = new MiDCVFFanLEDBulbAccessory(this); 37 | } 38 | var accessoriesArr = this.obj2array(this.accessories); 39 | 40 | this.platform.log.debug("[MiFanPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 41 | 42 | return accessoriesArr; 43 | } 44 | inherits(MiDCVariableFrequencyFan, Base); 45 | 46 | MiDCVFFanFanAccessory = function(dThis) { 47 | this.device = dThis.device; 48 | this.name = dThis.config['fanName']; 49 | this.platform = dThis.platform; 50 | } 51 | 52 | MiDCVFFanFanAccessory.prototype.getServices = function() { 53 | var that = this; 54 | var services = []; 55 | 56 | var infoService = new Service.AccessoryInformation(); 57 | infoService 58 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 59 | .setCharacteristic(Characteristic.Model, "Mi DC VF Fan") 60 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 61 | services.push(infoService); 62 | 63 | var fanService = new Service.Fanv2(this.name); 64 | var activeCharacteristic = fanService.getCharacteristic(Characteristic.Active); 65 | var lockPhysicalControlsCharacteristic = fanService.addCharacteristic(Characteristic.LockPhysicalControls); 66 | var swingModeControlsCharacteristic = fanService.addCharacteristic(Characteristic.SwingMode); 67 | var rotationSpeedCharacteristic = fanService.addCharacteristic(Characteristic.RotationSpeed); 68 | var rotationDirectionCharacteristic = fanService.addCharacteristic(Characteristic.RotationDirection); 69 | 70 | var currentTemperatureCharacteristic = fanService.addCharacteristic(Characteristic.CurrentTemperature); 71 | var currentRelativeHumidityCharacteristic = fanService.addCharacteristic(Characteristic.CurrentRelativeHumidity); 72 | 73 | // power 74 | activeCharacteristic 75 | .on('get', function(callback) { 76 | that.device.call("get_prop", ["power"]).then(result => { 77 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - Active - getActive: " + result); 78 | callback(null, result[0] === "on" ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE); 79 | }).catch(function(err) { 80 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - Active - getActive Error: " + err); 81 | callback(err); 82 | }); 83 | }.bind(this)) 84 | .on('set', function(value, callback) { 85 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - Active - setActive: " + value); 86 | that.device.call("set_power", [value ? "on" : "off"]).then(result => { 87 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - Active - setActive Result: " + result); 88 | if(result[0] === "ok") { 89 | callback(null); 90 | } else { 91 | callback(new Error(result[0])); 92 | } 93 | }).catch(function(err) { 94 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - Active - setActive Error: " + err); 95 | callback(err); 96 | }); 97 | }.bind(this)); 98 | 99 | // child_lock 100 | lockPhysicalControlsCharacteristic 101 | .on('get', function(callback) { 102 | that.device.call("get_prop", ["child_lock"]).then(result => { 103 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 104 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 105 | }).catch(function(err) { 106 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 107 | callback(err); 108 | }); 109 | }.bind(this)) 110 | .on('set', function(value, callback) { 111 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - LockPhysicalControls - setLockPhysicalControls: " + value); 112 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 113 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 114 | if(result[0] === "ok") { 115 | callback(null); 116 | } else { 117 | callback(new Error(result[0])); 118 | } 119 | }).catch(function(err) { 120 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 121 | callback(err); 122 | }); 123 | }.bind(this)); 124 | 125 | // angle_enable 126 | swingModeControlsCharacteristic 127 | .on('get', function(callback) { 128 | that.device.call("get_prop", ["angle_enable"]).then(result => { 129 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - SwingMode - getSwingModeControls: " + result); 130 | callback(null, result[0] === "on" ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED); 131 | }).catch(function(err) { 132 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - SwingMode - getSwingModeControls Error: " + err); 133 | callback(err); 134 | }); 135 | }.bind(this)) 136 | .on('set', function(value, callback) { 137 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - SwingMode - setSwingModeControls: " + value); 138 | that.device.call("set_angle_enable", [value ? "on" : "off"]).then(result => { 139 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - SwingMode - setSwingModeControls Result: " + result); 140 | if(result[0] === "ok") { 141 | callback(null); 142 | } else { 143 | callback(new Error(result[0])); 144 | } 145 | }).catch(function(err) { 146 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - SwingMode - setSwingModeControls Error: " + err); 147 | callback(err); 148 | }); 149 | }.bind(this)); 150 | 151 | // natural_level speed_level 152 | rotationDirectionCharacteristic 153 | .on('get', function(callback) { 154 | that.device.call("get_prop", ["natural_level"]).then(result => { 155 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationDirection - getRotationDirection: " + result); 156 | if(result[0] > 0) { 157 | callback(null, Characteristic.RotationDirection.COUNTER_CLOCKWISE); 158 | } else { 159 | callback(null, Characteristic.RotationDirection.CLOCKWISE); 160 | } 161 | }).catch(function(err) { 162 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - RotationDirection - getRotationDirection Error: " + err); 163 | callback(err); 164 | }); 165 | }.bind(this)) 166 | .on('set', function(value, callback, context) { 167 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationDirection - setRotationDirection: " + value); 168 | if(Characteristic.RotationDirection.COUNTER_CLOCKWISE == value) { 169 | that.device.call("set_natural_level", [rotationSpeedCharacteristic.value]).then(result => { 170 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationDirection - setRotationDirection Result: " + result); 171 | if(result[0] === "ok") { 172 | callback(null); 173 | } else { 174 | callback(new Error(result[0])); 175 | } 176 | }).catch(function(err) { 177 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - RotationDirection - setRotationDirection Error: " + err); 178 | callback(err); 179 | }); 180 | } else { 181 | that.device.call("set_speed_level", [rotationSpeedCharacteristic.value]).then(result => { 182 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationDirection - setRotationDirection Result: " + result); 183 | if(result[0] === "ok") { 184 | callback(null); 185 | } else { 186 | callback(new Error(result[0])); 187 | } 188 | }).catch(function(err) { 189 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - RotationDirection - setRotationDirection Error: " + err); 190 | callback(err); 191 | }); 192 | } 193 | }.bind(this)); 194 | 195 | // speed_level natural_level 196 | rotationSpeedCharacteristic 197 | .on('get', function(callback) { 198 | that.device.call("get_prop", ["natural_level", "speed_level"]).then(result => { 199 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationSpeed - getRotationSpeed: " + result); 200 | if(result[0] > 0) { 201 | callback(null, result[0]); 202 | } else { 203 | callback(null, result[1]); 204 | } 205 | }).catch(function(err) { 206 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - RotationSpeed - getRotationSpeed Error: " + err); 207 | callback(err); 208 | }); 209 | }.bind(this)) 210 | .on('set', function(value, callback) { 211 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed: " + value); 212 | if(value > 0) { 213 | if(Characteristic.RotationDirection.COUNTER_CLOCKWISE == rotationDirectionCharacteristic.value) { 214 | that.device.call("set_natural_level", [value]).then(result => { 215 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 216 | if(result[0] === "ok") { 217 | callback(null); 218 | } else { 219 | callback(new Error(result[0])); 220 | } 221 | }).catch(function(err) { 222 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 223 | callback(err); 224 | }); 225 | } else { 226 | that.device.call("set_speed_level", [value]).then(result => { 227 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 228 | if(result[0] === "ok") { 229 | callback(null); 230 | } else { 231 | callback(new Error(result[0])); 232 | } 233 | }).catch(function(err) { 234 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 235 | callback(err); 236 | }); 237 | } 238 | } 239 | }.bind(this)); 240 | 241 | currentTemperatureCharacteristic.on('get', function(callback) { 242 | this.device.call("get_prop", ["temp_dec"]).then(result => { 243 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - Temperature - getTemperature: " + result); 244 | callback(null, result[0] / 10); 245 | }).catch(function(err) { 246 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - Temperature - getTemperature Error: " + err); 247 | callback(err); 248 | }); 249 | }.bind(this)); 250 | 251 | currentRelativeHumidityCharacteristic.on('get', function(callback) { 252 | this.device.call("get_prop", ["humidity"]).then(result => { 253 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanFanAccessory - Humidity - getHumidity: " + result); 254 | callback(null, result[0]); 255 | }).catch(function(err) { 256 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanFanAccessory - Humidity - getHumidity Error: " + err); 257 | callback(err); 258 | }); 259 | }.bind(this)); 260 | services.push(fanService); 261 | 262 | return services; 263 | } 264 | 265 | MiDCVFFanTemperatureAccessory = function(dThis) { 266 | this.device = dThis.device; 267 | this.name = dThis.config['temperatureName']; 268 | this.platform = dThis.platform; 269 | } 270 | 271 | MiDCVFFanTemperatureAccessory.prototype.getServices = function() { 272 | var services = []; 273 | 274 | var infoService = new Service.AccessoryInformation(); 275 | infoService 276 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 277 | .setCharacteristic(Characteristic.Model, "Mi DC VF Fan") 278 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 279 | services.push(infoService); 280 | 281 | var temperatureService = new Service.TemperatureSensor(this.name); 282 | temperatureService 283 | .getCharacteristic(Characteristic.CurrentTemperature) 284 | .on('get', this.getTemperature.bind(this)) 285 | services.push(temperatureService); 286 | 287 | return services; 288 | } 289 | 290 | MiDCVFFanTemperatureAccessory.prototype.getTemperature = function(callback) { 291 | var that = this; 292 | this.device.call("get_prop", ["temp_dec"]).then(result => { 293 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanTemperatureAccessory - Temperature - getTemperature: " + result); 294 | callback(null, result[0] / 10); 295 | }).catch(function(err) { 296 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanTemperatureAccessory - Temperature - getTemperature Error: " + err); 297 | callback(err); 298 | }); 299 | } 300 | 301 | MiDCVFFanHumidityAccessory = function(dThis) { 302 | this.device = dThis.device; 303 | this.name = dThis.config['humidityName']; 304 | this.platform = dThis.platform; 305 | } 306 | 307 | MiDCVFFanHumidityAccessory.prototype.getServices = function() { 308 | var services = []; 309 | 310 | var infoService = new Service.AccessoryInformation(); 311 | infoService 312 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 313 | .setCharacteristic(Characteristic.Model, "Mi DC VF Fan") 314 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 315 | services.push(infoService); 316 | 317 | var humidityService = new Service.HumiditySensor(this.name); 318 | humidityService 319 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 320 | .on('get', this.getHumidity.bind(this)) 321 | services.push(humidityService); 322 | 323 | return services; 324 | } 325 | 326 | MiDCVFFanHumidityAccessory.prototype.getHumidity = function(callback) { 327 | var that = this; 328 | this.device.call("get_prop", ["humidity"]).then(result => { 329 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanHumidityAccessory - Humidity - getHumidity: " + result); 330 | callback(null, result[0]); 331 | }).catch(function(err) { 332 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanHumidityAccessory - Humidity - getHumidity Error: " + err); 333 | callback(err); 334 | }); 335 | } 336 | 337 | MiDCVFFanBuzzerSwitchAccessory = function(dThis) { 338 | this.device = dThis.device; 339 | this.name = dThis.config['buzzerSwitchName']; 340 | this.platform = dThis.platform; 341 | } 342 | 343 | MiDCVFFanBuzzerSwitchAccessory.prototype.getServices = function() { 344 | var services = []; 345 | 346 | var infoService = new Service.AccessoryInformation(); 347 | infoService 348 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 349 | .setCharacteristic(Characteristic.Model, "Mi DC VF Fan") 350 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 351 | services.push(infoService); 352 | 353 | var switchService = new Service.Switch(this.name); 354 | switchService 355 | .getCharacteristic(Characteristic.On) 356 | .on('get', this.getBuzzerState.bind(this)) 357 | .on('set', this.setBuzzerState.bind(this)); 358 | services.push(switchService); 359 | 360 | return services; 361 | } 362 | 363 | MiDCVFFanBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 364 | var that = this; 365 | this.device.call("get_prop", ["buzzer"]).then(result => { 366 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 367 | callback(null, result[0] === "on" ? 1 : 0); 368 | }).catch(function(err) { 369 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 370 | callback(err); 371 | }); 372 | } 373 | 374 | MiDCVFFanBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 375 | var that = this; 376 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanLEDBulbAccessory - BuzzerSwitch - setBuzzerState: " + value); 377 | that.device.call("set_buzzer", [value ? "on" : "off"]).then(result => { 378 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 379 | if(result[0] === "ok") { 380 | callback(null); 381 | } else { 382 | callback(new Error(result[0])); 383 | } 384 | }).catch(function(err) { 385 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 386 | callback(err); 387 | }); 388 | } 389 | 390 | MiDCVFFanLEDBulbAccessory = function(dThis) { 391 | this.device = dThis.device; 392 | this.name = dThis.config['ledBulbName']; 393 | this.platform = dThis.platform; 394 | } 395 | 396 | MiDCVFFanLEDBulbAccessory.prototype.getServices = function() { 397 | var that = this; 398 | var services = []; 399 | 400 | var infoService = new Service.AccessoryInformation(); 401 | infoService 402 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 403 | .setCharacteristic(Characteristic.Model, "Mi DC VF Fan") 404 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 405 | services.push(infoService); 406 | 407 | var switchLEDService = new Service.Lightbulb(this.name); 408 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 409 | var brightnessCharacteristic = switchLEDService.addCharacteristic(Characteristic.Brightness); 410 | 411 | onCharacteristic 412 | .on('get', function(callback) { 413 | this.device.call("get_prop", ["led_b"]).then(result => { 414 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanLEDBulbAccessory - switchLED - getLEDPower: " + result); 415 | callback(null, result[0] === 2 ? false : true); 416 | }).catch(function(err) { 417 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 418 | callback(err); 419 | }); 420 | }.bind(this)) 421 | .on('set', function(value, callback) { 422 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanLEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 423 | that.setLedB(value ? that.getLevelByBrightness(brightnessCharacteristic.value) : 2, callback); 424 | }.bind(this)); 425 | brightnessCharacteristic 426 | .on('get', function(callback) { 427 | this.device.call("get_prop", ["led_b"]).then(result => { 428 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanLEDBulbAccessory - switchLED - getLEDPower: " + result); 429 | if(result[0] == 0) { 430 | if(brightnessCharacteristic.value > 50 && brightnessCharacteristic.value <= 100) { 431 | callback(null, brightnessCharacteristic.value); 432 | } else { 433 | callback(null, 100); 434 | } 435 | } else if(result[0] == 1) { 436 | if(brightnessCharacteristic.value > 0 && brightnessCharacteristic.value <= 50) { 437 | callback(null, brightnessCharacteristic.value); 438 | } else { 439 | callback(null, 50); 440 | } 441 | } else if(result[0] == 2) { 442 | callback(null, 0); 443 | } 444 | }).catch(function(err) { 445 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 446 | callback(err); 447 | }); 448 | }.bind(this)); 449 | services.push(switchLEDService); 450 | 451 | return services; 452 | } 453 | 454 | MiDCVFFanLEDBulbAccessory.prototype.setLedB = function(led_b, callback) { 455 | var that = this; 456 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanLEDBulbAccessory - switchLED - setLedB: " + led_b); 457 | this.device.call("set_led_b", [led_b]).then(result => { 458 | that.platform.log.debug("[MiFanPlatform][DEBUG]MiDCVFFanLEDBulbAccessory - switchLED - setLEDBrightness Result: " + result); 459 | if(result[0] === "ok") { 460 | callback(null); 461 | } else { 462 | callback(new Error(result[0])); 463 | } 464 | }).catch(function(err) { 465 | that.platform.log.error("[MiFanPlatform][ERROR]MiDCVFFanLEDBulbAccessory - switchLED - setLEDBrightness Error: " + err); 466 | callback(err); 467 | }); 468 | } 469 | 470 | MiDCVFFanLEDBulbAccessory.prototype.getLevelByBrightness = function(brightness) { 471 | if(brightness == 0) { 472 | return 2; 473 | } else if(brightness > 0 && brightness <= 50) { 474 | return 1; 475 | } else if (brightness > 50 && brightness <= 100) { 476 | return 0; 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /Devices/ZhiMiDCVariableFrequencyFan.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 | ZhiMiDCVariableFrequencyFan = 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['fanDisable'] && this.config['fanName'] && this.config['fanName'] != "") { 24 | this.accessories['fanAccessory'] = new ZhiMiDCVFFanFanAccessory(this); 25 | } 26 | if(!this.config['temperatureDisable'] && this.config['temperatureName'] && this.config['temperatureName'] != "") { 27 | this.accessories['temperatureAccessory'] = new ZhiMiDCVFFanTemperatureAccessory(this); 28 | } 29 | if(!this.config['humidityDisable'] && this.config['humidityName'] && this.config['humidityName'] != "") { 30 | this.accessories['humidityAccessory'] = new ZhiMiDCVFFanHumidityAccessory(this); 31 | } 32 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 33 | this.accessories['buzzerSwitchAccessory'] = new ZhiMiDCVFFanBuzzerSwitchAccessory(this); 34 | } 35 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 36 | this.accessories['ledBulbAccessory'] = new ZhiMiDCVFFanLEDBulbAccessory(this); 37 | } 38 | var accessoriesArr = this.obj2array(this.accessories); 39 | 40 | this.platform.log.debug("[MiFanPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 41 | 42 | return accessoriesArr; 43 | } 44 | inherits(ZhiMiDCVariableFrequencyFan, Base); 45 | 46 | ZhiMiDCVFFanFanAccessory = function(dThis) { 47 | this.device = dThis.device; 48 | this.name = dThis.config['fanName']; 49 | this.platform = dThis.platform; 50 | } 51 | 52 | ZhiMiDCVFFanFanAccessory.prototype.getServices = function() { 53 | var that = this; 54 | var services = []; 55 | 56 | var infoService = new Service.AccessoryInformation(); 57 | infoService 58 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 59 | .setCharacteristic(Characteristic.Model, "ZhiMi DC VF Fan") 60 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 61 | services.push(infoService); 62 | 63 | var fanService = new Service.Fanv2(this.name); 64 | var activeCharacteristic = fanService.getCharacteristic(Characteristic.Active); 65 | var lockPhysicalControlsCharacteristic = fanService.addCharacteristic(Characteristic.LockPhysicalControls); 66 | var swingModeControlsCharacteristic = fanService.addCharacteristic(Characteristic.SwingMode); 67 | var rotationSpeedCharacteristic = fanService.addCharacteristic(Characteristic.RotationSpeed); 68 | var rotationDirectionCharacteristic = fanService.addCharacteristic(Characteristic.RotationDirection); 69 | 70 | var currentTemperatureCharacteristic = fanService.addCharacteristic(Characteristic.CurrentTemperature); 71 | var currentRelativeHumidityCharacteristic = fanService.addCharacteristic(Characteristic.CurrentRelativeHumidity); 72 | 73 | // power 74 | activeCharacteristic 75 | .on('get', function(callback) { 76 | that.device.call("get_prop", ["power"]).then(result => { 77 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Active - getActive: " + result); 78 | callback(null, result[0] === "on" ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE); 79 | }).catch(function(err) { 80 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - Active - getActive Error: " + err); 81 | callback(err); 82 | }); 83 | }.bind(this)) 84 | .on('set', function(value, callback) { 85 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Active - setActive: " + value); 86 | that.device.call("set_power", [value ? "on" : "off"]).then(result => { 87 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Active - setActive Result: " + result); 88 | if(result[0] === "ok") { 89 | callback(null); 90 | } else { 91 | callback(new Error(result[0])); 92 | } 93 | }).catch(function(err) { 94 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - Active - setActive Error: " + err); 95 | callback(err); 96 | }); 97 | }.bind(this)); 98 | 99 | // child_lock 100 | lockPhysicalControlsCharacteristic 101 | .on('get', function(callback) { 102 | that.device.call("get_prop", ["child_lock"]).then(result => { 103 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 104 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 105 | }).catch(function(err) { 106 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 107 | callback(err); 108 | }); 109 | }.bind(this)) 110 | .on('set', function(value, callback) { 111 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - LockPhysicalControls - setLockPhysicalControls: " + value); 112 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 113 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 114 | if(result[0] === "ok") { 115 | callback(null); 116 | } else { 117 | callback(new Error(result[0])); 118 | } 119 | }).catch(function(err) { 120 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 121 | callback(err); 122 | }); 123 | }.bind(this)); 124 | 125 | // angle_enable 126 | swingModeControlsCharacteristic 127 | .on('get', function(callback) { 128 | that.device.call("get_prop", ["angle_enable"]).then(result => { 129 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - SwingMode - getSwingModeControls: " + result); 130 | callback(null, result[0] === "on" ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED); 131 | }).catch(function(err) { 132 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - SwingMode - getSwingModeControls Error: " + err); 133 | callback(err); 134 | }); 135 | }.bind(this)) 136 | .on('set', function(value, callback) { 137 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - SwingMode - setSwingModeControls: " + value); 138 | that.device.call("set_angle_enable", [value ? "on" : "off"]).then(result => { 139 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - SwingMode - setSwingModeControls Result: " + result); 140 | if(result[0] === "ok") { 141 | callback(null); 142 | } else { 143 | callback(new Error(result[0])); 144 | } 145 | }).catch(function(err) { 146 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - SwingMode - setSwingModeControls Error: " + err); 147 | callback(err); 148 | }); 149 | }.bind(this)); 150 | 151 | // natural_level speed_level 152 | rotationDirectionCharacteristic 153 | .on('get', function(callback) { 154 | that.device.call("get_prop", ["natural_level"]).then(result => { 155 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationDirection - getRotationDirection: " + result); 156 | if(result[0] > 0) { 157 | callback(null, Characteristic.RotationDirection.COUNTER_CLOCKWISE); 158 | } else { 159 | callback(null, Characteristic.RotationDirection.CLOCKWISE); 160 | } 161 | }).catch(function(err) { 162 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - RotationDirection - getRotationDirection Error: " + err); 163 | callback(err); 164 | }); 165 | }.bind(this)) 166 | .on('set', function(value, callback, context) { 167 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationDirection - setRotationDirection: " + value); 168 | if(Characteristic.RotationDirection.COUNTER_CLOCKWISE == value) { 169 | that.device.call("set_natural_level", [rotationSpeedCharacteristic.value]).then(result => { 170 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationDirection - setRotationDirection Result: " + result); 171 | if(result[0] === "ok") { 172 | callback(null); 173 | } else { 174 | callback(new Error(result[0])); 175 | } 176 | }).catch(function(err) { 177 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - RotationDirection - setRotationDirection Error: " + err); 178 | callback(err); 179 | }); 180 | } else { 181 | that.device.call("set_speed_level", [rotationSpeedCharacteristic.value]).then(result => { 182 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationDirection - setRotationDirection Result: " + result); 183 | if(result[0] === "ok") { 184 | callback(null); 185 | } else { 186 | callback(new Error(result[0])); 187 | } 188 | }).catch(function(err) { 189 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - RotationDirection - setRotationDirection Error: " + err); 190 | callback(err); 191 | }); 192 | } 193 | }.bind(this)); 194 | 195 | // speed_level natural_level 196 | rotationSpeedCharacteristic 197 | .on('get', function(callback) { 198 | that.device.call("get_prop", ["natural_level", "speed_level"]).then(result => { 199 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationSpeed - getRotationSpeed: " + result); 200 | if(result[0] > 0) { 201 | callback(null, result[0]); 202 | } else { 203 | callback(null, result[1]); 204 | } 205 | }).catch(function(err) { 206 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - RotationSpeed - getRotationSpeed Error: " + err); 207 | callback(err); 208 | }); 209 | }.bind(this)) 210 | .on('set', function(value, callback) { 211 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed: " + value); 212 | if(value > 0) { 213 | if(Characteristic.RotationDirection.COUNTER_CLOCKWISE == rotationDirectionCharacteristic.value) { 214 | that.device.call("set_natural_level", [value]).then(result => { 215 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 216 | if(result[0] === "ok") { 217 | callback(null); 218 | } else { 219 | callback(new Error(result[0])); 220 | } 221 | }).catch(function(err) { 222 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 223 | callback(err); 224 | }); 225 | } else { 226 | that.device.call("set_speed_level", [value]).then(result => { 227 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 228 | if(result[0] === "ok") { 229 | callback(null); 230 | } else { 231 | callback(new Error(result[0])); 232 | } 233 | }).catch(function(err) { 234 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 235 | callback(err); 236 | }); 237 | } 238 | } 239 | }.bind(this)); 240 | 241 | currentTemperatureCharacteristic.on('get', function(callback) { 242 | this.device.call("get_prop", ["temp_dec"]).then(result => { 243 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Temperature - getTemperature: " + result); 244 | callback(null, result[0] / 10); 245 | }).catch(function(err) { 246 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - Temperature - getTemperature Error: " + err); 247 | callback(err); 248 | }); 249 | }.bind(this)); 250 | 251 | currentRelativeHumidityCharacteristic.on('get', function(callback) { 252 | this.device.call("get_prop", ["humidity"]).then(result => { 253 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Humidity - getHumidity: " + result); 254 | callback(null, result[0]); 255 | }).catch(function(err) { 256 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - Humidity - getHumidity Error: " + err); 257 | callback(err); 258 | }); 259 | }.bind(this)); 260 | services.push(fanService); 261 | 262 | var batteryService = new Service.BatteryService(); 263 | var batLowCharacteristic = batteryService.getCharacteristic(Characteristic.StatusLowBattery); 264 | var batLevelCharacteristic = batteryService.getCharacteristic(Characteristic.BatteryLevel); 265 | batLevelCharacteristic 266 | .on('get', function(callback) { 267 | that.device.call("get_prop", ["battery"]).then(result => { 268 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Battery - getLevel: " + result); 269 | batLowCharacteristic.updateValue(result[0] < 20 ? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); 270 | callback(null, result[0]); 271 | }).catch(function(err) { 272 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - Battery - getLevel Error: " + err); 273 | callback(err); 274 | }); 275 | }.bind(this)); 276 | var batChargingStateCharacteristic = batteryService.getCharacteristic(Characteristic.ChargingState); 277 | batChargingStateCharacteristic 278 | .on('get', function(callback) { 279 | that.device.call("get_prop", ["ac_power"]).then(result => { 280 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanFanAccessory - Battery - getChargingState: " + result); 281 | callback(null, result[0] === "on" ? Characteristic.ChargingState.CHARGING : Characteristic.ChargingState.NOT_CHARGING); 282 | }).catch(function(err) { 283 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanFanAccessory - Battery - getChargingState Error: " + err); 284 | callback(err); 285 | }); 286 | }.bind(this)); 287 | services.push(batteryService); 288 | 289 | return services; 290 | } 291 | 292 | ZhiMiDCVFFanTemperatureAccessory = function(dThis) { 293 | this.device = dThis.device; 294 | this.name = dThis.config['temperatureName']; 295 | this.platform = dThis.platform; 296 | } 297 | 298 | ZhiMiDCVFFanTemperatureAccessory.prototype.getServices = function() { 299 | var services = []; 300 | 301 | var infoService = new Service.AccessoryInformation(); 302 | infoService 303 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 304 | .setCharacteristic(Characteristic.Model, "ZhiMi DC VF Fan") 305 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 306 | services.push(infoService); 307 | 308 | var temperatureService = new Service.TemperatureSensor(this.name); 309 | temperatureService 310 | .getCharacteristic(Characteristic.CurrentTemperature) 311 | .on('get', this.getTemperature.bind(this)) 312 | services.push(temperatureService); 313 | 314 | return services; 315 | } 316 | 317 | ZhiMiDCVFFanTemperatureAccessory.prototype.getTemperature = function(callback) { 318 | var that = this; 319 | this.device.call("get_prop", ["temp_dec"]).then(result => { 320 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanTemperatureAccessory - Temperature - getTemperature: " + result); 321 | callback(null, result[0] / 10); 322 | }).catch(function(err) { 323 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanTemperatureAccessory - Temperature - getTemperature Error: " + err); 324 | callback(err); 325 | }); 326 | } 327 | 328 | ZhiMiDCVFFanHumidityAccessory = function(dThis) { 329 | this.device = dThis.device; 330 | this.name = dThis.config['humidityName']; 331 | this.platform = dThis.platform; 332 | } 333 | 334 | ZhiMiDCVFFanHumidityAccessory.prototype.getServices = function() { 335 | var services = []; 336 | 337 | var infoService = new Service.AccessoryInformation(); 338 | infoService 339 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 340 | .setCharacteristic(Characteristic.Model, "ZhiMi DC VF Fan") 341 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 342 | services.push(infoService); 343 | 344 | var humidityService = new Service.HumiditySensor(this.name); 345 | humidityService 346 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 347 | .on('get', this.getHumidity.bind(this)) 348 | services.push(humidityService); 349 | 350 | return services; 351 | } 352 | 353 | ZhiMiDCVFFanHumidityAccessory.prototype.getHumidity = function(callback) { 354 | var that = this; 355 | this.device.call("get_prop", ["humidity"]).then(result => { 356 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanHumidityAccessory - Humidity - getHumidity: " + result); 357 | callback(null, result[0]); 358 | }).catch(function(err) { 359 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanHumidityAccessory - Humidity - getHumidity Error: " + err); 360 | callback(err); 361 | }); 362 | } 363 | 364 | ZhiMiDCVFFanBuzzerSwitchAccessory = function(dThis) { 365 | this.device = dThis.device; 366 | this.name = dThis.config['buzzerSwitchName']; 367 | this.platform = dThis.platform; 368 | } 369 | 370 | ZhiMiDCVFFanBuzzerSwitchAccessory.prototype.getServices = function() { 371 | var services = []; 372 | 373 | var infoService = new Service.AccessoryInformation(); 374 | infoService 375 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 376 | .setCharacteristic(Characteristic.Model, "ZhiMi DC VF Fan") 377 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 378 | services.push(infoService); 379 | 380 | var switchService = new Service.Switch(this.name); 381 | switchService 382 | .getCharacteristic(Characteristic.On) 383 | .on('get', this.getBuzzerState.bind(this)) 384 | .on('set', this.setBuzzerState.bind(this)); 385 | services.push(switchService); 386 | 387 | return services; 388 | } 389 | 390 | ZhiMiDCVFFanBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 391 | var that = this; 392 | this.device.call("get_prop", ["buzzer"]).then(result => { 393 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 394 | callback(null, result[0] === "on" ? 1 : 0); 395 | }).catch(function(err) { 396 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 397 | callback(err); 398 | }); 399 | } 400 | 401 | ZhiMiDCVFFanBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 402 | var that = this; 403 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanLEDBulbAccessory - BuzzerSwitch - setBuzzerState: " + value); 404 | that.device.call("set_buzzer", [value ? "on" : "off"]).then(result => { 405 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 406 | if(result[0] === "ok") { 407 | callback(null); 408 | } else { 409 | callback(new Error(result[0])); 410 | } 411 | }).catch(function(err) { 412 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 413 | callback(err); 414 | }); 415 | } 416 | 417 | ZhiMiDCVFFanLEDBulbAccessory = function(dThis) { 418 | this.device = dThis.device; 419 | this.name = dThis.config['ledBulbName']; 420 | this.platform = dThis.platform; 421 | } 422 | 423 | ZhiMiDCVFFanLEDBulbAccessory.prototype.getServices = function() { 424 | var that = this; 425 | var services = []; 426 | 427 | var infoService = new Service.AccessoryInformation(); 428 | infoService 429 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 430 | .setCharacteristic(Characteristic.Model, "ZhiMi DC VF Fan") 431 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 432 | services.push(infoService); 433 | 434 | var switchLEDService = new Service.Lightbulb(this.name); 435 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 436 | var brightnessCharacteristic = switchLEDService.addCharacteristic(Characteristic.Brightness); 437 | 438 | onCharacteristic 439 | .on('get', function(callback) { 440 | this.device.call("get_prop", ["led_b"]).then(result => { 441 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanLEDBulbAccessory - switchLED - getLEDPower: " + result); 442 | callback(null, result[0] === 2 ? false : true); 443 | }).catch(function(err) { 444 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 445 | callback(err); 446 | }); 447 | }.bind(this)) 448 | .on('set', function(value, callback) { 449 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanLEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 450 | that.setLedB(value ? that.getLevelByBrightness(brightnessCharacteristic.value) : 2, callback); 451 | }.bind(this)); 452 | brightnessCharacteristic 453 | .on('get', function(callback) { 454 | this.device.call("get_prop", ["led_b"]).then(result => { 455 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanLEDBulbAccessory - switchLED - getLEDPower: " + result); 456 | if(result[0] == 0) { 457 | if(brightnessCharacteristic.value > 50 && brightnessCharacteristic.value <= 100) { 458 | callback(null, brightnessCharacteristic.value); 459 | } else { 460 | callback(null, 100); 461 | } 462 | } else if(result[0] == 1) { 463 | if(brightnessCharacteristic.value > 0 && brightnessCharacteristic.value <= 50) { 464 | callback(null, brightnessCharacteristic.value); 465 | } else { 466 | callback(null, 50); 467 | } 468 | } else if(result[0] == 2) { 469 | callback(null, 0); 470 | } 471 | }).catch(function(err) { 472 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 473 | callback(err); 474 | }); 475 | }.bind(this)); 476 | services.push(switchLEDService); 477 | 478 | return services; 479 | } 480 | 481 | ZhiMiDCVFFanLEDBulbAccessory.prototype.setLedB = function(led_b, callback) { 482 | var that = this; 483 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanLEDBulbAccessory - switchLED - setLedB: " + led_b); 484 | this.device.call("set_led_b", [led_b]).then(result => { 485 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiDCVFFanLEDBulbAccessory - switchLED - setLEDBrightness Result: " + result); 486 | if(result[0] === "ok") { 487 | callback(null); 488 | } else { 489 | callback(new Error(result[0])); 490 | } 491 | }).catch(function(err) { 492 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiDCVFFanLEDBulbAccessory - switchLED - setLEDBrightness Error: " + err); 493 | callback(err); 494 | }); 495 | } 496 | 497 | ZhiMiDCVFFanLEDBulbAccessory.prototype.getLevelByBrightness = function(brightness) { 498 | if(brightness == 0) { 499 | return 2; 500 | } else if(brightness > 0 && brightness <= 50) { 501 | return 1; 502 | } else if (brightness > 50 && brightness <= 100) { 503 | return 0; 504 | } 505 | } 506 | -------------------------------------------------------------------------------- /Devices/ZhiMiNaturalWindFan.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 | ZhiMiNaturalWindFan = 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['fanDisable'] && this.config['fanName'] && this.config['fanName'] != "") { 24 | this.accessories['fanAccessory'] = new ZhiMiFWFanFanAccessory(this); 25 | } 26 | if(!this.config['temperatureDisable'] && this.config['temperatureName'] && this.config['temperatureName'] != "") { 27 | this.accessories['temperatureAccessory'] = new ZhiMiFWFanTemperatureAccessory(this); 28 | } 29 | if(!this.config['humidityDisable'] && this.config['humidityName'] && this.config['humidityName'] != "") { 30 | this.accessories['humidityAccessory'] = new ZhiMiFWFanHumidityAccessory(this); 31 | } 32 | if(!this.config['buzzerSwitchDisable'] && this.config['buzzerSwitchName'] && this.config['buzzerSwitchName'] != "") { 33 | this.accessories['buzzerSwitchAccessory'] = new ZhiMiFWFanBuzzerSwitchAccessory(this); 34 | } 35 | if(!this.config['ledBulbDisable'] && this.config['ledBulbName'] && this.config['ledBulbName'] != "") { 36 | this.accessories['ledBulbAccessory'] = new ZhiMiFWFanLEDBulbAccessory(this); 37 | } 38 | var accessoriesArr = this.obj2array(this.accessories); 39 | 40 | this.platform.log.debug("[MiFanPlatform][DEBUG]Initializing " + this.config["type"] + " device: " + this.config["ip"] + ", accessories size: " + accessoriesArr.length); 41 | 42 | return accessoriesArr; 43 | } 44 | inherits(ZhiMiNaturalWindFan, Base); 45 | 46 | ZhiMiFWFanFanAccessory = function(dThis) { 47 | this.device = dThis.device; 48 | this.name = dThis.config['fanName']; 49 | this.platform = dThis.platform; 50 | } 51 | 52 | ZhiMiFWFanFanAccessory.prototype.getServices = function() { 53 | var that = this; 54 | var services = []; 55 | 56 | var infoService = new Service.AccessoryInformation(); 57 | infoService 58 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 59 | .setCharacteristic(Characteristic.Model, "ZhiMi NW Fan") 60 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 61 | services.push(infoService); 62 | 63 | var fanService = new Service.Fanv2(this.name); 64 | var activeCharacteristic = fanService.getCharacteristic(Characteristic.Active); 65 | var lockPhysicalControlsCharacteristic = fanService.addCharacteristic(Characteristic.LockPhysicalControls); 66 | var swingModeControlsCharacteristic = fanService.addCharacteristic(Characteristic.SwingMode); 67 | var rotationSpeedCharacteristic = fanService.addCharacteristic(Characteristic.RotationSpeed); 68 | var rotationDirectionCharacteristic = fanService.addCharacteristic(Characteristic.RotationDirection); 69 | 70 | var currentTemperatureCharacteristic = fanService.addCharacteristic(Characteristic.CurrentTemperature); 71 | var currentRelativeHumidityCharacteristic = fanService.addCharacteristic(Characteristic.CurrentRelativeHumidity); 72 | 73 | // power 74 | activeCharacteristic 75 | .on('get', function(callback) { 76 | that.device.call("get_prop", ["power"]).then(result => { 77 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - Active - getActive: " + result); 78 | callback(null, result[0] === "on" ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE); 79 | }).catch(function(err) { 80 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - Active - getActive Error: " + err); 81 | callback(err); 82 | }); 83 | }.bind(this)) 84 | .on('set', function(value, callback) { 85 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - Active - setActive: " + value); 86 | that.device.call("set_power", [value ? "on" : "off"]).then(result => { 87 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - Active - setActive Result: " + result); 88 | if(result[0] === "ok") { 89 | callback(null); 90 | } else { 91 | callback(new Error(result[0])); 92 | } 93 | }).catch(function(err) { 94 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - Active - setActive Error: " + err); 95 | callback(err); 96 | }); 97 | }.bind(this)); 98 | 99 | // child_lock 100 | lockPhysicalControlsCharacteristic 101 | .on('get', function(callback) { 102 | that.device.call("get_prop", ["child_lock"]).then(result => { 103 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - LockPhysicalControls - getLockPhysicalControls: " + result); 104 | callback(null, result[0] === "on" ? Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED : Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED); 105 | }).catch(function(err) { 106 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - LockPhysicalControls - getLockPhysicalControls Error: " + err); 107 | callback(err); 108 | }); 109 | }.bind(this)) 110 | .on('set', function(value, callback) { 111 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - LockPhysicalControls - setLockPhysicalControls: " + value); 112 | that.device.call("set_child_lock", [value ? "on" : "off"]).then(result => { 113 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - LockPhysicalControls - setLockPhysicalControls Result: " + result); 114 | if(result[0] === "ok") { 115 | callback(null); 116 | } else { 117 | callback(new Error(result[0])); 118 | } 119 | }).catch(function(err) { 120 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - LockPhysicalControls - setLockPhysicalControls Error: " + err); 121 | callback(err); 122 | }); 123 | }.bind(this)); 124 | 125 | // angle_enable 126 | swingModeControlsCharacteristic 127 | .on('get', function(callback) { 128 | that.device.call("get_prop", ["angle_enable"]).then(result => { 129 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - SwingMode - getSwingModeControls: " + result); 130 | callback(null, result[0] === "on" ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED); 131 | }).catch(function(err) { 132 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - SwingMode - getSwingModeControls Error: " + err); 133 | callback(err); 134 | }); 135 | }.bind(this)) 136 | .on('set', function(value, callback) { 137 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - SwingMode - setSwingModeControls: " + value); 138 | that.device.call("set_angle_enable", [value ? "on" : "off"]).then(result => { 139 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - SwingMode - setSwingModeControls Result: " + result); 140 | if(result[0] === "ok") { 141 | callback(null); 142 | } else { 143 | callback(new Error(result[0])); 144 | } 145 | }).catch(function(err) { 146 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - SwingMode - setSwingModeControls Error: " + err); 147 | callback(err); 148 | }); 149 | }.bind(this)); 150 | 151 | // natural_level speed_level 152 | rotationDirectionCharacteristic 153 | .on('get', function(callback) { 154 | that.device.call("get_prop", ["natural_level"]).then(result => { 155 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationDirection - getRotationDirection: " + result); 156 | if(result[0] > 0) { 157 | callback(null, Characteristic.RotationDirection.COUNTER_CLOCKWISE); 158 | } else { 159 | callback(null, Characteristic.RotationDirection.CLOCKWISE); 160 | } 161 | }).catch(function(err) { 162 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - RotationDirection - getRotationDirection Error: " + err); 163 | callback(err); 164 | }); 165 | }.bind(this)) 166 | .on('set', function(value, callback, context) { 167 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationDirection - setRotationDirection: " + value); 168 | if(Characteristic.RotationDirection.COUNTER_CLOCKWISE == value) { 169 | that.device.call("set_natural_level", [rotationSpeedCharacteristic.value]).then(result => { 170 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationDirection - setRotationDirection Result: " + result); 171 | if(result[0] === "ok") { 172 | callback(null); 173 | } else { 174 | callback(new Error(result[0])); 175 | } 176 | }).catch(function(err) { 177 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - RotationDirection - setRotationDirection Error: " + err); 178 | callback(err); 179 | }); 180 | } else { 181 | that.device.call("set_speed_level", [rotationSpeedCharacteristic.value]).then(result => { 182 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationDirection - setRotationDirection Result: " + result); 183 | if(result[0] === "ok") { 184 | callback(null); 185 | } else { 186 | callback(new Error(result[0])); 187 | } 188 | }).catch(function(err) { 189 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - RotationDirection - setRotationDirection Error: " + err); 190 | callback(err); 191 | }); 192 | } 193 | }.bind(this)); 194 | 195 | // speed_level natural_level 196 | rotationSpeedCharacteristic 197 | .on('get', function(callback) { 198 | that.device.call("get_prop", ["natural_level", "speed_level"]).then(result => { 199 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationSpeed - getRotationSpeed: " + result); 200 | if(result[0] > 0) { 201 | callback(null, result[0]); 202 | } else { 203 | callback(null, result[1]); 204 | } 205 | }).catch(function(err) { 206 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - RotationSpeed - getRotationSpeed Error: " + err); 207 | callback(err); 208 | }); 209 | }.bind(this)) 210 | .on('set', function(value, callback) { 211 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationSpeed - setRotationSpeed: " + value); 212 | if(value > 0) { 213 | if(Characteristic.RotationDirection.COUNTER_CLOCKWISE == rotationDirectionCharacteristic.value) { 214 | that.device.call("set_natural_level", [value]).then(result => { 215 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 216 | if(result[0] === "ok") { 217 | callback(null); 218 | } else { 219 | callback(new Error(result[0])); 220 | } 221 | }).catch(function(err) { 222 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 223 | callback(err); 224 | }); 225 | } else { 226 | that.device.call("set_speed_level", [value]).then(result => { 227 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - RotationSpeed - setRotationSpeed Result: " + result); 228 | if(result[0] === "ok") { 229 | callback(null); 230 | } else { 231 | callback(new Error(result[0])); 232 | } 233 | }).catch(function(err) { 234 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - RotationSpeed - setRotationSpeed Error: " + err); 235 | callback(err); 236 | }); 237 | } 238 | } 239 | }.bind(this)); 240 | 241 | currentTemperatureCharacteristic.on('get', function(callback) { 242 | this.device.call("get_prop", ["temp_dec"]).then(result => { 243 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - Temperature - getTemperature: " + result); 244 | callback(null, result[0] / 10); 245 | }).catch(function(err) { 246 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - Temperature - getTemperature Error: " + err); 247 | callback(err); 248 | }); 249 | }.bind(this)); 250 | 251 | currentRelativeHumidityCharacteristic.on('get', function(callback) { 252 | this.device.call("get_prop", ["humidity"]).then(result => { 253 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanFanAccessory - Humidity - getHumidity: " + result); 254 | callback(null, result[0]); 255 | }).catch(function(err) { 256 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanFanAccessory - Humidity - getHumidity Error: " + err); 257 | callback(err); 258 | }); 259 | }.bind(this)); 260 | services.push(fanService); 261 | 262 | return services; 263 | } 264 | 265 | ZhiMiFWFanTemperatureAccessory = function(dThis) { 266 | this.device = dThis.device; 267 | this.name = dThis.config['temperatureName']; 268 | this.platform = dThis.platform; 269 | } 270 | 271 | ZhiMiFWFanTemperatureAccessory.prototype.getServices = function() { 272 | var services = []; 273 | 274 | var infoService = new Service.AccessoryInformation(); 275 | infoService 276 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 277 | .setCharacteristic(Characteristic.Model, "ZhiMi NW Fan") 278 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 279 | services.push(infoService); 280 | 281 | var temperatureService = new Service.TemperatureSensor(this.name); 282 | temperatureService 283 | .getCharacteristic(Characteristic.CurrentTemperature) 284 | .on('get', this.getTemperature.bind(this)) 285 | services.push(temperatureService); 286 | 287 | return services; 288 | } 289 | 290 | ZhiMiFWFanTemperatureAccessory.prototype.getTemperature = function(callback) { 291 | var that = this; 292 | this.device.call("get_prop", ["temp_dec"]).then(result => { 293 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanTemperatureAccessory - Temperature - getTemperature: " + result); 294 | callback(null, result[0] / 10); 295 | }).catch(function(err) { 296 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanTemperatureAccessory - Temperature - getTemperature Error: " + err); 297 | callback(err); 298 | }); 299 | } 300 | 301 | ZhiMiFWFanHumidityAccessory = function(dThis) { 302 | this.device = dThis.device; 303 | this.name = dThis.config['humidityName']; 304 | this.platform = dThis.platform; 305 | } 306 | 307 | ZhiMiFWFanHumidityAccessory.prototype.getServices = function() { 308 | var services = []; 309 | 310 | var infoService = new Service.AccessoryInformation(); 311 | infoService 312 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 313 | .setCharacteristic(Characteristic.Model, "ZhiMi NW Fan") 314 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 315 | services.push(infoService); 316 | 317 | var humidityService = new Service.HumiditySensor(this.name); 318 | humidityService 319 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 320 | .on('get', this.getHumidity.bind(this)) 321 | services.push(humidityService); 322 | 323 | return services; 324 | } 325 | 326 | ZhiMiFWFanHumidityAccessory.prototype.getHumidity = function(callback) { 327 | var that = this; 328 | this.device.call("get_prop", ["humidity"]).then(result => { 329 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanHumidityAccessory - Humidity - getHumidity: " + result); 330 | callback(null, result[0]); 331 | }).catch(function(err) { 332 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanHumidityAccessory - Humidity - getHumidity Error: " + err); 333 | callback(err); 334 | }); 335 | } 336 | 337 | ZhiMiFWFanBuzzerSwitchAccessory = function(dThis) { 338 | this.device = dThis.device; 339 | this.name = dThis.config['buzzerSwitchName']; 340 | this.platform = dThis.platform; 341 | } 342 | 343 | ZhiMiFWFanBuzzerSwitchAccessory.prototype.getServices = function() { 344 | var services = []; 345 | 346 | var infoService = new Service.AccessoryInformation(); 347 | infoService 348 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 349 | .setCharacteristic(Characteristic.Model, "ZhiMi NW Fan") 350 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 351 | services.push(infoService); 352 | 353 | var switchService = new Service.Switch(this.name); 354 | switchService 355 | .getCharacteristic(Characteristic.On) 356 | .on('get', this.getBuzzerState.bind(this)) 357 | .on('set', this.setBuzzerState.bind(this)); 358 | services.push(switchService); 359 | 360 | return services; 361 | } 362 | 363 | ZhiMiFWFanBuzzerSwitchAccessory.prototype.getBuzzerState = function(callback) { 364 | var that = this; 365 | this.device.call("get_prop", ["buzzer"]).then(result => { 366 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState: " + result); 367 | callback(null, result[0] === "on" ? 1 : 0); 368 | }).catch(function(err) { 369 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanBuzzerSwitchAccessory - BuzzerSwitch - getBuzzerState Error: " + err); 370 | callback(err); 371 | }); 372 | } 373 | 374 | ZhiMiFWFanBuzzerSwitchAccessory.prototype.setBuzzerState = function(value, callback) { 375 | var that = this; 376 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanLEDBulbAccessory - BuzzerSwitch - setBuzzerState: " + value); 377 | that.device.call("set_buzzer", [value ? "on" : "off"]).then(result => { 378 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Result: " + result); 379 | if(result[0] === "ok") { 380 | callback(null); 381 | } else { 382 | callback(new Error(result[0])); 383 | } 384 | }).catch(function(err) { 385 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanBuzzerSwitchAccessory - BuzzerSwitch - setBuzzerState Error: " + err); 386 | callback(err); 387 | }); 388 | } 389 | 390 | ZhiMiFWFanLEDBulbAccessory = function(dThis) { 391 | this.device = dThis.device; 392 | this.name = dThis.config['ledBulbName']; 393 | this.platform = dThis.platform; 394 | } 395 | 396 | ZhiMiFWFanLEDBulbAccessory.prototype.getServices = function() { 397 | var that = this; 398 | var services = []; 399 | 400 | var infoService = new Service.AccessoryInformation(); 401 | infoService 402 | .setCharacteristic(Characteristic.Manufacturer, "XiaoMi") 403 | .setCharacteristic(Characteristic.Model, "ZhiMi NW Fan") 404 | .setCharacteristic(Characteristic.SerialNumber, "Undefined"); 405 | services.push(infoService); 406 | 407 | var switchLEDService = new Service.Lightbulb(this.name); 408 | var onCharacteristic = switchLEDService.getCharacteristic(Characteristic.On); 409 | var brightnessCharacteristic = switchLEDService.addCharacteristic(Characteristic.Brightness); 410 | 411 | onCharacteristic 412 | .on('get', function(callback) { 413 | this.device.call("get_prop", ["led_b"]).then(result => { 414 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanLEDBulbAccessory - switchLED - getLEDPower: " + result); 415 | callback(null, result[0] === 2 ? false : true); 416 | }).catch(function(err) { 417 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 418 | callback(err); 419 | }); 420 | }.bind(this)) 421 | .on('set', function(value, callback) { 422 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanLEDBulbAccessory - switchLED - setLEDPower: " + value + ", nowValue: " + onCharacteristic.value); 423 | that.setLedB(value ? that.getLevelByBrightness(brightnessCharacteristic.value) : 2, callback); 424 | }.bind(this)); 425 | brightnessCharacteristic 426 | .on('get', function(callback) { 427 | this.device.call("get_prop", ["led_b"]).then(result => { 428 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanLEDBulbAccessory - switchLED - getLEDPower: " + result); 429 | if(result[0] == 0) { 430 | if(brightnessCharacteristic.value > 50 && brightnessCharacteristic.value <= 100) { 431 | callback(null, brightnessCharacteristic.value); 432 | } else { 433 | callback(null, 100); 434 | } 435 | } else if(result[0] == 1) { 436 | if(brightnessCharacteristic.value > 0 && brightnessCharacteristic.value <= 50) { 437 | callback(null, brightnessCharacteristic.value); 438 | } else { 439 | callback(null, 50); 440 | } 441 | } else if(result[0] == 2) { 442 | callback(null, 0); 443 | } 444 | }).catch(function(err) { 445 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanLEDBulbAccessory - switchLED - getLEDPower Error: " + err); 446 | callback(err); 447 | }); 448 | }.bind(this)); 449 | services.push(switchLEDService); 450 | 451 | return services; 452 | } 453 | 454 | ZhiMiFWFanLEDBulbAccessory.prototype.setLedB = function(led_b, callback) { 455 | var that = this; 456 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanLEDBulbAccessory - switchLED - setLedB: " + led_b); 457 | this.device.call("set_led_b", [led_b]).then(result => { 458 | that.platform.log.debug("[MiFanPlatform][DEBUG]ZhiMiFWFanLEDBulbAccessory - switchLED - setLEDBrightness Result: " + result); 459 | if(result[0] === "ok") { 460 | callback(null); 461 | } else { 462 | callback(new Error(result[0])); 463 | } 464 | }).catch(function(err) { 465 | that.platform.log.error("[MiFanPlatform][ERROR]ZhiMiFWFanLEDBulbAccessory - switchLED - setLEDBrightness Error: " + err); 466 | callback(err); 467 | }); 468 | } 469 | 470 | ZhiMiFWFanLEDBulbAccessory.prototype.getLevelByBrightness = function(brightness) { 471 | if(brightness == 0) { 472 | return 2; 473 | } else if(brightness > 0 && brightness <= 50) { 474 | return 1; 475 | } else if (brightness > 50 && brightness <= 100) { 476 | return 0; 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # homebridge-mi-fan 2 | [![npm version](https://badge.fury.io/js/homebridge-mi-fan.svg)](https://badge.fury.io/js/homebridge-mi-fan) 3 | 4 | XiaoMi fan plugins for HomeBridge. 5 | 6 | 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)), [ABC](https://github.com/hassbian-ABC), 小马哥, all other developer and testers. 7 | 8 | **Note: If you find bugs, please submit them to [issues](https://github.com/YinHangCode/homebridge-mi-fan/issues) or 9 | QQ Group: [245480](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=gZitewfJ7tC8UBPco-vHE-lWlQ2MSFj4&authKey=vM9HTpEBVpb6vVIHtwnRxFdsUKN0dh1A%2FUihq0BnOtLzEykzEaBZVQjbYINWucxd&noverify=0&group_code=245480) 10 | (~~previous [15987618](https://qm.qq.com/cgi-bin/qm/qr?k=ZiAkKhlOCyjpSq94Xb6-MsiKCxLtoDAJ&jump_from=webapi)~~) 11 | (~~previous [107927710](//shang.qq.com/wpa/qunwpa?idkey=8b9566598f40dd68412065ada24184ef72c6bddaa11525ca26c4e1536a8f2a3d)~~).** 12 | 13 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/master/images/ZhiMiDCVariableFrequencyFan.jpg) 14 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/master/images/ZhiMiNaturalWindFan.jpg) 15 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/master/images/MiDCVariableFrequencyFan.jpg) 16 | ![](https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/master/images/DmakerFan.jpg) 17 | 18 | 19 | 20 | ## Supported Devices 21 | 1.ZhiMiDCVariableFrequencyFan(智米直流变频落地扇 799RMB) 22 | 2.ZhiMiNaturalWindFan(智米自然风风扇 599RMB) 23 | 3.MiDCVariableFrequencyFan(米家直流变频落地扇 399RMB) 24 | 4.DmakerFan(米家风扇1X 299RMB) 25 | 5.DmakerFanp5c(新款米家智能直流变频落地扇1X) 26 | 27 | 28 | ## Pre-Requirements 29 | 1.Make sure your IOS version is ios11 or later. 30 | ## Installation 31 | 1. Install HomeBridge, please follow it's [README](https://github.com/nfarina/homebridge/blob/master/README.md). 32 | 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). 33 | 2. Make sure you can see HomeBridge in your iOS devices, if not, please go back to step 1. 34 | 3. Install packages. 35 | ``` 36 | npm install -g homebridge-mi-fan 37 | ``` 38 | ## Configuration 39 | ``` 40 | "platforms": [{ 41 | "platform": "MiFanPlatform", 42 | "deviceCfgs": [{ 43 | "type": "ZhiMiDCVariableFrequencyFan", 44 | "ip": "192.168.1.xxx", 45 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 46 | "fanName": "room fan", 47 | "fanDisable": false, 48 | "temperatureName": "room temperature", 49 | "temperatureDisable": false, 50 | "humidityName": "room humidity", 51 | "humidityDisable": false, 52 | "buzzerSwitchName": "fan buzzer switch", 53 | "buzzerSwitchDisable": true, 54 | "ledBulbName": "fan led switch", 55 | "ledBulbDisable": true 56 | }, { 57 | "type": "ZhiMiNaturalWindFan", 58 | "ip": "192.168.1.xxx", 59 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 60 | "fanName": "room fan", 61 | "fanDisable": false, 62 | "temperatureName": "room temperature", 63 | "temperatureDisable": false, 64 | "humidityName": "room humidity", 65 | "humidityDisable": false, 66 | "buzzerSwitchName": "fan buzzer switch", 67 | "buzzerSwitchDisable": true, 68 | "ledBulbName": "fan led switch", 69 | "ledBulbDisable": true 70 | }, { 71 | "type": "MiDCVariableFrequencyFan", 72 | "ip": "192.168.1.xxx", 73 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 74 | "fanName": "room fan", 75 | "fanDisable": false, 76 | "temperatureName": "room temperature", 77 | "temperatureDisable": false, 78 | "humidityName": "room humidity", 79 | "humidityDisable": false, 80 | "buzzerSwitchName": "fan buzzer switch", 81 | "buzzerSwitchDisable": true, 82 | "ledBulbName": "fan led switch", 83 | "ledBulbDisable": true 84 | }, { 85 | "type": "DmakerFan", 86 | "ip": "192.168.1.xxx", 87 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 88 | "fanName": "room fan", 89 | "fanDisable": false, 90 | "buzzerSwitchName": "fan buzzer switch", 91 | "buzzerSwitchDisable": true, 92 | "ledBulbName": "fan led switch", 93 | "ledBulbDisable": true 94 | }, 95 | { 96 | "type": "DmakerFanP5c", 97 | "ip": "192.168.1.xxx", 98 | "token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 99 | "deviceId":"xxxxxxx", 100 | "fanName": "room fan", 101 | "fanDisable": false, 102 | "buzzerSwitchName": "fan buzzer switch", 103 | "buzzerSwitchDisable": true, 104 | "ledBulbName": "fan led switch", 105 | "ledBulbDisable": true 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.2 (2024-04-24) 141 | 1.add support for DmakerFanP5c. 142 | ### 0.1.1 (2019-06-03) 143 | 1.add support for DmakerFan. 144 | ### 0.1.0 (2018-07-11) 145 | 1.add support for Mi DC VariableFrequency Fan. 146 | 2.add support for ZhiMi NaturalWind Fan. 147 | ### 0.0.5 (2018-02-10) 148 | 1.update 'package.json'. 149 | ### 0.0.4 (2017-09-11) 150 | 1.optimized code. 151 | ### 0.0.3 (2017-09-09) 152 | 1.optimized code. 153 | ### 0.0.2 (2017-09-09) 154 | 1.fixed bug that led switch error. 155 | ### 0.0.1 (2017-09-05) 156 | 1.support for ZhiMi DC VariableFrequency Fan. 157 | -------------------------------------------------------------------------------- /images/DmakerFan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/57dbc286dd76e8b6ab53e76966bf1e3d74b9e8e8/images/DmakerFan.jpg -------------------------------------------------------------------------------- /images/MiDCVariableFrequencyFan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/57dbc286dd76e8b6ab53e76966bf1e3d74b9e8e8/images/MiDCVariableFrequencyFan.jpg -------------------------------------------------------------------------------- /images/ZhiMiDCVariableFrequencyFan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/57dbc286dd76e8b6ab53e76966bf1e3d74b9e8e8/images/ZhiMiDCVariableFrequencyFan.jpg -------------------------------------------------------------------------------- /images/ZhiMiNaturalWindFan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YinHangCode/homebridge-mi-fan/57dbc286dd76e8b6ab53e76966bf1e3d74b9e8e8/images/ZhiMiNaturalWindFan.jpg -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./Devices/ZhiMiDCVariableFrequencyFan'); 2 | require('./Devices/ZhiMiNaturalWindFan'); 3 | require('./Devices/MiDCVariableFrequencyFan'); 4 | require('./Devices/DmakerFan'); 5 | require('./Devices/DmakerFanP5c'); 6 | 7 | var fs = require('fs'); 8 | var packageFile = require("./package.json"); 9 | var PlatformAccessory, Accessory, Service, Characteristic, UUIDGen; 10 | 11 | module.exports = function(homebridge) { 12 | if(!isConfig(homebridge.user.configPath(), "platforms", "MiFanPlatform")) { 13 | return; 14 | } 15 | 16 | PlatformAccessory = homebridge.platformAccessory; 17 | Accessory = homebridge.hap.Accessory; 18 | Service = homebridge.hap.Service; 19 | Characteristic = homebridge.hap.Characteristic; 20 | UUIDGen = homebridge.hap.uuid; 21 | 22 | homebridge.registerPlatform('homebridge-mi-fan', 'MiFanPlatform', MiFanPlatform, true); 23 | } 24 | 25 | function isConfig(configFile, type, name) { 26 | var config = JSON.parse(fs.readFileSync(configFile)); 27 | if("accessories" === type) { 28 | var accessories = config.accessories; 29 | for(var i in accessories) { 30 | if(accessories[i]['accessory'] === name) { 31 | return true; 32 | } 33 | } 34 | } else if("platforms" === type) { 35 | var platforms = config.platforms; 36 | for(var i in platforms) { 37 | if(platforms[i]['platform'] === name) { 38 | return true; 39 | } 40 | } 41 | } else { 42 | } 43 | 44 | return false; 45 | } 46 | 47 | function MiFanPlatform(log, config, api) { 48 | if(null == config) { 49 | return; 50 | } 51 | 52 | this.Accessory = Accessory; 53 | this.PlatformAccessory = PlatformAccessory; 54 | this.Service = Service; 55 | this.Characteristic = Characteristic; 56 | this.UUIDGen = UUIDGen; 57 | 58 | this.log = log; 59 | this.config = config; 60 | 61 | if (api) { 62 | this.api = api; 63 | } 64 | 65 | this.log.info("[MiFanPlatform][INFO]***********************************************************"); 66 | this.log.info("[MiFanPlatform][INFO] MiFanPlatform v%s By YinHang", packageFile.version); 67 | this.log.info("[MiFanPlatform][INFO] GitHub: https://github.com/YinHangCode/homebridge-mi-fan "); 68 | this.log.info("[MiFanPlatform][INFO] QQ Group: 107927710 "); 69 | this.log.info("[MiFanPlatform][INFO]***********************************************************"); 70 | this.log.info("[MiFanPlatform][INFO]start success..."); 71 | } 72 | 73 | MiFanPlatform.prototype = { 74 | accessories: function(callback) { 75 | var myAccessories = []; 76 | 77 | var deviceCfgs = this.config['deviceCfgs']; 78 | if(deviceCfgs instanceof Array) { 79 | for (var i = 0; i < deviceCfgs.length; i++) { 80 | var deviceCfg = deviceCfgs[i]; 81 | if(null == deviceCfg['type'] || "" == deviceCfg['type']) { 82 | continue; 83 | } 84 | if(null == deviceCfg['token'] || "" == deviceCfg['token'] || null == deviceCfg['ip'] || "" == deviceCfg['ip']) { 85 | continue; 86 | } 87 | 88 | if (deviceCfg['type'] == "ZhiMiDCVariableFrequencyFan") { 89 | new ZhiMiDCVariableFrequencyFan(this, deviceCfg).forEach(function(accessory, index, arr){ 90 | myAccessories.push(accessory); 91 | }); 92 | } else if (deviceCfg['type'] == "ZhiMiNaturalWindFan") { 93 | new ZhiMiNaturalWindFan(this, deviceCfg).forEach(function(accessory, index, arr){ 94 | myAccessories.push(accessory); 95 | }); 96 | } else if (deviceCfg['type'] == "MiDCVariableFrequencyFan") { 97 | new MiDCVariableFrequencyFan(this, deviceCfg).forEach(function(accessory, index, arr){ 98 | myAccessories.push(accessory); 99 | }); 100 | } else if (deviceCfg['type'] == "DmakerFan") { 101 | new DmakerFan(this, deviceCfg).forEach(function(accessory, index, arr){ 102 | myAccessories.push(accessory); 103 | }); 104 | } else if(deviceCfg['type'] == "DmakerFanP5c"){ 105 | new DmakerFanP5c(this, deviceCfg).forEach(function(accessory, index, arr){ 106 | myAccessories.push(accessory); 107 | }); 108 | } else { 109 | } 110 | } 111 | this.log.info("[MiFanPlatform][INFO]device size: " + deviceCfgs.length + ", accessories size: " + myAccessories.length); 112 | } 113 | 114 | callback(myAccessories); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "homebridge-mi-fan", 3 | "version": "0.1.2", 4 | "description": "XiaoMi fan plugins for HomeBridge(https://github.com/nfarina/homebridge).", 5 | "keywords": [ 6 | "homebridge-plugin", 7 | "xiaomi", 8 | "mi", 9 | "zhimi", 10 | "fan" 11 | ], 12 | "author": "YinHang", 13 | "homepage": "https://github.com/YinHangCode/homebridge-mi-fan", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/YinHangCode/homebridge-mi-fan" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/YinHangCode/homebridge-mi-fan/issues" 20 | }, 21 | "engines": { 22 | "node": ">=7.0.0", 23 | "homebridge": ">=0.4.1" 24 | }, 25 | "dependencies": { 26 | "miio": "0.14.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /utils/Utils.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports.buildCommandArgs = function buildCommandArgs(deviceId, siid, piid, value) { 4 | let args = [{'did': deviceId, 'siid': siid, 'piid': piid}] 5 | if (value != null) { 6 | args[0]['value'] = value; 7 | } 8 | 9 | return args; 10 | } 11 | module.exports.isSuccess = function isSuccess(result) { 12 | return result[0].code === 0 13 | } 14 | 15 | 16 | --------------------------------------------------------------------------------