UNPKG

homebridge-xiaomi-roborock-vacuum

Version:

Xiaomi Vacuum Cleaner - 1st (Mi Robot), 2nd (Roborock S50 + S55), 3rd Generation (Roborock S6) and S5 Max - plugin for Homebridge.

140 lines 4.34 kB
"use strict"; const { TimedDiscovery, BasicDiscovery, search, addService, removeService, } = require("tinkerhub-discovery"); const { Children } = require("abstract-things"); const util = require("util"); const dns = require("dns"); const network = require("./network"); const infoFromHostname = require("./infoFromHostname"); const connectToDevice = require("./connectToDevice"); const tryAdd = Symbol("tryAdd"); const Browser = (module.exports.Browser = class Browser extends TimedDiscovery { static get type() { return "miio"; } constructor(options) { super({ maxStaleTime: (options.cacheTime || 1800) * 1000, }); this.manualTokens = options.tokens || {}; this[tryAdd] = this[tryAdd].bind(this); this.start(); } _manualToken(id) { return this.manualTokens[id] || null; } start() { this.handle = network.ref(); network.on("device", this[tryAdd]); super.start(); } stop() { super.stop(); network.removeListener("device", this[tryAdd]); this.handle.release(); } [search]() { network.search(); } [tryAdd](device) { const service = { id: device.id, address: device.address, port: device.port, token: device.token || this._manualToken(device.id), autoToken: device.autoToken, connect: function (options = {}) { return connectToDevice(Object.assign({ address: this.address, port: this.port, model: this.model, }, options)); }, }; const add = () => this[addService](service); // Give us five seconds to try resolve some extras for new devices setTimeout(add, 5000); dns.lookupService(service.address, service.port, (err, hostname) => { if (err || !hostname) { add(); return; } service.hostname = hostname; const info = infoFromHostname(hostname); if (info) { service.model = info.model; } add(); }); } [util.inspect.custom]() { return "MiioBrowser{}"; } }); class Devices extends BasicDiscovery { static get type() { return "miio:devices"; } constructor(options) { super(); this._filter = options && options.filter; this._skipSubDevices = options && options.skipSubDevices; this._browser = new Browser(options).map((reg) => { return connectToDevice({ address: reg.address, port: reg.port, model: reg.model, withPlaceholder: true, token: options.token, }); }); this._browser.on("available", (s) => { this[addService](s); if (s instanceof Children) { this._bindSubDevices(s); } }); this._browser.on("unavailable", (s) => { this[removeService](s); }); } start() { super.start(); this._browser.start(); } stop() { super.stop(); this._browser.stop(); } [util.inspect.custom]() { return "MiioDevices{}"; } _bindSubDevices(device) { if (this._skipSubDevices) return; const handleAvailable = (sub) => { if (!sub.miioModel) return; const reg = { id: sub.internalId, model: sub.model, type: sub.type, parent: device, device: sub, }; if (this._filter && !this._filter(reg)) { // Filter does not match sub device return; } // Register and emit event this[addService](sub); }; device.on("thing:available", handleAvailable); device.on("thing:unavailable", (sub) => this[removeService](sub.id)); // Register initial devices for (const child of device.children()) { handleAvailable(child); } } } module.exports.Devices = Devices; //# sourceMappingURL=discovery.js.map