diff --git a/blynk-node.js b/blynk-node.js index ace1964..acb7633 100644 --- a/blynk-node.js +++ b/blynk-node.js @@ -19,6 +19,7 @@ var MsgType = { exports.TcpClient = function(options) { var self = this; events.EventEmitter.call(this); + this.name = 'TcpClient'; var options = options || {}; self.addr = options.addr || "blynk-cloud.com"; @@ -75,6 +76,7 @@ util.inherits(exports.TcpClient, events.EventEmitter); exports.TcpServer = function(options) { var self = this; events.EventEmitter.call(this); + this.name = 'TcpServer'; var options = options || {}; self.addr = options.addr || '0.0.0.0'; @@ -128,6 +130,7 @@ util.inherits(exports.TcpServer, events.EventEmitter); exports.SslClient = function(options) { var self = this; events.EventEmitter.call(this); + this.name = 'SslClient'; var options = options || {}; var certs_path = options.certs_path || default_certs_path; @@ -240,6 +243,7 @@ util.inherits(exports.SslClient, events.EventEmitter); exports.SslServer = function(options) { var self = this; events.EventEmitter.call(this); + this.name = 'SslServer'; var options = options || {}; var certs_path = options.certs_path || default_certs_path; @@ -307,6 +311,7 @@ var scale = function(value, inMin, inMax, outMin, outMax) { exports.BoardMRAA = function() { var self = this; + this.name = 'MRAA'; var mraa = require('mraa'); console.log('MRAA Version: ' + mraa.getVersion()); this.init = function(blynk) { @@ -346,6 +351,7 @@ exports.BoardMRAA = function() { exports.BoardOnOff = function() { var self = this; var Gpio; + this.name = 'OnOff'; try { Gpio = require('onoff').Gpio; console.log("OnOff mode"); diff --git a/blynk.js b/blynk.js index 4d5c487..3444135 100644 --- a/blynk.js +++ b/blynk.js @@ -5,6 +5,10 @@ var C = { }; +/* library version */ +var BLYNK_VERSION = '0.4.7'; +var BLYNK_INFO_DEVICE = ''; + /* * Helpers */ @@ -79,6 +83,111 @@ var BlynkState = { DISCONNECTED : 3 }; + +/* +* function from node-red-contrib-blynk-ws +*/ + +function getKeyByValue(obj, value) { + //return Object.keys(obj).find(key => obj[key] === value); //javascript ES6 only + return Object.keys(obj).filter(function(key) {return obj[key] === value;})[0]; +} + +function getCommandByCode(cmd) { + var key = getKeyByValue(MsgType, cmd); + if(key !== undefined ) return key; + else return cmd; +} + +function getStatusByCode(statusCode) { + var key = getKeyByValue(MsgStatus, statusCode); + if(key !== undefined ) return key; + else return statusCode; +} + +/* return a full decoded message for debug */ +function messageToDebugString(data) { + var msgCount = 0; + var dbgStr= ""; + + while(data.length>0) { + msgCount++; + var cmd = decodeCommand(data); + data=data.substr(cmd.msgLength); //remove current message from data + if(msgCount>1) dbgStr = dbgStr + "\n" + commandToDebugString(cmd); + else dbgStr = commandToDebugString(cmd); + } + if(msgCount>1) return "Multiple Command, num: "+msgCount + "\n"+ dbgStr; + else return dbgStr; +} + +/* return a decoded command for debug */ +function commandToDebugString(cmd) { + var dbgStr= ""; + if (cmd.type !== MsgType.RSP ) { + var logdata = cmd.body; + if (cmd.type === MsgType.LOGIN) logdata = String("********************************" + cmd.body.slice(-5)).slice(-32); + if (cmd.type === MsgType.BRIDGE) { + var values = cmd.body.split("\0"); + if(values.length == 3 && values[1] == "i") { + logdata = values[0]+"\0"+values[1]+"\0"+String("********************************" + values[2].slice(-5)).slice(-32); + } + } + dbgStr="Cmd: " + cmd.typeString + ", Id: " + cmd.msgId + ", len: " + cmd.len + ", data: " + JSON.stringify(logdata.replace(new RegExp("\u0000", "g"),"|")); + } + else { + dbgStr="Cmd: " + cmd.typeString + ", Id: " + cmd.msgId + ", responseCode: " + getStatusByCode(cmd.len); + } + return dbgStr; +} + +/* decode a single blynk command */ +function decodeCommand(data) { + var cmd = {}; + + cmd.type = data.charCodeAt(0); + cmd.typeString = getCommandByCode(cmd.type); + cmd.msgId = data.charCodeAt(1) << 8 | data.charCodeAt(2); + cmd.len = data.charCodeAt(3) << 8 | data.charCodeAt(4); + cmd.msgLength = 5; + + switch(cmd.type) { + case MsgType.HW: + case MsgType.BRIDGE: + cmd.body = data.substr(5, cmd.len); + cmd.msgLength = cmd.msgLength + cmd.len; + + if (cmd.body !== "") { + var values = cmd.body.split("\0"); + if (values.length > 1) { + cmd.operation = values[0]; + cmd.pin = values[1]; + if (values.length > 2) { + cmd.value = values[2]; + //we have an array of cmds, return array as well + cmd.array = values.slice(2, values.length); + } + } + else if (values.length == 1) { ///handle "pm" single message + cmd.operation = values[0]; + } + } + break; + case MsgType.RSP: + cmd.status = data.charCodeAt(3) << 8 | data.charCodeAt(4); + break; + default: + cmd.body = data.substr(5, cmd.len); + cmd.msgLength = cmd.msgLength + cmd.len; + break; + } + + return cmd; +} + +/* end function from node-red-contrib-blynk-ws */ + + if (isBrowser()) { var bl_browser = require('./blynk-browser.js'); var events = require('events'); @@ -164,6 +273,7 @@ if (isEspruino()) { var BoardEspruinoPico = function(values) { var self = this; + this.name = "EspruinoPico"; this.init = function(blynk) { self.blynk = blynk; }; @@ -201,6 +311,7 @@ if (isEspruino()) { var BoardEspruinoLinux = function(values) { var self = this; + this.name = "EspruinoLinux"; this.init = function(blynk) { self.blynk = blynk; }; @@ -235,6 +346,7 @@ if (isEspruino()) { */ var BoardDummy = function() { + this.name = "BoardDummy"; this.init = function(blynk) {}; this.process = function(values) { switch (values[0]) { @@ -261,17 +373,25 @@ var Blynk = function(auth, options) { events.EventEmitter.call(this); } + this.debug = false; //if true enable protocol log use "Debug" to activate + + this.auth = auth; var options = options || {}; this.heartbeat = options.heartbeat || (10*1000); + if(options.logo != undefined) this.logo = options.logo + // Auto-detect board if (options.board) { this.board = options.board; + BLYNK_INFO_DEVICE += options.board + ' - '; } else if (isEspruino()) { this.board = new BoardEspruinoPico(); + BLYNK_INFO_DEVICE += 'EspruinoPico - '; } else if (isBrowser()) { this.board = new BoardDummy(); + BLYNK_INFO_DEVICE += 'Dummy - '; } else { [ bl_node.BoardMRAA, @@ -280,6 +400,8 @@ var Blynk = function(auth, options) { ].some(function(b){ try { self.board = new b(); + + BLYNK_INFO_DEVICE += self.board.name + ' - '; return true; } catch (e) { @@ -292,12 +414,16 @@ var Blynk = function(auth, options) { // Auto-detect connector if (options.connector) { this.conn = options.connector; + BLYNK_INFO_DEVICE += options.connector.name; } else if (isEspruino()) { this.conn = new EspruinoTCP(options); + BLYNK_INFO_DEVICE += 'Espruino TCP'; } else if (isBrowser()) { this.conn = new bl_browser.WsClient(options); + BLYNK_INFO_DEVICE += 'Browser WS'; } else { this.conn = new bl_node.SslClient(options); + BLYNK_INFO_DEVICE += 'NodeJS Wss'; } this.buff_in = ''; @@ -305,6 +431,11 @@ var Blynk = function(auth, options) { this.vpins = []; this.profile = options.profile; + this.Debug = function(debug) { + if(debug == undefined) debug = true; + self.debug = debug; + }; + this.VirtualPin = function(vPin) { if (needsEmitter()) { events.EventEmitter.call(this); @@ -371,6 +502,32 @@ var Blynk = function(auth, options) { }; }; + var logo = ''; + if (self.logo == 'NO_FANCY_LOGO') { + logo = "\nBlynk JS v" + BLYNK_VERSION + " on " + BLYNK_INFO_DEVICE; + } + else if(self.logo == 'FANCY_LOGO_3D') { + logo = "\n" + + " ____ ___ __\n" + + " /\\ _`\\ /\\_ \\ /\\ \\ _\n" + + " \\ \\ \\_\\ \\\\//\\ \\ __ __ ___ \\ \\ \\/ \\\n" + + " \\ \\ _ < \\ \\ \\ /\\ \\/\\ \\ /' _ `\\\\ \\ , <\n" + + " \\ \\ \\_\\ \\ \\_\\ \\_\\ \\ \\_\\ \\ /\\ \\/\\ \\\\ \\ \\\\`\\\n" + + " \\ \\____/ /\\____\\\\/`____ \\\\ \\_\\ \\_\\\\ \\_\\\\_\\\n" + + " \\/___/ \\/____/ `/___/\\ \\\\/_/\\/_/ \\/_//_/\n" + + " /\\___/\n" + + " \\/__/ JS v" + BLYNK_VERSION + " on " + BLYNK_INFO_DEVICE + "\n"; + } + else { + logo = "\n" + + " ___ __ __\n" + + " / _ )/ /_ _____ / /__\n" + + " / _ / / // / _ \\/ '_/\n" + + " /____/_/\\_, /_//_/_/\\_\\\n" + + " /___/ JS v" + BLYNK_VERSION + " on " + BLYNK_INFO_DEVICE + "\n"; + } + console.log(logo); + if (needsEmitter()) { util.inherits(this.VirtualPin, events.EventEmitter); util.inherits(this.WidgetBridge, events.EventEmitter); @@ -390,6 +547,9 @@ Blynk.prototype.onReceive = function(data) { var self = this; self.buff_in += data; while (self.buff_in.length >= 5) { + if(self.debug) { + console.log("RECV <- " + messageToDebugString(self.buff_in)); + } var msg_type = self.buff_in.charCodeAt(0); var msg_id = self.buff_in.charCodeAt(1) << 8 | self.buff_in.charCodeAt(2); var msg_len = self.buff_in.charCodeAt(3) << 8 | self.buff_in.charCodeAt(4); @@ -408,7 +568,7 @@ Blynk.prototype.onReceive = function(data) { self.sendMsg(MsgType.PING); }, self.heartbeat); console.log('Authorized'); - self.sendMsg(MsgType.INTERNAL, ['ver', '0.4.7', 'dev', 'js']); + self.sendMsg(MsgType.INTERNAL, ['ver', BLYNK_VERSION, 'dev', 'js']); self.emit('connect'); } else { console.log('Could not login:', string_of_enum(MsgStatus, msg_len)); @@ -511,7 +671,9 @@ Blynk.prototype.sendRsp = function(msg_type, msg_id, msg_len, data) { }*/ data = blynkHeader(msg_type, msg_id, msg_len) + data; } - + if(self.debug) { + console.log("SEND -> " + messageToDebugString(data)); + } self.conn.write(data) // TODO: track also recieving time diff --git a/examples/nodejs/client-ssl-local.js b/examples/nodejs/client-ssl-local.js index 201c75f..1e38361 100755 --- a/examples/nodejs/client-ssl-local.js +++ b/examples/nodejs/client-ssl-local.js @@ -7,6 +7,7 @@ var AUTH = 'YOUR_AUTH_TOKEN'; var blynk = new Blynk.Blynk(AUTH, options= { addr:"127.0.0.1", port:8441 } ); +//blynk.Debug(); //remove comment to enable Protocol Log var v1 = new blynk.VirtualPin(1); var v9 = new blynk.VirtualPin(9); diff --git a/examples/nodejs/client-ssl.js b/examples/nodejs/client-ssl.js index 8eba471..a0771e5 100755 --- a/examples/nodejs/client-ssl.js +++ b/examples/nodejs/client-ssl.js @@ -5,6 +5,7 @@ var Blynk = require('blynk-library'); var AUTH = 'YOUR_AUTH_TOKEN'; var blynk = new Blynk.Blynk(AUTH); +//blynk.Debug(); //remove comment to enable Protocol Log var v1 = new blynk.VirtualPin(1); var v9 = new blynk.VirtualPin(9); diff --git a/examples/nodejs/client-tcp-local.js b/examples/nodejs/client-tcp-local.js index 37d788a..f409a03 100755 --- a/examples/nodejs/client-tcp-local.js +++ b/examples/nodejs/client-tcp-local.js @@ -7,6 +7,7 @@ var AUTH = 'YOUR_AUTH_TOKEN'; var blynk = new Blynk.Blynk(AUTH, options = { connector : new Blynk.TcpClient( options = { addr:"127.0.0.1", port:8442 } ) }); +//blynk.Debug(); //remove comment to enable Protocol Log var v1 = new blynk.VirtualPin(1); var v9 = new blynk.VirtualPin(9); diff --git a/examples/nodejs/client-tcp.js b/examples/nodejs/client-tcp.js index 116f160..51d4bf3 100755 --- a/examples/nodejs/client-tcp.js +++ b/examples/nodejs/client-tcp.js @@ -7,6 +7,7 @@ var AUTH = 'YOUR_AUTH_TOKEN'; var blynk = new Blynk.Blynk(AUTH, options = { connector : new Blynk.TcpClient() }); +//blynk.Debug(); //remove comment to enable Protocol Log var v1 = new blynk.VirtualPin(1); var v9 = new blynk.VirtualPin(9); diff --git a/examples/nodejs/client-with-bridge.js b/examples/nodejs/client-with-bridge.js index c0d8d0c..83b96d8 100644 --- a/examples/nodejs/client-with-bridge.js +++ b/examples/nodejs/client-with-bridge.js @@ -5,6 +5,7 @@ var Blynk = require('blynk-library'); var AUTH = 'YOUR_AUTH_TOKEN'; var blynk = new Blynk.Blynk(AUTH); +//blynk.Debug(); //remove comment to enable Protocol Log var v1 = new blynk.VirtualPin(1); var v9 = new blynk.VirtualPin(9); diff --git a/examples/nodejs/client-with-syncall.js b/examples/nodejs/client-with-syncall.js index c94d79c..252e814 100644 --- a/examples/nodejs/client-with-syncall.js +++ b/examples/nodejs/client-with-syncall.js @@ -4,6 +4,7 @@ var AUTH = 'YOUR_AUTH_TOKEN'; var BlynkLib = require('blynk-library'); var blynk = new BlynkLib.Blynk(AUTH); +//blynk.Debug(); //remove comment to enable Protocol Log var v1 = new blynk.VirtualPin(1); v1.on('write', function(param) {