UNPKG

node-red-contrib-marantz-http

Version:

Maranz AV Reciever Control for node-red throught HTTP protocol

353 lines (325 loc) 12.1 kB
/** * Created by aborovsky on 11.05.2015. */ var util = require('util'); var DEBUG = false; var connectionFSM = require('./lib/connectionFSM.js'); module.exports = function(RED) { /** * ====== Marantz-controller ================ * Holds configuration for marantzjs host+port, * initializes new marantzjs connections * ========================================== */ function MarantzControllerNode(config) { RED.nodes.createNode(this, config); this.name = config.name; this.host = config.host; this.port = config.port; this.marantz = null; var node = this; /** * Initialize an marantz_telnet socket, calling the handler function * when successfully connected, passing it the marantz_telnet connection */ this.initializeMarantzConnection = function(handler) { var afterConnected = function() { handler(node.marantz); }; if (node.marantz) { DEBUG && RED.comms.publish("debug", { name: node.name, msg: 'already configured connection to Marantz at ' + config.host + ':' + config.port }); if (handler && (typeof handler === 'function')) { if (node.marantz.isConnected()) afterConnected(); else { node.marantz.connect(); node.marantz.off('connected', afterConnected); node.marantz.on('connected', afterConnected); } } return node.marantz; } node.log('configuring connection to Marantz at ' + config.host + ':' + config.port); node.marantz = new connectionFSM({ host: config.host, port: config.port, debug: DEBUG }); node.marantz.connect(); if (handler && (typeof handler === 'function')) { node.marantz.off('connected', afterConnected); node.marantz.on('connected', afterConnected); } DEBUG && RED.comms.publish("debug", { name: node.name, msg: 'Marantz: successfully connected to ' + config.host + ':' + config.port }); return node.marantz; }; this.on("close", function() { node.log('disconnecting from marantz device at ' + config.host + ':' + config.port); node.marantz && node.marantz.disconnect && node.marantz.disconnect(); node.marantz = null; }); } RED.nodes.registerType("marantz-http-controller", MarantzControllerNode); /** * ====== Marantz-out ======================= * Sends outgoing Marantz from * messages received via node-red flows * ======================================= */ function MarantzOut(config) { RED.nodes.createNode(this, config); this.name = config.name; var controllerNode = RED.nodes.getNode(config.controller); this.unit_number = config.unit_number; this.marantzcommand = config.marantzcommand; var node = this; this.on("input", function(msg) { DEBUG && RED.comms.publish("debug", { name: node.name, msg: 'marantzout.onInput msg[' + util.inspect(msg) + ']' }); if (!(msg && msg.hasOwnProperty('payload'))) return; var payload = msg.payload; if (typeof(msg.payload) === "object") { payload = msg.payload; } else if (typeof(msg.payload) === "string") { try { payload = JSON.parse(msg.payload); if (typeof (payload) === 'number') payload = {cmd: msg.payload.toString()}; } catch (e) { payload = {cmd: msg.payload.toString()}; } } else payload = {cmd: msg.payload.toString()}; if (payload == null) { node.log('marantzout.onInput: illegal msg.payload!'); return; } //If msg.topic is filled, than set it as cmd if (msg.topic) { if (payload.value === null || payload.value === undefined) payload.value = payload.cmd; payload = {cmd: msg.topic.toString(), value: payload.value}; } if (node.marantzcommand && node.marantzcommand !== 'empty') { try { payload = JSON.parse(node.marantzcommand); if (typeof (payload) === 'number') payload.cmd = node.marantzcommand.toString(); } catch (e) { payload.cmd = node.marantzcommand.toString(); } } node.send(payload, function(err) { if (err) { node.error('send error: ' + err); } if (typeof(msg.cb) === 'function') msg.cb(err); }); }); this.on("close", function() { node.log('marantzOut.close'); }); node.status({fill: "yellow", shape: "dot", text: "inactive"}); function nodeStatusConnected() { node.status({fill: "green", shape: "dot", text: "connected"}); } function nodeStatusDisconnected() { node.status({fill: "red", shape: "dot", text: "disconnected"}); } function nodeStatusReconnect() { node.status({fill: "yellow", shape: "ring", text: "reconnecting"}); } function nodeStatusConnecting() { node.status({fill: "green", shape: "ring", text: "connecting"}); } controllerNode.initializeMarantzConnection(function(fsm) { if (fsm.connected) nodeStatusConnected(); else nodeStatusDisconnected(); fsm.off('connecting', nodeStatusConnecting); fsm.on('connecting', nodeStatusConnecting); fsm.off('connected', nodeStatusConnected); fsm.on('connected', nodeStatusConnected); fsm.off('disconnected', nodeStatusDisconnected); fsm.on('disconnected', nodeStatusDisconnected); fsm.off('reconnect', nodeStatusReconnect); fsm.on('reconnect', nodeStatusReconnect); }); this.send = function(data, callback) { DEBUG && RED.comms.publish("debug", {name: node.name, msg: 'send data[' + JSON.stringify(data) + ']'}); controllerNode.initializeMarantzConnection(function(fsm) { try { DEBUG && RED.comms.publish("debug", {name: node.name, msg: "send: " + JSON.stringify(data)}); data.cmd = data.cmd || data.method; data.value = data.value || data.params; switch (data.cmd.toLowerCase()) { case 'power': case 'pw': case 'power state': case 'pwstate': data.value = '' + data.value; fsm.connection.setPowerState(data.value.toLowerCase() === 'on' || data.value === '1' || data.value === 'true' || data.value.toLowerCase() === 'pwon').then(function(response) { callback && callback(null, response); }, function(error) { callback && callback(error); }); break; case 'si': case 'select_input': case 'select input': case 'input': fsm.connection.setInputSource('' + data.value).then(function(response) { callback && callback(null, response); }, function(error) { callback && callback(error); }); break; case 'mute': case 'mute_state': case 'mute state': data.value = '' + data.value; fsm.connection.setMuteState(data.value.toLowerCase() === 'on' || data.value === '1' || data.value === 'true').then(function(response) { callback && callback(null, response); }, function(error) { callback && callback(error); }); break; case 'volume_down': case 'volume down': case 'voldown': case 'vol_down': case 'volumedown': fsm.connection.volumeDown().then(function(response) { callback && callback(null, response); }, function(error) { callback && callback(error); }); break; case 'volume_up': case 'volume up': case 'volup': case 'vol_up': case 'volumeup': fsm.connection.volumeUp().then(function(response) { callback && callback(null, response); }, function(error) { callback && callback(error); }); break; case 'volume': case 'volume level': case 'volume_level': case 'vol_level': case 'vollevel': fsm.connection.setVolumePercent(parseInt(data.value)).then(function(response) { callback && callback(response); }, function(error) { callback && callback(error, response); }); break; /* MOVIE MUSIC GAME DIRECT PURE DIRECT STEREO AUTO DOLBY DIGITAL DTS SURROUND AURO3D AURO2D SURR MCH STEREO VIRTUAL LEFT RIGHT */ case 'surround': case 'surround mode': case 'surround_mode': case 'sm': case 'ms': fsm.connection.setSurroundMode(data.value ? data.value.toString() : '').then(function(response) { callback && callback(response); }, function(error) { callback && callback(error, response); }); break; default: node.log('Cannot proceed unknown cmd[' + data.cmd + '] for msg[' + JSON.stringify(data) +']'); } } catch (err) { node.error('error calling send: ' + err); callback && callback(err); } }); } } RED.nodes.registerType("marantz-http-out", MarantzOut); /** * ====== Marantz-IN ======================== * Handles incoming Global Cache, injecting * json into node-red flows * ======================================= */ function MarantzIn(config) { RED.nodes.createNode(this, config); this.name = config.name; this.connection = null; var node = this; var controllerNode = RED.nodes.getNode(config.controller); /* ===== Node-Red events ===== */ function nodeStatusConnecting() { node.status({fill: "green", shape: "ring", text: "connecting"}); } function nodeStatusConnected() { node.status({fill: "green", shape: "dot", text: "connected"}); } function nodeStatusDisconnected() { node.status({fill: "red", shape: "dot", text: "disconnected"}); } function nodeStatusReconnect() { node.status({fill: "yellow", shape: "ring", text: "reconnecting"}); } node.receiveNotification = function(notification, data) { DEBUG && RED.comms.publish("debug", { name: node.name, msg: 'marantz event data[' + JSON.stringify(data) + ']' }); node.send({ topic: 'marantz', payload: { 'notification': notification, 'data': data } }); }; controllerNode.initializeMarantzConnection(function(fsm) { if (fsm.connected) nodeStatusConnected(); else nodeStatusDisconnected(); fsm.off('connecting', nodeStatusConnecting); fsm.on('connecting', nodeStatusConnecting); fsm.off('connected', nodeStatusConnected); fsm.on('connected', nodeStatusConnected); fsm.off('disconnected', nodeStatusDisconnected); fsm.on('disconnected', nodeStatusDisconnected); fsm.off('reconnect', nodeStatusReconnect); fsm.on('reconnect', nodeStatusReconnect); }); } RED.nodes.registerType("marantz-http-in", MarantzIn); }