Skip to content

Instantly share code, notes, and snippets.

@imbrianj
Created September 30, 2017 20:02
Show Gist options
  • Save imbrianj/77c51bf029148ec166b9f74b4e7a9160 to your computer and use it in GitHub Desktop.
Save imbrianj/77c51bf029148ec166b9f74b4e7a9160 to your computer and use it in GitHub Desktop.
/* global Buffer */
/**
* Copyright (c) 2014 brian@bevey.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
module.exports = (function () {
'use strict';
/**
* @author brian@bevey.org
* @fileoverview Basic control of Samsung SmartTVs from 2011 onward.
* @requires net
* @note This is wouldn't be possible without the fine work done here:
* http://forum.samygo.tv/viewtopic.php?f=12&t=1792
*/
return {
version : 20150921,
inputs : ['command', 'text'],
/**
* Whitelist of available key codes to use.
*/
keymap : ['0', '1', '16_9', '2', '3', '3SPEED', '4', '5', '6', '7', '8', '9', '11', '12', '4_3', 'AD', 'ADDDEL', 'ALT_MHP', 'ANGLE', 'ANTENA', 'ANYNET', 'ANYVIEW', 'APP_LIST', 'ASPECT', 'AUTO_ARC_ANTENNA_AIR', 'AUTO_ARC_ANTENNA_CABLE', 'AUTO_ARC_ANTENNA_SATELLITE', 'AUTO_ARC_ANYNET_AUTO_START', 'AUTO_ARC_ANYNET_MODE_OK', 'AUTO_ARC_AUTOCOLOR_FAIL', 'AUTO_ARC_AUTOCOLOR_SUCCESS', 'AUTO_ARC_CAPTION_ENG', 'AUTO_ARC_CAPTION_KOR', 'AUTO_ARC_CAPTION_OFF', 'AUTO_ARC_CAPTION_ON', 'AUTO_ARC_C_FORCE_AGING', 'AUTO_ARC_JACK_IDENT', 'AUTO_ARC_LNA_OFF', 'AUTO_ARC_LNA_ON', 'AUTO_ARC_PIP_CH_CHANGE', 'AUTO_ARC_PIP_DOUBLE', 'AUTO_ARC_PIP_LARGE', 'AUTO_ARC_PIP_LEFT_BOTTOM', 'AUTO_ARC_PIP_LEFT_TOP', 'AUTO_ARC_PIP_RIGHT_BOTTOM', 'AUTO_ARC_PIP_RIGHT_TOP', 'AUTO_ARC_PIP_SMALL', 'AUTO_ARC_PIP_SOURCE_CHANGE', 'AUTO_ARC_PIP_WIDE', 'AUTO_ARC_RESET', 'AUTO_ARC_USBJACK_INSPECT', 'AUTO_FORMAT', 'AUTO_PROGRAM', 'AV1', 'AV2', 'AV3', 'BACK_MHP', 'BOOKMARK', 'CALLER_ID', 'CAPTION', 'CATV_MODE', 'CHDOWN', 'CHUP', 'CH_LIST', 'CLEAR', 'CLOCK_DISPLAY', 'COMPONENT1', 'COMPONENT2', 'CONTENTS', 'CONVERGENCE', 'CONVERT_AUDIO_MAINSUB', 'CUSTOM', 'CYAN', 'DEVICE_CONNECT', 'DISC_MENU', 'DMA', 'DNET', 'DNIe', 'DNSe', 'DOOR', 'DOWN', 'DSS_MODE', 'DTV', 'DTV_LINK', 'DTV_SIGNAL', 'DVD_MODE', 'DVI', 'DVR', 'DVR_MENU', 'DYNAMIC', 'ENTER', 'ENTERTAINMENT', 'ESAVING', 'EXIT', 'EXT1', 'EXT10', 'EXT11', 'EXT12', 'EXT13', 'EXT14', 'EXT15', 'EXT16', 'EXT17', 'EXT18', 'EXT19', 'EXT2', 'EXT20', 'EXT21', 'EXT22', 'EXT23', 'EXT24', 'EXT25', 'EXT26', 'EXT27', 'EXT28', 'EXT29', 'EXT3', 'EXT30', 'EXT31', 'EXT32', 'EXT33', 'EXT34', 'EXT35', 'EXT36', 'EXT37', 'EXT38', 'EXT39', 'EXT4', 'EXT40', 'EXT41', 'EXT5', 'EXT6', 'EXT7', 'EXT8', 'EXT9', 'FACTORY', 'FAVCH', 'FF', 'FF_', 'FM_RADIO', 'GAME', 'GREEN', 'GUIDE', 'HDMI', 'HDMI1', 'HDMI2', 'HDMI3', 'HDMI4', 'HELP', 'HOME', 'ID_INPUT', 'ID_SETUP', 'INFO', 'INSTANT_REPLAY', 'LEFT', 'LINK', 'LIVE', 'MAGIC_BRIGHT', 'MAGIC_CHANNEL', 'MDC', 'MENU', 'MIC', 'MORE', 'MOVIE1', 'MS', 'MTS', 'MUTE', 'NINE_SEPERATE', 'OPEN', 'PANNEL_CHDOWN', 'PANNEL_CHUP', 'PANNEL_ENTER', 'PANNEL_MENU', 'PANNEL_POWER', 'PANNEL_SOURCE', 'PANNEL_VOLDOW', 'PANNEL_VOLUP', 'PANORAMA', 'PAUSE', 'PCMODE', 'PERPECT_FOCUS', 'PICTURE_SIZE', 'PIP_CHDOWN', 'PIP_CHUP', 'PIP_ONOFF', 'PIP_SCAN', 'PIP_SIZE', 'PIP_SWAP', 'PLAY', 'PLUS100', 'PMODE', 'POWER', 'POWEROFF', 'POWERON', 'PRECH', 'PRINT', 'PROGRAM', 'QUICK_REPLAY', 'REC', 'RED', 'REPEAT', 'RESERVED1', 'RETURN', 'REWIND', 'REWIND_', 'RIGHT', 'RSS', 'RSURF', 'SCALE', 'SEFFECT', 'SETUP_CLOCK_TIMER', 'SLEEP', 'SOURCE', 'SRS', 'STANDARD', 'STB_MODE', 'STILL_PICTURE', 'STOP', 'SUB_TITLE', 'SVIDEO1', 'SVIDEO2', 'SVIDEO3', 'TOOLS', 'TOPMENU', 'TTX_MIX', 'TTX_SUBFACE', 'TURBO', 'TV', 'TV_MODE', 'UP', 'VCHIP', 'VCR_MODE', 'VOLDOWN', 'VOLUP', 'WHEEL_LEFT', 'WHEEL_RIGHT', 'W_LINK', 'YELLOW', 'ZOOM1', 'ZOOM2', 'ZOOM_IN', 'ZOOM_MOVE', 'ZOOM_OUT'],
/**
* Simple base64 encoder as the Samsung TVs require some embedded base64
* data.
*/
base64Encode : function (string) {
return new Buffer(string).toString('base64');
},
/**
* Prepares and calls send() to request the current state.
*/
state : function (controller, config, callback) {
var samsung = { device : {}, config : {}};
callback = callback || function () {};
samsung.command = 'state';
samsung.device.deviceId = controller.config.deviceId;
samsung.device.deviceIp = controller.config.deviceIp;
samsung.device.localTimeout = controller.config.localTimeout || config.localTimeout;
samsung.config.serverIp = config.serverIp;
samsung.config.serverMac = config.serverMac;
samsung.callback = function (err, reply) {
if (reply) {
callback(samsung.device.deviceId, null, 'ok');
}
else if (err) {
callback(samsung.device.deviceId, err);
}
};
this.send(samsung);
},
send : function (config) {
var net = require('net'),
samsung = {},
client = new net.Socket();
samsung.deviceIp = config.device.deviceIp;
samsung.devicePort = config.device.devicePort || 8001;
samsung.path = config.config.path || '/api/v2/channels/samsung.remote.control?name=';
samsung.timeout = config.device.localTimeout || config.config.localTimeout;
samsung.command = config.command || '';
samsung.text = config.text || '';
samsung.callback = config.callback || function () {};
samsung.message = {
method : 'ms.remote.control',
params : {
Cmd : 'Click',
DataOfCmd : samsung.command,
Option : false,
TypeOfRemote : 'SendRemoteKey'
}
};
// unsure of this value?
// https://github.com/Ape/samsungctl/blob/master/samsungctl/remote_websocket.py#L23
client.connect({ port : samsung.devicePort,
host : samsung.deviceIp,
path : samsung.path });
client.once('connect', function () {
console.log('Connected');
if ((samsung.command) || (samsung.text)) {
client.write(samsung.message);
}
client.end();
samsung.callback(null, 'ok');
});
if (samsung.command === 'state') {
console.log('Trying to poll');
client.setTimeout(samsung.timeout, function () {
client.destroy();
samsung.callback({ code : 'ETIMEDOUT' });
});
}
client.once('error', function (err) {
console.log('Error');
if ((err.code !== 'ETIMEDOUT') || (samsung.command !== 'state')) {
console.log('Timeout');
samsung.callback(err);
}
});
}
};
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment