diff --git a/README.md b/README.md index 22c56d1..9de2246 100644 --- a/README.md +++ b/README.md @@ -15,21 +15,18 @@ npm install --save miio const miio = require('miio'); ``` -Create a handle to the device: +Resolve a handle to the device: ```javascript -// Create a device - with a model to get a more specific device instance -const device = miio.createDevice({ - token: 'token-as-hex', // Token of device - model: 'zhimi.airpurifier.m1', - address: '192.168.100.8' -}); +// Resolve a device, resolving the token automatically if possible +miio.device({ address: '192.168.100.8' }) + .then(console.log) + .catch(console.error); -// Create a new generic device by skipping the model -const device = miio.createDevice({ - token: 'token-as-hex', // Token of device - address: '192.168.100.8' -}); +// Resolve a device, specifying the token (see below for how to get the token) +miio.device({ address: '192.168.100.8', token: 'token-as-hex' }) + .then(console.log) + .catch(console.error); ``` Call methods to interact with the device: @@ -88,7 +85,44 @@ token of those devices. ## Discovering devices -Devices use mDNS for discovery, but this library does not contain a mDNS +Use `miio.browser()` to look for devices on the local network. This method of +discovery will tell you directly if a device reveals its token and can be +auto-connected to. It will not tell you the model of devices until they are +connected to via `miio.device()`. + +Example: + +```javascript +const browser = miio.browser({ + cacheTime: 300 // 5 minutes. Default is 1800 seconds (30 minutes) +}); + +const devices = {}; +browser.on('available', reg => { + if(! reg.token) { + console.log(reg.id, 'hides its token'); + return; + } + + miio.device(reg) + .then(device => { + devices[reg.id] = device; + + // Do something useful with the device + }) + .catch(handleErrorProperlyHere); +}); + +browser.on('unavailable', reg => { + const device = devices[reg.id]; + if(! device) return; + + device.destroy(); + delete devices[reg.id]; +}) +``` + +You can also use mDNS for discovery, but this library does not contain a mDNS implementation. You can choose a mDNS-implementation suitable for your needs. Devices announce themselves via `_miio._udp` and should work for most devices, in certain cases you might need to restart your device to make it @@ -138,6 +172,20 @@ Currently implemented devices are: See [documentation for devices](devices.md) for information about the API for each type. +## Advanced: Skip model and token checks + +The `miio.device` function will return a promise that checks that we can +communicate with the device and what model it is. If you wish to skip this +step and just create a reference to a device use `miio.createDevice`: + +```javascript +const device = miio.createDevice({ + address: '192.168.100.8', + token: 'token-as-hex', + model: 'zhimi.airpurifier.m1' +}); +``` + ## Advanced: Device management Get information and update the wireless settings of devices via the management diff --git a/discovery.js b/discovery.js index 7004328..e7862fd 100644 --- a/discovery.js +++ b/discovery.js @@ -32,14 +32,17 @@ class Browser { this._socket.on('message', (msg, rinfo) => { const buf = Buffer.from(msg); this._packet.raw = buf; + let token = this._packet.checksum.toString('hex'); + if(token.match(/^[fF]+$/)) { + token = null; + } + this._addService({ id: this._packet.deviceId, address: rinfo.address, port: rinfo.port, - token: this._packet.checksum.toString('hex') + token: token }); - - // TODO: Is there any way to discover the model of the device? }); this._searchHandle = setInterval(this._search.bind(this), this.cacheTime / 3); diff --git a/index.js b/index.js index 9ac744f..cd04285 100644 --- a/index.js +++ b/index.js @@ -21,15 +21,39 @@ module.exports.Device = Device; module.exports.devices = devices; /** - * Create a device from from the given options. This will either create a + * Resolve a device from the given options. + * + * Options: + * * `address`, **required** the address to the device as an IP or hostname + * * `port`, optional port number, if not specified the default 54391 will be used + * * `token`, optional token of the device + */ +module.exports.device = function(options) { + // Create a temporary device and fetch info from device + const temp = new Device(options); + return temp.call('miIO.info') + .then(data => { + temp.destroy(); + return createDevice({ + address: options.address, + port: options.port, + model: data.model, + token: data.token + }); + }); +}; + +/** + * Create a device from the given options. This will either create a * specific device if the type is known, or a generic device if it is unknown. * * Options: * * `address`, **required** the address to the device as an IP or hostname * * `port`, optional port number, if not specified the default 54391 will be used * * `model`, optional model if known, allows a more specific type to be returned + * * `token`, optional token of the device */ -module.exports.createDevice = function(options) { +const createDevice = module.exports.createDevice = function(options) { if(! options.address) throw new Error('Address to device is required'); const d = devices[options.model];