node-red-contrib-blynk-ws
Advanced tools
Comparing version 0.6.0 to 0.7.0
@@ -9,2 +9,19 @@ # Changelog | ||
## [0.7.0] - 2018-07-30 | ||
### Added | ||
- Node - *Styled Button* - New node to simplify the use of this new button | ||
- Node - *Set Property* - Implemented "onColor, offColor, onBackColor, offBackColor" property for Styled Button widget (blynk cloud or local server >= v0.36.2) | ||
- Node - *Set Property* - Implemented "fraction" property for Slide widget (blynk cloud or local server >= v0.33.3) | ||
- Node - *Table* - Implemented "select, deselcet and order" commands | ||
### Changed | ||
- Code refactor - Extract blynk method and variable to files in "libs" directory | ||
- Node - *Notify* - Rate limit increased to 5 msg/s (Blynk Library 0.5.3) | ||
### Fixed | ||
- Node - *zeRGBa* - Check if the widget is configured in merge mode, otherwise it will generate an alert | ||
- Missing log on respond illegal command | ||
- Message ID overflow - see Blynk Library JS [PR #44](https://github.com/vshymanskyy/blynk-library-js/pull/44) | ||
- Show protocol warning in debug panel | ||
## [0.6.0] - 2018-05-07 | ||
@@ -102,3 +119,4 @@ ### Added | ||
[Unreleased]: https://github.com/gablau/node-red-contrib-blynk-ws/compare/0.6.0...HEAD | ||
[Unreleased]: https://github.com/gablau/node-red-contrib-blynk-ws/compare/0.7.0...HEAD | ||
[0.7.0]: https://github.com/gablau/node-red-contrib-blynk-ws/compare/0.6.0...0.7.0 | ||
[0.6.0]: https://github.com/gablau/node-red-contrib-blynk-ws/compare/0.5.2...0.6.0 | ||
@@ -105,0 +123,0 @@ [0.5.1]: https://github.com/gablau/node-red-contrib-blynk-ws/compare/0.5.1...0.5.2 |
module.exports = function(RED) { | ||
"use strict"; | ||
var ws = require("ws"); | ||
var srs = require("secure-random-string"); | ||
var LIBRARY_INFO = "0.6.0 2018-05-07"; | ||
var LIBRARY_INFO = "0.7.0 2018-07-30"; //node-red lib version | ||
/* ##### BLYNK STUFF ###### */ | ||
//library 0.4.7 - 2017-04-09 | ||
//library 0.5.1 - 2018-02-20 | ||
//library 0.5.2 - 2018-03-04 | ||
//server 0.23.5 - 2017-04-07 | ||
//server 0.32.2 - 2018-02-28 | ||
//server 0.34.0 - 2018-04-06 | ||
var BLYNK_VERSION = "0.5.2"; //blynk library version | ||
var BLYNK_HEARTBEAT = 10; //seconds | ||
var BLYNK_PROTOCOL_MAX_LENGTH = 32767; //java Short.MAX_VALUE | ||
var BLYNK_MAX_CMD_IN_MESSAGE = 1024; //max command in a single message | ||
//blynk util | ||
var blynkUtil = require('./../libs/blynk-util.js'); | ||
//blynk lib | ||
var blynkLib = require('./../libs/blynk-lib.js'); | ||
var MsgType = { | ||
RSP : 0, | ||
//app commands | ||
REGISTER : 1, //"mail pass" | ||
LOGIN : 2, //"token" or "mail pass" | ||
SAVE_PROF : 3, | ||
LOAD_PROF : 4, | ||
GET_TOKEN : 5, | ||
PING : 6, | ||
ACTIVATE : 7, //"DASH_ID" | ||
DEACTIVATE : 8, // | ||
REFRESH : 9, //"refreshToken DASH_ID" | ||
GET_GRAPH_DATA : 10, | ||
GET_GRAPH_DATA_RESPONSE : 11, | ||
//HARDWARE commands | ||
TWEET : 12, | ||
EMAIL : 13, | ||
NOTIFY : 14, | ||
BRIDGE : 15, | ||
HW_SYNC : 16, | ||
INTERNAL : 17, //0x11 | ||
SMS : 18, | ||
PROPERTY : 19, | ||
HW : 20, //0x14 | ||
//app commands | ||
CREATE_DASH : 21, | ||
UPDATE_DASH : 22, | ||
DELETE_DASH : 23, | ||
LOAD_PROF_GZ : 24, | ||
APP_SYNC : 25, | ||
SHARING : 26, | ||
ADD_PUSH_TOKEN : 27, | ||
EXPORT_GRAPH_DATA : 28, | ||
//app sharing commands | ||
GET_SHARED_DASH : 29, | ||
GET_SHARE_TOKEN : 30, | ||
REFRESH_SHARE_TOKEN : 31, | ||
SHARE_LOGIN : 32, | ||
//app commands | ||
CREATE_WIDGET : 33, | ||
UPDATE_WIDGET : 34, | ||
DELETE_WIDGET : 35, | ||
//energy commands | ||
GET_ENERGY : 36, | ||
ADD_ENERGY : 37, | ||
UPDATE_PROJECT_SETTINGS : 38, | ||
GET_SERVER : 40, | ||
CONNECT_REDIRECT : 41, | ||
CREATE_DEVICE : 42, | ||
UPDATE_DEVICE : 43, | ||
DELETE_DEVICE : 44, | ||
GET_DEVICES : 45, | ||
CREATE_TAG : 46, | ||
UPDATE_TAG : 47, | ||
DELETE_TAG : 48, | ||
GET_TAGS : 49, | ||
APP_CONNECTED : 50, | ||
//web sockets | ||
WEB_SOCKETS : 52, | ||
EVENTOR : 53, | ||
WEB_HOOKS : 54, | ||
CREATE_APP : 55, | ||
UPDATE_APP : 56, | ||
DELETE_APP : 57, | ||
GET_PROJECT_BY_TOKEN : 58, | ||
EMAIL_QR : 59, | ||
GET_ENHANCED_GRAPH_DATA : 60, | ||
DELETE_ENHANCED_GRAPH_DATA : 61, | ||
GET_CLONE_CODE : 62, | ||
GET_PROJECT_BY_CLONE_CODE : 63, | ||
HARDWARE_LOG_EVENT : 64, | ||
HARDWARE_RESEND_FROM_BLUETOOTH : 65, | ||
LOGOUT : 66, | ||
CREATE_TILE_TEMPLATE : 67, | ||
UPDATE_TILE_TEMPLATE : 68, | ||
DELETE_TILE_TEMPLATE : 69, | ||
GET_WIDGET : 70, | ||
DEVICE_OFFLINE : 71, | ||
OUTDATED_APP_NOTIFICATION : 72, | ||
/* | ||
//http codes. Used only for stats | ||
HTTP_IS_HARDWARE_CONNECTED : 82, | ||
HTTP_IS_APP_CONNECTED : 83, | ||
HTTP_GET_PIN_DATA : 84, | ||
HTTP_UPDATE_PIN_DATA : 85, | ||
HTTP_NOTIFY : 86, | ||
HTTP_EMAIL : 87, | ||
HTTP_GET_PROJECT : 88, | ||
HTTP_QR : 89, | ||
HTTP_GET_HISTORY_DATA : 90, | ||
HTTP_START_OTA : 91, | ||
HTTP_STOP_OTA : 92, | ||
HTTP_CLONE : 93, | ||
HTTP_TOTAL : 94, | ||
*/ | ||
}; | ||
var MsgStatus = { | ||
OK : 200, | ||
QUOTA_LIMIT_EXCEPTION : 1, | ||
ILLEGAL_COMMAND : 2, | ||
NOT_REGISTERED : 3, | ||
ALREADY_REGISTERED : 4, | ||
NOT_AUTHENTICATED : 5, | ||
NOT_ALLOWED : 6, | ||
DEVICE_NOT_IN_NETWORK : 7, | ||
NO_ACTIVE_DASHBOARD : 8, | ||
INVALID_TOKEN : 9, | ||
ILLEGAL_COMMAND_BODY : 11, | ||
GET_GRAPH_DATA_EXCEPTION : 12, | ||
NOTIFICATION_INVALID_BODY : 13, | ||
NOTIFICATION_NOT_AUTHORIZED : 14, | ||
NOTIFICATION_ERROR : 15, | ||
//reserved | ||
BLYNK_TIMEOUT : 16, | ||
NO_DATA_EXCEPTION : 17, | ||
//DEVICE_WENT_OFFLINE : 18, //removed | ||
SERVER_EXCEPTION : 19, | ||
//NOT_SUPPORTED_VERSION : 20, //removed | ||
ENERGY_LIMIT : 21, | ||
FACEBOOK_USER_LOGIN_WITH_PASS : 22, | ||
}; | ||
/* 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; | ||
} | ||
/* build a blynk header */ | ||
function blynkHeader(msg_type, msg_id, msg_len) { | ||
return String.fromCharCode( | ||
msg_type, | ||
msg_id >> 8, msg_id & 0xFF, | ||
msg_len >> 8, msg_len & 0xFF | ||
); | ||
} | ||
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; | ||
} | ||
/* ##### END BLYNK STUFF ###### */ | ||
function getTimestamp(){ | ||
@@ -312,2 +58,5 @@ return parseInt((new Date).getTime()/1000); | ||
this.LIBRARY_INFO = LIBRARY_INFO; | ||
this.RED = RED; | ||
//heartbit | ||
@@ -318,5 +67,4 @@ this.last_activity_in = 0; | ||
//iniziate SRS | ||
srs({length: 16, alphanumeric: true}); | ||
this.setMaxListeners(100); | ||
@@ -337,3 +85,3 @@ | ||
} | ||
}, BLYNK_HEARTBEAT * 1000); | ||
}, blynkLib.BLYNK_HEARTBEAT * 1000); | ||
@@ -404,5 +152,5 @@ this.closing = false; | ||
data = data.toString("binary"); //convert to string | ||
if(data.length > BLYNK_PROTOCOL_MAX_LENGTH){ | ||
if(data.length > blynkLib.BLYNK_PROTOCOL_MAX_LENGTH){ | ||
node.warn(RED._("Message too long: "+data.length+"bytes")); | ||
node.sendRsp(MsgType.RSP, node.msg_id, MsgStatus.ILLEGAL_COMMAND); | ||
node.sendRspIllegalCmd(node.msg_id); | ||
return; | ||
@@ -413,13 +161,13 @@ } | ||
if (node.dbg_low) { | ||
node.log("RECV <- " + messageToDebugString(data)); | ||
node.log("RECV <- " + blynkUtil.messageToDebugString(data)); | ||
} | ||
while(data.length>0) { | ||
msgcount++; | ||
if(msgcount>BLYNK_MAX_CMD_IN_MESSAGE) { | ||
if(msgcount > blynkLib.BLYNK_MAX_CMD_IN_MESSAGE) { | ||
node.warn(RED._("Too Blynk commands in a single message: "+msgcount)); | ||
node.sendRsp(MsgType.RSP, node.msg_id, MsgStatus.ILLEGAL_COMMAND); | ||
node.sendRspIllegalCmd(node.msg_id); | ||
break; | ||
} | ||
var cmd = decodeCommand(data); | ||
var cmd = blynkUtil.decodeCommand(data); | ||
data=data.substr(cmd.msgLength); //remove current message from data | ||
@@ -461,129 +209,2 @@ | ||
/* process received Command */ | ||
BlynkClientNode.prototype.processCommand = function (cmd) { | ||
if (!this.logged) { | ||
if (cmd.type === MsgType.RSP && cmd.msgId === 1) { | ||
if (cmd.len === MsgStatus.OK || cmd.len === MsgStatus.ALREADY_REGISTERED) { | ||
this.log("Client logged"); | ||
this.logged = true; | ||
this.sendInfo(); | ||
this.emit("connected", ""); | ||
} | ||
else if(cmd.len === MsgStatus.BLYNK_INVALID_TOKEN) { | ||
this.log("Invalid auth token"); | ||
} | ||
else if(cmd.len === MsgStatus.NOT_AUTHENTICATED) { | ||
this.log("Not autenticated"); | ||
} | ||
else { | ||
this.log("Connect failed. code: "+cmd.len); | ||
} | ||
} | ||
if(cmd.type === MsgType.RSP && cmd.len === MsgStatus.NOT_AUTHENTICATED) { | ||
this.log("Not autenticated"); | ||
} | ||
if(cmd.type === MsgType.CONNECT_REDIRECT) { | ||
//handle server redirect | ||
var schema = "ws://"; | ||
var port = 80; | ||
if (this.path.startsWith("wss://")) { | ||
schema = "wss://"; | ||
port = 443; | ||
} | ||
var values = cmd.body.split("\0"); | ||
var serverip = values[0]; | ||
if(values[1]>0) port = values[1]; | ||
var newpath = schema + serverip + ":" + port + "/websockets"; | ||
this.path = newpath; | ||
this.warn(RED._("Connection redirecting to: ") + newpath); | ||
} | ||
} else { // | ||
this.last_activity_in = getTimestamp(); | ||
switch (cmd.type) { | ||
case MsgType.RSP: | ||
if (cmd.status !== MsgStatus.OK) { //handle not ok response message | ||
var error=false; | ||
for (var k in MsgStatus) { | ||
if (MsgStatus.hasOwnProperty(k)) { | ||
if(cmd.status == MsgStatus[k]) error=true; | ||
} | ||
} | ||
if(error) { | ||
switch(cmd.status){ | ||
case MsgStatus.NOT_AUTHENTICATED: | ||
this.log("Not autenticated"); | ||
break; | ||
case MsgStatus.BLYNK_INVALID_TOKEN: | ||
this.log("Invalid auth token"); | ||
break; | ||
case MsgStatus.ILLEGAL_COMMAND_BODY: | ||
//this.log("Illegal command body"); | ||
break; | ||
} | ||
} | ||
else { | ||
this.warn(RED._("Unhandled RSP type: ") + commandToDebugString(cmd)); | ||
} | ||
} | ||
break; | ||
case MsgType.LOGIN: | ||
case MsgType.PING: | ||
this.sendRsp(MsgType.RSP, this.msg_id, MsgStatus.OK); | ||
break; | ||
case MsgType.HW: | ||
case MsgType.BRIDGE: | ||
//this.warn(RED._(cmd.typeString+" cmd: ") + JSON.stringify(cmd)); | ||
switch (cmd.operation) { | ||
//input nodes | ||
case "vw": | ||
this.handleWriteEvent(cmd); | ||
break; | ||
case "vr": | ||
this.handleReadEvent(cmd); | ||
break; | ||
case "pm": | ||
// skip message "pin mode" | ||
break; | ||
default: | ||
this.warn(RED._("Invalid "+cmd.typeString+" cmd: ") + commandToDebugString(cmd)); | ||
this.sendRsp(MsgType.RSP, this.msg_id, MsgStatus.ILLEGAL_COMMAND); | ||
} | ||
break; | ||
case MsgType.INTERNAL: | ||
switch (cmd.body) { | ||
//app event node | ||
case "acon": | ||
case "adis": | ||
this.handleAppEvent(cmd.body); | ||
break; | ||
default: | ||
this.warn(RED._("Invalid INTERNAL cmd: ") + commandToDebugString(cmd)); | ||
//this.sendRsp(MsgType.RSP, this.msg_id, MsgStatus.ILLEGAL_COMMAND); | ||
} | ||
break; | ||
case MsgType.GET_TOKEN: | ||
this.sendRsp(MsgType.GET_TOKEN, this.msg_id, this.key.length, this.key); | ||
break; | ||
case MsgType.LOAD_PROF: | ||
//this.sendRsp(MsgType.LOAD_PROF, this.msg_id, profile.length, self.profile); | ||
break; | ||
case MsgType.DEBUG_PRINT: | ||
this.log("Server: " + cmd.body); | ||
break; | ||
case MsgType.REGISTER: | ||
case MsgType.SAVE_PROF: | ||
case MsgType.ACTIVATE: | ||
case MsgType.DEACTIVATE: | ||
case MsgType.REFRESH: | ||
// skip this message types | ||
break; | ||
default: | ||
this.warn(RED._("Invalid header type: ") + commandToDebugString(cmd)); | ||
this.sendRsp(MsgType.RSP, this.msg_id, MsgStatus.ILLEGAL_COMMAND); | ||
} | ||
} | ||
}; | ||
BlynkClientNode.prototype.registerInputNode = function (handler) { | ||
@@ -610,2 +231,15 @@ var pinlog = ""; | ||
}; | ||
BlynkClientNode.prototype.registerGenericNode = function (handler, name) { | ||
var pinlog = ""; | ||
var nodeType = ""; | ||
if(handler.pin != undefined) { | ||
pinlog = " pin: " + handler.pin; | ||
} | ||
if(handler.nodeType != undefined) { | ||
nodeType = " type: " + handler.nodeType; | ||
} | ||
this.log("Register "+name+" node" + nodeType + pinlog); | ||
}; | ||
@@ -618,187 +252,60 @@ /* check is pin need to be logged */ | ||
/* build a blynk command */ | ||
BlynkClientNode.prototype.blynkCmd = function (msg_type, values, msg_id) { | ||
var self = this; | ||
values = values || [""]; | ||
if (msg_type === MsgType.RSP) { | ||
return blynkHeader(msg_type, (msg_id-1), values); | ||
} | ||
else { | ||
msg_id = msg_id || (self.msg_id++); | ||
if( typeof values === "string" || typeof values === "number" ) { | ||
values = [ values ]; | ||
} | ||
var data = values.join("\0"); | ||
return blynkHeader(msg_type, msg_id, data.length) + data; | ||
} | ||
}; | ||
BlynkClientNode.prototype.blynkCmd = blynkLib.blynkCmd; | ||
/* send a response message */ | ||
BlynkClientNode.prototype.sendRsp = function (msg_type, msg_id, msg_len, msg_data) { | ||
var data = msg_data || ""; | ||
var msg = null; | ||
if (msg_type === MsgType.RSP) { | ||
msg = this.blynkCmd(msg_type, msg_len, msg_id); | ||
} | ||
else { | ||
msg = this.blynkCmd(msg_type, data, msg_id); | ||
} | ||
BlynkClientNode.prototype.sendRsp = blynkLib.sendRsp; | ||
this.sendMsg(msg); | ||
}; | ||
/* send binary message througth websocket */ | ||
BlynkClientNode.prototype.sendMsg = function (data) { | ||
if (this.dbg_low) { | ||
this.log("SEND -> " + messageToDebugString(data)); | ||
} | ||
BlynkClientNode.prototype.sendMsg = blynkLib.sendMsg; | ||
//convert to Uint8Array | ||
var rawdata = new Uint8Array(data.length); | ||
for (var i = 0, j = data.length; i < j; ++i) { | ||
rawdata[i] = data.charCodeAt(i); | ||
} | ||
this.last_activity_out = this.last_heart_beat = getTimestamp(); | ||
this.websocket.send(rawdata); | ||
}; | ||
/* Send multiple command message - delete key */ | ||
BlynkClientNode.prototype.sendMsgMulti = function (key) { | ||
this.sendMsg(this.msgList[key]); | ||
delete this.msgList[key]; //unset key | ||
}; | ||
BlynkClientNode.prototype.sendMsgMulti = blynkLib.sendMsgMulti; | ||
/* Start multiple command message - generate key */ | ||
BlynkClientNode.prototype.startMsgMulti = function () { | ||
var key = srs({length: 16, alphanumeric: true}); | ||
this.msgList[key] = ""; | ||
return key; | ||
}; | ||
BlynkClientNode.prototype.startMsgMulti = blynkLib.startMsgMulti; | ||
/* process received Command */ | ||
BlynkClientNode.prototype.processCommand = blynkLib.processCommand; | ||
/* send login message */ | ||
BlynkClientNode.prototype.login = function(token) { | ||
if(this.dbg_all){ | ||
this.log("login -> " + String("********************************" + token.slice(-5)).slice(-32)); | ||
} | ||
this.sendMsg(this.blynkCmd(MsgType.LOGIN, token, 1)); | ||
}; | ||
BlynkClientNode.prototype.login = blynkLib.login; | ||
/* send Illegal command response message */ | ||
BlynkClientNode.prototype.sendRspIllegalCmd = blynkLib.sendRspIllegalCmd; | ||
/* send ping message */ | ||
BlynkClientNode.prototype.ping = function() { | ||
if(this.dbg_all || this.dbg_read){ | ||
this.log("ping"); | ||
} | ||
this.last_heart_beat = getTimestamp(); | ||
this.sendMsg(this.blynkCmd(MsgType.PING)); | ||
}; | ||
BlynkClientNode.prototype.ping = blynkLib.ping; | ||
/* send info message */ | ||
BlynkClientNode.prototype.sendInfo = function () { | ||
var info = [ | ||
"ver", BLYNK_VERSION, | ||
"h-beat", BLYNK_HEARTBEAT, | ||
"buff-in", BLYNK_PROTOCOL_MAX_LENGTH, | ||
"dev", "node-red", | ||
"con", "Blynk-ws", | ||
"build", LIBRARY_INFO, | ||
]; | ||
this.msg_id++; | ||
this.sendMsg(this.blynkCmd(MsgType.INTERNAL, info)); | ||
}; | ||
BlynkClientNode.prototype.sendInfo = blynkLib.sendInfo; | ||
/* send syncAll message */ | ||
BlynkClientNode.prototype.syncAll = function(msgkey) { | ||
if(this.dbg_all || this.dbg_sync){ | ||
this.log("syncAll: -> all"); | ||
} | ||
var msg = this.blynkCmd(MsgType.HW_SYNC); | ||
if(this.multi_cmd && msgkey != undefined) | ||
this.msgList[msgkey] = this.msgList[msgkey] + msg; | ||
else this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.syncAll = blynkLib.ping; | ||
/* send syncVirtual message */ | ||
BlynkClientNode.prototype.syncVirtual = function(vpin, msgkey) { | ||
if(this.dbg_all || this.dbg_sync || this.isLogPin(vpin)){ | ||
this.log("syncVirtual: -> " + JSON.stringify(["vr", vpin])); | ||
} | ||
var msg = this.blynkCmd(MsgType.HW_SYNC , ["vr", vpin]); | ||
if(this.multi_cmd && msgkey != undefined) | ||
this.msgList[msgkey] = this.msgList[msgkey] + msg; | ||
else this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.syncVirtual = blynkLib.syncVirtual; | ||
/* send virtualWrite message */ | ||
BlynkClientNode.prototype.virtualWrite = function(vpin, val, msgkey) { | ||
if(this.dbg_all || this.dbg_write || this.isLogPin(vpin)){ | ||
this.log("virtualWrite: -> " + JSON.stringify(["vw", vpin].concat(val))); | ||
} | ||
var msg = this.blynkCmd(MsgType.HW, ["vw", vpin].concat(val)); | ||
if(this.multi_cmd && msgkey != undefined) | ||
this.msgList[msgkey] = this.msgList[msgkey] + msg; | ||
else this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.virtualWrite = blynkLib.virtualWrite; | ||
/* send setProperty message - set msgkey form multimple command message*/ | ||
BlynkClientNode.prototype.setProperty = function(vpin, prop, val, msgkey) { | ||
if(this.dbg_all || this.dbg_prop || this.isLogPin(vpin)){ | ||
this.log("setProperty -> " + JSON.stringify([vpin, prop].concat(val))); | ||
} | ||
var msg = this.blynkCmd(MsgType.PROPERTY, [vpin, prop].concat(val)); | ||
if(this.multi_cmd && msgkey != undefined) | ||
this.msgList[msgkey] = this.msgList[msgkey] + msg; | ||
else this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.setProperty = blynkLib.setProperty; | ||
BlynkClientNode.prototype.sendEmail = function(to, subject, message) { | ||
if(this.dbg_all || this.dbg_mail){ | ||
this.log("sendEmail -> " + JSON.stringify([to, subject, message])); | ||
} | ||
this.sendMsg(this.blynkCmd(MsgType.EMAIL, [to, subject, message])); | ||
}; | ||
BlynkClientNode.prototype.sendNotify = function(message) { | ||
if(this.dbg_all || this.dbg_notify){ | ||
this.log("sendNotify -> " + JSON.stringify([message])); | ||
} | ||
this.sendMsg(this.blynkCmd(MsgType.NOTIFY, [message])); | ||
}; | ||
/* send mail message */ | ||
BlynkClientNode.prototype.sendEmail = blynkLib.sendEmail; | ||
/* send notify message */ | ||
BlynkClientNode.prototype.sendNotify = blynkLib.sendNotify; | ||
/* send bridgeSetAuthToken message */ | ||
BlynkClientNode.prototype.bridgeSetAuthToken = function(bpin, token) { | ||
if(this.dbg_all || this.dbg_bridge || this.isLogPin(bpin)){ | ||
var logtoken = String("********************************" + token.slice(-5)).slice(-32); | ||
this.log("bridgeSetAuthToken: -> " + JSON.stringify([bpin, "i", logtoken])); | ||
} | ||
var msg = this.blynkCmd(MsgType.BRIDGE, [bpin, "i", token]); | ||
this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.bridgeSetAuthToken = blynkLib.bridgeSetAuthToken; | ||
/* send bridgeVirtualWrite message */ | ||
BlynkClientNode.prototype.bridgeVirtualWrite = function(bpin, pin, val) { | ||
if(this.dbg_all || this.dbg_bridge || this.isLogPin(bpin)){ | ||
this.log("bridgeVirtualWrite: -> " + JSON.stringify([bpin, "vw", pin].concat(val))); | ||
} | ||
var msg = this.blynkCmd(MsgType.BRIDGE, [bpin, "vw", pin].concat(val)); | ||
this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.bridgeVirtualWrite = blynkLib.bridgeVirtualWrite; | ||
/* send bridgeAnalogWrite message */ | ||
BlynkClientNode.prototype.bridgeAnalogWrite = function(bpin, pin, val) { | ||
if(this.dbg_all || this.dbg_bridge || this.isLogPin(bpin)){ | ||
this.log("bridgeAnalogWrite: -> " + JSON.stringify([bpin, "aw", pin].concat(val))); | ||
} | ||
var msg = this.blynkCmd(MsgType.BRIDGE, [bpin, "aw", pin].concat(val)); | ||
this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.bridgeAnalogWrite = blynkLib.bridgeAnalogWrite; | ||
/* send bridgeDigitalWrite message */ | ||
BlynkClientNode.prototype.bridgeDigitalWrite = function(bpin, pin, val) { | ||
if(this.dbg_all || this.dbg_bridge || this.isLogPin(bpin)){ | ||
this.log("bridgeDigitalWrite: -> " + JSON.stringify([bpin, "dw", pin].concat(val))); | ||
} | ||
var msg = this.blynkCmd(MsgType.BRIDGE, [bpin, "dw", pin].concat(val)); | ||
this.sendMsg(msg); | ||
}; | ||
BlynkClientNode.prototype.bridgeDigitalWrite = blynkLib.bridgeDigitalWrite; | ||
@@ -812,3 +319,4 @@ BlynkClientNode.prototype.handleWriteEvent = function(command) { | ||
//this.log(util.inspect(this._inputNodes[i], false, 1)) | ||
if ((this._inputNodes[i].nodeType == "write" || this._inputNodes[i].nodeType == "zergba") && | ||
if ((this._inputNodes[i].nodeType == "write" || this._inputNodes[i].nodeType == "zergba" || | ||
this._inputNodes[i].nodeType == "style-btn") && | ||
(this._inputNodes[i].pin == command.pin || this._inputNodes[i].pin_all ) ) { | ||
@@ -819,2 +327,3 @@ var msg; | ||
case 'write': | ||
case 'style-btn': | ||
@@ -832,21 +341,2 @@ msg = { | ||
function rgbToHex(r, g, b) { | ||
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); | ||
} | ||
function hexToRgb(hex) { | ||
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") | ||
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; | ||
hex = hex.replace(shorthandRegex, function(m, r, g, b) { | ||
return r + r + g + g + b + b; | ||
}); | ||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); | ||
return result ? { | ||
r: parseInt(result[1], 16), | ||
g: parseInt(result[2], 16), | ||
b: parseInt(result[3], 16) | ||
} : null; | ||
} | ||
msg = { | ||
@@ -857,15 +347,21 @@ payload: command.value, | ||
msg.hex = rgbToHex(parseInt(command.array[0]), parseInt(command.array[1]), parseInt(command.array[2])); | ||
var color = hexToRgb(msg.hex); | ||
msg.r = color.r; | ||
msg.g = color.g; | ||
msg.b = color.b; | ||
msg.rgb = color.r+";"+color.g+";"+color.b; | ||
msg.payload = [color.r, color.g, color.b]; | ||
if (Array.isArray(command.array) && command.array.length == 3) { | ||
this._inputNodes[i].status({ | ||
fill: "green", | ||
shape: "dot", | ||
text: this._inputNodes[i].connected_label + " ["+color.r+", "+color.g+", "+color.b+"]", | ||
}); | ||
msg.hex = blynkUtil.rgbToHex(parseInt(command.array[0]), parseInt(command.array[1]), parseInt(command.array[2])); | ||
var color = blynkUtil.hexToRgb(msg.hex); | ||
msg.r = color.r; | ||
msg.g = color.g; | ||
msg.b = color.b; | ||
msg.rgb = color.r+";"+color.g+";"+color.b; | ||
msg.payload = [color.r, color.g, color.b]; | ||
this._inputNodes[i].status({ | ||
fill: "green", | ||
shape: "dot", | ||
text: this._inputNodes[i].connected_label + " ["+color.r+", "+color.g+", "+color.b+"]", | ||
}); | ||
} | ||
else { | ||
this.warn(RED._("blynk-ws-client.warn.zergba")); | ||
} | ||
break; | ||
@@ -872,0 +368,0 @@ |
@@ -14,3 +14,3 @@ module.exports = function(RED) { | ||
this.blynkClient.registerInputNode(this); | ||
// TODO: nls | ||
this.blynkClient.on("opened", function(n) { | ||
@@ -20,3 +20,3 @@ node.status({ | ||
shape: "dot", | ||
text: "blynk-ws-in-app.status.connecting" + n | ||
text: RED._("blynk-ws-in-app.status.connecting") + n | ||
}); | ||
@@ -23,0 +23,0 @@ }); |
@@ -20,3 +20,3 @@ module.exports = function(RED) { | ||
this.blynkClient.registerInputNode(this); | ||
// TODO: nls | ||
this.blynkClient.on("opened", function(n) { | ||
@@ -26,3 +26,3 @@ node.status({ | ||
shape: "dot", | ||
text: "blynk-ws-in-read.status.connecting" + n | ||
text: RED._("blynk-ws-in-read.status.connecting") + n | ||
}); | ||
@@ -29,0 +29,0 @@ }); |
@@ -20,3 +20,3 @@ module.exports = function(RED) { | ||
this.blynkClient.registerInputNode(this); | ||
// TODO: nls | ||
this.blynkClient.on("opened", function(n) { | ||
@@ -26,3 +26,3 @@ node.status({ | ||
shape: "dot", | ||
text: "blynk-ws-in-write.status.connecting" + n | ||
text: RED._("blynk-ws-in-write.status.connecting") + n | ||
}); | ||
@@ -29,0 +29,0 @@ }); |
@@ -29,3 +29,3 @@ module.exports = function(RED) { | ||
shape: "dot", | ||
text: "blynk-ws-out-bridge.status.connecting" + n | ||
text: RED._("blynk-ws-out-bridge.status.connecting") + n | ||
}); | ||
@@ -32,0 +32,0 @@ }); |
@@ -12,3 +12,4 @@ module.exports = function(RED) { | ||
if (this.blynkClient) { | ||
// TODO: nls | ||
this.blynkClient.registerGenericNode(this, 'email'); | ||
this.blynkClient.on("opened", function(n) { | ||
@@ -18,3 +19,3 @@ node.status({ | ||
shape: "dot", | ||
text: "blynk-ws-out-email.status.connecting" + n | ||
text: RED._("blynk-ws-out-email.status.connecting") + n | ||
}); | ||
@@ -26,3 +27,3 @@ }); | ||
shape: "dot", | ||
text: "blynk-ws-out-email.status.connected" + n | ||
text: RED._("blynk-ws-out-email.status.connected") + n | ||
}); | ||
@@ -29,0 +30,0 @@ }); |
@@ -13,3 +13,4 @@ module.exports = function(RED) { | ||
if (this.blynkClient) { | ||
// TODO: nls | ||
this.blynkClient.registerGenericNode(this, 'LCD'); | ||
this.blynkClient.on("opened", function(n) { | ||
@@ -19,3 +20,3 @@ node.status({ | ||
shape: "dot", | ||
text: "blynk-ws-out-lcd.status.connecting" + n | ||
text: RED._("blynk-ws-out-lcd.status.connecting") + n | ||
}); | ||
@@ -27,3 +28,3 @@ }); | ||
shape: "dot", | ||
text: "blynk-ws-out-lcd.status.connected-fixed" + node.pin | ||
text: RED._("blynk-ws-out-lcd.status.connected-fixed") + node.pin | ||
}); | ||
@@ -30,0 +31,0 @@ }); |
@@ -15,3 +15,4 @@ module.exports = function(RED) { | ||
if (this.blynkClient) { | ||
this.log("Register notify node - on client: " + this.blynkClient.name); | ||
//this.log("Register notify node - on client: " + this.blynkClient.name); | ||
this.blynkClient.registerGenericNode(this, 'notify'); | ||
@@ -22,3 +23,3 @@ this.blynkClient.on("opened", function(n) { | ||
shape: "dot", | ||
text: "blynk-ws-out-notify.status.connecting" + n | ||
text: RED._("blynk-ws-out-notify.status.connecting") + n | ||
}); | ||
@@ -34,3 +35,3 @@ }); | ||
shape: "dot", | ||
text: "blynk-ws-out-notify.status.connected" + queuestr | ||
text: RED._("blynk-ws-out-notify.status.connected") + queuestr | ||
}); | ||
@@ -37,0 +38,0 @@ }); |
@@ -26,3 +26,3 @@ module.exports = function(RED) { | ||
shape: "dot", | ||
text: "blynk-ws-out-set-property.status.connecting" + n | ||
text: RED._("blynk-ws-out-set-property.status.connecting") + n | ||
}); | ||
@@ -103,9 +103,9 @@ }); | ||
} | ||
//buttons | ||
//buttons and styled buttons label | ||
if ((msg.hasOwnProperty("onlabel") || msg.hasOwnProperty("offlabel")) && node.blynkClient && node.blynkClient.logged) { | ||
if (msg.hasOwnProperty("onlabel")){ | ||
if (msg.hasOwnProperty("onlabel")) { | ||
var onlabel = Buffer.isBuffer(msg.onlabel) ? msg.onlabel : RED.util.ensureString(msg.onlabel); | ||
node.blynkClient.setProperty(pin, "onLabel", onlabel, msgkey); | ||
} | ||
if (msg.hasOwnProperty("offlabel")){ | ||
if (msg.hasOwnProperty("offlabel")) { | ||
var offlabel = Buffer.isBuffer(msg.offlabel) ? msg.offlabel : RED.util.ensureString(msg.offlabel); | ||
@@ -115,2 +115,23 @@ node.blynkClient.setProperty(pin, "offLabel", offlabel, msgkey); | ||
} | ||
//styled buttons color (need server v0.36.2) | ||
if ((msg.hasOwnProperty("onColor") || msg.hasOwnProperty("offColor") || | ||
msg.hasOwnProperty("onBackColor") || msg.hasOwnProperty("offBackColor")) | ||
&& node.blynkClient && node.blynkClient.logged) { | ||
if (msg.hasOwnProperty("onColor")) { | ||
var onColor = Buffer.isBuffer(msg.onColor) ? msg.onColor : RED.util.ensureString(msg.onColor); | ||
node.blynkClient.setProperty(pin, "onColor", onColor, msgkey); | ||
} | ||
if (msg.hasOwnProperty("offColor")) { | ||
var offColor = Buffer.isBuffer(msg.offColor) ? msg.offColor : RED.util.ensureString(msg.offColor); | ||
node.blynkClient.setProperty(pin, "offColor", offColor, msgkey); | ||
} | ||
if (msg.hasOwnProperty("onBackColor")) { | ||
var onBackColor = Buffer.isBuffer(msg.onBackColor) ? msg.onBackColor : RED.util.ensureString(msg.onBackColor); | ||
node.blynkClient.setProperty(pin, "onBackColor", onBackColor, msgkey); | ||
} | ||
if (msg.hasOwnProperty("offBackColor")) { | ||
var offBackColor = Buffer.isBuffer(msg.offBackColor) ? msg.offBackColor : RED.util.ensureString(msg.offBackColor); | ||
node.blynkClient.setProperty(pin, "offBackColor", offBackColor, msgkey); | ||
} | ||
} | ||
//menu | ||
@@ -136,2 +157,7 @@ else if (msg.hasOwnProperty("labels") && node.blynkClient && node.blynkClient.logged) { | ||
} | ||
//fraction on slider widget (need server v0.33.3) | ||
else if (msg.hasOwnProperty("maximumFractionDigits") && node.blynkClient && node.blynkClient.logged) { | ||
var fraction = Buffer.isBuffer(msg.maximumFractionDigits) ? msg.maximumFractionDigits : RED.util.ensureString(msg.maximumFractionDigits); | ||
node.blynkClient.setProperty(pin, "maximumFractionDigits", fraction, msgkey); | ||
} | ||
@@ -138,0 +164,0 @@ if(node.blynkClient.multi_cmd) { |
@@ -23,3 +23,3 @@ module.exports = function(RED) { | ||
shape: "dot", | ||
text: "blynk-ws-out-sync.status.connecting" + n | ||
text: RED._("blynk-ws-out-sync.status.connecting") + n | ||
}); | ||
@@ -26,0 +26,0 @@ }); |
@@ -14,3 +14,4 @@ module.exports = function(RED) { | ||
if (this.blynkClient) { | ||
// TODO: nls | ||
this.blynkClient.registerGenericNode(this, 'table'); | ||
this.blynkClient.on("opened", function(n) { | ||
@@ -20,3 +21,3 @@ node.status({ | ||
shape: "dot", | ||
text: "blynk-ws-out-table.status.connecting" + n | ||
text: RED._("blynk-ws-out-table.status.connecting") + n | ||
}); | ||
@@ -28,3 +29,3 @@ }); | ||
shape: "dot", | ||
text: "blynk-ws-out-table.status.connected-fixed" + node.pin | ||
text: RED._("blynk-ws-out-table.status.connected") + node.pin | ||
}); | ||
@@ -97,3 +98,21 @@ }); | ||
} | ||
if (msg.hasOwnProperty("select")) { | ||
if(Number.isInteger(msg.select) && msg.select>=0) { | ||
node.blynkClient.virtualWrite(node.pin, ["select", msg.select.toString()], msgkey); | ||
} | ||
} | ||
if (msg.hasOwnProperty("deselect")) { | ||
if(Number.isInteger(msg.deselect) && msg.deselect>=0) { | ||
node.blynkClient.virtualWrite(node.pin, ["deselect", msg.deselect.toString()], msgkey); | ||
} | ||
} | ||
if (msg.hasOwnProperty("order")) { | ||
var args = Array.isArray(msg.order) ? msg.order : []; | ||
if(args.length==2) { | ||
var cmd = ["order"]; | ||
node.blynkClient.virtualWrite(node.pin, cmd.concat(args), msgkey); | ||
} | ||
} | ||
if(node.blynkClient.multi_cmd) { | ||
@@ -100,0 +119,0 @@ node.blynkClient.sendMsgMulti(msgkey); |
@@ -23,3 +23,3 @@ module.exports = function(RED) { | ||
shape: "dot", | ||
text: "blynk-ws-out-write.status.connecting" + n | ||
text: RED._("blynk-ws-out-write.status.connecting") + n | ||
}); | ||
@@ -26,0 +26,0 @@ }); |
module.exports = function(RED) { | ||
"use strict"; | ||
var blynkUtil = require('./../libs/blynk-util.js'); | ||
function BlynkZergbaNode(n) { | ||
@@ -13,22 +15,2 @@ RED.nodes.createNode(this, n); | ||
function rgbToHex(r, g, b) { | ||
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); | ||
} | ||
function hexToRgb(hex) { | ||
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") | ||
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; | ||
hex = hex.replace(shorthandRegex, function(m, r, g, b) { | ||
return r + r + g + g + b + b; | ||
}); | ||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); | ||
return result ? { | ||
r: parseInt(result[1], 16), | ||
g: parseInt(result[2], 16), | ||
b: parseInt(result[3], 16) | ||
} : null; | ||
} | ||
this.blynkClient = RED.nodes.getNode(this.client); | ||
@@ -41,3 +23,3 @@ if (this.blynkClient) { | ||
shape: "dot", | ||
text: "blynk-ws-zergba.status.connecting" + n | ||
text: RED._("blynk-ws-zergba.status.connecting") + n | ||
}); | ||
@@ -78,3 +60,3 @@ }); | ||
var hex = Buffer.isBuffer(msg.hex) ? msg.hex : RED.util.ensureString(msg.hex); | ||
var color = hexToRgb(hex); | ||
var color = blynkUtil.hexToRgb(hex); | ||
newmsg.hex = hex; | ||
@@ -92,3 +74,3 @@ newmsg.r = color.r; | ||
var b = Buffer.isBuffer(msg.b) ? msg.b : RED.util.ensureString(msg.b); | ||
newmsg.hex = rgbToHex(parseInt(r), parseInt(g), parseInt(b)); | ||
newmsg.hex = blynkUtil.rgbToHex(parseInt(r), parseInt(g), parseInt(b)); | ||
newmsg.r = msg.r; | ||
@@ -103,4 +85,4 @@ newmsg.g = msg.g; | ||
if(tmpcolor.length == 3){ | ||
newmsg.hex = rgbToHex(parseInt(tmpcolor[0]), parseInt(tmpcolor[1]), parseInt(tmpcolor[2])); | ||
var color = hexToRgb(newmsg.hex); | ||
newmsg.hex = blynkUtil.rgbToHex(parseInt(tmpcolor[0]), parseInt(tmpcolor[1]), parseInt(tmpcolor[2])); | ||
var color = blynkUtil.hexToRgb(newmsg.hex); | ||
newmsg.r = color.r; | ||
@@ -115,4 +97,4 @@ newmsg.g = color.g; | ||
if(tmpcolor.length ==3){ | ||
newmsg.hex = rgbToHex(parseInt(tmpcolor[0]), parseInt(tmpcolor[1]), parseInt(tmpcolor[2])); | ||
var color = hexToRgb(newmsg.hex); | ||
newmsg.hex = blynkUtil.rgbToHex(parseInt(tmpcolor[0]), parseInt(tmpcolor[1]), parseInt(tmpcolor[2])); | ||
var color = blynkUtil.hexToRgb(newmsg.hex); | ||
newmsg.r = color.r; | ||
@@ -119,0 +101,0 @@ newmsg.g = color.g; |
@@ -13,3 +13,4 @@ { | ||
"pin-value":"Set Property node - The msg.pin must be between 0 and 127.", | ||
"property":"Set Property node - Please select a property." | ||
"property":"Set Property node - Please select a property.", | ||
"zergba":"Warning - zeRGBa not configured in merge mode." | ||
}, | ||
@@ -16,0 +17,0 @@ "errors": { |
@@ -6,3 +6,3 @@ { | ||
"connecting": "connecting ", | ||
"connected-fixed": "connected to pin V", | ||
"connected": "connected to pin V", | ||
"disconnected": "disconnected" | ||
@@ -17,2 +17,2 @@ }, | ||
} | ||
} | ||
} |
{ | ||
"name": "node-red-contrib-blynk-ws", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"description": "Node Red integration with Blynk App and Server through websockets", | ||
@@ -44,5 +44,6 @@ "scripts": { | ||
"blynk-ws-out-table": "nodes/blynk-ws-out-table.js", | ||
"blynk-ws-zergba": "nodes/blynk-ws-zergba.js" | ||
"blynk-ws-zergba": "nodes/blynk-ws-zergba.js", | ||
"blynk-ws-style-btn": "nodes/blynk-ws-style-btn.js" | ||
} | ||
} | ||
} |
@@ -36,15 +36,21 @@ [![npm version](https://img.shields.io/npm/v/node-red-contrib-blynk-ws.svg)](https://www.npmjs.com/package/node-red-contrib-blynk-ws) | ||
- read event | ||
- write event | ||
- app event | ||
- write command | ||
- bridge command | ||
- sync command | ||
- set property command | ||
- emails widget | ||
- notify widget | ||
- LCD widget | ||
- Table widget | ||
- zeRGBa widget | ||
**Events:** | ||
- read | ||
- write | ||
- app (connected/disconected) | ||
**Commands:** | ||
- write | ||
- bridge | ||
- sync (virtual/all) | ||
- set property | ||
**Widgets:** | ||
- emails | ||
- notify | ||
- LCD | ||
- table | ||
- zeRGBa | ||
- styled button | ||
### Changelog | ||
@@ -89,3 +95,3 @@ | ||
### Implementations for other platforms | ||
* [Arduino](https://github.com/blynkkk/blynk-library) | ||
* [C++, Arduino](https://github.com/blynkkk/blynk-library) | ||
* [Node.js, Espruino, Browsers](https://github.com/vshymanskyy/blynk-library-js) | ||
@@ -92,0 +98,0 @@ * [Particle](https://github.com/vshymanskyy/blynk-library-spark) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
151302
57
2295
112