node-red-contrib-lgtv-with-fullscreen
Version:
Node-RED Nodes to control LG webOS Smart TVs, with browser fullscreen
218 lines (188 loc) • 6.27 kB
JavaScript
module.exports = function (RED) {
let status;
let token;
let lgtv;
function LgtvConfigNode(config) {
RED.nodes.createNode(this, config);
const node = this;
node.host = config.host;
node.users = {};
const subscriptions = {};
const lgtv = require('lgtv2')({
url: 'ws://' + node.host + ':3000',
clientKey: node.credentials.token,
saveKey(key, cb) {
token = key;
RED.nodes.addCredentials(node.id, {
token: key
});
if (typeof cb === 'function') {
cb();
}
}
});
lgtv.on('connecting', () => {
node.setStatus('connecting');
});
lgtv.on('connect', () => {
node.setStatus('connect');
node.connected = true;
Object.keys(subscriptions).forEach(url => {
lgtv.subscribe(url, (err, res) => {
node.subscriptionHandler(url, err, res);
});
});
lgtv.getSocket('ssap://com.webos.service.networkinput/getPointerInputSocket',
(err, sock) => {
if (!err) {
node.buttonSocket = sock;
}
}
);
node.emit('tvconnect');
});
lgtv.on('error', e => {
node.connected = false;
node.setStatus(e.code);
});
lgtv.on('close', () => {
node.emit('tvclose');
node.connected = false;
node.buttonSocket = null;
node.setStatus('close');
});
lgtv.on('prompt', () => {
node.setStatus('prompt');
});
this.subscriptionHandler = function (url, err, res) {
if (subscriptions[url]) {
Object.keys(subscriptions[url]).forEach(id => {
subscriptions[url][id](err, res);
});
}
};
this.subscribe = function (id, url, callback) {
if (!subscriptions[url]) {
subscriptions[url] = {};
if (node.connected) {
lgtv.subscribe(url, (err, res) => {
node.subscriptionHandler(url, err, res);
});
}
}
subscriptions[url][id] = callback;
};
this.request = function (url, payload, callback) {
if (node.connected) {
lgtv.request(url, payload, callback);
}
};
this.fullscreen = function () {
if (node.buttonSocket) {
const command = "move\n" + "dx:" + 11 + "\n" + "dy:-8\n" + "down:0\n" + "\n";
for (let i = 0; i < 22; i++) {
node.buttonSocket.send(command);
}
setTimeout(() => {
node.buttonSocket.send('click');
}, 5000);
}
}
this.register = function (lgtvNode) {
node.users[lgtvNode.id] = lgtvNode;
};
this.deregister = function (lgtvNode, done) {
delete node.users[lgtvNode.id];
Object.keys(subscriptions).forEach(url => {
delete subscriptions[url][lgtvNode.id];
});
return done();
};
this.setStatus = function (c) {
status = c;
let s;
switch (c) {
case 'connecting':
s = {
fill: 'yellow',
shape: 'ring',
text: 'node-red:common.status.connecting'
};
break;
case 'prompt':
s = {
fill: 'yellow',
shape: 'ring',
text: c
};
break;
case 'connect':
s = {
fill: 'green',
shape: 'dot',
text: 'node-red:common.status.connected'
};
break;
case 'disconnected':
s = {
fill: 'red',
shape: 'ring',
text: 'node-red:common.status.disconnected'
};
break;
default:
s = {
fill: 'red',
shape: 'ring',
text: c
};
}
Object.keys(node.users).forEach(id => {
node.users[id].status(s);
});
};
}
RED.httpAdmin.get('/lgtv-connect', (req, res) => {
if (!status || status === 'Close') {
lgtv = require('lgtv2')({
url: 'ws://' + req.query.host + ':3000',
saveKey(key, cb) {
token = key;
RED.nodes.addCredentials(req.query.id, {
token: key
});
if (typeof cb === 'function') {
cb();
}
}
});
status = 'Connecting';
setTimeout(() => {
lgtv.disconnect();
status = '';
}, 31000);
lgtv.on('connecting', () => {
status = 'Connecting';
});
lgtv.on('connect', () => {
lgtv.disconnect();
status = 'Connected';
});
lgtv.on('error', e => {
status = 'Error: ' + e.code.toLowerCase();
});
lgtv.on('prompt', () => {
status = 'Please answer the prompt on your TV';
});
}
res.status(200).send(JSON.stringify({
state: status,
token
}));
});
RED.nodes.registerType('lgtv-config', LgtvConfigNode, {
credentials: {
token: { type: 'text' }
}
});
};