From 14c29b6718c68cb8d36d23b4f9a4510f4f647071 Mon Sep 17 00:00:00 2001 From: Nico Melone Date: Thu, 14 Dec 2023 13:16:36 -0600 Subject: [PATCH] updated code for chunking and reorganized --- .DS_Store | Bin 10244 -> 10244 bytes Pub_Sub/.DS_Store | Bin 24580 -> 26628 bytes .../convert_config.cpython-310.pyc | Bin 2902 -> 0 bytes .../__pycache__/convert_config.cpython-39.pyc | Bin 2492 -> 0 bytes ...bbflow_tb_v1.cfg => abbflow_rtu_tb_v1.cfg} | 0 .../thingsboard/abbflow_rtu_tb_v3.cfg | 4 - .../thingsboard/abbflow_tcp_tb_v3 lively.cfg | 383 ++++ .../thingsboard/abbflow_tcp_tb_v3.cfg | 4 - .../advvfdipp/thingsboard/advvfdipp_tb_v5.cfg | 2 +- .../thingsboard/sub/receiveCommand.py | 6 +- .../thingsboard/advvfdipp_sru_tb_v3.cfg | 1960 +++++++++++++++++ .../thingsboard/sub/receiveCommand.py | 6 +- .../advvfdipp_wo_downhole_tb_v2.cfg | 654 ++++++ .../thingsboard/sub/receiveCommand.py | 6 +- .../cameratrailer/thingsboard/pub/sendData.py | 1 + .../thingsboard/pub/sendData.py | 1 + .../thingsboard/cpadvvfdipp_tb_v5.cfg | 1221 ++++++++++ .../cpadvvfdipp/thingsboard/pub/sendAlarms.py | 201 ++ .../cpadvvfdipp/thingsboard/pub/sendData.py | 323 +++ .../thingsboard/sub/receiveCommand.py | 278 +++ Pub_Sub/fkplcpond/thingsboard/bn_pond.cfg | 592 ----- .../thingsboard/fkplcpond_ec2_2_1.cfg | 594 ----- ...{plcpond_tb_v2.cfg => fkplcpond_tb_v4.cfg} | 224 +- .../fkplcpond/thingsboard/plcpond_tb_v1.cfg | 504 ----- Pub_Sub/flowmeterskid/message_example.json | 33 + .../flowmeterskid/thingsboard/pub/sendData.py | 2 + .../thingsboard/pub/sendDataGPTEnhanced.py | 405 ++++ Pub_Sub/gateway/thingsboard/pub/sendData.py | 43 +- .../thingsboard/pub/sendData.py} | 33 +- Pub_Sub/hrswd/thingsboard/pub/sendData.py | 15 +- .../hrswd/thingsboard/sub/receiveCommand.py | 20 +- .../hrtankbattery/thingsboard/pub/sendData.py | 17 +- .../thingsboard/sub/receiveCommand.py | 19 +- .../thingsboard/pub/sendData.py | 16 +- .../thingsboard/pub/sendData.py | 16 +- .../thingsboard/sub/receiveCommand.py | 18 +- .../tankalarms/thingsboard/pub/sendAlarms.py | 12 + .../tankalarms/thingsboard/pub/sendData.py | 179 ++ .../thingsboard/sub/receiveAttributes.py | 35 + .../thingsboard/sub/receiveCommand.py | 33 +- .../thingsboard/tankalarms_tb_v1.cfg | 8 - .../thingsboard/pub/sendData.py | 18 +- .../thingsboard/sub/receiveCommand.py | 20 +- .../convert_config.cpython-310.pyc | Bin 0 -> 2945 bytes {Pub_Sub => code snippets}/base.py | 0 .../config_manager.ipynb | 0 .../config_manager_v2.ipynb | 0 {Pub_Sub => code snippets}/convert_config.py | 4 +- .../receiveAttributeResponse.py | 0 .../receiveAttributeUpdate.py | 0 code snippets/totalizer checker 2.ipynb | 495 +++++ code snippets/totalizer checker.ipynb | 463 ++++ 52 files changed, 7044 insertions(+), 1824 deletions(-) delete mode 100644 Pub_Sub/__pycache__/convert_config.cpython-310.pyc delete mode 100644 Pub_Sub/__pycache__/convert_config.cpython-39.pyc rename Pub_Sub/abbflow_rtu/thingsboard/{abbflow_tb_v1.cfg => abbflow_rtu_tb_v1.cfg} (100%) create mode 100644 Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3 lively.cfg create mode 100644 Pub_Sub/advvfdipp_sru/thingsboard/advvfdipp_sru_tb_v3.cfg create mode 100644 Pub_Sub/advvfdipp_wo_downhole/thingsboard/advvfdipp_wo_downhole_tb_v2.cfg create mode 100644 Pub_Sub/cpadvvfdipp/thingsboard/cpadvvfdipp_tb_v5.cfg create mode 100644 Pub_Sub/cpadvvfdipp/thingsboard/pub/sendAlarms.py create mode 100644 Pub_Sub/cpadvvfdipp/thingsboard/pub/sendData.py create mode 100644 Pub_Sub/cpadvvfdipp/thingsboard/sub/receiveCommand.py delete mode 100644 Pub_Sub/fkplcpond/thingsboard/bn_pond.cfg delete mode 100644 Pub_Sub/fkplcpond/thingsboard/fkplcpond_ec2_2_1.cfg rename Pub_Sub/fkplcpond/thingsboard/{plcpond_tb_v2.cfg => fkplcpond_tb_v4.cfg} (50%) delete mode 100644 Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v1.cfg create mode 100644 Pub_Sub/flowmeterskid/message_example.json create mode 100644 Pub_Sub/flowmeterskid/thingsboard/pub/sendDataGPTEnhanced.py rename Pub_Sub/{hrtankbattery/thingsboard/pub/sendDataNoel.py => hrbooster/thingsboard/pub/sendData.py} (82%) create mode 100644 Pub_Sub/tankalarms/thingsboard/pub/sendAlarms.py create mode 100644 Pub_Sub/tankalarms/thingsboard/pub/sendData.py create mode 100644 Pub_Sub/tankalarms/thingsboard/sub/receiveAttributes.py rename Pub_Sub/{fkplcpond => tankalarms}/thingsboard/sub/receiveCommand.py (67%) create mode 100644 code snippets/__pycache__/convert_config.cpython-310.pyc rename {Pub_Sub => code snippets}/base.py (100%) rename {Pub_Sub => code snippets}/config_manager.ipynb (100%) rename {Pub_Sub => code snippets}/config_manager_v2.ipynb (100%) rename {Pub_Sub => code snippets}/convert_config.py (96%) rename {Pub_Sub => code snippets}/receiveAttributeResponse.py (100%) rename {Pub_Sub => code snippets}/receiveAttributeUpdate.py (100%) create mode 100644 code snippets/totalizer checker 2.ipynb create mode 100644 code snippets/totalizer checker.ipynb diff --git a/.DS_Store b/.DS_Store index 47f6042c6e0129876f9672a04e132a733e23712a..f918af50b5df573af1b4fabd81025a8af82281d5 100644 GIT binary patch delta 1442 zcmcJOT}&KR6vyv>pm4`dyBFxTv%s=T*Fwbwc3IHHN<&Mj$Vb3JVfj$9>Xd?K4_vM#;S>ZGuD`x_|gZ_J3C8E)i>ij%$;-2 zJ^wrB+}}ApaC+ceKk8l^SaG3lSz_yO*N2;0TY~;bB)SyzFGic2g8r81vaj@^qOz5# zqe;y$L!mVY1%;c6iYc{R+s7M3agtRmF4l)zB2k_hZm~1Nq1HR?)X373NZoUYOQ!0 zdM266NTgHAMOf994#!U6NX~+K&ij5hmwAqnL&d=$SjLjSBAvGB{wTyZoZmNdm z_qwxz_7KTE;-#%SDyw(ZH8!{I?da+qSaq?I(lW^{jcJOio7%LdrbpvOLe&*bKXQ0M zQ_Pu>jAm$4Np(n%Vwz7#>Bdzkc;$+myw}~uHhYVhw;|WR)A~VFHSxtBL$YCi$nIaxe#;4Sz zqjrZBrL0FB$*5_AcgS(>k=kepf?_O@nw#SV898@WZkP8{_7;7>KD;+>nEgjpJ%7I3 zDc?ic$8^k?iKo^61zk-$TAgwarFOe*zn#>nXl5!OtdjdF9ku25DGFDz`*@!`DDxZ8 z^o(Zm3*h(3mwAIS>s&=)*0}&e0_}Cqr_;}E8~*$XLW!5ukSJ*`k?Z7Fa)YdsKOmq061Knv1`l>3fL*9T1b3qid(n+S3}F}}m_Sy=G-jYd z#{!PyBo=WBPvA+M!C5?q^SFTL@d94P8+a3M;~jj0FYqP4!WypOCtSzRSQm-~Du_av zP$@JDA)!f#2+cy9a8T$GdY#`FkS}BW=CXwQtz#ayb)k~hzVz>N;On}#t6S>*U+2L4 z*BpGaHAnt7_x2rrdmN%|`>k$oKb1Y@6_sAeXI=ExWNo8*r{rUsID2%}Hfw6RS;V<> z%-e%L9}_t5ju{I3Bv!y-7IT|hg4{&jXuV64SRuz+T&*bg$dc5)Pqe3rk=)*n16;{w zl+r-HciI2O%ID-N`GNdMej_(fgw31~A9kYw&76#b=t2*A(Z}hCVGQG(5EVx_9uHy` zCNdn66BC@0hw%s=#bbCJPvaRpne(4mFVP2`hjZrp z&L#hIzTa7ySeZCEj?S|a=d01VS|Ki@F4_}`g@Zd{(PQD@-QAIBcR1J+U2XNk#I2Lj>TfV;b3z4C@zpIe2^*ii?#$9^S%4F@KOggt)fBwic2+bL9==dV~30WP*#_%XY)758z3iRMb9;Fot3jA2<}(WmvU1C_`_%y_)l^$>3m;PVF!44^T1Qh^ zeLQdKS#Q#iI?C9rsCNAuQkK0(GwjUzV6(cPv6*7=gPJBw7gg1jjNC92SfHnd|iwjhii#IO^+=*I~5VhsCm z07)FiEgEjc5oE9k3pS47K|F+qaU4(LIXsUSaT;gw8qVW&T)-!|h)ehy-{Log6h$df zN|j2*r!;w`D_B25;>uCnA0_O3(Hz*i^iMPghDY{}{tL|`|A*#F6-9n)d>d=)T8dD| z`Uaf$1LI7sZ}2xZ@qp9bvbj(ctwA0T8zez&tti_!Nm(Z0@nmNx5DCKDjLv)W&~v99SGrCH}<#;{W|nvH-=^KqcZw~n3}>g5}3gp zH0W;pOK$u*+>85gKUVMnPT(XShl3|@3QtQEUjAFiV}A`9Z#XZs&Of$ze6>9IYx(bw C{V@gr diff --git a/Pub_Sub/.DS_Store b/Pub_Sub/.DS_Store index ad5d486f19b6001fd4823d46c0d64a82c56a79e4..71eeee8e55c62379aea006919fe463abb2483661 100644 GIT binary patch delta 1346 zcma)6ZA@EL7(P!ww%f}`FBIr)Dcv0%gJBE3bfpx~6gHf!WAaf1l}QV|x+=6lTNa0t zB`!vEi{jB`iE(DeMg8FnySnhlITM$t$^2OM$3-w^CjK!oYSj6ad2U;Om>Atj&ewC^ z_q@+}^StNC1swSl4nhdJvvHY_C|h!@YqL;Hh=E^r_>AY-Zo^7M)l=`7!DwJR1MO;d zmc-MOQxmDw6a$EnHg`JdbiH#UUnE9``4Jj*RMJtQ+c7Q(*|ajKOvN&Zd1YrTqohX@ zld0rT;-Er58`x^#%lQiWl|!U~hSJ5LDUys$D_4Y4b4is|6i2fYiP>x-^RVFJxExyT z5c#n@=V+Fcngy|69OQ({9DUPX zyJ&KSyjogWQrG;Q1;Fe@>AV_a?_$XXf^>Xb#(1X_U z|F@Rwtg5bV$+VJ*>k!mbO)oWlLM{ERH|KBZzeR2L9sg{Z;=L$9E-;}HA|I#$Q zUY4*u1B&PHJWk>zoWjd^g~{&>RJ=vooi4_@__#kM)Y0sV@H;?$_2#tTWn7XU3M)rNLFO07Li-a@$dv delta 1044 zcma)5K}-`t6#diP!je`gSVU>93pPryVt1Doxu6g*0*P&k5)z}e+bsptvISZVDk%pp z#6%_En~4|WNfRNHctvA+GqkPeFcxciI10(^DsrvsnY z2Jl+LAs+O+bF-7UD7RymTq!3Z2?dykG^7ZVkRd-glrz(M&eVy@L+B%P{=D@&TejOyW2JX&i6>F1Si1Vhg8U8=fg~{qNWWbrW7Tn+J z!taA6uhtz2$>D{Nd`DHzkg0Sj5iFnAu-MkjH(IZ>komV8LYTg}+aD22FaHFT4f9iQG;_$Ijld46PklYoG zSo-v+VY0O-)(>mw?e*cv*_1W&O8*1K7`|y#w<*xe3j;S?_$YQ7?}zpYEDpF5Q+aRv z7c2YdJQ=DgLuaz8?1LhGv*hVeA}a$4!W^B~(qlL2eo)mcG6NU-A>A;yG8T-gfW-a zO*2O;P=l*uP5i~EQ{c}oycL3Ww6y@^F8U4r>s$btIyg)?=cZQuDqy`agfX||p$@j1 U+#Y0K$AYnpYrZ4=_Ru%SAGBinc>n+a diff --git a/Pub_Sub/__pycache__/convert_config.cpython-310.pyc b/Pub_Sub/__pycache__/convert_config.cpython-310.pyc deleted file mode 100644 index ebbcb139dc5a4f4b1fdebc2d2b854fc171260b34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2902 zcmaJ@&u<$=6yDk2acn0|LaT(7nhH@|iKHNCpo$QpA#D$}B1I^w1u~9jlWgMbx-)A+ zt+hZ(xl#4V)#jEn5?B6@y>dYL3y_M`@V!~PStn_CH9vM{cHVp6eDA#p3x%A9=eOTO z?_c!(rjP8SrK6?tJbI*+~DR@t!i?M+h{HBa2Ku3$9N8{ z!^e3Zt;-9%h<1!m@JX~eeu+<^9q0PGR-QhF6s^n>+Y1^Y_bLrW1A~WjaZ&D~$Q4wP z7HfylC1No&<2pB<8P5w{7U?}BW_`Ay>Cn@}duT9iUHeFrZy#Viy^l~h#>!?TVWMNT zqpc4=gJf4p_Ji#sGbuK9yvE+D-}Juz(U(zThAl5h%v~9xZiaP!q$g&p9_=J->qrv? zsPtlW@f+z0xfuA3aB(GUwD-Lrl8g8J=ze>1@%~!vL2$nw@Y;iWpWga-ajm^sTgP}K z41VxLR71PvZ!ff-B)M&G_-T>7WVp*Fnakcg5fk_rfySU&6a~$<=tKY{)~>vQN5P~6 zCjC%X5E(s_AnNKH8HfTG5M9ec6a&;*jhiSIiakq^IhD?31r1;-k^Lo)@R4^)f)q){ z9=H9*-d4RXlks+ofLd(_4Jqg_6I(Wf--^msVzq=HM8d|XaHt{+#2Bh0LyS{DkE)s@ zCagzTyR9Hjt0Jb7;webAR(q4EEa{&-V9Mj2Kbg_RTNrpfSZkOa<_WoFi*g z=W6O6saY}W>3wa~F*Z`yn9G_)tXNl$Law5m(@2e4EgPptmYBk;b3w|TGlGt-7KJsb zj*b+TbZ9QqaWXdh;KbH#CT7VHQhxZ1P`QH9H&VIS)#JfQF_?Ag?W8`)T*?}y{N1Q@ zE^P=u@=AB1U}+8Xy;DlqLD>}3ke0E{I-q4Rm$+DU$R60DNO{)SoLUO^<=!O{ipCt@CB4HMPyA*K`2mB0Q9zc@$1Ke}eDi+d5wQ@%_7s`uIRn_Y|RT|2f`wC}EV zo!Hs6dNw!uOfJPv&*^JoDRMD7cF1Bj^xGJI%k5R4J1crB)hYact-NZImtg|CG#<8ox?xmRO2Z5WsMikj1?~!o48Q2Nd~hL_Wp0>57=c;iU13Ehsk@j?m$fbAE#+QmEG5b% zCWoSBSB)fgnr*5!Lg$Jvsy1Q`T1D_g_oJ$_g|J;|?L*OK0hQq<*fIyyQX{@?sd(;d!bM`zp_M(-56{*SnY4MxHmVNJO~Im(~tP&DWvwe@t4 z^hLLiUqF>UOR2hR_N6YOjeVT`Q&+Q{HMh3}>Az41c zzUU417+FOWQ&GpRykLvRCwMyVQphQBp9eRhG;x+1h@#OjnNl>Wcdidtm4fg!%gSRa zV&Os(`axpJR@0Bf4PZ1l-ZUvE?tXpG15Kn#vWW$LO7DoJtQgHaigF5SN>KBxg!dg* z#EIr{KITg`f9`xJVymBSq7!MmNHGeR=?G}Q!bL*>16t{=OJSl{I)#VzJ+gaCQM+uN zsxNM1vosr%ljd3H@z>2m69Sr9(2d6yO!&?w(Fw4n$P_YSm9P} diff --git a/Pub_Sub/__pycache__/convert_config.cpython-39.pyc b/Pub_Sub/__pycache__/convert_config.cpython-39.pyc deleted file mode 100644 index f3b7b51aac122b5c769f1b785c5ee00ae0949274..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2492 zcmc&$&2QX96rb_edN-SGl9ob>1gLOerP57HTPhS)l^W7kLQ$j?MXZ3u@i>W-jlG?* zNn1Imz_DtN95=`OEnGN{#EDb>gy{|Nu8 zG4?kd#)pN&eN6Q;7QqDXvmM^$oc31V>RN`{U0c|~`IU7Y;R+Ab6*b|5dZI2Gpfxce znxMXz6fMxYxFDuL8)90_fKCW&g|#mpK?-Yg?L|qLifAe1#5f+Li;wvLQ!QZ0Si$z8 zOU4UmCM;pUv|nA>?nFT!^Jo`3hE9?eScjg#3&-Yjbcx`7%bNRx}v-L0T zLb7ip$H~T_qg&x-6mBoZ{pg!#vC6cQ4x&UmTPnrcPXlpiX=e~*o0_j5GC2vA-Yj;$ zQ;}4iBo5QgLK@~fQIe_7!#I1CuXP?R_Z}yYf<*KlKfFD6v$LG9^;Wwr0=0ECqQHqOSeI> zT*)N7YMfLqE&5IC)Xd%>U!&hBGKEZS^3S=vg#G_xtek>qJt@-Nq-v;~!3$%hyhuBW z`#Vfh`PwwzR!zDLPQ|23Vn4y#QT$%qEmOOUV8Msh0jnnUYMIuz#v{1OlGZ56sjTM8 zM7PTrF1Bq+$s|$kOgl0Pgd_|&X9fkWm!&;r0{1?yD2gUU#zJhaagWOna1KfR(Ws>2 zeQ-ynj2U7T*3hE*M9nhv=(;^5>D~2$99)^`N(UyRe=%$Vk&Ht#9P>8Yzwdy61fPkiVk_{-zuh>V10$pDf4fIf5Jb4XHdihWasQB3^Mj# z!DdY7%diz*Alxzf@};(Os-&F5ZTTfFw`n<}!KdKe!&C+`NH%fWP3^4(D!Ow^5(<`I zquek}+B7doa9?H)L5>MonSAttF)>Dkzv$Qg E1+JatEdT%j diff --git a/Pub_Sub/abbflow_rtu/thingsboard/abbflow_tb_v1.cfg b/Pub_Sub/abbflow_rtu/thingsboard/abbflow_rtu_tb_v1.cfg similarity index 100% rename from Pub_Sub/abbflow_rtu/thingsboard/abbflow_tb_v1.cfg rename to Pub_Sub/abbflow_rtu/thingsboard/abbflow_rtu_tb_v1.cfg diff --git a/Pub_Sub/abbflow_rtu/thingsboard/abbflow_rtu_tb_v3.cfg b/Pub_Sub/abbflow_rtu/thingsboard/abbflow_rtu_tb_v3.cfg index 07a5519..81fe166 100644 --- a/Pub_Sub/abbflow_rtu/thingsboard/abbflow_rtu_tb_v3.cfg +++ b/Pub_Sub/abbflow_rtu/thingsboard/abbflow_rtu_tb_v3.cfg @@ -290,10 +290,6 @@ { "key": "MAC", "value": "00:18:05:1e:94:f4" - }, - { - "key": "MAC_UPPER", - "value": "00:18:05:1A:E5:57" } ], "quickfaas": { diff --git a/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3 lively.cfg b/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3 lively.cfg new file mode 100644 index 0000000..896f18b --- /dev/null +++ b/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3 lively.cfg @@ -0,0 +1,383 @@ +{ + "controllers": [ + { + "protocol": "Modbus-TCP", + "name": "abbflow", + "args": { + "slaveAddr": 1, + "int16Ord": "ba", + "int32Ord": "abcd", + "float32Ord": "abcd", + "continuousAcquisition": 0 + }, + "samplePeriod": 1, + "expired": 10000, + "endpoint": "192.168.1.11:502" + } + ], + "groups": [ + { + "name": "default", + "uploadInterval": 600, + "reference": 10 + } + ], + "measures": [ + { + "name": "volume_flow", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44001", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44001", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "today_volume", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44003", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44003", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "battery_voltage", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44005", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44005", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "differential_pressure", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44007", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44007", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "yesterday_volume", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44009", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44009", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "accumulated_volume", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44011", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44011", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "static_pressure", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44013", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44013", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "temperature", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44015", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44015", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "charger_voltage", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44017", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44017", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "last_calculation_period_volume", + "ctrlName": "abbflow", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "44019", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "44019", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + } + ], + "alarms": [], + "misc": { + "maxAlarmRecordSz": 2000, + "logLvl": "INFO", + "coms": [ + { + "name": "rs232", + "baud": 9600, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + }, + { + "name": "rs485", + "baud": 9600, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + } + ] + }, + "clouds": [ + { + "cacheSize": 100, + "enable": 1, + "name": "default", + "type": "Standard MQTT", + "args": { + "host": "hp.henrypump.cloud", + "port": 1883, + "clientId": "unknown", + "auth": 1, + "tls": 0, + "cleanSession": 1, + "mqttVersion": "v3.1.1", + "keepalive": 60, + "key": "", + "cert": "", + "rootCA": "", + "verifyServer": 0, + "verifyClient": 0, + "username": "unknown", + "passwd": "unknown", + "authType": 1 + } + } + ], + "labels": [ + { + "key": "SN", + "value": "GF5022210011330" + }, + { + "key": "MAC", + "value": "00:18:05:1e:95:14" + } + ], + "quickfaas": { + "genericFuncs": [], + "uploadFuncs": [ + { + "name": "Send Data", + "trigger": "measure_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "groups": [ + "default" + ], + "funcName": "sendData", + "script": "# Enter your python code.\nimport json, os, time\nfrom datetime import datetime as dt\nfrom datetime import timedelta as td\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot(reason=\"Rebooting for config file update\"):\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n logger.info(reason)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.debug(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.debug(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.debug(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.debug(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.debug(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.debug(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.debug(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.debug(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.debug(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.debug(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\ndef get_totalizers():\n try:\n with open(\"/var/user/files/totalizers.json\", \"r\") as t:\n totalizers = json.load(t)\n if not totalizers:\n logger.debug(\"-----INITIALIZING TOTALIZERS-----\")\n totalizers = {\n \"dayDate\": \"2022-01-01\",\n \"week\": 0,\n \"monthDate\": \"2022-01-01\",\n \"year\": 0,\n \"lifetime\": 0,\n \"dayHolding\": 0,\n \"weekHolding\": 0,\n \"monthHolding\": 0,\n \"yearHolding\": 0\n }\n except:\n totalizers = {\n \"dayDate\": \"2022-01-01\",\n \"week\": 0,\n \"monthDate\": \"2022-01-01\",\n \"year\": 0,\n \"lifetime\": 0,\n \"dayHolding\": 0,\n \"weekHolding\": 0,\n \"monthHolding\": 0,\n \"yearHolding\": 0\n }\n return totalizers\n\ndef saveTotalizers(totalizers):\n try:\n with open(\"/var/user/files/totalizers.json\", \"w\") as t:\n json.dump(totalizers,t)\n except Exception as e:\n logger.error(e)\n\ndef totalizeDay(lifetime):\n totalizers = get_totalizers()\n now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)\n now = now - td(seconds=60*60*8) #time shifted back 8 hours\n reset = False\n value = lifetime - totalizers[\"dayHolding\"]\n if not now.date() == dt.strptime(totalizers[\"dayDate\"], \"%Y-%m-%d\").date():\n totalizers[\"dayHolding\"] = lifetime\n totalizers[\"dayDate\"] = str(now.date())\n saveTotalizers(totalizers)\n reset = True\n return (value,reset)\n\ndef totalizeMonth(lifetime):\n totalizers = get_totalizers()\n now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)\n now = now - td(seconds=60*60*8) #time shifted back 8 hours\n now = dt.strptime(f\"{now.year}-{now.month}\", \"%Y-%m\")\n reset = False\n value = lifetime - totalizers[\"monthHolding\"]\n if not now.date() == dt.strptime(totalizers[\"monthDate\"], \"%Y-%m-%d\").date():\n totalizers[\"monthHolding\"] = lifetime\n totalizers[\"monthDate\"] = str(now.date())\n saveTotalizers(totalizers)\n reset = True\n return (value,reset)\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sendData(message):\n logger.debug(message)\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n payload = {\"ts\": (round(dt.timestamp(dt.now())/600)*600)*1000, \"values\": {}}\n resetPayload = {\"ts\": \"\", \"values\": {}}\n\n for measure in message[\"measures\"]:\n try:\n if abs(payload[\"ts\"]/1000 - measure[\"timestamp\"]) > 3600:\n reboot(reason=\"Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}\".format(payload[\"ts\"]/1000,measure[\"timestamp\"]))\n if measure[\"health\"] == 1:\n if measure[\"name\"] in [\"accumulated_volume\"]:\n payload[\"values\"][\"today_volume\"], dayReset = totalizeDay(measure[\"value\"])\n payload[\"values\"][\"month_volume\"], monthReset = totalizeMonth(measure[\"value\"])\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"] \n elif measure[\"name\"] in [\"today_volume\", \"yesterday_volume\"]:\n pass\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n \n for chunk in chunk_payload(payload=payload):\n publish(__topic__, json.dumps(chunk), __qos__)\n time.sleep(2)\n\n publish(\"v1/devices/me/attributes\", json.dumps({\"latestReportTime\": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)\n\n if dayReset:\n resetPayload[\"values\"][\"yesterday_volume\"] = payload[\"values\"][\"today_volume\"]\n resetPayload[\"values\"][\"today_volume\"] = 0\n if monthReset:\n resetPayload[\"values\"][\"last_month_volume\"] = payload[\"values\"][\"month_volume\"]\n resetPayload[\"values\"][\"month_volume\"] = 0\n \n if resetPayload[\"values\"]:\n resetPayload[\"ts\"] = 1 + (round(dt.timestamp(dt.now())/600)*600)*1000\n publish(__topic__, json.dumps(resetPayload), __qos__) \n \n", + "msgType": 0, + "cloudName": "default" + } + ], + "downloadFuncs": [ + { + "name": "Commands", + "topic": "v1/devices/me/rpc/request/+", + "qos": 1, + "funcName": "receiveCommand", + "payload_type": "JSON", + "script": "import json, time\nfrom datetime import datetime as dt\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sync():\n #get new values and send\n payload = {\"ts\": round(dt.timestamp(dt.now()))*1000, \"values\": {}}\n topic = \"v1/devices/me/telemetry\"\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(topic))\n logger.debug(\"Sending value: {}\".format(payload))\n for chunk in chunk_payload(payload=payload):\n publish(topic, json.dumps(chunk), 1)\n time.sleep(2)\n\ndef writeplctag(value, wizard_api):\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n message = {\"abbflow\":{value[\"measurement\"]: value[\"value\"]}}\n resp = wizard_api.write_plc_values(message)\n #logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.debug(e)\n return False\n \ndef receiveCommand(topic, payload, wizard_api):\n try:\n logger.debug(topic)\n logger.debug(json.loads(payload))\n p = json.loads(payload)\n command = p[\"method\"]\n commands = {\n \"sync\": sync,\n \"writeplctag\": writeplctag,\n } \n if command == \"setPLCTag\":\n result = commands[\"writeplctag\"](p[\"params\"],wizard_api)\n if result:\n sync()\n #commands[command](p[\"mac\"].lower(),p[\"payload\"][\"value\"], wizard_api)\n #logger.debug(command)\n ack(topic.split(\"/\")[-1], wizard_api)\n except Exception as e:\n logger.debug(e)\n \n\ndef ack(msgid, wizard_api):\n #logger.debug(msgid)\n #logger.debug(mac)\n #logger.debug(name)\n #logger.debug(value)\n wizard_api.mqtt_publish(\"v1/devices/me/rpc/response/\" + str(msgid), json.dumps({\"msg\": {\"time\": time.time()}, \"metadata\": \"\", \"msgType\": \"\"}))", + "msgType": 0, + "cloudName": "default", + "trigger": "command_event" + } + ] + }, + "modbusSlave": { + "enable": 0, + "protocol": "Modbus-TCP", + "port": 502, + "slaveAddr": 1, + "int16Ord": "ab", + "int32Ord": "abcd", + "float32Ord": "abcd", + "maxConnection": 5, + "mapping_table": [] + }, + "iec104Server": { + "enable": 0, + "cotSize": 2, + "port": 2404, + "serverList": [ + { + "asduAddr": 1 + } + ], + "kValue": 12, + "wValue": 8, + "t0": 15, + "t1": 15, + "t2": 10, + "t3": 20, + "maximumLink": 5, + "timeSet": 1, + "byteOrder": "abcd", + "mapping_table": [] + }, + "opcuaServer": { + "enable": 0, + "port": 4840, + "maximumLink": 5, + "securityMode": 0, + "identifierType": "String", + "mapping_table": [] + }, + "bindConfig": { + "enable": 0, + "bind": { + "modelId": "", + "modelName": "", + "srcId": "", + "srcName": "", + "devId": "", + "devName": "" + }, + "varGroups": [], + "variables": [], + "alerts": [] + }, + "southMetadata": {}, + "bindMetadata": { + "version": "", + "timestamp": "" + } +} \ No newline at end of file diff --git a/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3.cfg b/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3.cfg index 3ba7739..f1ee0a8 100644 --- a/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3.cfg +++ b/Pub_Sub/abbflow_tcp/thingsboard/abbflow_tcp_tb_v3.cfg @@ -289,10 +289,6 @@ { "key": "MAC", "value": "00:18:05:1e:95:14" - }, - { - "key": "MAC_UPPER", - "value": "00:18:05:1A:E5:57" } ], "quickfaas": { diff --git a/Pub_Sub/advvfdipp/thingsboard/advvfdipp_tb_v5.cfg b/Pub_Sub/advvfdipp/thingsboard/advvfdipp_tb_v5.cfg index 66687ae..7cd04fe 100644 --- a/Pub_Sub/advvfdipp/thingsboard/advvfdipp_tb_v5.cfg +++ b/Pub_Sub/advvfdipp/thingsboard/advvfdipp_tb_v5.cfg @@ -1153,7 +1153,7 @@ "qos": 1, "funcName": "receiveCommand", "payload_type": "JSON", - "script": "import json, time\nfrom datetime import datetime as dt\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sync():\n #get new values and send\n payload = {\"ts\": round(dt.timestamp(dt.now()))*1000, \"values\": {}}\n topic = \"v1/devices/me/telemetry\"\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(topic))\n logger.debug(\"Sending value: {}\".format(payload))\n for chunk in chunk_payload(payload=payload):\n publish(topic, json.dumps(chunk), 1)\n time.sleep(2)\ndef writeplctag(value):\n #value in the form {\"measurement\": , \"value\": }\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.debug(e)\n return False\n \ndef receiveCommand(topic, payload):\n try:\n logger.debug(topic)\n logger.debug(json.loads(payload))\n p = json.loads(payload)\n command = p[\"method\"]\n commands = {\n \"sync\": sync,\n \"writeplctag\": writeplctag,\n } \n if command == \"setPLCTag\":\n try:\n result = commands[\"writeplctag\"](p[\"params\"])\n logger.debug(result)\n except Exception as e:\n logger.error(e)\n elif command == \"changeSetpoint\":\n try:\n logger.debug(\"attempting controlpoint write\")\n params_type = {\"measurement\": \"pidcontrolmode\", \"value\": p[\"params\"][\"setpointType\"]}\n if params_type[\"value\"]:\n commands[\"writeplctag\"](params_type)\n time.sleep(2)\n except Exception as e:\n logger.error(\"DID NOT WRITE CONTROL MODE\")\n logger.error(e)\n try:\n logger.debug(\"attempting setpoint write\")\n modes = {0: \"flowsetpoint\", 1: \"fluidlevelsetpoint\", 2: \"tubingpressuresetpoint\", 3: \"manualfrequencysetpoint\"}\n params_value = {\"value\": p[\"params\"][\"setpointValue\"]}\n if params_value[\"value\"]:\n params_value[\"measurement\"] = modes[getMode()]\n result = commands[\"writeplctag\"](params_value)\n logger.debug(result)\n except Exception as e:\n logger.error(\"DID NOT WRITE SETPOINT\")\n logger.error(e)\n #logger.debug(command)\n ack(topic.split(\"/\")[-1])\n time.sleep(5)\n sync()\n except Exception as e:\n logger.debug(e)\n \n\ndef ack(msgid):\n #logger.debug(msgid)\n #logger.debug(mac)\n #logger.debug(name)\n #logger.debug(value)\n publish(\"v1/devices/me/rpc/response/\" + str(msgid), json.dumps({\"msg\": {\"time\": time.time()}, \"metadata\": \"\", \"msgType\": \"\"}), 1)\n\ndef getMode():\n try:\n data = recall()\n for controller in data:\n for measure in controller[\"measures\"]:\n if measure[\"name\"] == \"pidcontrolmode\":\n return measure[\"value\"]\n except:\n return None\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "script": "import json, time\nfrom datetime import datetime as dt\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sync():\n #get new values and send\n payload = {\"ts\": round(dt.timestamp(dt.now()))*1000, \"values\": {}}\n topic = \"v1/devices/me/telemetry\"\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(topic))\n logger.debug(\"Sending value: {}\".format(payload))\n for chunk in chunk_payload(payload=payload):\n publish(topic, json.dumps(chunk), 1)\n time.sleep(2)\ndef writeplctag(value):\n #value in the form {\"measurement\": , \"value\": }\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.debug(e)\n return False\n \ndef receiveCommand(topic, payload):\n try:\n logger.debug(topic)\n logger.debug(json.loads(payload))\n p = json.loads(payload)\n command = p[\"method\"]\n commands = {\n \"sync\": sync,\n \"writeplctag\": writeplctag,\n } \n if command == \"setPLCTag\":\n try:\n result = commands[\"writeplctag\"](p[\"params\"])\n logger.debug(result)\n except Exception as e:\n logger.error(e)\n elif command == \"changeSetpoint\":\n try:\n logger.debug(\"attempting controlpoint write\")\n params_type = {\"measurement\": \"pidcontrolmode\", \"value\": p[\"params\"][\"setpointType\"]}\n if params_type[\"value\"]:\n commands[\"writeplctag\"](params_type)\n time.sleep(2)\n except Exception as e:\n logger.error(\"DID NOT WRITE CONTROL MODE\")\n logger.error(e)\n try:\n logger.debug(\"attempting setpoint write\")\n modes = {0: \"flowsetpoint\", 1: \"fluidlevelsetpoint\", 2: \"tubingpressuresetpoint\", 3: \"manualfrequencysetpoint\"}\n params_value = {\"value\": p[\"params\"][\"setpointValue\"]}\n if params_value[\"value\"]:\n params_value[\"measurement\"] = modes[getMode()]\n result = commands[\"writeplctag\"](params_value)\n logger.debug(result)\n except Exception as e:\n logger.error(\"DID NOT WRITE SETPOINT\")\n logger.error(e)\n #logger.debug(command)\n ack(topic.split(\"/\")[-1])\n time.sleep(5)\n sync()\n except Exception as e:\n logger.debug(e)\n \n\ndef ack(msgid):\n #logger.debug(msgid)\n #logger.debug(mac)\n #logger.debug(name)\n #logger.debug(value)\n publish(\"v1/devices/me/rpc/response/\" + str(msgid), json.dumps({\"msg\": {\"time\": time.time()}, \"metadata\": \"\", \"msgType\": \"\"}), 1)\n\ndef getMode():\n try:\n data = recall()\n for controller in data:\n for measure in controller[\"measures\"]:\n if measure[\"name\"] == \"pidcontrolmode\":\n return measure[\"value\"]\n except:\n return None\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", "msgType": 0, "trigger": "command_event", "cloudName": "default" diff --git a/Pub_Sub/advvfdipp/thingsboard/sub/receiveCommand.py b/Pub_Sub/advvfdipp/thingsboard/sub/receiveCommand.py index f2161f0..d4fa423 100644 --- a/Pub_Sub/advvfdipp/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/advvfdipp/thingsboard/sub/receiveCommand.py @@ -26,10 +26,10 @@ def sync(): for measure in controller["measures"]: #publish measure if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]: - payload[measure["name"]] = convert_int(measure["name"], measure["value"]) - payload[measure["name"]+ "_int"] = measure["value"] + payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"]) + payload["values"][measure["name"]+ "_int"] = measure["value"] else: - payload[measure["name"]] = measure["value"] + payload["values"][measure["name"]] = measure["value"] logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) for chunk in chunk_payload(payload=payload): diff --git a/Pub_Sub/advvfdipp_sru/thingsboard/advvfdipp_sru_tb_v3.cfg b/Pub_Sub/advvfdipp_sru/thingsboard/advvfdipp_sru_tb_v3.cfg new file mode 100644 index 0000000..9bd251e --- /dev/null +++ b/Pub_Sub/advvfdipp_sru/thingsboard/advvfdipp_sru_tb_v3.cfg @@ -0,0 +1,1960 @@ +{ + "controllers": [ + { + "protocol": "EtherNet/IP", + "name": "advvfdipp", + "args": {}, + "samplePeriod": 2, + "expired": 10000, + "endpoint": "192.168.1.10:44818" + }, + { + "protocol": "Modbus-RTU", + "name": "SRU", + "args": { + "slaveAddr": 234, + "int16Ord": "ab", + "int32Ord": "abcd", + "float32Ord": "abcd", + "continuousAcquisition": 1, + "maxContinuousNumber": 64 + }, + "endpoint": "rs485", + "samplePeriod": 10, + "expired": 10000 + } + ], + "groups": [ + { + "name": "default", + "uploadInterval": 600, + "reference": 45 + }, + { + "name": "converter", + "uploadInterval": 10 + }, + { + "name": "null", + "uploadInterval": 3600 + } + ], + "measures": [ + { + "name": "SRU_Data[0]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30001", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30001", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[1]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30002", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30002", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[2]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30003", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30003", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[3]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30004", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30004", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[4]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30005", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30005", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[5]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30006", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30006", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[6]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30007", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30007", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[7]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30008", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30008", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[8]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30009", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30009", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[9]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30010", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30010", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[10]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30011", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30011", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[11]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30012", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30012", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[12]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30013", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30013", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[13]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30014", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30014", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[14]", + "ctrlName": "SRU", + "group": "converter", + "uploadType": "periodic", + "dataType": "INT", + "addr": "30015", + "decimal": "", + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "regAddr": "30015", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowrate", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_Flowmeter", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "fluidlevel", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_FluidLevel", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "intakepressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_IntakePressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "intaketemperature", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_IntakeTemperature", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "tubingpressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_TubingPressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "wellstatus", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Device_Status_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "vfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "VFD_SpeedFdbk", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowtotal", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Flow_Total[0]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "energytotal", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Energy_Total[0]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "vfdcurrent", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "VFD_OutCurrent", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "downholesensorstatus", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Downhole_Sensor_Status_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "fluidspecificgravity", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_FluidSpecificGravity", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowtotalyesterday", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Flow_Total[1]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "energytotalyesterday", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Energy_Total[1]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmflowrate", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_Flowmeter", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmintakepressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_IntakePressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmintaketemperature", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_IntakeTemperature", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmtubingpressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_TubingPressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmvfd", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_VFD", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmlockout", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_Lockout", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "runpermissive", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Run_Permissive_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "startpermissive", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Start_Permissive_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmfluidlevel", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_FluidLevel", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "pressureshutdownlimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakePressure.Val_LoLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "pressurestartuplimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakePressure.Val_HiLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "temperatureshutdownlimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakeTemperature.Val_HiLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "temperaturestartuplimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakeTemperature.Val_LoLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "sensorheight", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_DHSensorDistToIntake", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "last_vfd_fault_code", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "PowerFlex755.Val_LastFaultCode", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "vfd_fault", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "sts_CurrentVFDFaultCode", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "controllerfault_io", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "ControllerFault_IO", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "controllerfault_program", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "ControllerFault_Program", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "minvfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "PowerFlex755.Cfg_MinSpdRef", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "maxvfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "PowerFlex755.Cfg_MaxSpdRef", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "startcommand", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "cmd_Start", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "stopcommand", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "cmd_Stop", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "pidcontrolmode", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "DINT", + "addr": "sts_PID_Control", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowsetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_FlowSP", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "tubingpressuresetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_TubingPressureSP", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "fluidlevelsetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_FluidLevelSP", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "manualfrequencysetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_ManualSP", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "resetalarms", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "cmd_ResetAlarms", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowrate_gpm", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_Flowmeter_BarrelsPerMinute", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowmeter_fault", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "PROMAG_300:I1.Connection_Fault", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[0]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[0]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[1]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[1]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[2]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[2]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[3]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[3]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[4]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[4]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[5]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[5]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[6]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[6]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[7]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[7]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[8]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[8]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[9]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[9]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[10]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[10]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[11]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[11]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[12]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[12]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[13]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[13]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[14]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[14]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[15]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[15]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "SRU_Data[16]", + "ctrlName": "advvfdipp", + "group": "null", + "uploadType": "periodic", + "dataType": "INT", + "addr": "SRU_Data[16]", + "decimal": 2, + "len": 1, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "ctrlName": "SRU", + "dataType": "INT", + "readWrite": "ro", + "uploadType": "periodic", + "group": "converter", + "name": "SRU_Data[15]", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "regAddr": "30016", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "addr": "30016" + }, + { + "ctrlName": "SRU", + "dataType": "INT", + "readWrite": "ro", + "uploadType": "periodic", + "group": "converter", + "name": "SRU_Data[16]", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "regAddr": "30017", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "addr": "30017" + } + ], + "alarms": [ + { + "name": "alarmflowrate", + "ctrlName": "advvfdipp", + "measureName": "alarmflowrate", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Flow Rate Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmintakepressure", + "ctrlName": "advvfdipp", + "measureName": "alarmintakepressure", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Intake Pressure Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmintaketemperature", + "ctrlName": "advvfdipp", + "measureName": "alarmintaketemperature", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Intake Temperature Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmtubingpressure", + "ctrlName": "advvfdipp", + "measureName": "alarmtubingpressure", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Tubing Pressure Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmvfd", + "ctrlName": "advvfdipp", + "measureName": "alarmvfd", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "VFD Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmlockout", + "ctrlName": "advvfdipp", + "measureName": "alarmlockout", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Lockout Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmfluidlevel", + "ctrlName": "advvfdipp", + "measureName": "alarmfluidlevel", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Fluid Level Alarm triggered", + "alarmLable": "default" + }, + { + "name": "controllerfault_io", + "ctrlName": "advvfdipp", + "measureName": "controllerfault_io", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Controller IO Alarm triggered", + "alarmLable": "default" + }, + { + "name": "controllerfault_program", + "ctrlName": "advvfdipp", + "measureName": "controllerfault_program", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Controller Fault Alarm triggered", + "alarmLable": "default" + }, + { + "name": "flowmeter_fault", + "ctrlName": "advvfdipp", + "measureName": "flowmeter_fault", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Flow Meter Alarm triggered", + "alarmLable": "default" + } + ], + "misc": { + "maxAlarmRecordSz": 2000, + "logLvl": "INFO", + "coms": [ + { + "name": "rs232", + "baud": 9600, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + }, + { + "name": "rs485", + "baud": 38400, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + } + ] + }, + "clouds": [ + { + "cacheSize": 100, + "enable": 1, + "type": "Standard MQTT", + "args": { + "host": "hp.henrypump.cloud", + "port": 1883, + "clientId": "unknown", + "auth": 1, + "tls": 0, + "cleanSession": 1, + "mqttVersion": "v3.1.1", + "keepalive": 120, + "key": "", + "cert": "", + "rootCA": "", + "verifyServer": 0, + "verifyClient": 0, + "username": "unknown", + "passwd": "unknown", + "authType": 1 + }, + "name": "default" + } + ], + "labels": [ + { + "key": "SN", + "value": "GF5022215013085" + }, + { + "key": "MAC", + "value": "00:18:05:1f:8d:43" + } + ], + "quickfaas": { + "genericFuncs": [], + "uploadFuncs": [ + { + "name": "Send Data", + "trigger": "measure_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "groups": [ + "default" + ], + "funcName": "sendData", + "script": "# Enter your python code.\nimport json, os, time\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot(reason=\"Rebooting for config file update\"):\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n logger.info(reason)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.debug(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.debug(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.debug(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.debug(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.debug(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.debug(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.debug(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.debug(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.debug(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.debug(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sendData(message):\n #logger.debug(message)\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n payload = {\"ts\": (round(dt.timestamp(dt.now())/600)*600)*1000, \"values\": {}}\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n if abs(payload[\"ts\"]/1000 - measure[\"timestamp\"]) > 3600:\n reboot(reason=\"Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}\".format(payload[\"ts\"]/1000,measure[\"timestamp\"]))\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n logger.debug(\"Converting DINT/BOOL to STRING\")\n value = convert_int(measure[\"name\"], measure[\"value\"])\n logger.debug(\"Converted {} to {}\".format(measure[\"value\"], value))\n payload[\"values\"][measure[\"name\"]] = value\n payload[\"values\"][measure[\"name\"] + \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"] \n except Exception as e:\n logger.error(e)\n \n for chunk in chunk_payload(payload=payload):\n publish(__topic__, json.dumps(chunk), __qos__)\n time.sleep(2)\n publish(\"v1/devices/me/attributes\", json.dumps({\"latestReportTime\": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n\n ", + "msgType": 0, + "cloudName": "default" + }, + { + "name": "sendToPLC", + "trigger": "measure_event", + "topic": "v1", + "qos": 1, + "groups": [ + "converter" + ], + "funcName": "sendToPLC", + "script": "# Enter your python code.\nimport json, time\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n\ndef writeplctag(value):\n #value in the form {\"measurement\": , \"value\": }\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.error(e)\n return False\n\ndef sendToPLC(message):\n logger.debug(message)\n for measure in message[\"measures\"]:\n logger.debug(measure)\n #{'ctrlName': 'modbus_converter', 'name': 'SRU_Data[1]', 'health': 1, 'timestamp': 1664894200, 'value': 47}\n writeplctag({\"measurement\": measure[\"name\"], \"value\": measure[\"value\"]})\n #time.sleep(2)\n ", + "msgType": 0, + "cloudName": "default" + }, + { + "name": "sendAlarm", + "trigger": "warning_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "funcName": "sendAlarm", + "script": "# Enter your python code.\nimport json, time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.measure import recall\n\n\ndef sendAlarm(message):\n logger.info(message)\n payload = {}\n payload[\"ts\"] = time.time()*1000\n payload[\"values\"] = {message[\"measureName\"]: message[\"value\"]}\n publish(__topic__, json.dumps(payload), __qos__)\n sync()\n\ndef sync():\n #get new values and send\n payload = {\"ts\": time.time()*1000, \"values\": {}}\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(__topic__))\n logger.debug(\"Sending value: {}\".format(payload))\n publish(__topic__, json.dumps(payload), 1)\n\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "alarms": [ + "default" + ], + "msgType": 0, + "cloudName": "default" + } + ], + "downloadFuncs": [ + { + "name": "Commands", + "topic": "v1/devices/me/rpc/request/+", + "qos": 1, + "funcName": "receiveCommand", + "payload_type": "JSON", + "script": "import json, time\nfrom datetime import datetime as dt\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sync():\n #get new values and send\n payload = {\"ts\": round(dt.timestamp(dt.now()))*1000, \"values\": {}}\n topic = \"v1/devices/me/telemetry\"\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(topic))\n logger.debug(\"Sending value: {}\".format(payload))\n for chunk in chunk_payload(payload=payload):\n publish(topic, json.dumps(chunk), 1)\n time.sleep(2)\ndef writeplctag(value):\n #value in the form {\"measurement\": , \"value\": }\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.debug(e)\n return False\n \ndef receiveCommand(topic, payload):\n try:\n logger.debug(topic)\n logger.debug(json.loads(payload))\n p = json.loads(payload)\n command = p[\"method\"]\n commands = {\n \"sync\": sync,\n \"writeplctag\": writeplctag,\n } \n if command == \"setPLCTag\":\n try:\n result = commands[\"writeplctag\"](p[\"params\"])\n logger.debug(result)\n except Exception as e:\n logger.error(e)\n elif command == \"changeSetpoint\":\n try:\n logger.debug(\"attempting controlpoint write\")\n params_type = {\"measurement\": \"pidcontrolmode\", \"value\": p[\"params\"][\"setpointType\"]}\n if params_type[\"value\"]:\n commands[\"writeplctag\"](params_type)\n time.sleep(2)\n except Exception as e:\n logger.error(\"DID NOT WRITE CONTROL MODE\")\n logger.error(e)\n try:\n logger.debug(\"attempting setpoint write\")\n modes = {0: \"flowsetpoint\", 1: \"fluidlevelsetpoint\", 2: \"tubingpressuresetpoint\", 3: \"manualfrequencysetpoint\"}\n params_value = {\"value\": p[\"params\"][\"setpointValue\"]}\n if params_value[\"value\"]:\n params_value[\"measurement\"] = modes[getMode()]\n result = commands[\"writeplctag\"](params_value)\n logger.debug(result)\n except Exception as e:\n logger.error(\"DID NOT WRITE SETPOINT\")\n logger.error(e)\n #logger.debug(command)\n ack(topic.split(\"/\")[-1])\n time.sleep(5)\n sync()\n except Exception as e:\n logger.debug(e)\n \n\ndef ack(msgid):\n #logger.debug(msgid)\n #logger.debug(mac)\n #logger.debug(name)\n #logger.debug(value)\n publish(\"v1/devices/me/rpc/response/\" + str(msgid), json.dumps({\"msg\": {\"time\": time.time()}, \"metadata\": \"\", \"msgType\": \"\"}), 1)\n\ndef getMode():\n try:\n data = recall()\n for controller in data:\n for measure in controller[\"measures\"]:\n if measure[\"name\"] == \"pidcontrolmode\":\n return measure[\"value\"]\n except:\n return None\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "msgType": 0, + "trigger": "command_event", + "cloudName": "default" + } + ] + }, + "modbusSlave": { + "enable": 0, + "protocol": "Modbus-TCP", + "port": 502, + "slaveAddr": 1, + "int16Ord": "ab", + "int32Ord": "abcd", + "float32Ord": "abcd", + "maxConnection": 5, + "mapping_table": [] + }, + "iec104Server": { + "enable": 0, + "cotSize": 2, + "port": 2404, + "serverList": [ + { + "asduAddr": 1 + } + ], + "kValue": 12, + "wValue": 8, + "t0": 15, + "t1": 15, + "t2": 10, + "t3": 20, + "maximumLink": 5, + "timeSet": 1, + "byteOrder": "abcd", + "mapping_table": [] + }, + "opcuaServer": { + "enable": 0, + "port": 4840, + "maximumLink": 5, + "securityMode": 0, + "identifierType": "String", + "mapping_table": [] + }, + "bindConfig": { + "enable": 0, + "bind": { + "modelId": "", + "modelName": "", + "srcId": "", + "srcName": "", + "devId": "", + "devName": "" + }, + "varGroups": [], + "variables": [], + "alerts": [] + }, + "southMetadata": {}, + "bindMetadata": { + "version": "", + "timestamp": "" + } +} \ No newline at end of file diff --git a/Pub_Sub/advvfdipp_sru/thingsboard/sub/receiveCommand.py b/Pub_Sub/advvfdipp_sru/thingsboard/sub/receiveCommand.py index f2161f0..d4fa423 100644 --- a/Pub_Sub/advvfdipp_sru/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/advvfdipp_sru/thingsboard/sub/receiveCommand.py @@ -26,10 +26,10 @@ def sync(): for measure in controller["measures"]: #publish measure if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]: - payload[measure["name"]] = convert_int(measure["name"], measure["value"]) - payload[measure["name"]+ "_int"] = measure["value"] + payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"]) + payload["values"][measure["name"]+ "_int"] = measure["value"] else: - payload[measure["name"]] = measure["value"] + payload["values"][measure["name"]] = measure["value"] logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) for chunk in chunk_payload(payload=payload): diff --git a/Pub_Sub/advvfdipp_wo_downhole/thingsboard/advvfdipp_wo_downhole_tb_v2.cfg b/Pub_Sub/advvfdipp_wo_downhole/thingsboard/advvfdipp_wo_downhole_tb_v2.cfg new file mode 100644 index 0000000..498038f --- /dev/null +++ b/Pub_Sub/advvfdipp_wo_downhole/thingsboard/advvfdipp_wo_downhole_tb_v2.cfg @@ -0,0 +1,654 @@ +{ + "controllers": [ + { + "protocol": "EtherNet/IP", + "name": "advvfdipp", + "args": { + "slot": 0 + }, + "samplePeriod": 2, + "expired": 10000, + "endpoint": "192.168.1.10:44818", + "enablePerOnchange": 0 + } + ], + "measures": [ + { + "name": "flowrate", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_Flowmeter_BarrelsPerDay", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "fluidlevel", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_FluidLevel", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "tubingpressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_TubingPressure", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "wellstatus", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Device_Status_INT", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "vfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "VFD_SpeedFdbk", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "flowtotal", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Flow_Total[0]", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "energytotal", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Energy_Total[0]", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "vfdcurrent", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "VFD_OutCurrent", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "fluidspecificgravity", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_FluidSpecificGravity", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "flowtotalyesterday", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Flow_Total[1]", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "energytotalyesterday", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Energy_Total[1]", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "alarmflowrate", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_Flowmeter", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "alarmtubingpressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_TubingPressure", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "alarmvfd", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_VFD", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "alarmlockout", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_Lockout", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "runpermissive", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Run_Permissive_INT", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "startpermissive", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Start_Permissive_INT", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "alarmfluidlevel", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_FluidLevel", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "last_vfd_fault_code", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "PowerFlex755.Val_LastFaultCode", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "vfd_fault", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "sts_CurrentVFDFaultCode", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "controllerfault_io", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "ControllerFault_IO", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "controllerfault_program", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "ControllerFault_Program", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "minvfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "PowerFlex755.Cfg_MinSpdRef", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "maxvfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "PowerFlex755.Cfg_MaxSpdRef", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "startcommand", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "cmd_Start", + "bitMap": 0, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "stopcommand", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "cmd_Stop", + "bitMap": 0, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "pidcontrolmode", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "DINT", + "addr": "sts_PID_Control", + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "flowsetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_FlowSP", + "decimal": 2, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "tubingpressuresetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_TubingPressureSP", + "decimal": 2, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "fluidlevelsetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_FluidLevelSP", + "decimal": 2, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "manualfrequencysetpoint", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_PID_ManualSP", + "decimal": 2, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "resetalarms", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "cmd_ResetAlarms", + "bitMap": 0, + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "flowrate_gpm", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_Flowmeter_BarrelsPerMinute", + "decimal": 2, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + }, + { + "name": "flowmeter_fault", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "Flowmeter:I1.Connection_Fault", + "bitMap": 0, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0 + } + ], + "alarmLables": [ + "default" + ], + "alarms": [], + "groups": [ + { + "name": "default", + "uploadInterval": 600, + "reference": 45 + } + ], + "misc": { + "maxAlarmRecordSz": 2000, + "logLvl": "INFO", + "coms": [ + { + "name": "rs232", + "baud": 9600, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + }, + { + "name": "rs485", + "baud": 19200, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + } + ] + }, + "clouds": [ + { + "cacheSize": 10000, + "enable": 1, + "type": "Standard MQTT", + "args": { + "host": "hp.henrypump.cloud", + "port": 1883, + "clientId": "unknown", + "auth": 1, + "tls": 0, + "cleanSession": 1, + "mqttVersion": "v3.1.1", + "keepalive": 120, + "key": "", + "cert": "", + "rootCA": "", + "verifyServer": 0, + "verifyClient": 0, + "username": "unknown", + "passwd": "unknown", + "authType": 1, + "willQos": 0, + "willRetain": 0, + "willTopic": "", + "willPayload": "" + }, + "name": "default" + } + ], + "quickfaas": { + "genericFuncs": [], + "uploadFuncs": [ + { + "name": "Send Data", + "trigger": "measure_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "groups": [ + "default" + ], + "funcName": "sendData", + "script": "# Enter your python code.\nimport json, os, time\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot(reason=\"Rebooting for config file update\"):\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n logger.info(reason)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.debug(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.debug(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.debug(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.debug(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.debug(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.debug(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.debug(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.debug(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.debug(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.debug(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sendData(message):\n #logger.debug(message)\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n payload = {\"ts\": (round(dt.timestamp(dt.now())/600)*600)*1000, \"values\": {}}\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n if abs(payload[\"ts\"]/1000 - measure[\"timestamp\"]) > 3600:\n reboot(reason=\"Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}\".format(payload[\"ts\"]/1000,measure[\"timestamp\"]))\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n logger.debug(\"Converting DINT/BOOL to STRING\")\n value = convert_int(measure[\"name\"], measure[\"value\"])\n logger.debug(\"Converted {} to {}\".format(measure[\"value\"], value))\n payload[\"values\"][measure[\"name\"]] = value\n payload[\"values\"][measure[\"name\"] + \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"] \n except Exception as e:\n logger.error(e)\n \n for chunk in chunk_payload(payload=payload):\n publish(__topic__, json.dumps(chunk), __qos__)\n time.sleep(2)\n publish(\"v1/devices/me/attributes\", json.dumps({\"latestReportTime\": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n\n ", + "msgType": 0, + "cloudName": "default" + }, + { + "name": "sendAlarm", + "trigger": "warning_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "funcName": "sendAlarm", + "script": "# Enter your python code.\nimport json, time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.measure import recall\n\n\ndef sendAlarm(message):\n logger.info(message)\n payload = {}\n payload[\"ts\"] = time.time()*1000\n payload[\"values\"] = {message[\"measureName\"]: message[\"value\"]}\n publish(__topic__, json.dumps(payload), __qos__)\n sync()\n\ndef sync():\n #get new values and send\n payload = {\"ts\": time.time()*1000, \"values\": {}}\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(__topic__))\n logger.debug(\"Sending value: {}\".format(payload))\n publish(__topic__, json.dumps(payload), 1)\n\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "alarms": [ + "default" + ], + "msgType": 0, + "cloudName": "default" + } + ], + "downloadFuncs": [ + { + "name": "Commands", + "topic": "v1/devices/me/rpc/request/+", + "qos": 1, + "funcName": "receiveCommand", + "payload_type": "JSON", + "script": "import json, time\nfrom datetime import datetime as dt\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sync():\n #get new values and send\n payload = {\"ts\": round(dt.timestamp(dt.now()))*1000, \"values\": {}}\n topic = \"v1/devices/me/telemetry\"\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(topic))\n logger.debug(\"Sending value: {}\".format(payload))\n for chunk in chunk_payload(payload=payload):\n publish(topic, json.dumps(chunk), 1)\n time.sleep(2)\ndef writeplctag(value):\n #value in the form {\"measurement\": , \"value\": }\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.debug(e)\n return False\n \ndef receiveCommand(topic, payload):\n try:\n logger.debug(topic)\n logger.debug(json.loads(payload))\n p = json.loads(payload)\n command = p[\"method\"]\n commands = {\n \"sync\": sync,\n \"writeplctag\": writeplctag,\n } \n if command == \"setPLCTag\":\n try:\n result = commands[\"writeplctag\"](p[\"params\"])\n logger.debug(result)\n except Exception as e:\n logger.error(e)\n elif command == \"changeSetpoint\":\n try:\n logger.debug(\"attempting controlpoint write\")\n params_type = {\"measurement\": \"pidcontrolmode\", \"value\": p[\"params\"][\"setpointType\"]}\n if params_type[\"value\"]:\n commands[\"writeplctag\"](params_type)\n time.sleep(2)\n except Exception as e:\n logger.error(\"DID NOT WRITE CONTROL MODE\")\n logger.error(e)\n try:\n logger.debug(\"attempting setpoint write\")\n modes = {0: \"flowsetpoint\", 1: \"fluidlevelsetpoint\", 2: \"tubingpressuresetpoint\", 3: \"manualfrequencysetpoint\"}\n params_value = {\"value\": p[\"params\"][\"setpointValue\"]}\n if params_value[\"value\"]:\n params_value[\"measurement\"] = modes[getMode()]\n result = commands[\"writeplctag\"](params_value)\n logger.debug(result)\n except Exception as e:\n logger.error(\"DID NOT WRITE SETPOINT\")\n logger.error(e)\n #logger.debug(command)\n ack(topic.split(\"/\")[-1])\n time.sleep(5)\n sync()\n except Exception as e:\n logger.debug(e)\n \n\ndef ack(msgid):\n #logger.debug(msgid)\n #logger.debug(mac)\n #logger.debug(name)\n #logger.debug(value)\n publish(\"v1/devices/me/rpc/response/\" + str(msgid), json.dumps({\"msg\": {\"time\": time.time()}, \"metadata\": \"\", \"msgType\": \"\"}), 1)\n\ndef getMode():\n try:\n data = recall()\n for controller in data:\n for measure in controller[\"measures\"]:\n if measure[\"name\"] == \"pidcontrolmode\":\n return measure[\"value\"]\n except:\n return None\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "msgType": 0, + "trigger": "command_event", + "cloudName": "default" + } + ] + }, + "labels": [ + { + "key": "SN", + "value": "GF5022242024432" + }, + { + "key": "MAC", + "value": "00:18:05:24:cc:9a" + } + ], + "modbusSlave": { + "enable": 0, + "protocol": "Modbus-TCP", + "port": 502, + "slaveAddr": 1, + "int16Ord": "ab", + "int32Ord": "abcd", + "float32Ord": "abcd", + "maxConnection": 5, + "mapping_table": [] + }, + "modbusRTUSlave": { + "enable": 0, + "protocol": "Modbus-RTU", + "coms": "rs485", + "slaveAddr": 1, + "int16Ord": "ab", + "int32Ord": "abcd", + "float32Ord": "abcd", + "mapping_table": [] + }, + "iec104Server": { + "enable": 0, + "cotSize": 2, + "port": 2404, + "serverList": [ + { + "asduAddr": 1 + } + ], + "kValue": 12, + "wValue": 8, + "t0": 15, + "t1": 15, + "t2": 10, + "t3": 20, + "maximumLink": 5, + "timeSet": 1, + "byteOrder": "abcd", + "mapping_table": [] + }, + "iec104Client": { + "enable": 0, + "connectType": 2, + "serverAddr": "ipower.inhandcloud.cn", + "serverPort": 2404, + "communicationCode": "", + "protocol": 1, + "asduAddr": 1, + "tls": 0, + "mapping_table": { + "YX": [], + "YC": [], + "YK": [] + } + }, + "opcuaServer": { + "enable": 0, + "port": 4840, + "maximumLink": 5, + "securityMode": 0, + "identifierType": "String", + "certificate": "None", + "privateKey": "None", + "mapping_table": [] + }, + "southMetadata": {}, + "bindMetadata": { + "version": "", + "timestamp": "" + }, + "bindConfig": { + "enable": 0, + "bind": { + "modelId": "", + "modelName": "", + "srcId": "", + "srcName": "", + "devId": "", + "devName": "" + }, + "varGroups": [], + "variables": [], + "alerts": [] + }, + "version": "2.4.3" +} \ No newline at end of file diff --git a/Pub_Sub/advvfdipp_wo_downhole/thingsboard/sub/receiveCommand.py b/Pub_Sub/advvfdipp_wo_downhole/thingsboard/sub/receiveCommand.py index f2161f0..d4fa423 100644 --- a/Pub_Sub/advvfdipp_wo_downhole/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/advvfdipp_wo_downhole/thingsboard/sub/receiveCommand.py @@ -26,10 +26,10 @@ def sync(): for measure in controller["measures"]: #publish measure if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]: - payload[measure["name"]] = convert_int(measure["name"], measure["value"]) - payload[measure["name"]+ "_int"] = measure["value"] + payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"]) + payload["values"][measure["name"]+ "_int"] = measure["value"] else: - payload[measure["name"]] = measure["value"] + payload["values"][measure["name"]] = measure["value"] logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) for chunk in chunk_payload(payload=payload): diff --git a/Pub_Sub/cameratrailer/thingsboard/pub/sendData.py b/Pub_Sub/cameratrailer/thingsboard/pub/sendData.py index d65d142..5050957 100644 --- a/Pub_Sub/cameratrailer/thingsboard/pub/sendData.py +++ b/Pub_Sub/cameratrailer/thingsboard/pub/sendData.py @@ -150,6 +150,7 @@ def sendData(message,wizard_api): #publish(__topic__, json.dumps(message), __qos__) try: checkCredentialConfig() + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) except Exception as e: logger.error(f"Error in checkCredentialConfig: {e}") try: diff --git a/Pub_Sub/cameratrailer_hk/thingsboard/pub/sendData.py b/Pub_Sub/cameratrailer_hk/thingsboard/pub/sendData.py index 99b1dec..980eedb 100644 --- a/Pub_Sub/cameratrailer_hk/thingsboard/pub/sendData.py +++ b/Pub_Sub/cameratrailer_hk/thingsboard/pub/sendData.py @@ -199,6 +199,7 @@ def sendData(message,wizard_api): #publish(__topic__, json.dumps(message), __qos__) try: checkCredentialConfig() + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) except Exception as e: logger.error(f"Error in checkCredentialConfig: {e}") try: diff --git a/Pub_Sub/cpadvvfdipp/thingsboard/cpadvvfdipp_tb_v5.cfg b/Pub_Sub/cpadvvfdipp/thingsboard/cpadvvfdipp_tb_v5.cfg new file mode 100644 index 0000000..2a944a1 --- /dev/null +++ b/Pub_Sub/cpadvvfdipp/thingsboard/cpadvvfdipp_tb_v5.cfg @@ -0,0 +1,1221 @@ +{ + "controllers": [ + { + "protocol": "EtherNet/IP", + "name": "advvfdipp", + "args": {}, + "samplePeriod": 2, + "expired": 10000, + "endpoint": "192.168.1.10:44818" + } + ], + "groups": [ + { + "name": "default", + "uploadInterval": 600, + "reference": 45 + } + ], + "measures": [ + { + "name": "flowrate", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_Flowmeter_BarrelsPerDay", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "fluidlevel", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_FluidLevel", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "intakepressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_IntakePressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "intaketemperature", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_IntakeTemperature", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "tubingpressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "val_TubingPressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "wellstatus", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Device_Status_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "vfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "VFD_SpeedFdbk", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowtotal", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Flow_Total[0]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "energytotal", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Energy_Total[0]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "vfdcurrent", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "VFD_OutCurrent", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "downholesensorstatus", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Downhole_Sensor_Status_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "fluidspecificgravity", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_FluidSpecificGravity", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "flowtotalyesterday", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Flow_Total[1]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "energytotalyesterday", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Energy_Total[1]", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmflowrate", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_Flowmeter", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmintakepressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_IntakePressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmintaketemperature", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_IntakeTemperature", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmtubingpressure", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_TubingPressure", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmvfd", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_VFD", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmlockout", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_Lockout", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "runpermissive", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Run_Permissive_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "startpermissive", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "Start_Permissive_INT", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "alarmfluidlevel", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "alarm_FluidLevel", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "pressureshutdownlimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakePressure.Val_LoLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "pressurestartuplimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakePressure.Val_HiLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "temperatureshutdownlimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakeTemperature.Val_HiLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "temperaturestartuplimit", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "AIn_IntakeTemperature.Val_LoLim", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "sensorheight", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "cfg_DHSensorDistToIntake", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "last_vfd_fault_code", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "PowerFlex755.Val_LastFaultCode", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "vfd_fault", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "INT", + "addr": "sts_CurrentVFDFaultCode", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "controllerfault_io", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "ControllerFault_IO", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "controllerfault_program", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "ControllerFault_Program", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "minvfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "PowerFlex755.Cfg_MinSpdRef", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "name": "maxvfdfrequency", + "ctrlName": "advvfdipp", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "PowerFlex755.Cfg_MaxSpdRef", + "decimal": 2, + "len": 1, + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "gain": "", + "offset": "" + }, + { + "ctrlName": "advvfdipp", + "dataType": "BIT", + "addr": "cmd_Start", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "name": "startcommand", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "decimal": 2 + }, + { + "ctrlName": "advvfdipp", + "dataType": "BIT", + "addr": "cmd_Stop", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "name": "stopcommand", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "decimal": 2 + }, + { + "ctrlName": "advvfdipp", + "dataType": "DINT", + "addr": "sts_PID_Control", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "name": "pidcontrolmode", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "decimal": 2 + }, + { + "ctrlName": "advvfdipp", + "dataType": "FLOAT", + "addr": "cfg_PID_FlowSP", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "decimal": 2, + "name": "flowsetpoint", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "" + }, + { + "ctrlName": "advvfdipp", + "dataType": "FLOAT", + "addr": "cfg_PID_TubingPressureSP", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "decimal": 2, + "name": "tubingpressuresetpoint", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "" + }, + { + "ctrlName": "advvfdipp", + "dataType": "FLOAT", + "addr": "cfg_PID_FluidLevelSP", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "decimal": 2, + "name": "fluidlevelsetpoint", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "" + }, + { + "ctrlName": "advvfdipp", + "dataType": "FLOAT", + "addr": "cfg_PID_ManualSP", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "decimal": 2, + "name": "manualfrequencysetpoint", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "" + }, + { + "ctrlName": "advvfdipp", + "dataType": "BIT", + "addr": "cmd_ResetAlarms", + "readWrite": "rw", + "uploadType": "periodic", + "group": "default", + "name": "resetalarms", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "decimal": 2 + }, + { + "ctrlName": "advvfdipp", + "dataType": "FLOAT", + "addr": "val_Flowmeter_BarrelsPerMinute", + "readWrite": "ro", + "uploadType": "periodic", + "group": "default", + "decimal": 2, + "name": "flowrate_gpm", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "" + }, + { + "ctrlName": "advvfdipp", + "dataType": "BIT", + "addr": "PROMAG_300:I1.Connection_Fault", + "readWrite": "ro", + "uploadType": "periodic", + "group": "default", + "name": "flowmeter_fault", + "desc": "", + "unit": "", + "transformType": 0, + "gain": "1.0", + "offset": "0.0", + "maxValue": "", + "minValue": "", + "maxScaleValue": "", + "minScaleValue": "", + "decimal": 2 + } + ], + "alarms": [ + { + "name": "alarmflowrate", + "ctrlName": "advvfdipp", + "measureName": "alarmflowrate", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Flow Rate Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmintakepressure", + "ctrlName": "advvfdipp", + "measureName": "alarmintakepressure", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Intake Pressure Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmintaketemperature", + "ctrlName": "advvfdipp", + "measureName": "alarmintaketemperature", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Intake Temperature Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmtubingpressure", + "ctrlName": "advvfdipp", + "measureName": "alarmtubingpressure", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Tubing Pressure Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmvfd", + "ctrlName": "advvfdipp", + "measureName": "alarmvfd", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "VFD Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmlockout", + "ctrlName": "advvfdipp", + "measureName": "alarmlockout", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Lockout Alarm triggered", + "alarmLable": "default" + }, + { + "name": "alarmfluidlevel", + "ctrlName": "advvfdipp", + "measureName": "alarmfluidlevel", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Fluid Level Alarm triggered", + "alarmLable": "default" + }, + { + "name": "controllerfault_io", + "ctrlName": "advvfdipp", + "measureName": "controllerfault_io", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Controller IO Alarm triggered", + "alarmLable": "default" + }, + { + "name": "controllerfault_program", + "ctrlName": "advvfdipp", + "measureName": "controllerfault_program", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Controller Fault Alarm triggered", + "alarmLable": "default" + }, + { + "name": "flowmeter_fault", + "ctrlName": "advvfdipp", + "measureName": "flowmeter_fault", + "alarmLevel": 5, + "cond1": { + "op": "eq", + "value": "1.0" + }, + "condOp": "none", + "cond2": { + "op": "eq", + "value": "" + }, + "content": "Flow Meter Alarm triggered", + "alarmLable": "default" + } + ], + "misc": { + "maxAlarmRecordSz": 2000, + "logLvl": "INFO", + "coms": [ + { + "name": "rs232", + "baud": 9600, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + }, + { + "name": "rs485", + "baud": 19200, + "bits": 8, + "stopbits": 1, + "parityChk": "n" + } + ] + }, + "clouds": [ + { + "cacheSize": 100, + "enable": 1, + "type": "Standard MQTT", + "args": { + "host": "hp.henrypump.cloud", + "port": 1883, + "clientId": "unknown", + "auth": 1, + "tls": 0, + "cleanSession": 1, + "mqttVersion": "v3.1.1", + "keepalive": 120, + "key": "", + "cert": "", + "rootCA": "", + "verifyServer": 0, + "verifyClient": 0, + "username": "unknown", + "passwd": "unknown", + "authType": 1 + }, + "name": "default" + } + ], + "labels": [ + { + "key": "SN", + "value": "GF5022210011339" + }, + { + "key": "MAC", + "value": "00:18:05:1e:95:0f" + } + ], + "quickfaas": { + "genericFuncs": [], + "uploadFuncs": [ + { + "name": "Send Data", + "trigger": "measure_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "groups": [ + "default" + ], + "funcName": "sendData", + "script": "# Enter your python code.\nimport json, os, time\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot(reason=\"Rebooting for config file update\"):\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n logger.info(reason)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.debug(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.debug(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.debug(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.debug(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.debug(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.debug(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.debug(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.debug(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.debug(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.debug(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sendData(message):\n #logger.debug(message)\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n payload = {\"ts\": (round(dt.timestamp(dt.now())/600)*600)*1000, \"values\": {}}\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n if abs(payload[\"ts\"]/1000 - measure[\"timestamp\"]) > 3600:\n reboot(reason=\"Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}\".format(payload[\"ts\"]/1000,measure[\"timestamp\"]))\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n logger.debug(\"Converting DINT/BOOL to STRING\")\n value = convert_int(measure[\"name\"], measure[\"value\"])\n logger.debug(\"Converted {} to {}\".format(measure[\"value\"], value))\n payload[\"values\"][measure[\"name\"]] = value\n payload[\"values\"][measure[\"name\"] + \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"] \n except Exception as e:\n logger.error(e)\n \n for chunk in chunk_payload(payload=payload):\n publish(__topic__, json.dumps(chunk), __qos__)\n time.sleep(2)\n publish(\"v1/devices/me/attributes\", json.dumps({\"latestReportTime\": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n\n ", + "msgType": 0, + "cloudName": "default" + }, + { + "name": "sendAlarm", + "trigger": "warning_event", + "topic": "v1/devices/me/telemetry", + "qos": 1, + "funcName": "sendAlarm", + "script": "# Enter your python code.\nimport json, time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.measure import recall\n\n\ndef sendAlarm(message):\n logger.info(message)\n payload = {}\n payload[\"ts\"] = time.time()*1000\n payload[\"values\"] = {message[\"measureName\"]: message[\"value\"]}\n publish(__topic__, json.dumps(payload), __qos__)\n sync()\n\ndef sync():\n #get new values and send\n payload = {\"ts\": time.time()*1000, \"values\": {}}\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(__topic__))\n logger.debug(\"Sending value: {}\".format(payload))\n publish(__topic__, json.dumps(payload), 1)\n\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "alarms": [ + "default" + ], + "msgType": 0, + "cloudName": "default" + } + ], + "downloadFuncs": [ + { + "name": "Commands", + "topic": "v1/devices/me/rpc/request/+", + "qos": 1, + "funcName": "receiveCommand", + "payload_type": "JSON", + "script": "import json, time\nfrom datetime import datetime as dt\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sync():\n #get new values and send\n payload = {\"ts\": round(dt.timestamp(dt.now()))*1000, \"values\": {}}\n topic = \"v1/devices/me/telemetry\"\n try:\n data = recall()#json.loads(recall().decode(\"utf-8\"))\n except Exception as e:\n logger.error(e)\n logger.debug(data)\n for controller in data:\n for measure in controller[\"measures\"]:\n #publish measure\n if measure[\"name\"] in [\"wellstatus\",\"pidcontrolmode\",\"downholesensorstatus\",\"alarmflowrate\",\"alarmintakepressure\",\"alarmintaketemperature\",\"alarmtubingpressure\",\"alarmvfd\",\"alarmlockout\",\"alarmfluidlevel\",\"runpermissive\",\"startpermissive\",\"last_vfd_fault_code\",\"vfd_fault\", \"flowmeter_fault\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n payload[\"values\"][measure[\"name\"]+ \"_int\"] = measure[\"value\"]\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n logger.debug(\"Sending on topic: {}\".format(topic))\n logger.debug(\"Sending value: {}\".format(payload))\n for chunk in chunk_payload(payload=payload):\n publish(topic, json.dumps(chunk), 1)\n time.sleep(2)\ndef writeplctag(value):\n #value in the form {\"measurement\": , \"value\": }\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.debug(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.debug(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.debug(e)\n return False\n \ndef receiveCommand(topic, payload):\n try:\n logger.debug(topic)\n logger.debug(json.loads(payload))\n p = json.loads(payload)\n command = p[\"method\"]\n commands = {\n \"sync\": sync,\n \"writeplctag\": writeplctag,\n } \n if command == \"setPLCTag\":\n try:\n result = commands[\"writeplctag\"](p[\"params\"])\n logger.debug(result)\n except Exception as e:\n logger.error(e)\n elif command == \"changeSetpoint\":\n try:\n logger.debug(\"attempting controlpoint write\")\n params_type = {\"measurement\": \"pidcontrolmode\", \"value\": p[\"params\"][\"setpointType\"]}\n if params_type[\"value\"]:\n commands[\"writeplctag\"](params_type)\n time.sleep(2)\n except Exception as e:\n logger.error(\"DID NOT WRITE CONTROL MODE\")\n logger.error(e)\n try:\n logger.debug(\"attempting setpoint write\")\n modes = {0: \"flowsetpoint\", 1: \"fluidlevelsetpoint\", 2: \"tubingpressuresetpoint\", 3: \"manualfrequencysetpoint\"}\n params_value = {\"value\": p[\"params\"][\"setpointValue\"]}\n if params_value[\"value\"]:\n params_value[\"measurement\"] = modes[getMode()]\n result = commands[\"writeplctag\"](params_value)\n logger.debug(result)\n except Exception as e:\n logger.error(\"DID NOT WRITE SETPOINT\")\n logger.error(e)\n #logger.debug(command)\n ack(topic.split(\"/\")[-1])\n time.sleep(5)\n sync()\n except Exception as e:\n logger.debug(e)\n \n\ndef ack(msgid):\n #logger.debug(msgid)\n #logger.debug(mac)\n #logger.debug(name)\n #logger.debug(value)\n publish(\"v1/devices/me/rpc/response/\" + str(msgid), json.dumps({\"msg\": {\"time\": time.time()}, \"metadata\": \"\", \"msgType\": \"\"}), 1)\n\ndef getMode():\n try:\n data = recall()\n for controller in data:\n for measure in controller[\"measures\"]:\n if measure[\"name\"] == \"pidcontrolmode\":\n return measure[\"value\"]\n except:\n return None\n\ndef convert_int(plc_tag, value):\n well_status_codes = {\n 0: \"Running\",\n 1: \"Pumped Off\",\n 2: \"Alarmed\",\n 3: \"Locked Out\",\n 4: \"Stopped\"\n }\n\n pid_control_codes = {\n 0: \"Flow\",\n 1: \"Fluid Level\",\n 2: \"Tubing Pressure\",\n 3: \"Manual\"\n }\n\n downhole_codes = {\n 0: \"OK\",\n 1: \"Connecting\",\n 2: \"Open Circuit\",\n 3: \"Shorted\",\n 4: \"Cannot Decode\"\n }\n\n permissive_codes = {\n 0: \"OK\",\n 1: \"Flow\",\n 2: \"Intake Pressure\",\n 3: \"Intake Temperature\",\n 4: \"Tubing Pressure\",\n 5: \"VFD\",\n 6: \"Fluid Level\",\n 7: \"Min. Downtime\"\n }\n\n alarm_codes = {\n 0: \"OK\",\n 1: \"Alarm\"\n }\n\n alarm_vfd_codes = {\n 0: \"OK\",\n 1: \"Locked Out\"\n }\n\n vfd_fault_codes = {\n 0: \"No Fault\",\n 2: \"Auxiliary Input\",\n 3: \"Power Loss\",\n 4: \"UnderVoltage\",\n 5: \"OverVoltage\",\n 7: \"Motor Overload\",\n 8: \"Heatsink OverTemp\",\n 9: \"Thermister OverTemp\",\n 10: \"Dynamic Brake OverTemp\",\n 12: \"Hardware OverCurrent\",\n 13: \"Ground Fault\",\n 14: \"Ground Warning\",\n 15: \"Load Loss\",\n 17: \"Input Phase Loss\",\n 18: \"Motor PTC Trip\",\n 19: \"Task Overrun\",\n 20: \"Torque Prove Speed Band\",\n 21: \"Output Phase Loss\",\n 24: \"Decel Inhibit\",\n 25: \"OverSpeed Limit\",\n 26: \"Brake Slipped\",\n 27: \"Torque Prove Conflict\",\n 28: \"TP Encls Confict\",\n 29: \"Analog In Loss\",\n 33: \"Auto Restarts Exhausted\",\n 35: \"IPM OverCurrent\",\n 36: \"SW OverCurrent\",\n 38: \"Phase U to Ground\",\n 39: \"Phase V to Ground\",\n 40: \"Phase W to Ground\",\n 41: \"Phase UV Short\",\n 42: \"Phase VW Short\",\n 43: \"Phase WU Short\",\n 44: \"Phase UNeg to Ground\",\n 45: \"Phase VNeg to Ground\",\n 46: \"Phase WNeg to Ground\",\n 48: \"System Defaulted\",\n 49: \"Drive Powerup\",\n 51: \"Clear Fault Queue\",\n 55: \"Control Board Overtemp\",\n 59: \"Invalid Code\",\n 61: \"Shear Pin 1\",\n 62: \"Shear Pin 2\",\n 64: \"Drive Overload\",\n 66: \"OW Torque Level\",\n 67: \"Pump Off\",\n 71: \"Port 1 Adapter\",\n 72: \"Port 2 Adapter\",\n 73: \"Port 3 Adapter\",\n 74: \"Port 4 Adapter\",\n 75: \"Port 5 Adapter\",\n 76: \"Port 6 Adapter\",\n 77: \"IR Volts Range\",\n 78: \"FluxAmps Ref Range\",\n 79: \"Excessive Load\",\n 80: \"AutoTune Aborted\",\n 81: \"Port 1 DPI Loss\",\n 82: \"Port 2 DPI Loss\",\n 83: \"Port 3 DPI Loss\",\n 84: \"Port 4 DPI Loss\",\n 85: \"Port 5 DPI Loss\",\n 86: \"Port 6 DPI Loss\",\n 87: \"IXo Voltage Range\",\n 91: \"Primary Velocity Feedback Loss\",\n 93: \"Hardware Enable Check\",\n 94: \"Alternate Velocity Feedback Loss\",\n 95: \"Auxiliary Velocity Feedback Loss\",\n 96: \"Position Feedback Loss\",\n 97: \"Auto Tach Switch\",\n 100: \"Parameter Checksum\",\n 101: \"Power Down NVS Blank\",\n 102: \"NVS Not Blank\",\n 103: \"Power Down NVS Incompatible\",\n 104: \"Power Board Checksum\",\n 106: \"Incompat MCB-PB\",\n 107: \"Replaced MCB-PB\",\n 108: \"Analog Calibration Checksum\",\n 110: \"Invalid Power Board Data\",\n 111: \"Power Board Invalid ID\",\n 112: \"Power Board App Min Version\",\n 113: \"Tracking DataError\",\n 115: \"Power Down Table Full\",\n 116: \"Power Down Entry Too Large\",\n 117: \"Power Down Data Checksum\",\n 118: \"Power Board Power Down Checksum\",\n 124: \"App ID Changed\",\n 125: \"Using Backup App\",\n 134: \"Start on Power Up\",\n 137: \"External Precharge Error\",\n 138: \"Precharge Open\",\n 141: \"Autotune Enc Angle\",\n 142: \"Autotune Speed Restricted\",\n 143: \"Autotune Current Regulator\",\n 144: \"Autotune Inertia\",\n 145: \"Autotune Travel\",\n 13035: \"Net IO Timeout\",\n 13037: \"Net IO Timeout\"\n\n }\n\n plc_tags = {\n \"wellstatus\": well_status_codes.get(value, \"Invalid Code\"),\n \"pidcontrolmode\": pid_control_codes.get(value, \"Invalid Code\"),\n \"downholesensorstatus\": downhole_codes.get(value, \"Invalid Code\"),\n \"alarmflowrate\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintakepressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmintaketemperature\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmtubingpressure\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmvfd\": alarm_codes.get(value, \"Invalid Code\"),\n \"alarmlockout\": alarm_vfd_codes.get(value, \"Invalid Code\"),\n \"alarmfluidlevel\": alarm_codes.get(value, \"Invalid Code\"),\n \"runpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"startpermissive\": permissive_codes.get(value, \"Invalid Code\"),\n \"last_vfd_fault_code\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"vfd_fault\": vfd_fault_codes.get(value, \"Invalid Code\"),\n \"flowmeter_fault\": alarm_codes.get(value, \"Invalid Code\")\n }\n\n return plc_tags.get(plc_tag, \"Invalid Tag\")\n", + "msgType": 0, + "trigger": "command_event", + "cloudName": "default" + } + ] + }, + "modbusSlave": { + "enable": 0, + "protocol": "Modbus-TCP", + "port": 502, + "slaveAddr": 1, + "int16Ord": "ab", + "int32Ord": "abcd", + "float32Ord": "abcd", + "maxConnection": 5, + "mapping_table": [] + }, + "iec104Server": { + "enable": 0, + "cotSize": 2, + "port": 2404, + "serverList": [ + { + "asduAddr": 1 + } + ], + "kValue": 12, + "wValue": 8, + "t0": 15, + "t1": 15, + "t2": 10, + "t3": 20, + "maximumLink": 5, + "timeSet": 1, + "byteOrder": "abcd", + "mapping_table": [] + }, + "opcuaServer": { + "enable": 0, + "port": 4840, + "maximumLink": 5, + "securityMode": 0, + "identifierType": "String", + "mapping_table": [] + }, + "bindConfig": { + "enable": 0, + "bind": { + "modelId": "", + "modelName": "", + "srcId": "", + "srcName": "", + "devId": "", + "devName": "" + }, + "varGroups": [], + "variables": [], + "alerts": [] + }, + "southMetadata": {}, + "bindMetadata": { + "version": "", + "timestamp": "" + } +} \ No newline at end of file diff --git a/Pub_Sub/cpadvvfdipp/thingsboard/pub/sendAlarms.py b/Pub_Sub/cpadvvfdipp/thingsboard/pub/sendAlarms.py new file mode 100644 index 0000000..c5039e9 --- /dev/null +++ b/Pub_Sub/cpadvvfdipp/thingsboard/pub/sendAlarms.py @@ -0,0 +1,201 @@ +# Enter your python code. +import json, time +from common.Logger import logger +from quickfaas.remotebus import publish +from quickfaas.measure import recall + + +def sendAlarm(message): + logger.info(message) + payload = {} + payload["ts"] = time.time()*1000 + payload["values"] = {message["measureName"]: message["value"]} + publish(__topic__, json.dumps(payload), __qos__) + sync() + +def sync(): + #get new values and send + payload = {"ts": time.time()*1000, "values": {}} + try: + data = recall()#json.loads(recall().decode("utf-8")) + except Exception as e: + logger.error(e) + logger.debug(data) + for controller in data: + for measure in controller["measures"]: + #publish measure + if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]: + payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"]) + payload["values"][measure["name"]+ "_int"] = measure["value"] + else: + payload["values"][measure["name"]] = measure["value"] + logger.debug("Sending on topic: {}".format(__topic__)) + logger.debug("Sending value: {}".format(payload)) + publish(__topic__, json.dumps(payload), 1) + + +def convert_int(plc_tag, value): + well_status_codes = { + 0: "Running", + 1: "Pumped Off", + 2: "Alarmed", + 3: "Locked Out", + 4: "Stopped" + } + + pid_control_codes = { + 0: "Flow", + 1: "Fluid Level", + 2: "Tubing Pressure", + 3: "Manual" + } + + downhole_codes = { + 0: "OK", + 1: "Connecting", + 2: "Open Circuit", + 3: "Shorted", + 4: "Cannot Decode" + } + + permissive_codes = { + 0: "OK", + 1: "Flow", + 2: "Intake Pressure", + 3: "Intake Temperature", + 4: "Tubing Pressure", + 5: "VFD", + 6: "Fluid Level", + 7: "Min. Downtime" + } + + alarm_codes = { + 0: "OK", + 1: "Alarm" + } + + alarm_vfd_codes = { + 0: "OK", + 1: "Locked Out" + } + + vfd_fault_codes = { + 0: "No Fault", + 2: "Auxiliary Input", + 3: "Power Loss", + 4: "UnderVoltage", + 5: "OverVoltage", + 7: "Motor Overload", + 8: "Heatsink OverTemp", + 9: "Thermister OverTemp", + 10: "Dynamic Brake OverTemp", + 12: "Hardware OverCurrent", + 13: "Ground Fault", + 14: "Ground Warning", + 15: "Load Loss", + 17: "Input Phase Loss", + 18: "Motor PTC Trip", + 19: "Task Overrun", + 20: "Torque Prove Speed Band", + 21: "Output Phase Loss", + 24: "Decel Inhibit", + 25: "OverSpeed Limit", + 26: "Brake Slipped", + 27: "Torque Prove Conflict", + 28: "TP Encls Confict", + 29: "Analog In Loss", + 33: "Auto Restarts Exhausted", + 35: "IPM OverCurrent", + 36: "SW OverCurrent", + 38: "Phase U to Ground", + 39: "Phase V to Ground", + 40: "Phase W to Ground", + 41: "Phase UV Short", + 42: "Phase VW Short", + 43: "Phase WU Short", + 44: "Phase UNeg to Ground", + 45: "Phase VNeg to Ground", + 46: "Phase WNeg to Ground", + 48: "System Defaulted", + 49: "Drive Powerup", + 51: "Clear Fault Queue", + 55: "Control Board Overtemp", + 59: "Invalid Code", + 61: "Shear Pin 1", + 62: "Shear Pin 2", + 64: "Drive Overload", + 66: "OW Torque Level", + 67: "Pump Off", + 71: "Port 1 Adapter", + 72: "Port 2 Adapter", + 73: "Port 3 Adapter", + 74: "Port 4 Adapter", + 75: "Port 5 Adapter", + 76: "Port 6 Adapter", + 77: "IR Volts Range", + 78: "FluxAmps Ref Range", + 79: "Excessive Load", + 80: "AutoTune Aborted", + 81: "Port 1 DPI Loss", + 82: "Port 2 DPI Loss", + 83: "Port 3 DPI Loss", + 84: "Port 4 DPI Loss", + 85: "Port 5 DPI Loss", + 86: "Port 6 DPI Loss", + 87: "IXo Voltage Range", + 91: "Primary Velocity Feedback Loss", + 93: "Hardware Enable Check", + 94: "Alternate Velocity Feedback Loss", + 95: "Auxiliary Velocity Feedback Loss", + 96: "Position Feedback Loss", + 97: "Auto Tach Switch", + 100: "Parameter Checksum", + 101: "Power Down NVS Blank", + 102: "NVS Not Blank", + 103: "Power Down NVS Incompatible", + 104: "Power Board Checksum", + 106: "Incompat MCB-PB", + 107: "Replaced MCB-PB", + 108: "Analog Calibration Checksum", + 110: "Invalid Power Board Data", + 111: "Power Board Invalid ID", + 112: "Power Board App Min Version", + 113: "Tracking DataError", + 115: "Power Down Table Full", + 116: "Power Down Entry Too Large", + 117: "Power Down Data Checksum", + 118: "Power Board Power Down Checksum", + 124: "App ID Changed", + 125: "Using Backup App", + 134: "Start on Power Up", + 137: "External Precharge Error", + 138: "Precharge Open", + 141: "Autotune Enc Angle", + 142: "Autotune Speed Restricted", + 143: "Autotune Current Regulator", + 144: "Autotune Inertia", + 145: "Autotune Travel", + 13035: "Net IO Timeout", + 13037: "Net IO Timeout" + + } + + plc_tags = { + "wellstatus": well_status_codes.get(value, "Invalid Code"), + "pidcontrolmode": pid_control_codes.get(value, "Invalid Code"), + "downholesensorstatus": downhole_codes.get(value, "Invalid Code"), + "alarmflowrate": alarm_codes.get(value, "Invalid Code"), + "alarmintakepressure": alarm_codes.get(value, "Invalid Code"), + "alarmintaketemperature": alarm_codes.get(value, "Invalid Code"), + "alarmtubingpressure": alarm_codes.get(value, "Invalid Code"), + "alarmvfd": alarm_codes.get(value, "Invalid Code"), + "alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"), + "alarmfluidlevel": alarm_codes.get(value, "Invalid Code"), + "runpermissive": permissive_codes.get(value, "Invalid Code"), + "startpermissive": permissive_codes.get(value, "Invalid Code"), + "last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"), + "vfd_fault": vfd_fault_codes.get(value, "Invalid Code"), + "flowmeter_fault": alarm_codes.get(value, "Invalid Code") + } + + return plc_tags.get(plc_tag, "Invalid Tag") diff --git a/Pub_Sub/cpadvvfdipp/thingsboard/pub/sendData.py b/Pub_Sub/cpadvvfdipp/thingsboard/pub/sendData.py new file mode 100644 index 0000000..b5ef2e2 --- /dev/null +++ b/Pub_Sub/cpadvvfdipp/thingsboard/pub/sendData.py @@ -0,0 +1,323 @@ +# Enter your python code. +import json, os, time +from datetime import datetime as dt +from common.Logger import logger +from quickfaas.remotebus import publish +from quickfaas.global_dict import get as get_params +from quickfaas.global_dict import _set_global_args + +def reboot(reason="Rebooting for config file update"): + #basic = Basic() + logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10) + logger.info(reason) + r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read() + logger.info(f"REBOOT : {r}") + +def checkFileExist(filename): + path = "/var/user/files" + if not os.path.exists(path): + logger.debug("no folder making files folder in var/user") + os.makedirs(path) + with open(path + "/" + filename, "a") as f: + json.dump({}, f) + if not os.path.exists(path + "/" + filename): + logger.debug("no creds file making creds file") + with open(path + "/" + filename, "a") as f: + json.dump({}, f) + +def convertDStoJSON(ds): + j = dict() + for x in ds: + j[x["key"]] = x["value"] + return j + +def convertJSONtoDS(j): + d = [] + for key in j.keys(): + d.append({"key": key, "value": j[key]}) + return d + +def checkCredentialConfig(): + logger.debug("CHECKING CONFIG") + cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg" + credspath = "/var/user/files/creds.json" + cfg = dict() + with open(cfgpath, "r") as f: + cfg = json.load(f) + clouds = cfg.get("clouds") + logger.debug(clouds) + #if not configured then try to configure from stored values + if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown": + checkFileExist("creds.json") + with open(credspath, "r") as c: + creds = json.load(c) + if creds: + logger.debug("updating config with stored data") + clouds[0]["args"]["clientId"] = creds["clientId"] + clouds[0]["args"]["username"] = creds["userName"] + clouds[0]["args"]["passwd"] = creds["password"] + cfg["clouds"] = clouds + cfg = checkParameterConfig(cfg) + with open(cfgpath, "w", encoding='utf-8') as n: + json.dump(cfg, n, indent=1, ensure_ascii=False) + reboot() + else: + #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data + checkFileExist("creds.json") + with open(credspath, "r") as c: + logger.debug("updating stored file with new data") + cfg = checkParameterConfig(cfg) + with open(cfgpath, "w", encoding='utf-8') as n: + json.dump(cfg, n, indent=1, ensure_ascii=False) + creds = json.load(c) + if creds: + if creds["clientId"] != clouds[0]["args"]["clientId"]: + creds["clientId"] = clouds[0]["args"]["clientId"] + if creds["userName"] != clouds[0]["args"]["username"]: + creds["userName"] = clouds[0]["args"]["username"] + if creds["password"] != clouds[0]["args"]["passwd"]: + creds["password"] = clouds[0]["args"]["passwd"] + else: + creds["clientId"] = clouds[0]["args"]["clientId"] + creds["userName"] = clouds[0]["args"]["username"] + creds["password"] = clouds[0]["args"]["passwd"] + with open(credspath, "w") as cw: + json.dump(creds,cw) + +def checkParameterConfig(cfg): + logger.debug("Checking Parameters!!!!") + paramspath = "/var/user/files/params.json" + cfgparams = convertDStoJSON(cfg.get("labels")) + #check stored values + checkFileExist("params.json") + with open(paramspath, "r") as f: + logger.debug("Opened param storage file") + params = json.load(f) + if params: + if cfgparams != params: + #go through each param + #if not "unknown" and cfg and params aren't the same take from cfg likely updated manually + #if key in cfg but not in params copy to params + logger.debug("equalizing params between cfg and stored") + for key in cfgparams.keys(): + try: + if cfgparams[key] != params[key] and cfgparams[key] != "unknown": + params[key] = cfgparams[key] + except: + params[key] = cfgparams[key] + cfg["labels"] = convertJSONtoDS(params) + _set_global_args(convertJSONtoDS(params)) + with open(paramspath, "w") as p: + json.dump(params, p) + else: + with open(paramspath, "w") as p: + logger.debug("initializing param file with params in memory") + json.dump(convertDStoJSON(get_params()), p) + cfg["labels"] = get_params() + + return cfg + +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + +def sendData(message): + #logger.debug(message) + try: + checkCredentialConfig() + except Exception as e: + logger.error(e) + payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}} + for measure in message["measures"]: + try: + logger.debug(measure) + if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600: + reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"])) + if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]: + logger.debug("Converting DINT/BOOL to STRING") + value = convert_int(measure["name"], measure["value"]) + logger.debug("Converted {} to {}".format(measure["value"], value)) + payload["values"][measure["name"]] = value + payload["values"][measure["name"] + "_int"] = measure["value"] + else: + payload["values"][measure["name"]] = measure["value"] + except Exception as e: + logger.error(e) + + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) + +def convert_int(plc_tag, value): + well_status_codes = { + 0: "Running", + 1: "Pumped Off", + 2: "Alarmed", + 3: "Locked Out", + 4: "Stopped" + } + + pid_control_codes = { + 0: "Flow", + 1: "Fluid Level", + 2: "Tubing Pressure", + 3: "Manual" + } + + downhole_codes = { + 0: "OK", + 1: "Connecting", + 2: "Open Circuit", + 3: "Shorted", + 4: "Cannot Decode" + } + + permissive_codes = { + 0: "OK", + 1: "Flow", + 2: "Intake Pressure", + 3: "Intake Temperature", + 4: "Tubing Pressure", + 5: "VFD", + 6: "Fluid Level", + 7: "Min. Downtime" + } + + alarm_codes = { + 0: "OK", + 1: "Alarm" + } + + alarm_vfd_codes = { + 0: "OK", + 1: "Locked Out" + } + + vfd_fault_codes = { + 0: "No Fault", + 2: "Auxiliary Input", + 3: "Power Loss", + 4: "UnderVoltage", + 5: "OverVoltage", + 7: "Motor Overload", + 8: "Heatsink OverTemp", + 9: "Thermister OverTemp", + 10: "Dynamic Brake OverTemp", + 12: "Hardware OverCurrent", + 13: "Ground Fault", + 14: "Ground Warning", + 15: "Load Loss", + 17: "Input Phase Loss", + 18: "Motor PTC Trip", + 19: "Task Overrun", + 20: "Torque Prove Speed Band", + 21: "Output Phase Loss", + 24: "Decel Inhibit", + 25: "OverSpeed Limit", + 26: "Brake Slipped", + 27: "Torque Prove Conflict", + 28: "TP Encls Confict", + 29: "Analog In Loss", + 33: "Auto Restarts Exhausted", + 35: "IPM OverCurrent", + 36: "SW OverCurrent", + 38: "Phase U to Ground", + 39: "Phase V to Ground", + 40: "Phase W to Ground", + 41: "Phase UV Short", + 42: "Phase VW Short", + 43: "Phase WU Short", + 44: "Phase UNeg to Ground", + 45: "Phase VNeg to Ground", + 46: "Phase WNeg to Ground", + 48: "System Defaulted", + 49: "Drive Powerup", + 51: "Clear Fault Queue", + 55: "Control Board Overtemp", + 59: "Invalid Code", + 61: "Shear Pin 1", + 62: "Shear Pin 2", + 64: "Drive Overload", + 66: "OW Torque Level", + 67: "Pump Off", + 71: "Port 1 Adapter", + 72: "Port 2 Adapter", + 73: "Port 3 Adapter", + 74: "Port 4 Adapter", + 75: "Port 5 Adapter", + 76: "Port 6 Adapter", + 77: "IR Volts Range", + 78: "FluxAmps Ref Range", + 79: "Excessive Load", + 80: "AutoTune Aborted", + 81: "Port 1 DPI Loss", + 82: "Port 2 DPI Loss", + 83: "Port 3 DPI Loss", + 84: "Port 4 DPI Loss", + 85: "Port 5 DPI Loss", + 86: "Port 6 DPI Loss", + 87: "IXo Voltage Range", + 91: "Primary Velocity Feedback Loss", + 93: "Hardware Enable Check", + 94: "Alternate Velocity Feedback Loss", + 95: "Auxiliary Velocity Feedback Loss", + 96: "Position Feedback Loss", + 97: "Auto Tach Switch", + 100: "Parameter Checksum", + 101: "Power Down NVS Blank", + 102: "NVS Not Blank", + 103: "Power Down NVS Incompatible", + 104: "Power Board Checksum", + 106: "Incompat MCB-PB", + 107: "Replaced MCB-PB", + 108: "Analog Calibration Checksum", + 110: "Invalid Power Board Data", + 111: "Power Board Invalid ID", + 112: "Power Board App Min Version", + 113: "Tracking DataError", + 115: "Power Down Table Full", + 116: "Power Down Entry Too Large", + 117: "Power Down Data Checksum", + 118: "Power Board Power Down Checksum", + 124: "App ID Changed", + 125: "Using Backup App", + 134: "Start on Power Up", + 137: "External Precharge Error", + 138: "Precharge Open", + 141: "Autotune Enc Angle", + 142: "Autotune Speed Restricted", + 143: "Autotune Current Regulator", + 144: "Autotune Inertia", + 145: "Autotune Travel", + 13035: "Net IO Timeout", + 13037: "Net IO Timeout" + + } + + plc_tags = { + "wellstatus": well_status_codes.get(value, "Invalid Code"), + "pidcontrolmode": pid_control_codes.get(value, "Invalid Code"), + "downholesensorstatus": downhole_codes.get(value, "Invalid Code"), + "alarmflowrate": alarm_codes.get(value, "Invalid Code"), + "alarmintakepressure": alarm_codes.get(value, "Invalid Code"), + "alarmintaketemperature": alarm_codes.get(value, "Invalid Code"), + "alarmtubingpressure": alarm_codes.get(value, "Invalid Code"), + "alarmvfd": alarm_codes.get(value, "Invalid Code"), + "alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"), + "alarmfluidlevel": alarm_codes.get(value, "Invalid Code"), + "runpermissive": permissive_codes.get(value, "Invalid Code"), + "startpermissive": permissive_codes.get(value, "Invalid Code"), + "last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"), + "vfd_fault": vfd_fault_codes.get(value, "Invalid Code"), + "flowmeter_fault": alarm_codes.get(value, "Invalid Code") + } + + return plc_tags.get(plc_tag, "Invalid Tag") + + \ No newline at end of file diff --git a/Pub_Sub/cpadvvfdipp/thingsboard/sub/receiveCommand.py b/Pub_Sub/cpadvvfdipp/thingsboard/sub/receiveCommand.py new file mode 100644 index 0000000..d4fa423 --- /dev/null +++ b/Pub_Sub/cpadvvfdipp/thingsboard/sub/receiveCommand.py @@ -0,0 +1,278 @@ +import json, time +from datetime import datetime as dt +from quickfaas.measure import recall, write +from quickfaas.remotebus import publish +from common.Logger import logger + +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + +def sync(): + #get new values and send + payload = {"ts": round(dt.timestamp(dt.now()))*1000, "values": {}} + topic = "v1/devices/me/telemetry" + try: + data = recall()#json.loads(recall().decode("utf-8")) + except Exception as e: + logger.error(e) + logger.debug(data) + for controller in data: + for measure in controller["measures"]: + #publish measure + if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]: + payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"]) + payload["values"][measure["name"]+ "_int"] = measure["value"] + else: + payload["values"][measure["name"]] = measure["value"] + logger.debug("Sending on topic: {}".format(topic)) + logger.debug("Sending value: {}".format(payload)) + for chunk in chunk_payload(payload=payload): + publish(topic, json.dumps(chunk), 1) + time.sleep(2) +def writeplctag(value): + #value in the form {"measurement": , "value": } + try: + #value = json.loads(value.replace("'",'"')) + logger.debug(value) + #payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}] + message = [{"name": "advvfdipp", "measures":[{"name":value["measurement"], "value": value["value"]}]}] + resp = write(message) + logger.debug("RETURN FROM WRITE: {}".format(resp)) + return True + except Exception as e: + logger.debug(e) + return False + +def receiveCommand(topic, payload): + try: + logger.debug(topic) + logger.debug(json.loads(payload)) + p = json.loads(payload) + command = p["method"] + commands = { + "sync": sync, + "writeplctag": writeplctag, + } + if command == "setPLCTag": + try: + result = commands["writeplctag"](p["params"]) + logger.debug(result) + except Exception as e: + logger.error(e) + elif command == "changeSetpoint": + try: + logger.debug("attempting controlpoint write") + params_type = {"measurement": "pidcontrolmode", "value": p["params"]["setpointType"]} + if params_type["value"]: + commands["writeplctag"](params_type) + time.sleep(2) + except Exception as e: + logger.error("DID NOT WRITE CONTROL MODE") + logger.error(e) + try: + logger.debug("attempting setpoint write") + modes = {0: "flowsetpoint", 1: "fluidlevelsetpoint", 2: "tubingpressuresetpoint", 3: "manualfrequencysetpoint"} + params_value = {"value": p["params"]["setpointValue"]} + if params_value["value"]: + params_value["measurement"] = modes[getMode()] + result = commands["writeplctag"](params_value) + logger.debug(result) + except Exception as e: + logger.error("DID NOT WRITE SETPOINT") + logger.error(e) + #logger.debug(command) + ack(topic.split("/")[-1]) + time.sleep(5) + sync() + except Exception as e: + logger.debug(e) + + +def ack(msgid): + #logger.debug(msgid) + #logger.debug(mac) + #logger.debug(name) + #logger.debug(value) + publish("v1/devices/me/rpc/response/" + str(msgid), json.dumps({"msg": {"time": time.time()}, "metadata": "", "msgType": ""}), 1) + +def getMode(): + try: + data = recall() + for controller in data: + for measure in controller["measures"]: + if measure["name"] == "pidcontrolmode": + return measure["value"] + except: + return None + +def convert_int(plc_tag, value): + well_status_codes = { + 0: "Running", + 1: "Pumped Off", + 2: "Alarmed", + 3: "Locked Out", + 4: "Stopped" + } + + pid_control_codes = { + 0: "Flow", + 1: "Fluid Level", + 2: "Tubing Pressure", + 3: "Manual" + } + + downhole_codes = { + 0: "OK", + 1: "Connecting", + 2: "Open Circuit", + 3: "Shorted", + 4: "Cannot Decode" + } + + permissive_codes = { + 0: "OK", + 1: "Flow", + 2: "Intake Pressure", + 3: "Intake Temperature", + 4: "Tubing Pressure", + 5: "VFD", + 6: "Fluid Level", + 7: "Min. Downtime" + } + + alarm_codes = { + 0: "OK", + 1: "Alarm" + } + + alarm_vfd_codes = { + 0: "OK", + 1: "Locked Out" + } + + vfd_fault_codes = { + 0: "No Fault", + 2: "Auxiliary Input", + 3: "Power Loss", + 4: "UnderVoltage", + 5: "OverVoltage", + 7: "Motor Overload", + 8: "Heatsink OverTemp", + 9: "Thermister OverTemp", + 10: "Dynamic Brake OverTemp", + 12: "Hardware OverCurrent", + 13: "Ground Fault", + 14: "Ground Warning", + 15: "Load Loss", + 17: "Input Phase Loss", + 18: "Motor PTC Trip", + 19: "Task Overrun", + 20: "Torque Prove Speed Band", + 21: "Output Phase Loss", + 24: "Decel Inhibit", + 25: "OverSpeed Limit", + 26: "Brake Slipped", + 27: "Torque Prove Conflict", + 28: "TP Encls Confict", + 29: "Analog In Loss", + 33: "Auto Restarts Exhausted", + 35: "IPM OverCurrent", + 36: "SW OverCurrent", + 38: "Phase U to Ground", + 39: "Phase V to Ground", + 40: "Phase W to Ground", + 41: "Phase UV Short", + 42: "Phase VW Short", + 43: "Phase WU Short", + 44: "Phase UNeg to Ground", + 45: "Phase VNeg to Ground", + 46: "Phase WNeg to Ground", + 48: "System Defaulted", + 49: "Drive Powerup", + 51: "Clear Fault Queue", + 55: "Control Board Overtemp", + 59: "Invalid Code", + 61: "Shear Pin 1", + 62: "Shear Pin 2", + 64: "Drive Overload", + 66: "OW Torque Level", + 67: "Pump Off", + 71: "Port 1 Adapter", + 72: "Port 2 Adapter", + 73: "Port 3 Adapter", + 74: "Port 4 Adapter", + 75: "Port 5 Adapter", + 76: "Port 6 Adapter", + 77: "IR Volts Range", + 78: "FluxAmps Ref Range", + 79: "Excessive Load", + 80: "AutoTune Aborted", + 81: "Port 1 DPI Loss", + 82: "Port 2 DPI Loss", + 83: "Port 3 DPI Loss", + 84: "Port 4 DPI Loss", + 85: "Port 5 DPI Loss", + 86: "Port 6 DPI Loss", + 87: "IXo Voltage Range", + 91: "Primary Velocity Feedback Loss", + 93: "Hardware Enable Check", + 94: "Alternate Velocity Feedback Loss", + 95: "Auxiliary Velocity Feedback Loss", + 96: "Position Feedback Loss", + 97: "Auto Tach Switch", + 100: "Parameter Checksum", + 101: "Power Down NVS Blank", + 102: "NVS Not Blank", + 103: "Power Down NVS Incompatible", + 104: "Power Board Checksum", + 106: "Incompat MCB-PB", + 107: "Replaced MCB-PB", + 108: "Analog Calibration Checksum", + 110: "Invalid Power Board Data", + 111: "Power Board Invalid ID", + 112: "Power Board App Min Version", + 113: "Tracking DataError", + 115: "Power Down Table Full", + 116: "Power Down Entry Too Large", + 117: "Power Down Data Checksum", + 118: "Power Board Power Down Checksum", + 124: "App ID Changed", + 125: "Using Backup App", + 134: "Start on Power Up", + 137: "External Precharge Error", + 138: "Precharge Open", + 141: "Autotune Enc Angle", + 142: "Autotune Speed Restricted", + 143: "Autotune Current Regulator", + 144: "Autotune Inertia", + 145: "Autotune Travel", + 13035: "Net IO Timeout", + 13037: "Net IO Timeout" + + } + + plc_tags = { + "wellstatus": well_status_codes.get(value, "Invalid Code"), + "pidcontrolmode": pid_control_codes.get(value, "Invalid Code"), + "downholesensorstatus": downhole_codes.get(value, "Invalid Code"), + "alarmflowrate": alarm_codes.get(value, "Invalid Code"), + "alarmintakepressure": alarm_codes.get(value, "Invalid Code"), + "alarmintaketemperature": alarm_codes.get(value, "Invalid Code"), + "alarmtubingpressure": alarm_codes.get(value, "Invalid Code"), + "alarmvfd": alarm_codes.get(value, "Invalid Code"), + "alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"), + "alarmfluidlevel": alarm_codes.get(value, "Invalid Code"), + "runpermissive": permissive_codes.get(value, "Invalid Code"), + "startpermissive": permissive_codes.get(value, "Invalid Code"), + "last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"), + "vfd_fault": vfd_fault_codes.get(value, "Invalid Code"), + "flowmeter_fault": alarm_codes.get(value, "Invalid Code") + } + + return plc_tags.get(plc_tag, "Invalid Tag") diff --git a/Pub_Sub/fkplcpond/thingsboard/bn_pond.cfg b/Pub_Sub/fkplcpond/thingsboard/bn_pond.cfg deleted file mode 100644 index 8062258..0000000 --- a/Pub_Sub/fkplcpond/thingsboard/bn_pond.cfg +++ /dev/null @@ -1,592 +0,0 @@ -{ - "controllers": [ - { - "enable": 1, - "protocol": "AllenBradley MicroCip", - "name": "plcpond", - "samplePeriod": 10, - "desc": "", - "expired": 1000, - "args": { - "slot": 0, - "connectTimeOut": 10000 - }, - "enableDebug": 0, - "enablePerOnchange": 0, - "endpoint": "192.168.1.12:44818" - } - ], - "measures": [ - { - "name": "pond_1_level", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lev", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_1_total_bbls", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Total_Barrels", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_1_hi_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_1_Hi_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "bitMap": 0, - "reverseBit": 0, - "storageLwTSDB": 0 - }, - { - "name": "pond_1_hi_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Hi_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_1_hi_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Hi_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_1_lo_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_1_Lo_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "bitMap": 0, - "reverseBit": 0, - "storageLwTSDB": 0 - }, - { - "name": "pond_1_lo_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lo_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_1_lo_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lo_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_2_level", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lev", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_2_total_bbls", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Total_Barrels", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_2_hi_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_2_Hi_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "bitMap": 0, - "reverseBit": 0, - "storageLwTSDB": 0 - }, - { - "name": "pond_2_hi_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Hi_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_2_hi_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Hi_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "1.0", - "offset": "0.0", - "storageLwTSDB": 0 - }, - { - "name": "pond_2_lo_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_2_Lo_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "bitMap": 0, - "reverseBit": 0, - "storageLwTSDB": 0 - }, - { - "name": "pond_2_lo_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lo_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - }, - { - "name": "pond_2_lo_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lo_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "", - "storageLwTSDB": 0 - } - ], - "alarmLables": [ - "default" - ], - "alarms": [], - "groups": [ - { - "name": "default", - "uploadInterval": 600, - "reference": 16, - "LwTSDBSize": 1000, - "strategy": 1, - "historyDataPath": "/var/user/data/dbhome/device_supervisor/LwTSDB", - "enablePerOnchange": 0 - } - ], - "misc": { - "maxAlarmRecordSz": 2000, - "logLvl": "INFO", - "coms": [ - { - "name": "rs232", - "baud": 9600, - "bits": 8, - "stopbits": 1, - "parityChk": "n" - }, - { - "name": "rs485", - "baud": 9600, - "bits": 8, - "stopbits": 1, - "parityChk": "n" - } - ], - "cachePath": "/var/user/data/dbhome/device_supervisor/offlinedata", - "cacheSize": 10000, - "debugLogPath": "/var/user/data/dbhome/device_supervisor/debugLog", - "debugLogSize": 2000 - }, - "clouds": [ - { - "cacheSize": 100, - "enable": 1, - "name": "default", - "type": "Standard MQTT", - "args": { - "host": "hp.henrypump.cloud", - "port": 1883, - "clientId": "unknown", - "auth": 1, - "tls": 0, - "cleanSession": 0, - "mqttVersion": "v3.1.1", - "keepalive": 60, - "key": "", - "cert": "", - "rootCA": "", - "verifyServer": 0, - "verifyClient": 0, - "username": "unknown", - "passwd": "unknown", - "authType": 1, - "willQos": 0, - "willRetain": 0, - "willTopic": "", - "willPayload": "", - "tlsAuth": "caSelfSigned" - }, - "uploadRules": [] - } - ], - "quickfaas": { - "genericFuncs": [], - "uploadFuncs": [ - { - "name": "sendData", - "trigger": "measure_event", - "topic": "v1/devices/me/telemetry", - "qos": 1, - "groups": [ - "default" - ], - "funcName": "sendData", - "script": "# Enter your python code.\nimport json, os\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot():\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.info(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.info(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.info(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.info(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.info(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.info(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.info(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.info(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.info(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.info(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n\n\n\ndef sendData(message):\n payload = {}\n payload[\"ts\"] = (round(dt.timestamp(dt.now())/600)*600)*1000\n payload[\"values\"] = {}\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n publish(__topic__, json.dumps(payload), __qos__)", - "msgType": 0, - "cloudName": "default" - } - ], - "downloadFuncs": [] - }, - "labels": [ - { - "key": "SN", - "value": "GF5022311031664" - }, - { - "key": "MAC", - "value": "00:18:05:28:4a:40" - } - ], - "modbusSlave": { - "enable": 0, - "protocol": "Modbus-TCP", - "port": 502, - "slaveAddr": 1, - "int16Ord": "ab", - "int32Ord": "abcd", - "float32Ord": "abcd", - "maxConnection": 5, - "mapping_table": [] - }, - "modbusRTUSlave": { - "enable": 0, - "protocol": "Modbus-RTU", - "coms": "rs485", - "slaveAddr": 1, - "int16Ord": "ab", - "int32Ord": "abcd", - "float32Ord": "abcd", - "mapping_table": [] - }, - "iec104Server": { - "enable": 0, - "cotSize": 2, - "port": 2404, - "serverList": [ - { - "asduAddr": 1 - } - ], - "kValue": 12, - "wValue": 8, - "t0": 30, - "t1": 15, - "t2": 10, - "t3": 20, - "maximumLink": 5, - "timeSet": 1, - "byteOrder": "abcd", - "mapping_table": [] - }, - "iec101Server": { - "enable": 0, - "coms": "rs485", - "mode": "UnBalance", - "linkLen": 2, - "linkAddr": 1, - "asduLen": 2, - "ioaLen": 3, - "cotLen": 2, - "serverList": [ - { - "asduAddr": 1 - } - ], - "linkTimeOut": 2000, - "timeSet": 1, - "idleTimeOut": 10000, - "byteOrder": "abcd", - "mapping_table": { - "YX": [], - "YC": [], - "YK": [] - } - }, - "iec104Client": { - "enable": 0, - "connectType": 2, - "serverAddr": "ipower.inhandcloud.cn", - "serverPort": 2404, - "communicationCode": "", - "protocol": 1, - "asduAddr": 1, - "tls": 0, - "mapping_table": { - "YX": [], - "YC": [], - "YK": [] - } - }, - "opcuaServer": { - "enable": 0, - "port": 4840, - "maximumLink": 5, - "securityMode": 0, - "identifierType": "String", - "mapping_table": [], - "certificate": "None", - "privateKey": "None", - "pubsub": 0 - }, - "sl651Slave": { - "enable": 0, - "centerAaddr": 1, - "remoteAddr": "", - "addrCode": "", - "password": "", - "platform_list": [], - "mapping_table": [] - }, - "hj212Client": { - "enable": 0, - "platform_list": [], - "block_list": [], - "mapping_table": [] - }, - "southMetadata": {}, - "bindMetadata": { - "version": "", - "timestamp": "" - }, - "bindConfig": { - "enable": 0, - "bind": { - "modelId": "", - "modelName": "", - "srcId": "", - "srcName": "", - "devId": "", - "devName": "" - }, - "varGroups": [], - "variables": [], - "alerts": [] - }, - "templates": {}, - "version": "2.7.1" -} \ No newline at end of file diff --git a/Pub_Sub/fkplcpond/thingsboard/fkplcpond_ec2_2_1.cfg b/Pub_Sub/fkplcpond/thingsboard/fkplcpond_ec2_2_1.cfg deleted file mode 100644 index 2b2d63a..0000000 --- a/Pub_Sub/fkplcpond/thingsboard/fkplcpond_ec2_2_1.cfg +++ /dev/null @@ -1,594 +0,0 @@ -{ - "controllers": [ - { - "protocol": "EtherNet/IP", - "name": "plcpond", - "args": {}, - "samplePeriod": 10, - "expired": 10000, - "endpoint": "192.168.1.12:44818" - } - ], - "measures": [ - { - "name": "pond_1_level", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lev", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_total_bbls", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Total_Barrels", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_hi_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_1_Hi_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_hi_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Hi_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_hi_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Hi_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_lo_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_1_Lo_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_lo_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lo_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_lo_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lo_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_level", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lev", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_total_bbls", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Total_Barrels", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_hi_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_2_Hi_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_hi_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Hi_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_hi_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Hi_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_lo_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_2_Lo_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_lo_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lo_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_lo_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lo_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "air_comp_low_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "AL0_Air_Comp_Low", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "air_comp_val", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Val_Air_Comp_Out", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "air_comp_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "SPT_Low_Air_PSI", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - } - ], - "alarmLables": [ - "default" - ], - "alarms": [ - { - "name": "air_comp_low_alm", - "ctrlName": "plcpond", - "measureName": "air_comp_low_alm", - "alarmLevel": 5, - "cond1": { - "op": "eq", - "value": "1.0" - }, - "condOp": "none", - "cond2": { - "op": "eq", - "value": "" - }, - "content": "Alarm Triggered" - } - ], - "groups": [ - { - "name": "default", - "uploadInterval": 600, - "reference": 16 - } - ], - "misc": { - "maxAlarmRecordSz": 2000, - "logLvl": "INFO", - "coms": [ - { - "name": "rs232", - "baud": 9600, - "bits": 8, - "stopbits": 1, - "parityChk": "n" - }, - { - "name": "rs485", - "baud": 9600, - "bits": 8, - "stopbits": 1, - "parityChk": "n" - } - ] - }, - "clouds": [ - { - "cacheSize": 100, - "enable": 1, - "name": "default", - "type": "Standard MQTT", - "args": { - "host": "hp.henrypump.cloud", - "port": 1883, - "clientId": "unknown", - "auth": 1, - "tls": 0, - "cleanSession": 0, - "mqttVersion": "v3.1.1", - "keepalive": 60, - "key": "", - "cert": "", - "rootCA": "", - "verifyServer": 0, - "verifyClient": 0, - "username": "unknown", - "passwd": "unknown", - "authType": 1 - } - } - ], - "quickfaas": { - "genericFuncs": [], - "uploadFuncs": [ - { - "name": "sendData", - "trigger": "measure_event", - "topic": "v1/devices/me/telemetry", - "qos": 1, - "groups": [ - "default" - ], - "funcName": "sendData", - "script": "# Enter your python code.\nimport json, os\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot():\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.info(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.info(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.info(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.info(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.info(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.info(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.info(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.info(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.info(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.info(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n\n\n\ndef sendData(message):\n payload = {}\n payload[\"ts\"] = (round(dt.timestamp(dt.now())/600)*600)*1000\n payload[\"values\"] = {}\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n publish(__topic__, json.dumps(payload), __qos__)", - "msgType": 0, - "cloudName": "default" - }, - { - "name": "sendAlarm", - "trigger": "warning_event", - "topic": "v1/devices/me/telemetry", - "qos": 2, - "funcName": "sendAlarm", - "script": "import json, time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\n\n\ndef sendAlarm(message):\n logger.info(message)\n payload = {}\n payload[\"ts\"] = time.time()*1000\n payload[\"values\"] = {message[\"measureName\"]: message[\"value\"]}\n publish(__topic__, json.dumps(payload), __qos__)", - "alarms": [ - "air_comp_low_alm" - ], - "msgType": 0, - "cloudName": "default" - } - ], - "downloadFuncs": [] - }, - "labels": [ - { - "key": "SN", - "value": "GF5022223016182" - }, - { - "key": "MAC", - "value": "00:18:05:21:b3:11" - } - ], - "modbusSlave": { - "enable": 0, - "protocol": "Modbus-TCP", - "port": 502, - "slaveAddr": 1, - "int16Ord": "ab", - "int32Ord": "abcd", - "float32Ord": "abcd", - "maxConnection": 5, - "mapping_table": [] - }, - "modbusRTUSlave": { - "enable": 0, - "protocol": "Modbus-RTU", - "coms": "rs485", - "slaveAddr": 1, - "int16Ord": "ab", - "int32Ord": "abcd", - "float32Ord": "abcd", - "mapping_table": [] - }, - "iec104Server": { - "enable": 0, - "cotSize": 2, - "port": 2404, - "serverList": [ - { - "asduAddr": 1 - } - ], - "kValue": 12, - "wValue": 8, - "t0": 30, - "t1": 15, - "t2": 10, - "t3": 20, - "maximumLink": 5, - "timeSet": 1, - "byteOrder": "abcd", - "mapping_table": [] - }, - "iec104Client": { - "enable": 0, - "connectType": 2, - "serverAddr": "ipower.inhandcloud.cn", - "serverPort": 2404, - "communicationCode": "", - "protocol": 1, - "asduAddr": 1, - "tls": 0, - "mapping_table": { - "YX": [], - "YC": [], - "YK": [] - } - }, - "opcuaServer": { - "enable": 0, - "port": 4840, - "maximumLink": 5, - "securityMode": 0, - "identifierType": "String", - "mapping_table": [] - }, - "southMetadata": {}, - "bindMetadata": { - "version": "", - "timestamp": "" - }, - "bindConfig": { - "enable": 0, - "bind": { - "modelId": "", - "modelName": "", - "srcId": "", - "srcName": "", - "devId": "", - "devName": "" - }, - "varGroups": [], - "variables": [], - "alerts": [] - }, - "version": "2.3.1" -} \ No newline at end of file diff --git a/Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v2.cfg b/Pub_Sub/fkplcpond/thingsboard/fkplcpond_tb_v4.cfg similarity index 50% rename from Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v2.cfg rename to Pub_Sub/fkplcpond/thingsboard/fkplcpond_tb_v4.cfg index 551aeae..3ebac26 100644 --- a/Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v2.cfg +++ b/Pub_Sub/fkplcpond/thingsboard/fkplcpond_tb_v4.cfg @@ -1,11 +1,18 @@ { "controllers": [ { - "protocol": "EtherNet/IP", + "enable": 1, + "protocol": "AllenBradley MicroCip", "name": "plcpond", - "args": {}, "samplePeriod": 10, - "expired": 10000, + "desc": "", + "expired": 1000, + "args": { + "slot": 0, + "connectTimeOut": 10000 + }, + "enableDebug": 0, + "enablePerOnchange": 0, "endpoint": "192.168.1.12:44818" } ], @@ -28,7 +35,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_1_total_bbls", @@ -48,7 +56,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_1_hi_alm", @@ -68,7 +77,10 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "bitMap": 0, + "reverseBit": 0, + "storageLwTSDB": 0 }, { "name": "pond_1_hi_spt", @@ -88,7 +100,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_1_hi_clr_spt", @@ -108,7 +121,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_1_lo_alm", @@ -128,7 +142,10 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "bitMap": 0, + "reverseBit": 0, + "storageLwTSDB": 0 }, { "name": "pond_1_lo_spt", @@ -148,7 +165,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_1_lo_clr_spt", @@ -168,7 +186,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_2_level", @@ -188,7 +207,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_2_total_bbls", @@ -208,7 +228,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_2_hi_alm", @@ -228,7 +249,10 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "bitMap": 0, + "reverseBit": 0, + "storageLwTSDB": 0 }, { "name": "pond_2_hi_spt", @@ -248,7 +272,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_2_hi_clr_spt", @@ -268,7 +293,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "1.0", - "offset": "0.0" + "offset": "0.0", + "storageLwTSDB": 0 }, { "name": "pond_2_lo_alm", @@ -288,7 +314,10 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "bitMap": 0, + "reverseBit": 0, + "storageLwTSDB": 0 }, { "name": "pond_2_lo_spt", @@ -308,7 +337,8 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 }, { "name": "pond_2_lo_clr_spt", @@ -328,18 +358,84 @@ "maxScaleValue": "", "minScaleValue": "", "gain": "", - "offset": "" + "offset": "", + "storageLwTSDB": 0 + }, + { + "name": "air_comp_low_alm", + "ctrlName": "plcpond", + "group": "default", + "uploadType": "periodic", + "dataType": "BIT", + "addr": "AL0_Air_Comp_Low", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "storageLwTSDB": 0, + "reverseBit": 0, + "bitMap": 0 + }, + { + "name": "air_comp_val", + "ctrlName": "plcpond", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "Val_Air_Comp_Out", + "readWrite": "ro", + "unit": "", + "desc": "", + "transformType": 0, + "storageLwTSDB": 0, + "decimal": 2 + }, + { + "name": "air_comp_spt", + "ctrlName": "plcpond", + "group": "default", + "uploadType": "periodic", + "dataType": "FLOAT", + "addr": "SPT_Low_Air_PSI", + "readWrite": "rw", + "unit": "", + "desc": "", + "transformType": 0, + "storageLwTSDB": 0, + "decimal": 2 } ], "alarmLables": [ "default" ], - "alarms": [], + "alarms": [ + { + "name": "air_comp_low_alm", + "ctrlName": "plcpond", + "alarmLevel": 5, + "content": "Alarm Triggered", + "alarmLable": "default", + "measureName": "air_comp_low_alm", + "cond1": { + "op": "eq", + "value": "1" + }, + "cond2": { + "op": "eq", + "value": "" + }, + "condOp": "none" + } + ], "groups": [ { "name": "default", "uploadInterval": 600, - "reference": 16 + "reference": 16, + "LwTSDBSize": 1000, + "strategy": 1, + "historyDataPath": "/var/user/data/dbhome/device_supervisor/LwTSDB", + "enablePerOnchange": 0 } ], "misc": { @@ -360,11 +456,15 @@ "stopbits": 1, "parityChk": "n" } - ] + ], + "cachePath": "/var/user/data/dbhome/device_supervisor/offlinedata", + "cacheSize": 10000, + "debugLogPath": "/var/user/data/dbhome/device_supervisor/debugLog", + "debugLogSize": 2000 }, "clouds": [ { - "cacheSize": 100, + "cacheSize": 10000, "enable": 1, "name": "default", "type": "Standard MQTT", @@ -384,8 +484,14 @@ "verifyClient": 0, "username": "unknown", "passwd": "unknown", - "authType": 1 - } + "authType": 1, + "willQos": 0, + "willRetain": 0, + "willTopic": "", + "willPayload": "", + "tlsAuth": "caSelfSigned" + }, + "uploadRules": [] } ], "quickfaas": { @@ -400,9 +506,22 @@ "default" ], "funcName": "sendData", - "script": "# Enter your python code.\nimport json, os\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot():\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.info(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.info(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.info(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.info(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.info(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.info(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.info(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.info(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.info(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.info(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n\n\n\ndef sendData(message):\n payload = {}\n payload[\"ts\"] = (round(dt.timestamp(dt.now())/600)*600)*1000\n payload[\"values\"] = {}\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n publish(__topic__, json.dumps(payload), __qos__)", - "msgType": 0, - "cloudName": "default" + "script": "# Enter your python code.\nimport json, os, time\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\n\ndef reboot():\n #basic = Basic()\n logger.info(\"!\" * 10 + \"REBOOTING DEVICE\" + \"!\"*10)\n r = os.popen(\"kill -s SIGHUP `cat /var/run/python/supervisord.pid`\").read()\n logger.info(f\"REBOOT : {r}\")\n\ndef checkFileExist(filename):\n path = \"/var/user/files\"\n if not os.path.exists(path):\n logger.info(\"no folder making files folder in var/user\")\n os.makedirs(path)\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n if not os.path.exists(path + \"/\" + filename):\n logger.info(\"no creds file making creds file\")\n with open(path + \"/\" + filename, \"a\") as f:\n json.dump({}, f)\n\ndef convertDStoJSON(ds):\n j = dict()\n for x in ds:\n j[x[\"key\"]] = x[\"value\"]\n return j\n\ndef convertJSONtoDS(j):\n d = []\n for key in j.keys():\n d.append({\"key\": key, \"value\": j[key]})\n return d\n\ndef checkCredentialConfig():\n logger.info(\"CHECKING CONFIG\")\n cfgpath = \"/var/user/cfg/device_supervisor/device_supervisor.cfg\"\n credspath = \"/var/user/files/creds.json\"\n cfg = dict()\n with open(cfgpath, \"r\") as f:\n cfg = json.load(f)\n clouds = cfg.get(\"clouds\")\n logger.info(clouds)\n #if not configured then try to configure from stored values\n if clouds[0][\"args\"][\"clientId\"] == \"unknown\" or clouds[0][\"args\"][\"username\"] == \"unknown\" or not clouds[0][\"args\"][\"passwd\"] or clouds[0][\"args\"][\"passwd\"] == \"unknown\":\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n creds = json.load(c)\n if creds:\n logger.info(\"updating config with stored data\")\n clouds[0][\"args\"][\"clientId\"] = creds[\"clientId\"]\n clouds[0][\"args\"][\"username\"] = creds[\"userName\"]\n clouds[0][\"args\"][\"passwd\"] = creds[\"password\"]\n cfg[\"clouds\"] = clouds\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n reboot()\n else:\n #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data\n checkFileExist(\"creds.json\")\n with open(credspath, \"r\") as c:\n logger.info(\"updating stored file with new data\")\n cfg = checkParameterConfig(cfg)\n with open(cfgpath, \"w\", encoding='utf-8') as n:\n json.dump(cfg, n, indent=1, ensure_ascii=False)\n creds = json.load(c)\n if creds:\n if creds[\"clientId\"] != clouds[0][\"args\"][\"clientId\"]:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n if creds[\"userName\"] != clouds[0][\"args\"][\"username\"]:\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n if creds[\"password\"] != clouds[0][\"args\"][\"passwd\"]:\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n else:\n creds[\"clientId\"] = clouds[0][\"args\"][\"clientId\"]\n creds[\"userName\"] = clouds[0][\"args\"][\"username\"]\n creds[\"password\"] = clouds[0][\"args\"][\"passwd\"]\n with open(credspath, \"w\") as cw:\n json.dump(creds,cw)\n\ndef checkParameterConfig(cfg):\n logger.info(\"Checking Parameters!!!!\")\n paramspath = \"/var/user/files/params.json\"\n cfgparams = convertDStoJSON(cfg.get(\"labels\"))\n #check stored values \n checkFileExist(\"params.json\")\n with open(paramspath, \"r\") as f:\n logger.info(\"Opened param storage file\")\n params = json.load(f)\n if params:\n if cfgparams != params:\n #go through each param\n #if not \"unknown\" and cfg and params aren't the same take from cfg likely updated manually\n #if key in cfg but not in params copy to params\n logger.info(\"equalizing params between cfg and stored\")\n for key in cfgparams.keys():\n try:\n if cfgparams[key] != params[key] and cfgparams[key] != \"unknown\":\n params[key] = cfgparams[key]\n except:\n params[key] = cfgparams[key]\n cfg[\"labels\"] = convertJSONtoDS(params)\n _set_global_args(convertJSONtoDS(params))\n with open(paramspath, \"w\") as p:\n json.dump(params, p)\n else:\n with open(paramspath, \"w\") as p:\n logger.info(\"initializing param file with params in memory\")\n json.dump(convertDStoJSON(get_params()), p)\n cfg[\"labels\"] = get_params()\n \n return cfg\n\n# Helper function to split the payload into chunks\ndef chunk_payload(payload, chunk_size=20):\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n\ndef sendData(message):\n payload = {}\n payload[\"ts\"] = (round(dt.timestamp(dt.now())/600)*600)*1000\n payload[\"values\"] = {}\n try:\n checkCredentialConfig()\n except Exception as e:\n logger.error(e)\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n for chunk in chunk_payload(payload=payload):\n publish(__topic__, json.dumps(chunk), __qos__)\n time.sleep(2)\n publish(\"v1/devices/me/attributes\", json.dumps({\"latestReportTime\": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)", + "cloudName": "default", + "msgType": 0 + }, + { + "qos": 2, + "funcName": "sendAlarm", + "script": "import json, time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\n\n\ndef sendAlarm(message):\n logger.info(message)\n payload = {}\n payload[\"ts\"] = time.time()*1000\n payload[\"values\"] = {message[\"measureName\"]: message[\"value\"]}\n publish(__topic__, json.dumps(payload), __qos__,cloud_name=\"default\")", + "name": "sendAlarm", + "trigger": "warning_event", + "topic": "v1/devices/me/telemetry", + "cloudName": "default", + "alarms": [ + "default" + ], + "msgType": 0 } ], "downloadFuncs": [] @@ -410,11 +529,11 @@ "labels": [ { "key": "SN", - "value": "GF5022223016120" + "value": "GF5022311031664" }, { "key": "MAC", - "value": "00:18:05:21:b2:8a" + "value": "00:18:05:28:4a:40" } ], "modbusSlave": { @@ -458,6 +577,30 @@ "byteOrder": "abcd", "mapping_table": [] }, + "iec101Server": { + "enable": 0, + "coms": "rs485", + "mode": "UnBalance", + "linkLen": 2, + "linkAddr": 1, + "asduLen": 2, + "ioaLen": 3, + "cotLen": 2, + "serverList": [ + { + "asduAddr": 1 + } + ], + "linkTimeOut": 2000, + "timeSet": 1, + "idleTimeOut": 10000, + "byteOrder": "abcd", + "mapping_table": { + "YX": [], + "YC": [], + "YK": [] + } + }, "iec104Client": { "enable": 0, "connectType": 2, @@ -479,6 +622,24 @@ "maximumLink": 5, "securityMode": 0, "identifierType": "String", + "certificate": "None", + "privateKey": "None", + "pubsub": 0, + "mapping_table": [] + }, + "sl651Slave": { + "enable": 0, + "centerAaddr": 1, + "remoteAddr": "", + "addrCode": "", + "password": "", + "platform_list": [], + "mapping_table": [] + }, + "hj212Client": { + "enable": 0, + "platform_list": [], + "block_list": [], "mapping_table": [] }, "southMetadata": {}, @@ -500,5 +661,6 @@ "variables": [], "alerts": [] }, - "version": "2.3.1" + "templates": {}, + "version": "2.7.1" } \ No newline at end of file diff --git a/Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v1.cfg b/Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v1.cfg deleted file mode 100644 index ed0d4d0..0000000 --- a/Pub_Sub/fkplcpond/thingsboard/plcpond_tb_v1.cfg +++ /dev/null @@ -1,504 +0,0 @@ -{ - "controllers": [ - { - "protocol": "EtherNet/IP", - "name": "plcpond", - "args": {}, - "samplePeriod": 10, - "expired": 10000, - "endpoint": "192.168.1.12:44818" - } - ], - "measures": [ - { - "name": "pond_1_level", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lev", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_total_bbls", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Total_Barrels", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_hi_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_1_Hi_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_hi_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Hi_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_hi_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Hi_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_lo_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_1_Lo_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_lo_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lo_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_1_lo_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_1_Lo_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_level", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lev", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_total_bbls", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Total_Barrels", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_hi_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_2_Hi_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_hi_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Hi_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_hi_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Hi_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "1.0", - "offset": "0.0" - }, - { - "name": "pond_2_lo_alm", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "BIT", - "addr": "Pond_2_Lo_Alarm", - "decimal": 2, - "len": 1, - "readWrite": "ro", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_lo_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lo_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - }, - { - "name": "pond_2_lo_clr_spt", - "ctrlName": "plcpond", - "group": "default", - "uploadType": "periodic", - "dataType": "FLOAT", - "addr": "Pond_2_Lo_Clr_Setpoint", - "decimal": 2, - "len": 1, - "readWrite": "rw", - "unit": "", - "desc": "", - "transformType": 0, - "maxValue": "", - "minValue": "", - "maxScaleValue": "", - "minScaleValue": "", - "gain": "", - "offset": "" - } - ], - "alarmLables": [ - "default" - ], - "alarms": [], - "groups": [ - { - "name": "default", - "uploadInterval": 600, - "reference": 16 - } - ], - "misc": { - "maxAlarmRecordSz": 2000, - "logLvl": "INFO", - "coms": [ - { - "name": "rs232", - "baud": 9600, - "bits": 8, - "stopbits": 1, - "parityChk": "n" - }, - { - "name": "rs485", - "baud": 9600, - "bits": 8, - "stopbits": 1, - "parityChk": "n" - } - ] - }, - "clouds": [ - { - "cacheSize": 100, - "enable": 1, - "name": "default", - "type": "Standard MQTT", - "args": { - "host": "hp.henrypump.cloud", - "port": 1883, - "clientId": "hp", - "auth": 1, - "tls": 0, - "cleanSession": 0, - "mqttVersion": "v3.1.1", - "keepalive": 60, - "key": "", - "cert": "", - "rootCA": "", - "verifyServer": 0, - "verifyClient": 0, - "username": "hp", - "passwd": "hp", - "authType": 1 - } - } - ], - "quickfaas": { - "genericFuncs": [], - "uploadFuncs": [ - { - "name": "sendData", - "trigger": "measure_event", - "topic": "v1/devices/me/telemetry", - "qos": 1, - "groups": [ - "default" - ], - "funcName": "sendData", - "script": "# Enter your python code.\nimport json\nimport time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\n\n\ndef sendData(message):\n payload = {}\n payload[\"ts\"] = round(time.time() * 1000)\n payload[\"values\"] = {}\n for measure in message[\"measures\"]:\n try:\n logger.debug(measure)\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n publish(__topic__, json.dumps(payload), __qos__)", - "msgType": 0, - "cloudName": "default" - } - ], - "downloadFuncs": [] - }, - "labels": [ - { - "key": "SN", - "value": "GF5022223016120" - }, - { - "key": "MAC", - "value": "00:18:05:21:b2:8a" - } - ], - "modbusSlave": { - "enable": 0, - "protocol": "Modbus-TCP", - "port": 502, - "slaveAddr": 1, - "int16Ord": "ab", - "int32Ord": "abcd", - "float32Ord": "abcd", - "maxConnection": 5, - "mapping_table": [] - }, - "modbusRTUSlave": { - "enable": 0, - "protocol": "Modbus-RTU", - "coms": "rs485", - "slaveAddr": 1, - "int16Ord": "ab", - "int32Ord": "abcd", - "float32Ord": "abcd", - "mapping_table": [] - }, - "iec104Server": { - "enable": 0, - "cotSize": 2, - "port": 2404, - "serverList": [ - { - "asduAddr": 1 - } - ], - "kValue": 12, - "wValue": 8, - "t0": 30, - "t1": 15, - "t2": 10, - "t3": 20, - "maximumLink": 5, - "timeSet": 1, - "byteOrder": "abcd", - "mapping_table": [] - }, - "iec104Client": { - "enable": 0, - "connectType": 2, - "serverAddr": "ipower.inhandcloud.cn", - "serverPort": 2404, - "communicationCode": "", - "protocol": 1, - "asduAddr": 1, - "tls": 0, - "mapping_table": { - "YX": [], - "YC": [], - "YK": [] - } - }, - "opcuaServer": { - "enable": 0, - "port": 4840, - "maximumLink": 5, - "securityMode": 0, - "identifierType": "String", - "mapping_table": [] - }, - "southMetadata": {}, - "bindMetadata": { - "version": "", - "timestamp": "" - }, - "bindConfig": { - "enable": 0, - "bind": { - "modelId": "", - "modelName": "", - "srcId": "", - "srcName": "", - "devId": "", - "devName": "" - }, - "varGroups": [], - "variables": [], - "alerts": [] - }, - "version": "2.3.1" -} \ No newline at end of file diff --git a/Pub_Sub/flowmeterskid/message_example.json b/Pub_Sub/flowmeterskid/message_example.json new file mode 100644 index 0000000..0eb4e6b --- /dev/null +++ b/Pub_Sub/flowmeterskid/message_example.json @@ -0,0 +1,33 @@ +{ + "timestamp": 1702477801, + "group_name": "default", + "values": { + "flowmeter": { + "totalizer_3_unit": { + "raw_data": 11, + "timestamp": 1702477799, + "status": 1 + }, + "totalizer_3": { + "raw_data": 8746.4500000000007, + "timestamp": 1702477799, + "status": 1 + }, + "totalizer_2": { + "raw_data": 8746.4400000000005, + "timestamp": 1702477799, + "status": 1 + }, + "totalizer_1": { + "raw_data": 8746.4400000000005, + "timestamp": 1702477799, + "status": 1 + }, + "flowrate": { + "raw_data": 10.0, + "timestamp": 1702477799, + "status": 1 + } + } + } +} \ No newline at end of file diff --git a/Pub_Sub/flowmeterskid/thingsboard/pub/sendData.py b/Pub_Sub/flowmeterskid/thingsboard/pub/sendData.py index 3e78fa9..635fbe8 100644 --- a/Pub_Sub/flowmeterskid/thingsboard/pub/sendData.py +++ b/Pub_Sub/flowmeterskid/thingsboard/pub/sendData.py @@ -211,6 +211,8 @@ def sendData(message,wizard_api): publish(__topic__, json.dumps(chunk), __qos__) time.sleep(2) + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) + if dayReset: resetPayload["values"]["yesterday_volume"] = payload["values"]["day_volume"] resetPayload["values"]["day_volume"] = 0 diff --git a/Pub_Sub/flowmeterskid/thingsboard/pub/sendDataGPTEnhanced.py b/Pub_Sub/flowmeterskid/thingsboard/pub/sendDataGPTEnhanced.py new file mode 100644 index 0000000..9bb85e4 --- /dev/null +++ b/Pub_Sub/flowmeterskid/thingsboard/pub/sendDataGPTEnhanced.py @@ -0,0 +1,405 @@ +import json, os, time, shutil +from datetime import datetime as dt +from common.Logger import logger +from quickfaas.remotebus import publish +from mobiuspi_lib.gps import GPS +from quickfaas.global_dict import get as get_params +from quickfaas.global_dict import _set_global_args + +def reboot(reason="Rebooting for config file update"): + #basic = Basic() + logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10) + logger.info(reason) + r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read() + logger.info(f"REBOOT : {r}") + +def checkFileExist(filename): + path = "/var/user/files" + try: + if not os.path.exists(path): + logger.debug("no folder making files folder in var/user") + os.makedirs(path) + with open(path + "/" + filename, "a") as f: + json.dump({}, f) + except Exception as e: + logger.error(f"Something went wrong in checkFileExist while making folder: {e}") + + try: + if not os.path.exists(path + "/" + filename): + logger.debug("no creds file making creds file") + with open(path + "/" + filename, "a") as f: + json.dump({}, f) + except Exception as e: + logger.error(f"Something went wrong in checkFileExist wihle making file: {e}") + +def convertDStoJSON(ds): + j = dict() + try: + for x in ds: + j[x["key"]] = x["value"] + except Exception as e: + logger.error(f"Something went wrong in convertDStoJSON: {e}") + return j + +def convertJSONtoDS(j): + d = [] + try: + for key in j.keys(): + d.append({"key": key, "value": j[key]}) + except Exception as e: + logger.error(f"Something went wrong in convertJSONtoDS: {e}") + return d + +def checkCredentialConfig(): + logger.debug("CHECKING CONFIG") + cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg" + credspath = "/var/user/files/creds.json" + cfg = dict() + with open(cfgpath, "r") as f: + try: + cfg = json.load(f) + clouds = cfg.get("clouds") + logger.debug(clouds) + #if not configured then try to configure from stored values + if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown": + try: + checkFileExist("creds.json") + except Exception as e: + logger.error(f"Error in checkFileExist: {e}") + with open(credspath, "r") as c: + try: + creds = json.load(c) + if creds: + logger.debug("updating config with stored data") + clouds[0]["args"]["clientId"] = creds["clientId"] + clouds[0]["args"]["username"] = creds["userName"] + clouds[0]["args"]["passwd"] = creds["password"] + cfg["clouds"] = clouds + cfg = checkParameterConfig(cfg) + with open(cfgpath, "w", encoding='utf-8') as n: + json.dump(cfg, n, indent=1, ensure_ascii=False) + reboot() + except Exception as e: + logger.error(f"Error trying to load credentials from file: {e}") + else: + #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data + checkFileExist("creds.json") + with open(credspath, "r") as c: + logger.debug("updating stored file with new data") + cfg = checkParameterConfig(cfg) + with open(cfgpath, "w", encoding='utf-8') as n: + json.dump(cfg, n, indent=1, ensure_ascii=False) + creds = json.load(c) + if creds: + if creds["clientId"] != clouds[0]["args"]["clientId"]: + creds["clientId"] = clouds[0]["args"]["clientId"] + if creds["userName"] != clouds[0]["args"]["username"]: + creds["userName"] = clouds[0]["args"]["username"] + if creds["password"] != clouds[0]["args"]["passwd"]: + creds["password"] = clouds[0]["args"]["passwd"] + else: + creds["clientId"] = clouds[0]["args"]["clientId"] + creds["userName"] = clouds[0]["args"]["username"] + creds["password"] = clouds[0]["args"]["passwd"] + with open(credspath, "w") as cw: + json.dump(creds,cw) + except Exception as e: + logger.error(f"Somethign went wrong in checkCredentialConfig: {e}") + +def checkParameterConfig(cfg): + try: + logger.debug("Checking Parameters!!!!") + paramspath = "/var/user/files/params.json" + cfgparams = convertDStoJSON(cfg.get("labels")) + #check stored values + checkFileExist("params.json") + with open(paramspath, "r") as f: + logger.debug("Opened param storage file") + params = json.load(f) + if params: + if cfgparams != params: + #go through each param + #if not "unknown" and cfg and params aren't the same take from cfg likely updated manually + #if key in cfg but not in params copy to params + logger.debug("equalizing params between cfg and stored") + for key in cfgparams.keys(): + try: + if cfgparams[key] != params[key] and cfgparams[key] != "unknown": + params[key] = cfgparams[key] + except: + params[key] = cfgparams[key] + cfg["labels"] = convertJSONtoDS(params) + _set_global_args(convertJSONtoDS(params)) + with open(paramspath, "w") as p: + json.dump(params, p) + else: + with open(paramspath, "w") as p: + logger.debug("initializing param file with params in memory") + json.dump(convertDStoJSON(get_params()), p) + cfg["labels"] = get_params() + + return cfg + except Exception as e: + logger.error(f"Something went wrong in checkParameterConfig: {e}") + os.system(f'rm {paramspath}') + return cfg + +payload = {} + +def initialize_totalizers(): + return { + "day": 0, + "week": 0, + "month": 0, + "year": 0, + "lifetime": 0, + "dayHolding": 0, + "weekHolding": 0, + "monthHolding": 0, + "yearHolding": 0 + } + +def getTotalizers(file_path="/var/user/files/totalizers.json"): + """ + Retrieves totalizer data from a JSON file. + + :param file_path: Path to the JSON file storing totalizer data. + :return: Dictionary containing totalizer values. + """ + try: + with open(file_path, "r") as t: + totalizers = json.load(t) + if not totalizers or not isinstance(totalizers, dict): + logger.info("Invalid data format in the file. Initializing totalizers.") + totalizers = initialize_totalizers() + except FileNotFoundError: + logger.info("File not found. Initializing totalizers.") + totalizers = initialize_totalizers() + except json.JSONDecodeError: + timestamp = dt.now().strftime("%Y%m%d_%H%M%S") + # Split the file path and insert the timestamp before the extension + file_name, file_extension = os.path.splitext(file_path) + backup_file_path = f"{file_name}_{timestamp}{file_extension}" + shutil.copyfile(file_path, backup_file_path) + logger.error(f"Error decoding JSON. A backup of the file is created at {backup_file_path}. Initializing totalizers.") + totalizers = initialize_totalizers() + return totalizers + +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + + +def sendData(message,wizard_api): + logger.debug(message) + checkCredentialConfig() + payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}} + resetPayload = {"ts": "", "values": {}} + dayReset, weekReset, monthReset, yearReset = False, False, False, False + for measure in message["values"]["flowmeter"].keys(): + try: + if message["values"]["flowmeter"][measure]["status"] == 1: + if measure in ["totalizer_1"]: + payload["values"]["day_volume"], dayReset = totalizeDay(message["values"]["flowmeter"][measure]["raw_data"]) + payload["values"]["week_volume"], weekReset = totalizeWeek(message["values"]["flowmeter"][measure]["raw_data"]) + payload["values"]["month_volume"], monthReset = totalizeMonth(message["values"]["flowmeter"][measure]["raw_data"]) + payload["values"]["year_volume"], yearReset = totalizeYear(message["values"]["flowmeter"][measure]["raw_data"]) + payload["values"][measure] = message["values"]["flowmeter"][measure]["raw_data"] + except Exception as e: + logger.error(e) + try: + payload["values"]["latitude"], payload["values"]["longitude"], payload["values"]["speed"] = getGPS() + except: + logger.error("Could not get GPS coordinates") + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) + + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) + + if dayReset: + resetPayload["values"]["yesterday_volume"] = payload["values"]["day_volume"] + resetPayload["values"]["day_volume"] = 0 + if weekReset: + resetPayload["values"]["last_week_volume"] = payload["values"]["week_volume"] + resetPayload["values"]["week_volume"] = 0 + if monthReset: + resetPayload["values"]["last_month_volume"] = payload["values"]["month_volume"] + resetPayload["values"]["month_volume"] = 0 + if yearReset: + resetPayload["values"]["last_year_volume"] = payload["values"]["year_volume"] + resetPayload["values"]["year_volume"] = 0 + + if resetPayload["values"]: + resetPayload["ts"] = 1 + (round(dt.timestamp(dt.now())/600)*600)*1000 + publish(__topic__, json.dumps(resetPayload), __qos__) + +def saveTotalizers(totalizers, file_path="/var/user/files/totalizers.json"): + """ + Saves totalizer data to a JSON file. + + :param totalizers: Dictionary containing totalizer values to be saved. + :param file_path: Path to the JSON file where totalizer data will be saved. + """ + try: + with open(file_path, "w") as t: + json.dump(totalizers, t) + except (IOError, OSError, json.JSONEncodeError) as e: + logger.error(f"Error saving totalizers to {file_path}: {e}") + raise # Optionally re-raise the exception if it should be handled by the caller + +def getGPS(): + # Create a gps instance + gps = GPS() + + # Retrieve GPS information + position_status = gps.get_position_status() + logger.debug("position_status: ") + logger.debug(position_status) + latitude = position_status["latitude"].split(" ") + longitude = position_status["longitude"].split(" ") + lat_dec = int(latitude[0][:-1]) + (float(latitude[1][:-1])/60) + lon_dec = int(longitude[0][:-1]) + (float(longitude[1][:-1])/60) + if latitude[2] == "S": + lat_dec = lat_dec * -1 + if longitude[2] == "W": + lon_dec = lon_dec * -1 + #lat_dec = round(lat_dec, 7) + #lon_dec = round(lon_dec, 7) + logger.info("HERE IS THE GPS COORDS") + logger.info(f"LATITUDE: {lat_dec}, LONGITUDE: {lon_dec}") + speedKnots = position_status["speed"].split(" ") + speedMPH = float(speedKnots[0]) * 1.151 + return (f"{lat_dec:.8f}",f"{lon_dec:.8f}",f"{speedMPH:.2f}") + +def totalizeDay(lifetime, max_retries=3, retry_delay=2): + """ + Update and save daily totalizers based on the lifetime value. + + :param lifetime: The current lifetime total. + :param max_retries: Maximum number of save attempts. + :param retry_delay: Delay in seconds between retries. + :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails. + """ + totalizers = getTotalizers() + now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600) + reset = False + value = lifetime - totalizers["dayHolding"] + + if not int(now.strftime("%d")) == int(totalizers["day"]): + totalizers["dayHolding"] = lifetime + totalizers["day"] = int(now.strftime("%d")) + + for attempt in range(max_retries): + try: + saveTotalizers(totalizers) + reset = True + return (value, reset) + except Exception as e: + logger.error(f"Attempt {attempt + 1} failed to save totalizers: {e}") + if attempt < max_retries - 1: + time.sleep(retry_delay) + else: + logger.error("All attempts to save totalizers failed.") + return (None, False) + + return (value, reset) + +def totalizeWeek(lifetime, max_retries=3, retry_delay=2): + """ + Update and save weekly totalizers based on the lifetime value. + + :param lifetime: The current lifetime total. + :param max_retries: Maximum number of save attempts. + :param retry_delay: Delay in seconds between retries. + :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails. + """ + totalizers = getTotalizers() + now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600) + reset = False + value = lifetime - totalizers["weekHolding"] + if (not now.strftime("%U") == totalizers["week"] and now.strftime("%a") == "Sun") or totalizers["week"] == 0: + totalizers["weekHolding"] = lifetime + totalizers["week"] = now.strftime("%U") + + for attempt in range(max_retries): + try: + saveTotalizers(totalizers) + reset = True + return (value, reset) + except Exception as e: + logger.error(f"Attempt {attempt + 1} failed to save totalizers: {e}") + if attempt < max_retries - 1: + time.sleep(retry_delay) + else: + logger.error("All attempts to save totalizers failed.") + return (None, False) + return (value, reset) + +def totalizeMonth(lifetime, max_retries=3, retry_delay=2): + """ + Update and save monthly totalizers based on the lifetime value. + + :param lifetime: The current lifetime total. + :param max_retries: Maximum number of save attempts. + :param retry_delay: Delay in seconds between retries. + :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails. + """ + totalizers = getTotalizers() + now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600) + reset = False + value = lifetime - totalizers["monthHolding"] + if not int(now.strftime("%m")) == int(totalizers["month"]): + totalizers["monthHolding"] = lifetime + totalizers["month"] = now.strftime("%m") + + for attempt in range(max_retries): + try: + saveTotalizers(totalizers) + reset = True + return (value, reset) + except Exception as e: + logger.error(f"Attempt {attempt + 1} failed to save totalizers: {e}") + if attempt < max_retries - 1: + time.sleep(retry_delay) + else: + logger.error("All attempts to save totalizers failed.") + return (None, False) + + return (value,reset) + +def totalizeYear(lifetime, max_retries=3, retry_delay=2): + """ + Update and save yearly totalizers based on the lifetime value. + + :param lifetime: The current lifetime total. + :param max_retries: Maximum number of save attempts. + :param retry_delay: Delay in seconds between retries. + :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails. + """ + totalizers = getTotalizers() + now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600) + reset = False + value = lifetime - totalizers["yearHolding"] + if not int(now.strftime("%Y")) == int(totalizers["year"]): + totalizers["yearHolding"] = lifetime + totalizers["year"] = now.strftime("%Y") + + for attempt in range(max_retries): + try: + saveTotalizers(totalizers) + reset = True + return (value, reset) + except Exception as e: + logger.error(f"Attempt {attempt + 1} failed to save totalizers: {e}") + if attempt < max_retries - 1: + time.sleep(retry_delay) + else: + logger.error("All attempts to save totalizers failed.") + return (None, False) + return (value, reset) \ No newline at end of file diff --git a/Pub_Sub/gateway/thingsboard/pub/sendData.py b/Pub_Sub/gateway/thingsboard/pub/sendData.py index 5150983..5e0742b 100644 --- a/Pub_Sub/gateway/thingsboard/pub/sendData.py +++ b/Pub_Sub/gateway/thingsboard/pub/sendData.py @@ -1,21 +1,28 @@ # Enter your python code. -import json +import json, time from datetime import datetime as dt from common.Logger import logger from quickfaas.remotebus import publish -def chunk_payload(payload, chunk_size=20): - for controller, data in payload.items(): - for entry in data: - ts = entry['ts'] - values = entry['values'] - chunked_values = list(values.items()) - for i in range(0, len(chunked_values), chunk_size): - yield { - "controller": controller, - "ts": ts, - "values": dict(chunked_values[i:i + chunk_size]) - } +def chunk_payload(payload, chunk_size=20, is_attributes_payload=False): + if is_attributes_payload: + # For attributes payload, chunk the controllers + controllers = list(payload.items()) + for i in range(0, len(controllers), chunk_size): + yield dict(controllers[i:i + chunk_size]) + else: + # For data payload, chunk the values within each controller + for controller, data in payload.items(): + for entry in data: + ts = entry['ts'] + values = entry['values'] + chunked_values = list(values.items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "controller": controller, + "ts": ts, + "values": dict(chunked_values[i:i + chunk_size]) + } def sendData(message): #logger.debug(message) @@ -53,5 +60,11 @@ def sendData(message): #logger.debug(payload) - publish(__topic__, json.dumps(payload), __qos__) - publish("v1/gateway/attributes", json.dumps(attributes_payload), __qos__) \ No newline at end of file + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) + + for chunk in chunk_payload(payload=attributes_payload, is_attributes_payload=True): + publish("v1/gateway/attributes", json.dumps(attributes_payload), __qos__) + time.sleep(2) + \ No newline at end of file diff --git a/Pub_Sub/hrtankbattery/thingsboard/pub/sendDataNoel.py b/Pub_Sub/hrbooster/thingsboard/pub/sendData.py similarity index 82% rename from Pub_Sub/hrtankbattery/thingsboard/pub/sendDataNoel.py rename to Pub_Sub/hrbooster/thingsboard/pub/sendData.py index 6e4585f..0d5d4f3 100644 --- a/Pub_Sub/hrtankbattery/thingsboard/pub/sendDataNoel.py +++ b/Pub_Sub/hrbooster/thingsboard/pub/sendData.py @@ -6,10 +6,9 @@ from quickfaas.remotebus import publish from quickfaas.global_dict import get as get_params from quickfaas.global_dict import _set_global_args -def reboot(reason="Rebooting for config file update"): +def reboot(): #basic = Basic() logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10) - logger.info(reason) r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read() logger.info(f"REBOOT : {r}") @@ -38,21 +37,21 @@ def convertJSONtoDS(j): return d def checkCredentialConfig(): - logger.debug("CHECKING CONFIG") + logger.info("CHECKING CONFIG") cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg" credspath = "/var/user/files/creds.json" cfg = dict() with open(cfgpath, "r") as f: cfg = json.load(f) clouds = cfg.get("clouds") - logger.debug(clouds) + logger.info(clouds) #if not configured then try to configure from stored values if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown": checkFileExist("creds.json") with open(credspath, "r") as c: creds = json.load(c) if creds: - logger.debug("updating config with stored data") + logger.info("updating config with stored data") clouds[0]["args"]["clientId"] = creds["clientId"] clouds[0]["args"]["username"] = creds["userName"] clouds[0]["args"]["passwd"] = creds["password"] @@ -65,7 +64,7 @@ def checkCredentialConfig(): #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data checkFileExist("creds.json") with open(credspath, "r") as c: - logger.debug("updating stored file with new data") + logger.info("updating stored file with new data") cfg = checkParameterConfig(cfg) with open(cfgpath, "w", encoding='utf-8') as n: json.dump(cfg, n, indent=1, ensure_ascii=False) @@ -85,20 +84,20 @@ def checkCredentialConfig(): json.dump(creds,cw) def checkParameterConfig(cfg): - logger.debug("Checking Parameters!!!!") + logger.info("Checking Parameters!!!!") paramspath = "/var/user/files/params.json" cfgparams = convertDStoJSON(cfg.get("labels")) #check stored values checkFileExist("params.json") with open(paramspath, "r") as f: - logger.debug("Opened param storage file") + logger.info("Opened param storage file") params = json.load(f) if params: if cfgparams != params: #go through each param #if not "unknown" and cfg and params aren't the same take from cfg likely updated manually #if key in cfg but not in params copy to params - logger.debug("equalizing params between cfg and stored") + logger.info("equalizing params between cfg and stored") for key in cfgparams.keys(): try: if cfgparams[key] != params[key] and cfgparams[key] != "unknown": @@ -111,7 +110,7 @@ def checkParameterConfig(cfg): json.dump(params, p) else: with open(paramspath, "w") as p: - logger.debug("initializing param file with params in memory") + logger.info("initializing param file with params in memory") json.dump(convertDStoJSON(get_params()), p) cfg["labels"] = get_params() @@ -133,26 +132,14 @@ def sendData(message): except Exception as e: logger.error(e) payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}} - run_tanks = {} - for measure in message["measures"]: try: logger.debug(measure) - if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600: - reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"])) - if measure["name"] in ["oil_run_tank","water_run_tank"]: - run_tanks[measure["name"]] = measure["value"] - if "_level" in measure["name"]: - run_tanks[measure["name"]] = measure["value"] payload["values"][measure["name"]] = measure["value"] except Exception as e: logger.error(e) - payload["values"]["oil_run_tank_level"] = run_tanks["oil_0" + str(run_tanks["oil_run_tank"]) + "_level"] - payload["values"]["water_run_tank_level"] = run_tanks["water_0" + str(run_tanks["water_run_tank"]) + "_level"] - + for chunk in chunk_payload(payload=payload): publish(__topic__, json.dumps(chunk), __qos__) time.sleep(2) - publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) - diff --git a/Pub_Sub/hrswd/thingsboard/pub/sendData.py b/Pub_Sub/hrswd/thingsboard/pub/sendData.py index 53026f6..7b374af 100644 --- a/Pub_Sub/hrswd/thingsboard/pub/sendData.py +++ b/Pub_Sub/hrswd/thingsboard/pub/sendData.py @@ -1,5 +1,5 @@ # Enter your python code. -import json, os +import json, os, time from datetime import datetime as dt from common.Logger import logger from quickfaas.remotebus import publish @@ -117,6 +117,15 @@ def checkParameterConfig(cfg): return cfg +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sendData(message): #logger.debug(message) try: @@ -140,6 +149,8 @@ def sendData(message): logger.error(e) payload["values"]["oil_run_tank_level"] = run_tanks["oil_0" + str(run_tanks["oil_run_tank"]) + "_level"] payload["values"]["water_run_tank_level"] = run_tanks["water_0" + str(run_tanks["water_run_tank"]) + "_level"] - publish(__topic__, json.dumps(payload), __qos__) + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) diff --git a/Pub_Sub/hrswd/thingsboard/sub/receiveCommand.py b/Pub_Sub/hrswd/thingsboard/sub/receiveCommand.py index 3b7993b..e0ba0a0 100644 --- a/Pub_Sub/hrswd/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/hrswd/thingsboard/sub/receiveCommand.py @@ -1,11 +1,21 @@ import json, time +from datetime import datetime as dt from quickfaas.measure import recall, write from quickfaas.remotebus import publish from common.Logger import logger +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sync(): #get new values and send - payload = {} + payload = {"ts": round(dt.timestamp(dt.now()))*1000, "values": {}} topic = "v1/devices/me/telemetry" try: data = recall()#json.loads(recall().decode("utf-8")) @@ -15,10 +25,14 @@ def sync(): for controller in data: for measure in controller["measures"]: #publish measure - payload[measure["name"]] = measure["value"] + payload["values"][measure["name"]] = measure["value"] logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) - publish(topic, json.dumps(payload), 1) + for chunk in chunk_payload(payload=payload): + publish(topic, json.dumps(chunk), 1) + time.sleep(2) + + def writeplctag(value): #value in the form {"measurement": , "value": } try: diff --git a/Pub_Sub/hrtankbattery/thingsboard/pub/sendData.py b/Pub_Sub/hrtankbattery/thingsboard/pub/sendData.py index 53026f6..8eaf644 100644 --- a/Pub_Sub/hrtankbattery/thingsboard/pub/sendData.py +++ b/Pub_Sub/hrtankbattery/thingsboard/pub/sendData.py @@ -1,5 +1,5 @@ # Enter your python code. -import json, os +import json, os, time from datetime import datetime as dt from common.Logger import logger from quickfaas.remotebus import publish @@ -117,6 +117,15 @@ def checkParameterConfig(cfg): return cfg +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sendData(message): #logger.debug(message) try: @@ -140,6 +149,10 @@ def sendData(message): logger.error(e) payload["values"]["oil_run_tank_level"] = run_tanks["oil_0" + str(run_tanks["oil_run_tank"]) + "_level"] payload["values"]["water_run_tank_level"] = run_tanks["water_0" + str(run_tanks["water_run_tank"]) + "_level"] - publish(__topic__, json.dumps(payload), __qos__) + + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) diff --git a/Pub_Sub/hrtankbattery/thingsboard/sub/receiveCommand.py b/Pub_Sub/hrtankbattery/thingsboard/sub/receiveCommand.py index 3b7993b..f550b61 100644 --- a/Pub_Sub/hrtankbattery/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/hrtankbattery/thingsboard/sub/receiveCommand.py @@ -1,11 +1,21 @@ import json, time +from datetime import datetime as dt from quickfaas.measure import recall, write from quickfaas.remotebus import publish from common.Logger import logger +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sync(): #get new values and send - payload = {} + payload = {"ts": round(dt.timestamp(dt.now()))*1000, "values": {}} topic = "v1/devices/me/telemetry" try: data = recall()#json.loads(recall().decode("utf-8")) @@ -15,10 +25,13 @@ def sync(): for controller in data: for measure in controller["measures"]: #publish measure - payload[measure["name"]] = measure["value"] + payload["values"][measure["name"]] = measure["value"] logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) - publish(topic, json.dumps(payload), 1) + for chunk in chunk_payload(payload=payload): + publish(topic, json.dumps(chunk), 1) + time.sleep(2) + def writeplctag(value): #value in the form {"measurement": , "value": } try: diff --git a/Pub_Sub/hrvalvecontroller/thingsboard/pub/sendData.py b/Pub_Sub/hrvalvecontroller/thingsboard/pub/sendData.py index 7db8f4a..e1c2b79 100644 --- a/Pub_Sub/hrvalvecontroller/thingsboard/pub/sendData.py +++ b/Pub_Sub/hrvalvecontroller/thingsboard/pub/sendData.py @@ -1,4 +1,4 @@ -import json, os +import json, os, time from datetime import datetime as dt from datetime import timedelta as td from common.Logger import logger @@ -117,8 +117,16 @@ def checkParameterConfig(cfg): return cfg +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } -def sendData(message, wizard_api): +def sendData(message): payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}} resetPayload = {"ts": "", "values": {}} try: @@ -136,7 +144,9 @@ def sendData(message, wizard_api): payload["values"][measure] = message["values"]["hrvalvecontroller"][measure]["raw_data"] except Exception as e: logger.error(e) - publish(__topic__, json.dumps(payload), __qos__, cloud_name="default") + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__, cloud_name="default") if dayReset: diff --git a/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/pub/sendData.py b/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/pub/sendData.py index 4505d00..e8bcdb2 100644 --- a/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/pub/sendData.py +++ b/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/pub/sendData.py @@ -1,4 +1,4 @@ -import json, os +import json, os, time from common.Logger import logger from quickfaas.remotebus import publish from quickfaas.global_dict import get as get_params @@ -143,6 +143,15 @@ def checkParameterConfig(cfg): os.system(f'rm {paramspath}') return cfg +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sendData(message): payload = {} payload["ts"] = (round(dt.timestamp(dt.now())/600)*600)*1000 @@ -157,5 +166,8 @@ def sendData(message): payload["values"][measure["name"]] = measure["value"] except Exception as e: logger.error(e) - publish(__topic__, json.dumps(payload), __qos__) + + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) \ No newline at end of file diff --git a/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/sub/receiveCommand.py b/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/sub/receiveCommand.py index cfab9d3..615d3e1 100644 --- a/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/plcfreshwater_advvfdipp/thingsboard/sub/receiveCommand.py @@ -1,11 +1,21 @@ import json, time +from datetime import datetime as dt from quickfaas.measure import recall, write from quickfaas.remotebus import publish from common.Logger import logger +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sync(): #get new values and send - payload = {} + payload = {"ts": round(dt.timestamp(dt.now()))*1000, "values": {}} topic = "v1/devices/me/telemetry" try: data = recall()#json.loads(recall().decode("utf-8")) @@ -15,10 +25,12 @@ def sync(): for controller in data: for measure in controller["measures"]: #publish measure - payload[measure["name"]] = measure["value"] + payload["values"][measure["name"]] = measure["value"] logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) - publish(topic, json.dumps(payload), 1) + for chunk in chunk_payload(payload=payload): + publish(topic, json.dumps(chunk), 1) + time.sleep(2) def writeplctag(value): #value in the form {"measurement": , "value": } try: diff --git a/Pub_Sub/tankalarms/thingsboard/pub/sendAlarms.py b/Pub_Sub/tankalarms/thingsboard/pub/sendAlarms.py new file mode 100644 index 0000000..58497ef --- /dev/null +++ b/Pub_Sub/tankalarms/thingsboard/pub/sendAlarms.py @@ -0,0 +1,12 @@ +# Enter your python code. +import json, time +from common.Logger import logger +from quickfaas.remotebus import publish + + +def sendAlarm(message): + logger.info(message) + payload = {} + payload["ts"] = time.time()*1000 + payload["values"] = {message["measureName"]: message["value"]} + publish(__topic__, json.dumps(payload), __qos__) \ No newline at end of file diff --git a/Pub_Sub/tankalarms/thingsboard/pub/sendData.py b/Pub_Sub/tankalarms/thingsboard/pub/sendData.py new file mode 100644 index 0000000..86c1af0 --- /dev/null +++ b/Pub_Sub/tankalarms/thingsboard/pub/sendData.py @@ -0,0 +1,179 @@ +# Enter your python code. +import json, os, time +from datetime import datetime as dt +from common.Logger import logger +from mobiuspi_lib.gps import GPS +from quickfaas.remotebus import publish +from quickfaas.global_dict import get as get_params +from quickfaas.global_dict import _set_global_args + +def reboot(): + #basic = Basic() + logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10) + r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read() + logger.info(f"REBOOT : {r}") + +def checkFileExist(filename): + path = "/var/user/files" + if not os.path.exists(path): + logger.info("no folder making files folder in var/user") + os.makedirs(path) + with open(path + "/" + filename, "a") as f: + json.dump({}, f) + if not os.path.exists(path + "/" + filename): + logger.info("no creds file making creds file") + with open(path + "/" + filename, "a") as f: + json.dump({}, f) + +def convertDStoJSON(ds): + j = dict() + for x in ds: + j[x["key"]] = x["value"] + return j + +def convertJSONtoDS(j): + d = [] + for key in j.keys(): + d.append({"key": key, "value": j[key]}) + return d + +def checkCredentialConfig(): + logger.info("CHECKING CONFIG") + cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg" + credspath = "/var/user/files/creds.json" + cfg = dict() + with open(cfgpath, "r") as f: + cfg = json.load(f) + clouds = cfg.get("clouds") + logger.info(clouds) + #if not configured then try to configure from stored values + if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown": + checkFileExist("creds.json") + with open(credspath, "r") as c: + creds = json.load(c) + if creds: + logger.info("updating config with stored data") + clouds[0]["args"]["clientId"] = creds["clientId"] + clouds[0]["args"]["username"] = creds["userName"] + clouds[0]["args"]["passwd"] = creds["password"] + cfg["clouds"] = clouds + cfg = checkParameterConfig(cfg) + with open(cfgpath, "w", encoding='utf-8') as n: + json.dump(cfg, n, indent=1, ensure_ascii=False) + reboot() + else: + #assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data + checkFileExist("creds.json") + with open(credspath, "r") as c: + logger.info("updating stored file with new data") + cfg = checkParameterConfig(cfg) + with open(cfgpath, "w", encoding='utf-8') as n: + json.dump(cfg, n, indent=1, ensure_ascii=False) + creds = json.load(c) + if creds: + if creds["clientId"] != clouds[0]["args"]["clientId"]: + creds["clientId"] = clouds[0]["args"]["clientId"] + if creds["userName"] != clouds[0]["args"]["username"]: + creds["userName"] = clouds[0]["args"]["username"] + if creds["password"] != clouds[0]["args"]["passwd"]: + creds["password"] = clouds[0]["args"]["passwd"] + else: + creds["clientId"] = clouds[0]["args"]["clientId"] + creds["userName"] = clouds[0]["args"]["username"] + creds["password"] = clouds[0]["args"]["passwd"] + with open(credspath, "w") as cw: + json.dump(creds,cw) + +def checkParameterConfig(cfg): + logger.info("Checking Parameters!!!!") + paramspath = "/var/user/files/params.json" + cfgparams = convertDStoJSON(cfg.get("labels")) + #check stored values + checkFileExist("params.json") + with open(paramspath, "r") as f: + logger.info("Opened param storage file") + params = json.load(f) + if params: + if cfgparams != params: + #go through each param + #if not "unknown" and cfg and params aren't the same take from cfg likely updated manually + #if key in cfg but not in params copy to params + logger.info("equalizing params between cfg and stored") + for key in cfgparams.keys(): + try: + if cfgparams[key] != params[key] and cfgparams[key] != "unknown": + params[key] = cfgparams[key] + except: + params[key] = cfgparams[key] + cfg["labels"] = convertJSONtoDS(params) + _set_global_args(convertJSONtoDS(params)) + with open(paramspath, "w") as p: + json.dump(params, p) + else: + with open(paramspath, "w") as p: + logger.info("initializing param file with params in memory") + json.dump(convertDStoJSON(get_params()), p) + cfg["labels"] = get_params() + + return cfg + +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + +def getGPS(): + # Create a gps instance + gps = GPS() + + # Retrieve GPS information + position_status = gps.get_position_status() + logger.debug("position_status: ") + logger.debug(position_status) + latitude = position_status["latitude"].split(" ") + longitude = position_status["longitude"].split(" ") + lat_dec = int(latitude[0][:-1]) + (float(latitude[1][:-1])/60) + lon_dec = int(longitude[0][:-1]) + (float(longitude[1][:-1])/60) + if latitude[2] == "S": + lat_dec = lat_dec * -1 + if longitude[2] == "W": + lon_dec = lon_dec * -1 + #lat_dec = round(lat_dec, 7) + #lon_dec = round(lon_dec, 7) + logger.info("HERE IS THE GPS COORDS") + logger.info(f"LATITUDE: {lat_dec}, LONGITUDE: {lon_dec}") + speedKnots = position_status["speed"].split(" ") + speedMPH = float(speedKnots[0]) * 1.151 + publish(__topic__, json.dumps({"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values":{"latitude":f"{lat_dec:.8f}", "longitude":f"{lon_dec:.8f}", "speed": f"{speedMPH:.2f}"}}), __qos__) + publish("v1/devices/me/attributes", json.dumps({"latitude":f"{lat_dec:.8f}", "longitude":f"{lon_dec:.8f}", "speed": f"{speedMPH:.2f}"}), __qos__) + + + +def sendData(message): + payload = {} + payload["ts"] = (round(dt.timestamp(dt.now())/600)*600)*1000 + payload["values"] = {} + try: + checkCredentialConfig() + except Exception as e: + logger.error(e) + for measure in message["measures"]: + try: + logger.debug(measure) + payload["values"][measure["name"]] = measure["value"] + except Exception as e: + logger.error(e) + try: + getGPS() + except Exception as e: + logger.error(e) + + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) + + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) \ No newline at end of file diff --git a/Pub_Sub/tankalarms/thingsboard/sub/receiveAttributes.py b/Pub_Sub/tankalarms/thingsboard/sub/receiveAttributes.py new file mode 100644 index 0000000..ad15ce3 --- /dev/null +++ b/Pub_Sub/tankalarms/thingsboard/sub/receiveAttributes.py @@ -0,0 +1,35 @@ +# Enter your python code. +from common.Logger import logger +import json, time +from quickfaas.measure import recall, write +from quickfaas.remotebus import publish + +def writeplctag(value): + #value in the form {"measurement": , "value": } + try: + #value = json.loads(value.replace("'",'"')) + logger.debug(value) + #payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}] + message = [{"name": "tankalarms", "measures":[{"name":value["measurement"], "value": value["value"]}]}] + resp = write(message) + logger.debug("RETURN FROM WRITE: {}".format(resp)) + return True + except Exception as e: + logger.debug(e) + return False + +def receiveAttributes(topic, payload): + logger.debug(topic) + logger.debug(json.loads(payload)) + #payload format: {'tankalarms.water_hihi_spt': 12} + payload = json.loads(payload) + measures = list(payload.keys()) + logger.debug(measures) + if "tankalarms." in measures[0]: + measure = measures[0].split(".")[1] + else: + measure = measures[0] + logger.debug(measure) + writeplctag({"measurement": measure, "value": payload[measures[0]]}) + + \ No newline at end of file diff --git a/Pub_Sub/fkplcpond/thingsboard/sub/receiveCommand.py b/Pub_Sub/tankalarms/thingsboard/sub/receiveCommand.py similarity index 67% rename from Pub_Sub/fkplcpond/thingsboard/sub/receiveCommand.py rename to Pub_Sub/tankalarms/thingsboard/sub/receiveCommand.py index befb1c6..5b1bc29 100644 --- a/Pub_Sub/fkplcpond/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/tankalarms/thingsboard/sub/receiveCommand.py @@ -31,20 +31,22 @@ def sync(): for chunk in chunk_payload(payload=payload): publish(topic, json.dumps(chunk), 1) time.sleep(2) - -def writeplctag(value, wizard_api): + +def writeplctag(value): + #value in the form {"measurement": , "value": } try: #value = json.loads(value.replace("'",'"')) logger.debug(value) - message = {"plcpond":{value["measurement"]: value["value"]}} - resp = wizard_api.write_plc_values(message) - #logger.debug("RETURN FROM WRITE: {}".format(resp)) + #payload format: [{"name": "tankalarms", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}] + message = [{"name": "tankalarms", "measures":[{"name":value["measurement"], "value": value["value"]}]}] + resp = write(message) + logger.debug("RETURN FROM WRITE: {}".format(resp)) return True except Exception as e: logger.debug(e) return False -def receiveCommand(topic, payload, wizard_api): +def receiveCommand(topic, payload): try: logger.debug(topic) logger.debug(json.loads(payload)) @@ -55,19 +57,24 @@ def receiveCommand(topic, payload, wizard_api): "writeplctag": writeplctag, } if command == "setPLCTag": - result = commands["writeplctag"](p["params"],wizard_api) - if result: - sync() - #commands[command](p["mac"].lower(),p["payload"]["value"], wizard_api) + try: + result = commands["writeplctag"](p["params"]) + logger.debug(result) + except Exception as e: + logger.error(e) #logger.debug(command) - ack(topic.split("/")[-1], wizard_api) + ack(topic.split("/")[-1]) + time.sleep(5) + sync() except Exception as e: logger.debug(e) -def ack(msgid, wizard_api): +def ack(msgid): #logger.debug(msgid) #logger.debug(mac) #logger.debug(name) #logger.debug(value) - wizard_api.mqtt_publish("v1/devices/me/rpc/response/" + str(msgid), json.dumps({"msg": {"time": time.time()}, "metadata": "", "msgType": ""})) \ No newline at end of file + publish("v1/devices/me/rpc/response/" + str(msgid), json.dumps({"msg": {"time": time.time()}, "metadata": "", "msgType": ""}), 1) + + diff --git a/Pub_Sub/tankalarms/thingsboard/tankalarms_tb_v1.cfg b/Pub_Sub/tankalarms/thingsboard/tankalarms_tb_v1.cfg index 1d7daf0..8895319 100644 --- a/Pub_Sub/tankalarms/thingsboard/tankalarms_tb_v1.cfg +++ b/Pub_Sub/tankalarms/thingsboard/tankalarms_tb_v1.cfg @@ -646,14 +646,6 @@ { "key": "MAC", "value": "00:18:05:22:9c:ec" - }, - { - "key": "test", - "value": "wooopwooop" - }, - { - "key": "itME", - "value": "AAAHHHHH" } ], "modbusSlave": { diff --git a/Pub_Sub/valvecontroller/thingsboard/pub/sendData.py b/Pub_Sub/valvecontroller/thingsboard/pub/sendData.py index 4ac3aa2..0e5c4d3 100644 --- a/Pub_Sub/valvecontroller/thingsboard/pub/sendData.py +++ b/Pub_Sub/valvecontroller/thingsboard/pub/sendData.py @@ -1,5 +1,5 @@ # Enter your python code. -import json, os +import json, os, time from datetime import datetime as dt from common.Logger import logger from quickfaas.remotebus import publish @@ -116,6 +116,16 @@ def checkParameterConfig(cfg): return cfg + +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sendData(message): logger.debug(message) try: @@ -144,7 +154,11 @@ def sendData(message): payload["values"]["valve_status"] = 0 else: payload["values"]["valve_status"] = -1 - publish(__topic__, json.dumps(payload), __qos__) + + for chunk in chunk_payload(payload=payload): + publish(__topic__, json.dumps(chunk), __qos__) + time.sleep(2) + publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__) except Exception as e: logger.error(e) diff --git a/Pub_Sub/valvecontroller/thingsboard/sub/receiveCommand.py b/Pub_Sub/valvecontroller/thingsboard/sub/receiveCommand.py index 004afeb..554e467 100644 --- a/Pub_Sub/valvecontroller/thingsboard/sub/receiveCommand.py +++ b/Pub_Sub/valvecontroller/thingsboard/sub/receiveCommand.py @@ -1,19 +1,28 @@ import json, time +from datetime import datetime as dt from quickfaas.measure import recall, write from quickfaas.remotebus import publish from common.Logger import logger +# Helper function to split the payload into chunks +def chunk_payload(payload, chunk_size=20): + chunked_values = list(payload["values"].items()) + for i in range(0, len(chunked_values), chunk_size): + yield { + "ts": payload["ts"], + "values": dict(chunked_values[i:i+chunk_size]) + } + def sync(): #get new values and send - payload = {} + payload = {"ts": round(dt.timestamp(dt.now()))*1000, "values": {}} topic = "v1/devices/me/telemetry" try: data = recall()#json.loads(recall().decode("utf-8")) except Exception as e: logger.error(e) - logger.info(data) + logger.debug(data) for controller in data: - payload = {"ts": int(time.time()*1000), "values": {}} valve_open = 0 valve_close = 0 for measure in controller["measures"]: @@ -36,7 +45,10 @@ def sync(): payload["values"]["valve_status"] = "Unknown" logger.debug("Sending on topic: {}".format(topic)) logger.debug("Sending value: {}".format(payload)) - publish(topic, json.dumps(payload)) + for chunk in chunk_payload(payload=payload): + publish(topic, json.dumps(chunk), 1) + time.sleep(2) + def writeplctag(value): try: #value = json.loads(value.replace("'",'"')) diff --git a/code snippets/__pycache__/convert_config.cpython-310.pyc b/code snippets/__pycache__/convert_config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e223b946320f7b10b32602a6a855c021fffed41e GIT binary patch literal 2945 zcmaJ@-EJF26yDkYIJTQ6p;bZ(ra}}KkrV_?sUlR-&>x9fl_C_?0tIJhlWgMbx-)A+ zt+j+2xU4Gi1oj}t-;&dko7^UZh8nW$7MXn6j< zA^d;P`jbBLkB*O9DDpc9u5s4Xc3GVpN7PnDb+~F>2n~(7V zYKM>WB5IeHcp3E=KgTCf7x;NTiF%ytD_V8x5W8qqmfC*kMcl7>j5-Dn>Efc?Mv==9 zv6g82&?ROGG~+rqo*BK{lfXKhRUN)rhxJwsD|| z5>$He)xy`(7jhvCyl7!L^4hz87|VsbL42>hzHsm1+WqieBjjuM?|ypi;{`IZBEz87 z@-fMa!tZ?%uc6)uHs@PU(!!=c{ItkwGT&tr%w_K$iF5cE0mz_H6a~;XXvBae(JsCM zNr9yUEPY>BKp8!gfa>b2IiNxpK)sy@Dgm@J8aGia6nln%b84Ln3Lt=0ArvY;p(Jls z1Syh^J#Giy&PJml)A4qT;JVWeJt^o&Q(Jl>XvI}4wOS$wV_~CLI3&mdF$Qs9h;eEc zA?gK!Y9+?pO$Br&${0$^#~`h>+UrDUN&gf9QxWgn(X=k!K*#IBdWg|cHVpt8FzF0{ zW=;U41DG600LZQ>AjAX~PfI-73r9f^lNbdD}w7|c5Mc~T!_uH=nU zUT@So=T}7#`<2_|f)7F8o0XL9RZTI4-Ey{Bdo&H^5*O&kI*M2;khe~<<7kQu( zL;QlBjaNHk{pUAwJAcr1;zHu6@xovqcLwXvsECu(>ghnMrzf-;%pTEd^^{i6@>=mR z>{NgyGw#M|B&qbvY1q8^H**@_J)%$cIagbxpeZA-Q5j|sr_DZm`e1vt;8muugi@2sjlU;kk77mZ_bl#!3 zRN(;+uf$n)t#}Bv@i603$ZB*h4`)@v=rz--V=AoS?h*xIYROhJh{Y9PG&tfcbEocZ zW5)+yq{_sp1)@s-fMxU;O;3t@3Tnz?bF6~*Emp><7I8l2OErG#d?>7|pRS@2Yum^} z3YV!EXurZmLzDwr*#%8uqSrd52aO%FdqZ)&Y8|UDu4Az*Y%fylGZH7XCEh(iQ8y^k zu}nHrZ?%}(>ka8&|3pv%%9d4k5V~KfdxM~~l{pH