From 7802ab0f63fa62b416322cb5ba3a3454acad673d Mon Sep 17 00:00:00 2001 From: dehsgr Date: Sun, 22 Nov 2020 19:59:49 +0100 Subject: [PATCH] Initial commit. --- LICENSE | 12 +++++++ README.md | 16 +++++++++ meross/icons/smartplug.png | Bin 0 -> 8492 bytes meross/meross-config.html | 28 +++++++++++++++ meross/meross-config.js | 12 +++++++ meross/smartplug-control.html | 40 ++++++++++++++++++++++ meross/smartplug-control.js | 62 ++++++++++++++++++++++++++++++++++ package.json | 24 +++++++++++++ 8 files changed, 194 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 meross/icons/smartplug.png create mode 100644 meross/meross-config.html create mode 100644 meross/meross-config.js create mode 100644 meross/smartplug-control.html create mode 100644 meross/smartplug-control.js create mode 100644 package.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9233f80 --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +Copyright 2019 d3h56r + +Permission to use, copy, modify, and/or distribute this software for any purpose with +or without fee is hereby granted, provided that the above copyright notice and this +permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN +NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8546728 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# node-red-contrib-meross + +This provides nodes for locally controlling e.g. Meross Smart Plug (without cloud!). It's requiring a Merross token and a corresponding timestamp to be provided by you. You should get this data via network sniffer or traffic interception between your Meross app and your Smart Plug. node-red-contrib-meross delivers 2 nodes: + +## Meross Config +Meross Config is a config node to set the token and timestamp for being able to locally communicate with your devices. + +## Meross Smart Plug +Meross Smart Plug can be used to set smart plugs state and/or poll its current state. For setting smart plugs state to on|off you simply provide a boolean value (true|false). To request its current state you send any non-boolean payload. + +# Currently supported devices +- Meross Smart Plug MSS210(EU) + +# Requesting additional devices +To be able to implement additional devices feel free to provide sniffed communication between your app and devices. +You might also feel free to directly contribute in this project. \ No newline at end of file diff --git a/meross/icons/smartplug.png b/meross/icons/smartplug.png new file mode 100644 index 0000000000000000000000000000000000000000..fcdd61edd8b5f0b34114a7f62b75db8557dee3f8 GIT binary patch literal 8492 zcmV+{A=BQ8P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3;ucAPhmZ2w~wy@U@lupEr%^bX$g`vy=Y4w7Zd zexgNEHJ}nXL`EcFv;N=zZu39<$u2)8#9UHM>ETbPp}NK|<+*?A`EH+ZzMntt{ha;! zxbfrlgySL4Pk;ZJ+w1j>$K%Hveyr2KK5k0+@kw`~*Awpry*}CT%lvF4kGuQ04X=gj zy1%4a@@G@KyFbV4g~ycFU!Tv?KNiuy&F2R~#!EBuD(~F#)<5TaxEA>PxABPOyW=(3 z>&tlrADxF@mf(;t+k5|fp3e^Y;^g-7rTOmtAHRKbzH6_?{Wo8x_d@B{PuTct=N}h; z`e6V1&G7J-C)_5m-?#JnyZ0=6ue-Yz5*|&jjC#!5J9-Z*KW|l7ljmyzT*PNb zjG+XAeUkOjCi`UPvbFfJ5TJ(T&Ii|tfQ`{jjC8^K9cuHw&%4jy5#gQ*hCKnldA(B5i6mqCVA47~W#T<)?HMZnaNHL|9lR&OzpF@s0<(x~dxfNeRi6xa> zN~xt)S3MXQYpS`HT5D_0G(M=YR^#=JN4o32haP+CxtCsh8>G(&BaSrkD5H)x-SiWf zm}%x&W}R(Wvp|X!R$OW2RaRYXlWW`Wu;WfU@3QM|KcZ$|W&8c>529vYQFA9!dR_hz zH6ArNzn8Frlc<;xF&8Wm&x!yE?G&@8*btl|r?T^@f zMD8EO&BXGL;^zJ?az>&1{}DMu=zfmdFQPVu&ErJuR-t_Qc&d-*S82wTrl!{Z>(76< zQ14?uF%QQ^`pA{qnXTcToLd6!LNxiAX^ozv^R3$ijLd3Do09yqeBVuVIl&s=RxUNi zI^B*qZ@T3Bm^RHFeW?bpZ%_v}dylc&3LvL6`ZL>{{sB!#_HoC)aCy)-A9*GJ%q`Cr z%Xr3$vw72rf1==Lp^*j{fcNx^L?mDcxyC&J;=)=2wKDc5wtF~IBR0EQ->GcZ*D!PU zMvRDO?>pz+MzCcpf>>v^YsOXVUBu<$_1h{j%tycBHvPhH)*F6}v==+h1GErW#d%S) z5j3LIYz}9E5$11}G#_iemt1)-pLU76`PK8XPhXP+rK9ZN@m^SoOdGY=-JJ`udtlXc zpT{Ul{umUenL52}L{cr1%yn6!hC5fUdFS3@sELf{Z7oTt>qUOO1Fx4LsV#k#$%J^7Q@eKK#sn*@&Yb zl4dw!&W2p*u2wh0AYu;>QT?DvNrPO;CMQy*46?S?<-&fjn^o)#N&d)g>@~%hUhlr(GvFu+fnwgkf3_GECE+1d0GUzST*#wY(@R z{^^L^TyPCGN4mE{x;sw|^aUl6KZe_F`7khkHnZi^jW^rG^4ctk|E$Sgo<_YKZ(2gx zi|iVq@+M;}@tV1wq!TeA7kC!>a^4!iq*ZG^9LrBVHakBSrLrD7 z2^j%j21Jh{dV>lI`M!1Zjk}jVtb~)zE4aK z*r95(d#v&&@BQ*tv$`e0s^JBX!1Z=R7qILV9J@-#1aCE(*5MFrIkJvRI{k=zbd_^84!8&WviOic=?>=aPm$R0htYhs5wz(d2JOdw8LAlm?o^eQ_)ihg4*Ga z7zx@AQuGul9$gD^mMV2vC=wcp4|UU}*H#}65m-yOfOeShnVC~`CuNeGv`^(v!1D7? zbI?<^9W;_@;LR}(X&%m2y2?lxbK4><10lmBSw%;_pU1@NGETk3GrmF zWzYa{MBKuxJdopbD;A{*+(lt7$rBqgyPZWz+_lCW(wZ#U31SX|Oo1AJHxmTK-9=Qu z9`}Mw<3JwqZqPw*u4`d$KpWUXi04$4S)UY3kj4!Su5(bWb6Z@lq6nW#4sz&6GGtuX z2p#^tI*64Zj?2L@lciD6Zx=b%X@QsYHH;>>M^k}kl92%2TU#Y+Va1R!3S~cCE z_qzDg!~kl`s9roK89%_Gu%t!c9jzS?hF22c90di6)gg|!rj*-X){7xcJKrqoNg&_e z*(i3DwmQwFNB?p;bJzQ_T<#DRk`wqJ?6^4C;@&q!`&nwr$9aEV&U`lSyj>K3Y-HJ zU+%PR1GY*F=sYePQLX|b1W5W7Eu#KD08;w&+K)>}Ksynd51$xw1YD3qvp{g@K>>(H zB8x9V?;r&y0N|q87GvfUy2|6k#h*A@vK<=uxnGDJmC0`FOj)%F%2(cYRzxgc!JI*#uy>siBwSuZckmW7Lji$BSrCSMrNbId23R)b5c== zPd*OnvQj-ENH(60;FfS*uL)+fl06iyL`PpxSEx1EPcQYUOo=Dnv2&^`Q~RlviSTxv zhE{3(^l{R=WJDRvsnO`^YdBhbk~rXPh(XY{cYqQg=-6dN&;y{>2BbSiXw&0B(uRHE zkfAy-)Ie6Gkqx(|k&Gp?CznJ&)fe_eHExL$)WdEN2{G__m@sabNkKOYQEDZK8XPgv z62b3@;?R(B3|b3n333dfa@oma<+y*|FdmRhw~L3Nia((^U?n_3#u7z;|BI0N4 zaNrI*54$5MYo_A8gCev>te&5R&p*ikGJg@Ra$pLz zr7`xY3K)LE(X0RpmE$GeOwqzGZz4FDu!#o&0Y-S;Za%pSLqBtTQjk(UVW|#>9!Jjt zr=rW)XxJ-~Re@Jw&V6v^qA~(*oR>ETYVKOJUZX%kU`ww+u4Gn*-cj>Lt$GXk*&vkJe$;m>Q)c(HPs8qe%#4~A%+7~=uj!PoKZYS?ueU(t0f`NBbB=m zoQx43w8_+*R4p+_4Xlbq66Ma3gLFD|Ju)P22-+OSMMRf04jt_cU_Ss$Ya~lc(BUl&pK|{qA3iN3NK02TRu~Jxe7_QBH#G;@zFXNK}J}Ehd(gqM%a0;JMXEd?JL_X>0 zU=CZ0O$cs8ctu;V{-&W7Q{V0I zg!<~fZ^n_YgbZ=d8l1y~z&Ej$?14vtrovn&VI#u5BxJ{fM#;38 z71GHUSPL>&P*coU!h}1-pykGxJDA$EP&Xi`QIHhmU z!xBAS=LTC`IVnmT;)BiJO9wdVT2O!r#U?^v@`Ij&PGW~FLd2qF?M0oEo5)jfEeLZu zSUCOuglR%F0UB^-!r_X4hiH%*VcHwfUU(*c904>)D**Eqy{nTNm=N5cv{N8L zd_D}vJZI1~@1$aB@ zrsjiWW>Jw>4U;qweSs}+MLIPnu-!EmS{mR_qS5UT#!BnBMWa8`joLryhUc_@mcY9>j&^kxYLX$v&7K+KDX=#ruk2bz^H1 zOQ+Q~b%)}`0HF-loaqR@XyLr*>?CPV0J}Rh} z=Ph$d*ArVMY`HVtghlbz{yX(`JoLQryB_@3P7_H{5C@D;1`4EtwGRdEq^RJVqUwHmS1;G5P;7p{(#VW$YRLbkch-8XmbRAa6!^wvY|j9L20$)*a%@? zI*W*v?6nPM=AkD2gl>#8nD>w`TcU@QK_|f++B*`~RvpsGl%kwj&1j5yxChj0Hu2Qi z+}7z&mnH?P=+)h$L6!#2It|WeDlbDy*5n-zbujxuSEq^f5sAmPDHZ4D3@!nkvDSbR z1abYj_A^Jzu%M!-(S!PH)&p5II+cA!y3E;~K&dY@IRJN^gIY)xiJ{|+L$Z4G-A+s; z;)8Y(psL;^9a11YY;ic8>Zngr1872)?;rc|srt;iKc$6fDipEyLn-~!C*6DJC%-;tL`-&cUQE#96nq&znh`~sDk&@JPeO4b3^Wgq81dfL{oe!?FT9B zGaT}Xvp`D+6-5Ue&m7VS3sAr-=OEh6Hjdt-mmd8a&mabdJxQi}dTY+{Em{tj#1~+! zNRaj*sl}pljyg~Fgjk#(=cXo_MAm)sbz-3atV8$_-;WN#@eQeb7{~9b{ax%({UTSH zdB$P|Q)&NM&GV8rz}V{`VtKJ8+mE~$GKY3_fHHi61@p^(DqPqvi2H}2U@j_<1AjZ? z6UTlNLJdzY9J(|4XQ8SI|8pTw4O-`8)}H$lM^Z;ND2tRdlGFx5F(TD!^&}=OYb2AMHXDMT zR@UZGVa2y|5N5BrI%jy#+=*^|9W&VXF@p}~o_I$+ucO1V-$Qp7@67$EN2t#G;NtHV zG=ZJtR|+v>V&!*wPtF>0tM!xZ33UzaN9=}t=5=6v%&*fL^5~Ho_L^utE>($mQjpA8 zwRIiiQ-HtU*-IS23`MCKInE%d!cp@@^GCq{bKdniV+wSkcsWVcQDWBQk7!$a zXKeJzpkRvEOf{o>AHdY<&ZRO9ohhp7;u)@j94|6 zWJXe!&>%^)JqJ0d-ngVal<%4@&#CJ`s&e&*tebfITzY_wu#yfk>Gv>Q$*OyhNki6h zy$(pBh~~3ExvfsDW5=HaySW3%PlEjyO5$fm^s|yMS2_O`S=m2Ekf&na673wp>xRn5 z5xk-8%r-xr!8_l+pTXl`jms5Sh)5w8EWpM+t9#NzBOF8F>NvWrm}xTZ9FFtNllOJg zB86j3=L@mY@DVETfK=CLI*bKZQg}kEDG;^s=$<5R#v!iNJMjVoH18u^uIZ#GQaQSj zXEpX9cL^odr0sm5i_sZTkYvA8MLBBMuOcM@ttgNn9XHsK$4wC_*CP^+V|0~F!c}MQ zDkwt(r4iH+c&MCN(V%+)!Wvo-M!cL~YF~Y_Rb2@p0=M(D*Rfb_=4$+VVdy-sXIY~> zuQgsT{N?NR$MWXu`kz<$ODp=L+E9szKApjV2>a{W-FlCD6!w!@^EErr;nCb~d<=Uu zH_c*H5S`U07`?3_9J-PiX9JXcunxWg89_lo9_idg!v8_wL}-&^eGw&VbtZ3hO1Hd7 zlbz;@tm&+-3c+Bm$Vw41ZEHOu3l<8?J|b(SuZM{r)nxusn5%Zj3(U3oc5fhxkAJ#T zaayRZRG8PD3TVdnI~A?OFSVIz2RfN(P+i+Z4#fwirqFXobDQE$x|yhJHP3dqW~=HT z*s2)tL+blAaMv75H|i96$i#5x;#;1kzs}0Gdo`JuaSeT=uovOA*P)wY)7!mP_9HdE zjHAq*N2T)HA=F8(*BXEEIwdS_pu%^?5bfZr4-YcuTR#9nWutom3+I!)^)e6?{iS7qxNa0 zQW2uCvW{Hn%Vk#8F70qqW}qX;zg=b#QNWwsHuj&c_hRuG6Il+l`da&MXhTbraNB?$LkJnW}_X{Db-n1bl6zM zjs-9gU0Cap((zmidUVC_-qe^_eP=ZBHC|1pL-f-jOn82OJ2mS@3ekLTG)QnF9^#$u z;s%|O?qw+Q`uNw;w=P)xIQqVq^a$QX^|xu)uxpll`!dTMyJXf6qr`2Ky@Quy*mtwS zRlzT_l#X3@{bbiqW=SlU*BHLdo9)-Mzw(*+?zDgFGxObP|JG;byVL%y&&+qH9kV(b zNJr_g8XGS+T9bOz3y=7ORN%f%uYnX$s?P1t3a~d}Fw*T%z zqzV7_Cgr^yMe7HP{tt{7+76C&;i>=t0fcEoLr_UWLm+T+Z)Rz1WdHzpoPCi!NW(xJ z#a~mUqAem85pl>+oh*ooIBFG&P$AR`tvZ-o`UOoIk`@<7!L{Jv$70pN#aUMeS3wZ` z0C943Qgo3L|Cbb6#CUMrk9YSTckck9USgWnF%D>Y#Z1OyVmh-b242yF0rVk&kjyM& zPLdMv9AEeF@%1jsv%Js!IYMgIVt`L1o@ItvA>JUK-mDm$_ld)-AgjdZ#A7C1kob}7 zipy`D^9~Cotd5g1FsRA0S2E8 z*_0j0PgBU{fcG={rVP-33v{o!y*2l7`T(S;tHcd(a0ra%DSO@H-Cgay{d=a_-wzpk za)Y^({lowO00v@9M??S`00961($QXP00009a7bBm000XU000XU0RWnu7ytkO2XskI zMF->y77+>-P<&qc000F$NklZL1XQ-n%4NPXyr1sN2ikd+o?6b71=LP?D}onH^G1Dov` z=bSln@nQaO;M?o$z1Dw!mv!4Pgdq$rqFDuMD{umEGH_(-`~z4Id>;`z2IbAvgVp=h z@6}!Ii7xdQ^)YqqK$B}%H(EdbROhNK{l3KNeZZqY)z~gzHSiJe15g2u1EvAz0sB`U z1)c})h=@vm&fbOUww#$|>ZFv9RVS-c)MHXML48@Rs5{i_2Wp9@sQ0QZ>c#5HBvD00 z{ZgH&wyHO(*AB)(c_K!%q-@?Ao-MSZ}H)<) zcn>hO#>DPQf7YL90fv=i(~{G}s3SAmDB?HuCiRd3@BoLXH>b^V1~d|NR_Tu&>f}Li zRTre~B4)J$XO-^#0{E;! zfXP5x>6V@9Dqtz_Rzz&uYhoIqx}ijHOiPWV)gFlLr``>$16}|wszHvFT?D)ctXJo& z`}OqRW!|j~F6B7j^)y^X1=s+r1vaH@955-Dy#*KxECeoBZ>%e7^c3o9kUIwW5IC_w zY-t+)CL(s0?r#H5O?Po!61^DsM7<;;e(ke-P(28EyFhLuaA`!`5D{z2QNs zmjP8mCjxJ)2li#c`Y3RAj(-NGM#M*TS7s3(0v7_mr05*rkv<`)o(|lam)n8%i1?}D z@^SYw?S%|{u6kNu%;24cQ~G2?tm$tMZ{lCH-mQTSe}=oN{+cUljBR4dda>iAl^YJ}Q` z{NPcAaq(a*2F}g#x#~#~@kfc=VZbtAOp1=pR!CXb(ap@@@KWti#TkY1=x&T0U5fK( zcB5-}GX(!Gj7Js5uNB5?fbVKN`(6H5#jD-u`m32GE-u9>zy~>=2YdpI1Qtg`XN|+q zsZIlKND^sI!4*Qbz@t9}&OzRl2pf@V0H~GM=cXELBHk4DTo;9nS$v z>V3OKrBZLvUivm2rPjzM^#OHKwoY2|cW}xcP&b!a8y(&CUutrxmtcY9-D+p)ng7%+ z>W}%`lCmN?vv6u{WU?A+0Y^kvL@dkz{|?Yu*eZu-ku)*KRo$I=?^zM?WJGi|+8-=G zFsu%u->Nf#@xT>X44n!bQ8=MrXAgTh@N=Dg>T>zog}R_Lt?RNP8|cAf7PhLl70E?64We6sE7|=OeMCR+!GGBO8ErZ6YD8>e2tyb` a{rDdWMR*QjsjkQX0000 + RED.nodes.registerType('meross-config', { + category: 'config', + defaults: { + name: { value: '' }, + timestamp: { value: '', required: true, validate: RED.validators.number() }, + token: { value: '', required: true } + }, + label: function() { + return this.name || 'Meross'; + } + }); + + + diff --git a/meross/meross-config.js b/meross/meross-config.js new file mode 100644 index 0000000..cb6a435 --- /dev/null +++ b/meross/meross-config.js @@ -0,0 +1,12 @@ +module.exports = function(RED) { + function MerossNode(MyNode) { + RED.nodes.createNode(this, MyNode); + this.token = MyNode.token; + this.timestamp = MyNode.timestamp; + } + + RED.nodes.registerType("meross-config", MerossNode, { + token: { type: "text" }, + timestamp: { type: "text" } + }); +}; \ No newline at end of file diff --git a/meross/smartplug-control.html b/meross/smartplug-control.html new file mode 100644 index 0000000..9ff0960 --- /dev/null +++ b/meross/smartplug-control.html @@ -0,0 +1,40 @@ + + + + + + + + \ No newline at end of file diff --git a/meross/smartplug-control.js b/meross/smartplug-control.js new file mode 100644 index 0000000..1d50c14 --- /dev/null +++ b/meross/smartplug-control.js @@ -0,0 +1,62 @@ +const request = require('request'); + +module.exports = function(RED) { + 'use strict'; + + function SmartPlugNode(myNode) { + RED.nodes.createNode(this, myNode); + var Platform = this; + + this.config = RED.nodes.getNode(myNode.confignode); + this.ip = myNode.ip; + + this.on('input', function (msg) { + request.post({ + url: 'http://' + Platform.ip + '/config', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + 'header': { + 'messageId': 'd31722ef727e2314ad0736cb99beb11f', + 'method': (typeof msg.payload === 'boolean') ? + 'SET' : + 'GET', + 'from': 'http://' + Platform.ip + '/config', + 'sign': Platform.config.token, + 'namespace': (typeof msg.payload === 'boolean') ? + 'Appliance.Control.ToggleX' : + 'Appliance.System.All', + 'timestamp': parseInt(Platform.config.timestamp), + 'payloadVersion': 1 + }, + 'payload': (typeof msg.payload === 'boolean') ? + { + 'togglex': { + 'onoff': msg.payload ? 1 : 0, + 'channel': 0 + } + } : + {} + }) + }, function(myError, myResponse, myBody) { + if(myError) { + Platform.warn('There was an Error: ' + myError); + } else { + var j = JSON.parse(myResponse.body); + try { + var r = (j.header.method !== undefined && j.header.method === 'SETACK') ? + msg.payload : + j.payload.all.digest.togglex[0].onoff === 1 ? true : false; + } + catch (e) { + var r = 'Received unexpected data!'; + } + Platform.send({ payload : r }); + } + }); + }); + } + + RED.nodes.registerType('smartplug-control', SmartPlugNode); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..3eccca0 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "node-red-contrib-meross", + "version": "1.0.0", + "description": "This provides nodes for controlling Meross devices.", + "author": "d3h56r", + "license": "ISC", + "keywords": [ + "node-red", + "meross" + ], + "node-red": { + "nodes": { + "meross-config": "meross/meross-config.js", + "smartplug-control": "meross/smartplug-control.js" + } + }, + "repository": { + "type": "git", + "url": "https://github.com/dehsgr/node-red-contrib-meross.git" + }, + "dependencies": { + "request": "^2.75.0" + } +}