UNPKG

homebridge-philips-tv6

Version:

Homebridge Plugin for Philips Android TV API v6+

217 lines (200 loc) 7.16 kB
const request = require("request"); const wol = require('wake_on_lan'); class PhilipsTV { api = null; channelList = []; volume = { min: 0, max: 0, current: 0, muted: false }; constructor(config) { const wolURL = config.wol_url; const baseURL = `https://${config.ip_address}:1926/6/`; this.api = (path, body = null) => { return new Promise((success, fail) => { request({ rejectUnauthorized: false, timeout: 3000, auth: { user: config.username, pass: config.password, sendImmediately: false }, method: body ? "POST" : "GET", body: typeof body === "object" ? JSON.stringify(body) : body, url: `${baseURL}${path}` }, (error, response, body) => { if (error) { fail(error); } else { if (body && body.indexOf("{") !== -1) { try { success(JSON.parse(body)) } catch (e) { fail(e); } } else { success({}); } } }) }) }; this.wake = (callback) => { if (!wolURL) { callback(null, "EMPTY"); return; } if (wolURL.substring(0, 3).toUpperCase() === "WOL") { //Wake on lan request const macAddress = wolURL.replace(/^WOL[:]?[\/]?[\/]?/ig, ""); wol.wake(macAddress, function (error) { if (error) { callback(error); } else { callback(null, "OK"); } }); } else { if (wolURL.length > 3) { callback(new Error("Unsupported protocol: ", "ERROR")); } else { callback(null, "EMPTY"); } } }; } getPowerState = (callback) => { this.api("powerstate").then((data) => { callback && callback(null, data.powerstate === "On") }).catch((e) => { callback && callback(null, false) }) }; setPowerState = (value, callback) => { if (value) { this.wake((wolState) => { }); } this.api("powerstate", { powerstate: value ? "On" : "Standby" }).then((data) => { callback(null, value) }).catch(() => { callback(null, false) }); }; sendKey = key => this.api("input/key", {key}); setChannel = ccid => this.api("activities/tv", {channel: {ccid}, channelList: {id: "allsat"}}); launchApp = app => this.api("activities/launch", app); getChannelList = () => this.api("channeldb/tv/channelLists/all").then((response) => { if (response) { return response.Channel; } return []; }); presetToCCid = async preset => { if (!this.channelList.length) { this.channelList = await this.getChannelList(); } const channel = this.channelList.filter(item => parseInt(item.preset) === parseInt(preset)).pop(); return channel ? channel.ccid : 0; }; getCurrentSource = (inputs) => { return new Promise(async (resolve, reject) => { try { const current = await this.api("activities/current"); const currentPkgname = current.component.packageName; let currentTvPreset = 0; let selected = 0; if (currentPkgname === "org.droidtv.channels" || currentPkgname === "org.droidtv.playtv") { const currentTV = await this.api("activities/tv"); currentTvPreset = parseInt(currentTV.channel.preset, 10); } inputs.forEach((item, index) => { if (currentTvPreset && item.channel === currentTvPreset) { selected = index } else if (item.launch && item.launch.intent && item.launch.intent.component.packageName === currentPkgname) { selected = index } }); resolve(selected) } catch (e) { resolve(0) } }) }; setSource = async (input, callback) => { if (input.channel) { await this.sendKey("WatchTV"); // await this.sendKey("Digit" + input.channel); // await this.sendKey("Confirm"); const ccid = await this.presetToCCid(input.channel); await this.setChannel(ccid); } else if (input.launch) { await this.launchApp(input.launch); } else { await this.sendKey("WatchTV"); } callback(null); }; getAmbilightState = (callback) => { this.api("ambilight/power").then((data) => { callback(null, data.power === "On") }).catch(() => { callback(null, false) }) }; getVolumeState = (callback) => { this.api("audio/volume").then((data) => { this.volume = { ...this.volume, ...data }; const volume = Math.floor(((this.volume.current - this.volume.min) / (this.volume.max - this.volume.min)) * 100); callback(null, volume) }).catch(() => { callback(null, false) }) }; setVolumeState = (value, callback) => { this.volume.current = Math.round(this.volume.min + (this.volume.max - this.volume.min) * (value / 100)); this.api("audio/volume", this.volume).then(() => { callback(null, value); }).catch(() => { callback(null, false) }); }; setMuteState = (value, callback) => { this.volume.muted = !value; this.api("audio/volume", this.volume).then(() => { callback(null, value); }).catch(() => { callback(null, false) }); }; setAmbilightState = (value, callback) => { if (value) { this.api("ambilight/currentconfiguration", { styleName: "FOLLOW_VIDEO", isExpert: false, menuSetting: "NATURAL" }).then((data) => { callback(null, true) }).catch(() => { callback(null, false) }); } else { this.api("ambilight/power", { power: "Off" }).then((data) => { callback(null, false) }).catch(() => { callback(null, false) }); } } } module.exports = PhilipsTV;