From a9981fc84d6435f1f539df19111c2a0c260bf9ee Mon Sep 17 00:00:00 2001 From: chuyiwen Date: Thu, 14 Aug 2025 10:10:38 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=A4=9A=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E5=86=99=E5=85=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=B7=B7=E6=B7=86=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/gateway.iml | 12 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .../__pycache__/api_server.cpython-313.pyc | Bin 0 -> 71083 bytes .../__pycache__/cache_manager.cpython-313.pyc | Bin 0 -> 28564 bytes .../__pycache__/config_loader.cpython-313.pyc | Bin 0 -> 733 bytes .../config_manager.cpython-313.pyc | Bin 0 -> 5440 bytes .../config_validator.cpython-313.pyc | Bin 0 -> 2501 bytes .../__pycache__/plc_manager.cpython-313.pyc | Bin 0 -> 2081 bytes .../__pycache__/snap7_client.cpython-313.pyc | Bin 0 -> 13609 bytes gateway/api_server.py | 782 +++++++++++------- gateway/cache_manager.py | 107 +-- gateway/snap7_client.py | 238 ++++-- 15 files changed, 754 insertions(+), 413 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/gateway.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 gateway/__pycache__/api_server.cpython-313.pyc create mode 100644 gateway/__pycache__/cache_manager.cpython-313.pyc create mode 100644 gateway/__pycache__/config_loader.cpython-313.pyc create mode 100644 gateway/__pycache__/config_manager.cpython-313.pyc create mode 100644 gateway/__pycache__/config_validator.cpython-313.pyc create mode 100644 gateway/__pycache__/plc_manager.cpython-313.pyc create mode 100644 gateway/__pycache__/snap7_client.cpython-313.pyc diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/gateway.iml b/.idea/gateway.iml new file mode 100644 index 0000000..8b8c395 --- /dev/null +++ b/.idea/gateway.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..5e1fb45 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/gateway/__pycache__/api_server.cpython-313.pyc b/gateway/__pycache__/api_server.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f3655e6db35d877f6224206ad1fc736befc6c3d GIT binary patch literal 71083 zcmeHwX?PpQm0;r{0p1cxk>c3|C6SOskl-Oo6h)a5CF`(dnILQ>w9SA7NWvlkrUB@n z<3x5Y`ikkX9aFX^l5^N{GO?7?ijP>C$+zR3+5H9>ItvU&lhyZ)sAIqVzM&$`ZpQOt z_r0p_Mgwf10g1BZL@lweZ|FUcGu%eKj{Xi-F7d{;Q*}maCY5#RuWi@;6t< z;O0ff%2-vqnO!PQwM)&ZcWF4yE-k0srQ>ugzEkhc;4;W>CYMQm^_(7lHMUj5akbjmsNRn=&usgGm?BZ6C9H_eU}x_Ili|;lq(k z&iO^Z)9Z^YO$*PGePbT5FC~Q^q{3;&fJR83PT3 z%0lxpAk`RmVIeE+SBZ@qSL z`Wtgk9=r6__lGpJz9htZ{JWZ`!bKT< zrxW7(bA-FzJmD_-3%#b2p|ixNGBYSY{-{lwNYQ*%#$TZ-|ltZr_^+mXe>HDn(ebq!(%ka#l9iupSUKLX(!s9W(XsOGj+NFurh-UrOt~ClCz3Zri{LB6 zVHZa90|RdRxN~42qOng*L^8)bBO^%Rh7qUlF1UAckqnH3-yFN&H#*>S+Xu&-j)>mx zb#j0O#@hoL-YAqV+n*hPkC! zhitxL*mf`03h)*&^>jS2m-9UA9P)V|7=f{O(0*9_wNJPPpm-pB^Tc6ngUjvmK^vBe z1HvrC(4H$3@xks z$7OXVvS*jILQHnJg2hD3!==^mm>VuN;?LQ#s$&f=Hw5Z8&X#pTME-mRW5^BZmk0IB zf2S|M3WYH-0||!(8AvP&Js)caVq}?pY_B+^qRBDk3dW@JBXM8; z;nSB+K6dei6Bnl5o|}FKM)lmuZ(Kb7m`Tkc#dGBlm^2)V_hN*AWzGoEkt`t5q5T8c zy^*3Q2BWbxkjjgIjxgu)OO9|IM<}p;d&0hO%~jL|NRZ!5b1RLTth%4lXY9{Ue^%IIqhTPn~cEn z*gGlhu#`FbIlIs0aT`r44q4QjDuNj=){UjuAY?AUi!6)c0}B`8v9aDN2#zr4^Gm`x zW#OFsaBg*=W>+9*_ti{oLDoE@HDpnwNV^alOpwwFHxDrnsicVMi*h@ajcEn(075}8 z@Ey0>rUpc*{Tm?brSEJEN{N=?LkIsGb zePH`@U;ip){zH&iypRtgr@Q*UAm~!R$n2jc!PBoa@*HHZf&n98N@`4P2CHS<1dI6xq9@SAi)KwjsgM|hk4v3;BCc%I-68` zOqtwrNY5b#BDn%x5!&GD@P#;5xV7*IN`lr7Og)mZ{~-C*VwQ+%n34}d0j7222qhtd z!#U&uLIXCrI!ZsNRJb^&mkcy>=a^^6KIZK*i)otxh}RCmA7PjkmV^pd!2f?LDV*&V_)b3h=A)+_AB_KMJXC#Gu==iW zNqMNGK3GyeTe3P(u=<}0i>4ic!j&__!NQe+oRx$uIYha@8IT$|L>S==U-$w)7II_i z94SfAmS2ax5(s{g_U&<6L59mu5@(Ju@G9*sH zD0~q}%MHXYM}~5|uoqDucL^O|$n5wLXhlGv6SYmuzNOf&HjP4#Z}B;{C8z^(wYbZs z#!A?<7`ihO`YsRRnzeT!{8uNRGPGs6fivEFBrfX zg4!dLb&txbgVHicOLW#u{I%-Mx_wJ&+YonmPcuw5!!mdOnEu*e_?rww3SIiv+jGx; zn`$=~o|^%7bpC_aEIBfbvQiX zH0ijF_@;PbY-j+K0yhYMVAh~@W7bGEXz9KI|AYfZ7PkrEpu%f1P%T17RGx^=1h@rD zd#HL-uzJ(~sNVdhL(^HHsZ`eFU;Qig=-pSMg1F_zPl-4={aj@d%NnVRcEqiEq7hhs8;Mzg@?yM4LZK; z=w1BJmE6pxrPGz@ORY+!nzA)D1BMII6;cLL`nlI4N=)-xVMl7RI$Go zR55@i!_|6a6sum*#uF_X6eP8vw79iajaz5aTD2YfKsAE$tva{vo@|K85MweSMs3wY zI+fL6)8#SNESnlaNCja|OJ)Pi9iaZebNM?>Z}OHr$hTw!O4r*mt$C;-xedadq&E3( z{XJD;d;zHwB(^Sb>#a-OhI0Q65p4wEuz_lOxwP=-23edA+YF;V!cbJS^fEQ}_vd@kRZvr9Ti9;LN zM-ze@wE(ao&zOhnU~8L)TAXc7$&&lfRt7l+!8+#T8X)5sn2Mbp2!h;gWDmL=Xz{Z& zHLVn?(ctq;C|AWdx|a1hMBo5o;t=cgjJX_at;6Bi$WGWD4lw0)uE1|t;-J$t zGV1F9yo^Cb6Qf%I=WuytAac%>GP`k_Ay*@qqPs_&Ny`USKPIOPQXH*Lhr_N2C9VlF zfQHvQ+EW0uusL$DhKE~*l4A#Ks6hQ>f(4yK2LPqK7KK4z#;k(mNI)qYhT)%t1}y}p zFwEM3RAJ!o!-BIrTz+o{+nRjrnSlggd8J{@<=!7xV>)a_f~SSapvAdixP2IUJk5fK zJsy~G#+BJhTEv%05yzKH2Rj+W@ncdLN$u_JNh!wR8Io%!E#PLfv$HV)BkgRIXW5;| zS>^d|=cq-NjYG67W9^*i5{$H*-|YsT#d=-tAz+h_Ji-D);g=BDM<4BMoQMU%b$~RA zz^qXf_9e9%k_%bG@5M$!T)MR$&Xfrzm<_7O3<7B20ThqZ#X0i2DBEfxz z2@uoVW&Z*wMhhC%N%($jO;H%()#>BpU(lDMUEN@4VE4en3dp_DkhuzFqnzFxJSCIF#bVl>IFry1Gy53WbfS8$2LN}8ew!e z8arXo61!YiW2b1NgL}{LFf22|&6v|Y0;8vMP==haux*Fzu%ZtfCJGY>+S1sw1r)IX zEW6Rt)Y!VPO^wi~uElQa{TvuAC5_#C53J#nnjOS9O3h8!$}Pa6JJ??PL3YsP1`8(( zmQ#De)FMveisS@5AJ2BM&TAmYA z3dP|g#sl^-zth;klHW(uMk1|{3?>_4_D!)FEd$o|TiX_D#hr^weBB&pKdgvIJEmHE zOnL#8{REfZ2d@L0v{nny*|Y$gq#VoI=Cv(rTi3Qdc+-)(#pP2(>7dJ(5TQ7r21GUn zDTRlG6h{fPiS=--C1IjOV|xJWvH*?1`dTPWT5k53-eUI+jm9(kC<7YA*8|A&6E=;u zf0y;1JuIOLo=L2D%}nN{BY<)5r3DNT^9hVJ7N!)H8%jj&(~lE@8eWqZkjgv6 zxh8PY6^D@>qA`+K0+x2uZU{92$hBc2X0Cg{Vs2u;#Kv|5ooyJqtcSg@IL%u5 zDVDt}Q8k1P#ox&dG6XibVDb&9TVQboCnxk#0$-Qi@WXAv0FC=}9X~29tXT8Lrq?#T zz8O}<^$JVh;fg9)IWMd{UOrp6Hq16Yw=-N^eY|V7*b-)&pWAtkZJXYCuApdU&2iW9 z{!^K!^`|D!lzq7C!_L6{4+csf3Kl#xtqm6x%`;ici>@$PONyqo^QBCE!yAvh_Q>mx zK6lUb&T#F@>AS+lRmTs#W}e=CuB3cs$8%pkQ9fJJ8m`-LG$*{ga%S{sRbWl$?DEcV z-R7B`@T&Hs*?jbguG!@q!gZY(+j=zn9NwKPDxGK4HI?ToSIz96XH@l-(8lAdjy^E6 z2cFi%KCK9^Xgc0?YU!!nr#8XcZWX=`7&infI|3COA*Pe0ZwOX41u856x4C#e-%we4 zg)tPD{zcD~YNozzzLi;0Jd+hHF#d)13OMtvXqg{XF}X|TnLAX)1y>-=2b+JjIas(GoZyHPz+^UILzFZkxn4s5yzj&ibgy`!4-i>$TF);z zffo?dr%u%i2$q+Q;37`yIczFi97&K~W_gOHx2lK_4h*Dz9603amGSHW$6~c4g^U}U zG3~NtJa)i`(yZR6BEC6~(}kRVSj?iARR^sTU7Cehs5v^{kPF@;H;B7>ap^Gb5|;6L zOX6O@qcx+E5f1Xd= zeD~PJCx3b22=9v&bv@$H0|y*riL+52@hSpIg5E~pv6so)AR}5}dfo*dtu2t1Y*nZQ zPpB8c6%uG~HN$w8BwHda#8g1vZne~L-pU{i3iUt0yr=`;D!_g=K)xHi4)J$H)vg&< znbZ+2Do%UgCWFqJA{x*x_2hzN0yzqLqQ7mBE4i!J?J_ zXzBeAFOH|jn_E@9e;1KAyi9@hB_B8-6EAt<2$qAQhB6GWSLR3MRb(l?iS4YYUl-Q{ zWpG#!fzCPb4mnCB3q7x>qQIfZi)g?*i|fYs$b!HFazEY^iO0enk3(KwJpeJ0hP1GE z6@mOe2taOuzg0!m6najDD$KzObEu-{ql%ts{kfx;py z+-$2Ce75TRs&jkqzhcm>UOJsKTd?YihN;}9x>mpxm50k}!FTMK=cwmwC40OmRMQ%) zX${qE4%Td*t?3TcYzx+GJ2U*@;B3vkvz5JPt7@*0o(@~uLYA#T%hr%(XV9`UWZ4_E z?ET2ndsTyUaFtP2kE_nHYr!$BBJV1bS(HD|Waj2m36R-HaWC=mA92R;{!Bm>_SDta zAt3Gs8d<)tf!A@Dz#H65KXyI2jGHmKbyShQF7i;e|0H7ssx~R zDW-sh9*!<>k_C7FxI1~Car>bLVL86J377X07O~KdB-9c0Uz}nnG({)}m;Do#f-pz< zrSi7q6~d%3y*Tc1d%P3&A!l;%v1^G*Yr-!P4|;q)&p3K4BtsC^hpw_Na7;*Ah|J1t z!t{wd!93`PO1c}+e_=wQC(l87(&_|=Cb;Ekc zVDe7qSD_D%!s0^mltLG}J?@lJHb~d<6LuUD$B>`%qEiWRKXY=4tD%I^j!_RT?md#U zG#Ouj<_+tc1~*(!xq?^9xYO%}ot_Fsi(Q(Wa1bX_Ck*A(=?oQwE)sh3&P)!yb8H4vTYW*s>Aq zLDY|_X{fDrT~fy_K{Aax$CUVow9|+mN>W0MQUmzFBql!WFBzI0UJq_Hc7<%z{RDly zh)a#&6Q;x%lJq;(;2H=rMq3oroU7OB$ zlyCjbbi#?#8POLlWGZTtGS*rV->LD|!tSkaat%g0^IO}q3GE(5%;W0^VNET6XjAla{w}&&bxF<;fW$Xf{C<=7| z&nqBaQ9|B@&Kg34Nf8oUNfji8nvtx$_JV8Wn~e0q$a>sEW3Hk7n{aX51@;N&Rx&ZE zH^HIAa|mjf^j@d+uO)E<_fcz+#SeTjh)U3g14%*9&!WgN$am%?x7n5(OE$m4K!;o#^5 zBLm!aur{{~7JbQpf$0!OSPRspvk{Uftvji|2-7toLfpBR1wU%ow(G?eG2{T(0gnTT zB0}ti2iEN$9|Wzn-tYCpD%)YU2|U5ltD|?!;}c<8;b8$x3qgUky}<&r*%aV+HX`Pe zq6yhO-^D#(j|5kGnCX5R9gPl>LWiJblq~C|i$dgPA_^%rq2~Y}wU(t(bU~d`*jjY6 zh^8EnzDu`s$KU{^0^eP9rF1(0UTTJA?wceF;fTI;~WNakf0+>*g0NHz@Anv zC_OqByg)=>LuCdv!8yAgfpLOfBgDaoj2Vo<%ZMBa+?#ku5+T+#fpL}%&1TEG_2wqC zrOCKfc!&G}-ZqI5IJhCgB1WJ|DOwa3BNP`?q|{G^2TtB2rDO3(-eR%jjYx%9T$5M> z@=ow`iB^n6BN0IA)~2}Rz!+$k!pnY1=}=b@CwP*Q6OKlJjz`ZBNxjCTo+511qe9cM zNGSwBzSkR<9en6wa<@wL>j%ZE2(dHxC4O>9@SJO=mE81lc;Q)VZ~$Hm=m2vwjAE+ zsIQ}mcx|H2v@v005w-}?j9Mk|b|1h2=zQf;%}l%n2$$Z(@)Zyi7q*UFLzEMmkq z^Y#mVrYKVFaK+zkuqLTc$+OkAnFK z-J9zbg?W4r5Gxd^2gSWJ-RdPCM5)L|iLr$v<_{%;zSX27Fkw)R{M;A_VcG(AGb1J{o35zFKKYDl5?J;43+!lQ z56ME)2dtr_wrxQpIt$|LBYG4kY-B)3L2ev^h!)>PbPoUcgqLn(5RdFMX(JhQ8pioB z{rwoQ5D-sPs4(x`IRR0THA>E%6cU`wJmSnoFIXGoLf1|`1Dg_x>x0Ghq2iWcam#FR z+thYE8+i50tB>DzsykS=Zff_u_FfI{Rk-HJ02g`KKM<~{1CRe>l}9W2A8^zx%A03& zx%Aw;$s&m+B2MWeTAZRs^2vMv7TS1+R&WQ-q?33rw->45u7cv5Fd zPEF>I*`7H$H~l)Ck#*t4sfdnXxNkdnhd&AxM)VRVpUczG1UxksUA8$t280wR@eX}Y zBZh5PoMDp>Y`7hVK}V~3|j1QcmhqQ$uW|KCWD zUxJ*39`(69RcDv8$109iOlQD8l#sD4Xlx4^w*`&h)jMmv8+Xb4zOejkx$*d&C;EMjV7XrsqQ!wG5VT^n~LJI+-g5OCO45rN<4VFUMuA)83;6(kfp8!FwQ7Yr*7K3} z&9HYzHm%%_7BLqPYU;U??So;N{t}^nRyA8^?UFJN_(H-p!jJPL{MZ7i=?)Jac<%tSB@Frrh>c{9+P!w4 zkE6Ruuu+jbetS4Wf1PoJ%tf)Bs4>s!+j0!SO~ls5Fqy!*f%Lg zQI(Jkb~OxZuMrwSSa(HksmQtco6vGoaJlJ3{i!=)yI^Sfmf-R&v&(xv%m^;uGo5j+ zwk}k=E?B!RRJ$cuyXDNf+1g#f0(Ls{_l0G@FR28Ue!MkQ+ZL>CJLM0RZwi)gI*72O|IY&~1ODqOcFTzBskou~I~6>`Y0orFc)-9c>$=W6S|?e@;(NDY!k+-daLa}v zOY(y@`D!?vV@~kqk*$ccy>+N%D47Soa6V~L)boDL(6tK=FHM>+-=7`mVsgt!tY0S&nIQXCaiwr2mYMXq%9NiK-gAt zoTamg0I?>H9oW^NB$^fxV{ZEag|%fFGEHR@MJ%q8qV@Vv)gbI&Ouknq3AJF`m9}@r zi7Q17gRl<%OF-Z?(ZMF)qlG;$sA1Q)ujgiNHIY$eQ`&9}-YJ}HR7*Y78bG&) zJpjaWj&2`;q_DM6x&TM%ovc)I$6NH0iqYnQI z+XQEA$}dJseftG9I~n%Cc|Y#>p=9p-2z{XeAIVO*I$?9MTiBSuYpc9Y0@{_a3#@xU zV~|Dx3~}5i6E@ndymzrIBC+fw{+Q(TL>K=pq6O!Fz!%Zxp8ooUr~Ybg`sCb`Coa77 z%gZnQ{9lhe2LAl;X|&7Vd=|c)N55b+_x(5KPCfgtM;=$$qGd4Fhw=`Iq8d{oI zOKV3;TUjasdP76vNOSjT$lqpV)~hjZ=CwK_on7v ze;ghy|MuP!P^Bbiij&f0&si5BlN53Xu}c%sM2;@pn386#DeXur9^JOG2-Sz?lQYic z^(Ip9TS;)I!-|POS6L$(Ue2k?=nDSGr}$kzDj77AV&%GI(WOZU(WaihA@2 z{N%fCKMge#$-G1>5z&L6qG-dqo~KFl1J3NFjG{AN+qlO z)?Ug%;zRL_d$u(NX^z4X>eCO0@)H;&J;9_+v*OC-XtfI#yG(6-wsaV0fWboNnb|we2Jy+Ot8(SF2Vk^7Un;T z)(qvof)uxP9O-y~d(=Ksx5~)qIOL2{&~hwmSqNdvnAvQG4?N>{Lla8e+bWL_4ns|d z9-)iG&kn~P$11#z{WV^X#v}N1rleBcR(BR%-4Q~V&=pG29pn?$abV=9U0)cRVr9XQ)6~#@3tDQLE=+wJ z+-9dPy>5hXXs(UO981VP7sxM?!5|*&~%2U#KJM-1lFG zg(SK*AR1p%Q%6!<`(D&N5I=tD!dt%psWF;(o0>3GaL)uaDy5!&?t`yie)UM|=|2;D zEa=JZ%Ayt#M;0$;PNtq%Y9~5>`djoUrt_zNeE#&2OW*wYA_z-bD+N1;P<4^Tr`~{@ zik-MMw@)8I>FR63_kB`z_l0u^Q%8Lg-(cA4dimX%OK*Mu{ONa^lp#V21qw-dE|IRI z@Xf_g0xx7h&-v5OTzGc+{I9{A=%}!#;O8PMzfqJy{uH(#QA69!**n~yP{83}$1BCn zw1Vv$7tT`jOGfB&>LMx!DcHG4_H_J{Nd`)IP|H@umZz}C_LD^p>=qu_Yv=6a-n7w^ ziY^_CpJrwJBu(*P!nes5|F8}>+s^x0r}^kE^wihgN#8DtDV9=+-Rm2;?wx`0AQoeH zAc1)U+(3EeNJ>C+IWUj7T?+|G9rNJzC%{T>U8;jG<-zU|#Xi7(kZx&JqPkR$w;(V@ zs=E#*n_{&EvTJT@gY7bjSu55Duf#s6_%?C=B(vINT>Cm)HmDuomi0}ghJb^d%O`wz zG9i5>!5JbOK7}fE!?>_7+m--I5eve!?IeG8mVmTqCy6ECMrX2g zKr2`WXd*`!N;BmGh1A4vF7@Q;VdVA4c<(sDBTn3f3=VP^-~HMmnAUDj^5rJ^sjdkj z6{O|SLNW;Y61W$EZxL=SPOS4_2E6_RboBH!Q2|k(kYbrwiMq+|?6=~aKdm8f%TB*i zUB|>Bmd5l8cG;ykHxh|H1qXjx38#C+H~Qyd0=#tz$6{`7N#Uf3bO|SwBQXd}k#MeK z-ky+=A!NL6{TVn|lD+UP!XBcG-L!KauJe#rluHQ?dARYj9q7rgm)`i^h3`zyO@B*V zkVoC`^~W!K=T&}v^__2AeE0ba-$5lXwYB=UPtN`NYr+YFAkh+1N#~+2*Yjs2rn+4J znOIJju6W-*vXJr=*fy2QdZF~JVIXOdm?^=FBn|#I$tYBMip*jiLp(uP4oKb<*Ufy+ z@d+nqhcC^e$5wNjxh+MVU;@4t<)yjc2;meniINgOX_av3@?DY2biv5k50d@u(iMaC zYuR;Z#Dz1DnwnBM??|jxT89qbRNu9ma|C2klqZ&_$qdujS@Fw>FeEO#`a?P@KK&ta zn?#~ZiApOnmQU#%PdG_+*fo;yIRC{w((_LE;?P#yN>aKnfykq6^#%A>|gk*EPg;`+cL}>I9i@`E6#fP)|0>1G&)8AkltC$LN4JKzAVA{hj^_{*)k_&lm0#;(y~-XT+2$2eI7HybF`Hy*mtER z2=~#FM5R(v3^^l0Qc7!LJw*T*|Ep}7mgYzuerj-);U$NYIDe9L@nkC7b@&q8XCHHc z!NB>6NzUs&@`}n%@pJ7rE<`W?@M#ceRGEd9FYyEAw~i=HeVaH)YT6ty$j}zy#_{xo zHBs*I3+-g#?h~KjlJBkqM^>CcDh`{3qF-)0^V0E8y~X5f(8@}IaU3S*_7NibcDf0= z_-{4)VV+MuX;$Z&sAFAT_;wn8dfCN+jdFtXfE~bh_>HYU9%LE39 z%%_oz$4}0C;ggt@r6oxyY2JV&QJ7mwS;JzPM+J9oDnHU=rZGkX7C#{GVC`-P@KF40 zJz=FzFMfX|pceG3O>D|LsekX96~3z-LJ}3ZL3; zAW`%qsQkw}X$*Y2)awCNkF9k$92>;a3piTx5Q ze&?~#*tG>FsI1S!TIok3_kw)FPdyUNBT0kfUv)MPdK`yi7kz+=eB)!WaV8a)0pE*< zpZnp*i{F%IIU|JJ3lK!=;2V)vCwIWfnY~V*e`0|1_2jd>(r3B z6mlG4<}*H@T~sjDbM3$~rfBtv6|;qnft*HeCA^&MARkS{X=Z};w8l=D#B|VkQWt%o zn`F8o*`i%g%sS9mA+?bS#g_}hJ|eYI^oEI<5C zY?~Od>FW8n_U#PQuM=`vRW`<^vgvFYwoF^5Rowvyvaf*@h(B`m>V>=LuaU88Bq_3@ zZ-hG|W6Nwqyu;N7XvFItl~rrinZmKbPiU7@Jmrf;E(sxoEYr z>dgkBj1`Q@;4g==lYHxj`zpNWuu0q!3_2lrGn3nh_kdc4+kwHCG1!d39S}r{We-2* zzJdw91%b&B2OyF`$t99ODTN!vq#{7>Wz3YxErp+m0ZDHFw~TVw>s$o}l^FEkYweiJ z>w^NKm3sx>y@~;WN*c5alVUIPTeC_F-k&`X$djnWX3&~-LYoA*P= z^+y;-dZu-KsAXHQWm~A_o?y#8fxY_z&i%73zFy}i^ACIeZcm_pc=oQ5S<~p1!mNtCt4vl={ydYFn@@+mnGAd4 zz@EyukL2(uAvuPm<2D~~L&mxm$O^}LKSa>07YQxya%*gwdOpt49y^+?YTy&%*o|hC z8^yiZ(f7ig4Mw&wUU9TqGt4?+bXYTSye5Dzj#vQ_!`uKL(u#a2Pk`5p95Li`ghQGKl0)7br{jA7qjyPVF&7n-8425tZ>zMkBn(KNGV`U*D`=Pywv$z=Ty({3rlzwRBZ`2SV9e(gAJQQ4Ypu| zE!6P2V8iDEpC1f3#%CMc;acEM%~!HBkl|zi!^uI0lbeAICu2$Jd;!zGF|=++aNUm3 zI%{y9HPH7!z~z};cOaP4GIi(7u1}KLoh_@JalB$u;&e+4$mtBo=?ns=+Z^R|$q$o{ zQFD+O$#K(NLg!5G0`Z6W8025H4=7;s@3HeppQRp>jjG%Oas|*KLmqL77eUyJHCvw-0p@68W+ig_3HtMplT%&RwUEq9l$Dce$0-&!@Yq) zEK4`##A}-;F>}Vym3&>{0s zOl*E>vyl2es;6Et=rDs0GGt+fY#nCMkqpb(V>w52rgnz&m(93l^Xr7H>lCui=P|`q zGb6#GRa4vMGvY)^xS%v#usmF_jD*EkvoqTBc&YM#3YdaozL3RNqGA3Ut3-n;y}U|E ztjH-u8l%Cb*YuAE(7F>~K5<<}!yc1UDPvXhcg zvPjOv{7* z+CTvYy?SxD#9h(}jvbW${!Af3)H(`f@8hQ!((;H!6>P52DGMzR&3fdrX{{<8oC1$? z>u~xZPFJL`=yYWPtiG&XnQ2e2j6Fz@4gKN-#wOa9Vx+~$#1pnmL0XY%i=-X|N~R4b zE(U1z3%tErlurq!Ez(Ja$isOgzz;|Z(F!ccOPID~gIy-xULCDVuFxW|pF@2Vr!Ch} z2Wwu;v?bqL&qE|q zV-VYgCZdQ21}l{m@8Y8tzeW`&FHG5ziN^<+^9%+A2AS|AoNAygG&qM7Zp`9>jon?m*&i&bxMU9TVx%EJX^XA6p^ZO>L>xrVo&^dN&!I)_LA;PL5>vdHXX{l8#(05EIUrYzwMdQZUe18tFBT?e zsCP5{QRd9_i>y^(N(sx;Cn~Q`ld2WTYLM8nM20F>7n!6eDDs#VwIDQD2FgGcF7E0T z4d~GqQ3!5T6kj%#0BZ$P!}N=)btYrK2P|Rg1Z`Lzg)7`yvm~m!SVOEWGV={;Hnx{? z6Q*9+dwH#DuezGC=DXG1unVMF|PA=U-PJkw{PLA_%9cp0npXb}>3 z03)&Ix!+=N1cR?)@E8PdY9o4dFavX#HV=S!+y`pQdRIa_WF8%^Qb&xb7?;kx>;WgXb(S1bejd_@T`<>eJ% zpRcF@`+RW)Fx!gSW1UAkr}bw`YL3_cRZpnI5-hO@Ai9-7z!Kw<;+L|Y%MKN=!2&i= zd&h5!{u1Zlr!#>m&m5dB zsS6a;{qbyJ#Z^Y13pSl13autsP!m|O?&sdqmY*FsH5xE({%}R00Alaqd3nwH_X+o7 z-P)df&2J4Vc=&C;4#LR-3F9P+FbHzOImyFq)(O}o*KO8G@jw{ujj>K%yOlf7Jq6au z{THanWK|r8B-ARnXaS2Xq%4v~3p|qhTgb}&R}4~Tgxud@`Y0a^;NuYtL_Wy(Q&Y$fb&?+vj#?jHcplSabC=q}#`t{RbSa^yNq zGbB#OAva1Xq7m+e8{&wi>4m%aOWqMn(AwN;iLN7RC9u%1@}u;m$0hI|FL?5o7mhq; z(h#v4$;TxaN!5rzHfbfZoQ;rQPM*#}yfTGJK#w4Wt%O`Sd&wZnBz3{!x=?X@uoy*F z@m*8f&lZ-=tb2ZQAje33U|51#Tx3avSJD8wE1j(P#NZZ6q`18cZiwRx$a8x2se7fp zz{mEYts?H)rxLIn)gb||sHG%2h61pQ-AXl=5Zpn;c8u780Skdw1A(ZUV3J6q(mar? zmXZDUq@`}eCu)R%PvTuL(;6yo2$na5$~OheH=Q1xE$^Kzv<7ml1ebfD4yZ3jbi^Bx z1IHf5w1iZK109&*9>8D%gGmg=F?a$4Fo7`KOBlR{0WObmzr+BiuT(K3TnQ;rMV84o6|3QG1$JZLDtrhY(U z$iws%7;K!^;`98MGbFhJrRLM94()yb^FAoan`PKZ>O}HBq?*@a#C(|~?@aC~-HC%| zDlq3BNlvw4lUV3IkP)6?fiI>#87B^%X~2AYCHblhrDDE&As;-?Z&yh(W}WyPW@^8p zelXk6go)SBliT_2C6aW3(!RieBk+(jTw|VxM6jx;%4)i%Ed}i9;BFr8=GVpK*b%UP zF3|h=fYXa5_^zpID60K{YPg->A+1QD^m75n!-1jw;hF}qfW~uC#COrm6EbZYyl^=HPgxz=my6%_e> z&|J8k-xJ&1)u-+|wd2gAnAUbpZKP@MgS2ovzbiIv=NbQ*k-$DDCLX?~));EBqedVx z+`?=kN(h0{jx)A1cLwew17Y-9$=M4W`Q-uuEx80Uqn0M;d~Lj zZxko6PDdmMtdZa!jZXI9laMd6raqDYvSs+}9PnPQ87ddaaM+#W9(P2Gn}{dTb|*}7 zLAGSCh5H>6TSd%jxgsdSA{AY{;{$lTv+nb`sdc8@7cN1ns8}F zxPlF{E5W0nC=W=is5HF92o9)KSyS4N^kwtQz%MJLFAM6+LV7l+XFt*#!}^?Ov!BQg z=}Uw9(!lbb-|4pzY6GV_lqejUNvNy?Of$63<#=}qgDMQlAlPG4O)lm4PtqSV@lMI* z&|n_P8WFFA65;P>iSgwzQdBI+peOJFuy53q8kQR z?EM^$JE{YqM!}&X!VwGl9Ntx6fL4!)Vc72;@`0h*%Na0|AP}p;EyIA+Y##4WaU!*i z=sPKzy11(lhXdY=v@x$ysZ{@y+5J0a_dhcQ|IB2=|9@f1|AndlXD09eW*l6u+OGNo JLw*Rb{|{Fj+-?8> literal 0 HcmV?d00001 diff --git a/gateway/__pycache__/cache_manager.cpython-313.pyc b/gateway/__pycache__/cache_manager.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a917bb89fcea73a4c71bfdaefa3acaf209b8edb7 GIT binary patch literal 28564 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 Q0Q3Wh9BUzRjwjIh7r$JgqW}N^ literal 0 HcmV?d00001 diff --git a/gateway/__pycache__/config_manager.cpython-313.pyc b/gateway/__pycache__/config_manager.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48957b7b468aa4bddafa5ced339d59d46035c4a8 GIT binary patch literal 5440 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 D{~z#Y literal 0 HcmV?d00001 diff --git a/gateway/__pycache__/snap7_client.cpython-313.pyc b/gateway/__pycache__/snap7_client.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcf5711f2e64bd26abbd82df7f759a44e51ccced GIT binary patch literal 13609 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 MmzX}KP!c`=4>6J?+yDRo literal 0 HcmV?d00001 diff --git a/gateway/api_server.py b/gateway/api_server.py index a70941e..9cac2dc 100644 --- a/gateway/api_server.py +++ b/gateway/api_server.py @@ -6,13 +6,14 @@ from functools import wraps from config_manager import ConfigManager import logging + class APIServer: """REST API服务器,提供PLC数据访问和配置管理功能""" - + def __init__(self, cache_manager, config_path="config/config.json"): """ 初始化API服务器 - + Args: cache_manager: 缓存管理器实例 config_path: 配置文件路径 @@ -25,10 +26,10 @@ class APIServer: self.username = "admin" self.password = "admin123" # 实际应用中应从安全存储获取 self.start_time = time.strftime("%Y-%m-%d %H:%M:%S") - + # 在初始化方法中调用 setup_routes self.setup_routes() - + def check_auth(self, username, password): """验证用户名和密码""" return username == self.username and password == self.password @@ -36,22 +37,24 @@ class APIServer: def authenticate(self): """发送401响应要求认证""" return Response( - "Unauthorized", - 401, + "Unauthorized", + 401, {"WWW-Authenticate": 'Basic realm="PLC Gateway Configuration"'} ) def requires_auth(self, f): """装饰器:需要认证的路由,保留函数元数据""" + @wraps(f) def decorated(*args, **kwargs): if not self.auth_enabled: return f(*args, **kwargs) - + auth = request.authorization if not auth or not self.check_auth(auth.username, auth.password): return self.authenticate() return f(*args, **kwargs) + return decorated def get_summary(self): @@ -62,11 +65,12 @@ class APIServer: for area_name, area in areas.items(): last_update = self.cache_manager.last_update[plc_name][area_name] plc_status = self.cache_manager.plc_connection_status.get(plc_name, "unknown") - + summary[plc_name][area_name] = { "status": area["status"], "plc_connection_status": plc_status, - "last_update": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(last_update)) if last_update > 0 else "Never", + "last_update": time.strftime("%Y-%m-%d %H:%M:%S", + time.localtime(last_update)) if last_update > 0 else "Never", "size": area["size"], "type": area["type"] } @@ -74,7 +78,7 @@ class APIServer: def setup_routes(self): """设置所有API路由""" - + # =========================== # 主页面 - 状态摘要 # =========================== @@ -108,7 +112,7 @@ class APIServer:

PLC Gateway Status

Gateway running since: {{ start_time }}

""" - + for plc_name, areas in summary.items(): plc_status = self.cache_manager.plc_connection_status.get(plc_name, "unknown") plc_class = "" @@ -118,7 +122,7 @@ class APIServer: plc_class = "plc-disconnected" else: plc_class = "plc-never-connected" - + html += f'

PLC: {plc_name} (Status: {plc_status})

' html += """ @@ -131,11 +135,11 @@ class APIServer: """ - + for area_name, area in areas.items(): status_class = "" status_text = area["status"] - + if area["status"] == "connected": status_class = "status-connected" elif area["status"] == "never_connected": @@ -146,7 +150,7 @@ class APIServer: status_text = "Disconnected" else: status_class = "status-disconnected" - + html += f""" @@ -157,69 +161,76 @@ class APIServer: """ - + html += "
Last Update
{area_name}{area['last_update']}
" - + # 添加API文档部分 html += """

API Endpoints

- +
Single Read: GET /api/read////
Example: /api/read/PLC1/DB100_Read/10/4
- +
Single Write: POST /api/write///
Body: Raw binary data
Example: POST /api/write/PLC1/DB100_Write/10 with 4 bytes of data
- +
- Single Read_Bool: GET /api/read_bool////
- Example: /api/read_bool/PLC1/DB100_Read/0/2 + Single Data Write: POST /api/write_data////
+ Body: {"value": value}
+ Example: POST /api/write_data/PLC1/DB100_Write/10/int with {"value": 12345}
- +
- Single Write_Bool: POST /api/write_bool///
- Body: Raw binary data
- Example: POST /api/write_bool/PLC1/DB100_Write/0 -
- + Array Write: POST /api/write_array////
+ Body: {"values": [values]}
+ Example: POST /api/write_array/PLC1/DB100_Write/0/int with {"values": [1,2,3,4,5]} +
+ +
+ Bit Write: POST /api/write_bit////
+ Body: 0 or 1
+ Example: POST /api/write_bit/PLC1/DB100_Write/10/3 with 1 +
+
Batch Read: POST /api/batch_read
Body: JSON array of read requests
Example: [{"plc_name":"PLC1", "area_name":"DB100_Read", "offset":0, "length":4}]
- +
Batch Write: POST /api/batch_write
Body: JSON array of write requests
Example: [{"plc_name":"PLC1", "area_name":"DB100_Write", "offset":0, "data":[1,2,3,4]}]
- +
Configuration: GET/POST /api/config
Manage gateway configuration
- +
- + - + """ - + html += """ @@ -236,15 +247,17 @@ class APIServer: for plc_name in self.cache_manager.plc_connection_status: plc_statuses[plc_name] = { "status": self.cache_manager.plc_connection_status[plc_name], - "last_connected": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.cache_manager.plc_last_connected[plc_name])) - if self.cache_manager.plc_last_connected[plc_name] > 0 else "Never" + "last_connected": time.strftime("%Y-%m-%d %H:%M:%S", + time.localtime(self.cache_manager.plc_last_connected[plc_name])) + if self.cache_manager.plc_last_connected[plc_name] > 0 else "Never" } - + return jsonify({ "status": "running", "start_time": self.start_time, "plc_count": len(self.config_manager.get_config().get("plcs", [])), - "cache_size": sum(len(area["data"]) for plc in self.cache_manager.cache.values() for area in plc.values()), + "cache_size": sum( + len(area["data"]) for plc in self.cache_manager.cache.values() for area in plc.values()), "plc_statuses": plc_statuses }) @@ -257,7 +270,7 @@ class APIServer: """配置编辑页面""" config = self.config_manager.get_config() config_json = json.dumps(config, indent=2) - + html = """ @@ -322,14 +335,14 @@ class APIServer:

PLC Gateway Configuration

- + - +

Edit the configuration JSON below. Be careful with the syntax.

- +
@@ -338,9 +351,9 @@ class APIServer:
- +
- +

Configuration Guide

PLC Configuration:

@@ -350,7 +363,7 @@ class APIServer:
  • rack: Rack number (usually 0)
  • slot: Slot number (usually 1 for S7-1200)
  • - +

    Data Area Configuration:

    • name: Name of the data area
    • @@ -360,7 +373,7 @@ class APIServer:
    • size: Size in bytes
    • structure (optional): Define how to parse the data
    - +

    Example:

    {
       "plcs": [
    @@ -387,7 +400,7 @@ class APIServer:
     }
    - +