From 05e9000c431029a7c0ee95357d94391cb75342c2 Mon Sep 17 00:00:00 2001 From: Manuel83 Date: Thu, 1 Nov 2018 19:50:04 +0100 Subject: [PATCH] initial version --- .idea/craftbeerpi4.iml | 12 + .../inspectionProfiles/profiles_settings.xml | 7 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .idea/workspace.xml | 347 ++++++++++++++++++ core/__init__.py | 0 core/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 138 bytes core/__pycache__/cbpi.cpython-36.pyc | Bin 0 -> 6439 bytes core/__pycache__/eventbus.cpython-36.pyc | Bin 0 -> 2791 bytes core/__pycache__/plugin.cpython-36.pyc | Bin 0 -> 1826 bytes core/__pycache__/websocket.cpython-36.pyc | Bin 0 -> 2638 bytes core/api/__init__.py | 1 + core/api/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 183 bytes core/api/__pycache__/actor.cpython-36.pyc | Bin 0 -> 731 bytes core/api/__pycache__/decorator.cpython-36.pyc | Bin 0 -> 2826 bytes core/api/__pycache__/property.cpython-36.pyc | Bin 0 -> 2561 bytes core/api/__pycache__/sensor.cpython-36.pyc | Bin 0 -> 730 bytes core/api/actor.py | 16 + core/api/decorator.py | 82 +++++ core/api/property.py | 47 +++ core/api/sensor.py | 14 + core/cbpi.py | 152 ++++++++ core/controller/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 146 bytes .../actor_controller.cpython-36.pyc | Bin 0 -> 2466 bytes .../crud_controller.cpython-36.pyc | Bin 0 -> 2880 bytes .../sensor_controller.cpython-36.pyc | Bin 0 -> 1567 bytes .../system_controller.cpython-36.pyc | Bin 0 -> 1059 bytes core/controller/actor_controller.py | 71 ++++ core/controller/crud_controller.py | 86 +++++ core/controller/fermentation_controller.py | 0 core/controller/sensor_controller.py | 38 ++ core/controller/step_controller.py | 0 core/controller/system_controller.py | 23 ++ core/database/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 147 bytes .../database/__pycache__/model.cpython-36.pyc | Bin 0 -> 4531 bytes core/database/model.py | 156 ++++++++ core/database/orm_framework.py | 0 core/eventbus.py | 92 +++++ core/extension/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 148 bytes core/extension/dummy/__init__.py | 45 +++ .../dummy/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 1898 bytes core/helper/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 145 bytes .../__pycache__/jsondump.cpython-36.pyc | Bin 0 -> 855 bytes core/helper/jsondump.py | 26 ++ core/http_endpoints/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 143 bytes .../__pycache__/http_api.cpython-36.pyc | Bin 0 -> 1518 bytes .../__pycache__/http_login.cpython-36.pyc | Bin 0 -> 1296 bytes core/http_endpoints/http_api.py | 30 ++ core/http_endpoints/http_login.py | 29 ++ core/mqtt/__init__.py | 0 core/mqtt/mqtt.py | 90 +++++ core/mqtt/mqtt_matcher.py | 167 +++++++++ core/plugin.py | 46 +++ core/sql/create_table_user.sql | 104 ++++++ core/test.db | Bin 0 -> 49152 bytes core/websocket.py | 92 +++++ craftbeerpi.db | Bin 0 -> 49152 bytes create_password.py | 6 + logs/first_logfile2.log | 1 + logs/first_logfile2.log.2018-11-01_17-21 | 4 + logs/first_logfile2.log.2018-11-01_17-23 | 2 + logs/first_logfile2.log.2018-11-01_17-24 | 1 + logs/first_logfile2.log.2018-11-01_17-27 | 2 + logs/first_logfile2.log.2018-11-01_17-32 | 61 +++ main.py | 192 ++++++++++ requirements.txt | 37 ++ run.py | 12 + test.py | 0 tests/__init__.py | 0 tests/test_app.py | 70 ++++ 76 files changed, 2179 insertions(+) create mode 100644 .idea/craftbeerpi4.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml create mode 100644 core/__init__.py create mode 100644 core/__pycache__/__init__.cpython-36.pyc create mode 100644 core/__pycache__/cbpi.cpython-36.pyc create mode 100644 core/__pycache__/eventbus.cpython-36.pyc create mode 100644 core/__pycache__/plugin.cpython-36.pyc create mode 100644 core/__pycache__/websocket.cpython-36.pyc create mode 100644 core/api/__init__.py create mode 100644 core/api/__pycache__/__init__.cpython-36.pyc create mode 100644 core/api/__pycache__/actor.cpython-36.pyc create mode 100644 core/api/__pycache__/decorator.cpython-36.pyc create mode 100644 core/api/__pycache__/property.cpython-36.pyc create mode 100644 core/api/__pycache__/sensor.cpython-36.pyc create mode 100644 core/api/actor.py create mode 100644 core/api/decorator.py create mode 100644 core/api/property.py create mode 100644 core/api/sensor.py create mode 100644 core/cbpi.py create mode 100644 core/controller/__init__.py create mode 100644 core/controller/__pycache__/__init__.cpython-36.pyc create mode 100644 core/controller/__pycache__/actor_controller.cpython-36.pyc create mode 100644 core/controller/__pycache__/crud_controller.cpython-36.pyc create mode 100644 core/controller/__pycache__/sensor_controller.cpython-36.pyc create mode 100644 core/controller/__pycache__/system_controller.cpython-36.pyc create mode 100644 core/controller/actor_controller.py create mode 100644 core/controller/crud_controller.py create mode 100644 core/controller/fermentation_controller.py create mode 100644 core/controller/sensor_controller.py create mode 100644 core/controller/step_controller.py create mode 100644 core/controller/system_controller.py create mode 100644 core/database/__init__.py create mode 100644 core/database/__pycache__/__init__.cpython-36.pyc create mode 100644 core/database/__pycache__/model.cpython-36.pyc create mode 100644 core/database/model.py create mode 100644 core/database/orm_framework.py create mode 100644 core/eventbus.py create mode 100644 core/extension/__init__.py create mode 100644 core/extension/__pycache__/__init__.cpython-36.pyc create mode 100644 core/extension/dummy/__init__.py create mode 100644 core/extension/dummy/__pycache__/__init__.cpython-36.pyc create mode 100644 core/helper/__init__.py create mode 100644 core/helper/__pycache__/__init__.cpython-36.pyc create mode 100644 core/helper/__pycache__/jsondump.cpython-36.pyc create mode 100644 core/helper/jsondump.py create mode 100644 core/http_endpoints/__init__.py create mode 100644 core/http_endpoints/__pycache__/__init__.cpython-36.pyc create mode 100644 core/http_endpoints/__pycache__/http_api.cpython-36.pyc create mode 100644 core/http_endpoints/__pycache__/http_login.cpython-36.pyc create mode 100644 core/http_endpoints/http_api.py create mode 100644 core/http_endpoints/http_login.py create mode 100644 core/mqtt/__init__.py create mode 100644 core/mqtt/mqtt.py create mode 100644 core/mqtt/mqtt_matcher.py create mode 100644 core/plugin.py create mode 100644 core/sql/create_table_user.sql create mode 100644 core/test.db create mode 100644 core/websocket.py create mode 100644 craftbeerpi.db create mode 100644 create_password.py create mode 100644 logs/first_logfile2.log create mode 100644 logs/first_logfile2.log.2018-11-01_17-21 create mode 100644 logs/first_logfile2.log.2018-11-01_17-23 create mode 100644 logs/first_logfile2.log.2018-11-01_17-24 create mode 100644 logs/first_logfile2.log.2018-11-01_17-27 create mode 100644 logs/first_logfile2.log.2018-11-01_17-32 create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100644 test.py create mode 100644 tests/__init__.py create mode 100644 tests/test_app.py diff --git a/.idea/craftbeerpi4.iml b/.idea/craftbeerpi4.iml new file mode 100644 index 0000000..d7cfe33 --- /dev/null +++ b/.idea/craftbeerpi4.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..c23ecac --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0532208 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..87e58e4 --- /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..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..964274c --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,347 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1541098050947 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/__pycache__/__init__.cpython-36.pyc b/core/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bdfdffd07fad0d8eb6379fd4a58a686088572837 GIT binary patch literal 138 zcmXr!<>i{bWJfdu5IhDEFu(|8H~?`m3y?@*2xib^^jpbL1QJFNzs&VRi&Kk=^>Y*R zN>g*viZV-zlQZ1^~O@A}0U< literal 0 HcmV?d00001 diff --git a/core/__pycache__/cbpi.cpython-36.pyc b/core/__pycache__/cbpi.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5406ffc5ef4afd25cd50843ce66188f21d6da4d GIT binary patch literal 6439 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 Oe@!igby<_K)BgvK?-WP? literal 0 HcmV?d00001 diff --git a/core/__pycache__/eventbus.cpython-36.pyc b/core/__pycache__/eventbus.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d66f3010ae07e3c96f7a08955e453b75ea3ed347 GIT binary patch literal 2791 zcmZ`*-EJF26rP!#U9TM{O@9;`C?$eWWK~K~K?17qBOp*z2uLkW3DCv$Y@D?>yUxtI zB+>c?M{0Y6`T$%bfp`Qidcjl7EmwVoT=AXV*m0s_Wlv^j=KRcezH?^Znx3xxy<)#V zGsW1yY~m*|{s@n`1fiJXG239DGbNOBz?2j6p|c?rzr`Bz8FsL>7Rk|XtbG?VA=}`J zZ3t*{C7>-r2ij7dRZ_VJe8W|qsvNKlPn}b~s$!<1YHA8IeppqGs{ba`w3<1P8#Q%C z&0>B^Iq-bm`l}DZB>T8;PIwn^`Vk&;al*UuHXPWJ(1urNSN5kz+DmJx3T-uLZAG!t zVPgHDl_nWXw>V7DkN%V0Pw<#oh=}DZ05Xs`9qjS7hR_aHG@ZV|tu$f0`3KV;UJu_{ z{?>%rEN?fHKBje)nby{FJIc2D_m`Vd8kpvGFAkSmsScMzI@SHYS?cW}lpso?EC_s< zF=U!?kMGZ&h<$0a>0}HpX(!F?FbHfd2)0wzk7-;Ff}MUdK3b^;fr-=11c4?WMZ6QD zf;lS*As3?}0-sBvr}4JdDgwfY4oTwzp9F*4QLJ0l=W-`!9hUPIAl2a=a3<$N!RgHz z$lb-9ccc;H)K*5xW@_C)r)g$g(~G05NR_RbFjL`Xvma;0 zfov@@QDU-Y(h7?_S{X+svtF~;3lr7wG=X3pxU%kpX50_015Z{a#30A)ZJ$QY*I^qL zLS2WVIS0Xn&ue@JS)Ao_qE6X7JI>~4cZx2ErMFq&gru6@T6akm6gtmzqeX}FqV z)#pi!S#ABB;ohp&scy&u2~8!YUm`(`;`HIC+hG>8nsI!;+3K2k>?jf7qB#8waPTpj zndI{cl@__CAF+@SEco>|25mNQ_7v4$2ZcG119$h@1R#q8Vv!3-y!oT`-03*E%rU>| z5N~!agIN-LTzbnz!PlQ)(GA?hEB~*v@Xq>eN+eYwD>*36_wY z!E1w;r={Lf9*9^_G^y(t7@B7|Ky9*sMxC%BtP9iK~uaj{_Q3ca;6OXw8K@_4& zDjU=8+jtk0WF+;e_AeqJ96X)!R3|{`C3+>ZLg0S@=VfK|ct#n^|j1FJJ=2Mgi#tEqdLbo4RdmrA)7} zeDicR*+hYuaH>Cy%&^vCHX7 z{bZ!6{!jB4Xi7Q*{5*x`??;+XX->&`L`7bT7@wBj3a+|q&*+qg{AzL9L;hOBL7|07 zS(OANGD>~V^2kaQUuG*u-wX{$zeWpQlIrbdY#n4`g1+xzt)Lz?%#yyf;zoE88Jy## ztfLzD7smB>%$KE=I7LG>A1uKt3WTDBLu%8w%reAbe#S>dQAGG2DQ+t_OM6in!clDc zUF_Esi7ra&Dn_5-G4uhz&;{z^+}VlxKlV?bIryuWMN9P4bURruz26C2Y5aW`gKFVibIn_zTN-9;25ni{%*d_G&LP5V=|Ip3YFXj((?Z;fNB8Jg)Yc=b6sk_(K znpp^}NSs56a@QZo-^eLPpF78#{1<#m)y&E$u|x){rn{%>>-y@ep8E?6{;ykqedqdw z{7tSs7L0en)D}2SI88`O28806B{XFNM#-0iTiiY;+@7(4#hu5b>%M{gq)Uxk6f({< zjJyMx7eeYugrBY+27_HN)d45SfO0ZmoN{(f0LlU=+cXc7@i5LF9efqxc6?f3O)$() zZNh3vM`X%MR?;CELY|lQ)GFzW{7il##{kEzb5GM(WJdSEruGFryD05FazPJ&oI0Al zA|tDGW>niFXU60YSM#Y`0=Eyz$Ss}H9W^+553C91bNAAnQA$o9{tKZ62!Gs)(3m6m zh{C-a5!y3$L8W~wMw4UoLWR(}5n-`H*t->>JBjy;gc0u%H^ROK)WH6;Q8PjaFgggF0)KI*qbf z`n+>#A(sn!`uZu+9r(J=H-3R0B{|%jQcbXxpuO0Pwu!VMZN{Ok>hW*v)P}>TVL{Nfj2DGT5*{VO zG=@TlT1(?A9ZIcU#QLPm4C{SiY+T3dqSNA=qtWl=?SuZeN=VgD!)z>)V;O4|o%Dwg zGCt~uaUQ5JEfUd>aw+;nbwPT?uRiLVgiDP67<(lTIs>zAdm~wlbqLB_h9YKpZI|q=S9pxp>^X00X9t# z7>masU##K`B+MdVmV;ofYJ4=-utnl8$+-Jf`QYrL5ZN5NqKzq5+>QMNiZgH@SLEeK zus(1eAvs*D8GKzcfb)4AX*l1BwMd~=PeO$qBT?RN%h*uCV`D{$s^xN}P@sZoqykk` zhNgyU)2f+PWaOuq$S3ITp<4#mrE&?!*g2+sy;1OAt9HQ==CVc0r5kjSu2P?R^y7E$ zPBp(v@%`D{25k^e%n5adRia&6Jw}Z~P!gb3RV6+U+1X9fwI>d-(u9S7}~z zn5neE;XSRI-LtAW;$d+HD|kVAVG;M{SA9|`RBgHjg!F6P-gbTd4*mudVz*h_`Ue$5 B%SiwL literal 0 HcmV?d00001 diff --git a/core/__pycache__/websocket.cpython-36.pyc b/core/__pycache__/websocket.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..561bf6947e59e75665c6234d4a05941f68293d2e GIT binary patch literal 2638 zcma)8&2Jk;6rY*>@Y-=4C!}f9LKTXra0LlaAyO!)sI8z91Su&=F+!`&&cyL%y=%{m zabh_q=g7yEL;nFdAWocm;|`pMBd1@NYkJn^rhcc?EOmlr zK*{@rd)z-F+#j=MnU{EQM4A;&H%O!W81^S?4Qi&i*ope7=IvNR*BOZI1~b7uEo8Kv z3KQIp(iF8AR~$bsD7T=g2OtDNY)!@~XAdcNxO?O_9pMTOEZ#$h`@94e-}ZxtjF))@ z`X%9sK)8#9qiu>;!B*zeyf#5OW6E1%dn1qcghs5s6uK|7n8Bg=;2V+LhNkX-7|{_4 ziKd#3QFFALcw+*ZuS-dw%hp;Mk%S~uNmWlLH4gKVnK5h8F~tZ%Y}ne+SsAEC-MDcs zg~U^gql7k84@@-B_7yx!gTKH0`Xd!>|VXs0s)| zeOiHEl@8}7L0>+e)^Low)6Zh#i7&uKS%L*I;>8Ew7$kcQ^PpgWM{JQKbaWC{y4GM4 zPXfm|Z#Z%Rba@fQB^2mUAufPssu-B#aGwK|F6 z`jc7hxSCuw{fzZhp<2C;vkK)FZ&W#y2K*ydSmHj>9d zw2s?I{u_kE&7Q?wCm2pe@3eChEI!P}EBqN(U8IC)xWzF+3<<;AJdP9~bP|Xj(nfpO z8&gg%kV6M_KPeR>PjncgWccI$_apYYjr2kFx_uwITO?a>i4OKEa-V{ilzd9INbj!) zWaK7gT|uJmG5H(xra1%c2S8FAlT$e0G;UAm{Ry*X04?IFC$q`i$m3XGpbT;UD=3@2 z&B?CMz+Rgc-#iDj$+lY7j&WK?VU3&}xBF2l;T!~?@ zwXt*?HRI{L+m0V&f&*_^n;Wm24}=_E9jK)^&oU9~cAhQSb$n?6gk2K*vFKXsi)vVh zOj#=GUa@84d{G@{Cn>ZpR5#Dyuu@lwZUl8|8jh2A+r~*nCTCG|+u2TT<~9J(d+H#I zZCS@tjH?g2uo$YuuGU>Bv>P9()_t_O_wPQqZ(JVfNWNe!Kr8%eW&b!tg zV{YJs``{!?sb4^OLMbSYKq*MM<5bp2C|fYKr;q8x_P-p_Go*2zkj4knG*6M{5hSUT zlys1klM1Bwx6qriq&b4KswbrB{RI7K96dR`w>nu{gSD%AhC48;KB2`b(BhGHM(iB| zW3HtE{+IC94Fir@m&`qRqf6(QPXlH%q%kG&YbvKen5j5V;Xe~nP1%1C1x^RYe4rluJ17ziGtcJB be`c8pZWgKgE@qU%GXfw+l|iF*uXf`f#iL|z literal 0 HcmV?d00001 diff --git a/core/api/__init__.py b/core/api/__init__.py new file mode 100644 index 0000000..027ad5e --- /dev/null +++ b/core/api/__init__.py @@ -0,0 +1 @@ +__all__ = ["actor", "property", "sensor"] \ No newline at end of file diff --git a/core/api/__pycache__/__init__.cpython-36.pyc b/core/api/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adef98c9a10f2c1edf59d6a2a8314ae2783e07d2 GIT binary patch literal 183 zcmX|*u?oU46h&XH)gsjY=wb#(Mf?I6ana!so3st2O?XL%ev%*L5^!?!6P%0=UO0!l zT)69^SUg_$O9=qa$UkXp`-odc2@r{xH0c>cdW3QsGG2K@A-80#BtM3klf5%^D3dTp zy#>AhhmC&{sn_k+|mDetP5HOjZcm2qXz@y=?=DnpWSs~Do{l}B9JG349M Mh(XI;@;wxR4+Hr$nE(I) literal 0 HcmV?d00001 diff --git a/core/api/__pycache__/actor.cpython-36.pyc b/core/api/__pycache__/actor.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df979be2e184974e883acbfd43e6ab4a65f9a4f4 GIT binary patch literal 731 zcmbtSy-ve05VoD9b<-9QZxIPK0}KoZ6)~_?LWrddmWdM@DSz0h5EUDJ86Jbz@XA{- zapyo)5KNqO-)EhD-+i%jI39}tn^^$Ma%KHWmT5$-Z_*-rA-V_W-;d*KlWG%}vRXn}=dDQ=@m=07mbbCY zYhh&B6lt8)I*nzM#}W-pnn%lp$g8{+BEaE30HHm)+HnpiUz-Wq!$3y6&MKaE_UO#n zh?qtd8#MJps$HprK2}*>4SSpk#Qjnh-HztauS0|(0{YzYj}NEuW;A{@{(J@- aIO9I|xaX>~h&ukQ&GM6O?y2jAR`LPT@Pf&q5Zzr;62(ZelekXP7ODFIBq|CEZEvj+1Za$&s!LQ9P*D&xcV#L1AiZ40 zu^^vp!1^ogpXs&OQ-PlP7kcW5;?075&--mws2%6XL8#ZHS{5kuzg2SiKKV?V$&uq$IDsRGio>s4vPL-?+%RAPQ zD#9q>mj1^6-D~`m!rR6$9F5hWqkATex{br0>5dN?VJ{BSaF`5KBZ{?Zgh{Uf^I{#E zSnnn$b=MYjJT}U@Nocy(9fd<>i$i6)u|#4z<55(1^al9SHEgQbAXb_{s%aGt zf+Y?3HbsOOFV4@&Gp&xsDmB3{Op@N{Fef4&1zls3U_Ky!vFtkZAnw8fbxu(M zhk0BS(#9pX6^tpPZ?iOca@%NHC|HN+)`+RC;#Q$pdm8jxSc!+=LD2O*Z01rTYZlU_ zMG>JC!)Bu9dt7jjdye25IljU^i3{z(}*oO%D#aZ gU(#;9yFa1_lgje#n{j%qIWjOu+0I5P5Jpcdz literal 0 HcmV?d00001 diff --git a/core/api/__pycache__/property.cpython-36.pyc b/core/api/__pycache__/property.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..481a8ba970b19138273405f99e7c30892a7e2023 GIT binary patch literal 2561 zcmd6pOK;Oa5P*06Zkn_akHP_@N>oS&sX1^2p&+DkK#GuBF5zG~-fe5-#Aeqq-=K1GVvZ@u1~Wl6m25C;m-u!BGwVWOG=wU<&~P%QjEoINVV+TT--$HiB0t(Y z%J|4POD_m!;gknK*$IMa%8CTX-5~f>go%Fgg9sZmspik~!F$Pt98AMm!IOOv=Q27R z9K`uyF&Tt$8pv>(C43O2f)Bzh9%PFJx3eRGmSL3!G#*uQ%k}Y#3vySNS zpb6MvM65uA1L;9SXoouRJHEeU`F6GB$fp8l`j$ZR1%eRhj8fE4uJ#5hE*uPLUS%@d_$uCigb&$_Nr#> zTMGxTOk69%a96}{!MH^n12@D8OT_UE;SRPH@m{?T_V|~4N8`pwV!{6MxUGwDiyEM2 zYoEpTT&j1$kY%bHEz4`BkleHvS7mA;fIGMlx(r$BHguODx||c%YP()Vc`7tf3awEU9d}-llhrruNV1iU92KmEb z5G}#X1%M(6l_X)3O1345BOU32ccmwN@SdDV4&Ikj;0b#FUe%`28HG_i=#lRh%$xy8 z`bNZnzzZ`h?g4sM$lk5fN`qOA@-7?zo%!C|0M*^I$|9>}m7-C|=LBX{+WV=Gl(f7UFP%OT%Xn zq7Q_q8rhW?&xCmC(sHP14g`9NfFkt?0zTFVa48y>iDqzsGwyPSJ2o4`Ik7scq^I#2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CU-tT;#i>Qb`nidD zrKve-MVTeV$r<|TnI##eN&1PI`SHbxxdl0?`pNl4srtG3DWy57#rpB_nR%Hd@$q^E RmA5!-Afk34gNuQf0RZamB|ZQE literal 0 HcmV?d00001 diff --git a/core/controller/__pycache__/actor_controller.cpython-36.pyc b/core/controller/__pycache__/actor_controller.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a500f8b509bd64e0fb86efc27a4867214bebd388 GIT binary patch literal 2466 zcmZWr&2Aev5GJ`lTCHWtk)0+%(^i)rlpqq4q8B$P>N-iC7L@}hL4a+G#d^uutL&f2 zRh+2uNe0r3(HF=I^f`L%6Ksz?`4xKV3|F#TWfz%JM+6325iZ^iY*^<2%{@k-M0 z8k(=gt4Y&qQt}<)4zHgQUKb7Fi00JtTHJj~x+~|fE9uhGI2QZxSq(m(n4l&EF_G$TVavOA2Tju=+$53Bxnrk(ZQH&Q2ZA(!9Y<;B8Uk7Poorj0tC0 z=gxb|>)bsxr_^)B3SZ%kGs>^>rk1q$+NlMS#)YIBzrx#k#_CLOoo}3)Uh^F>iPr*D zJ}O)K9E+ocY-T8ajagHhz!apQ6EbB(Hlb5++XQ;P!I7F1GBk$P1RObKltcu^Y)xyN zz&6I<(b(<>h*;MtEj7x8lrF4UI=&yJQQ`Zg8Sdv1$cms4r6a{bqzWNRt9Y9WRoZ&8 z0za8b#4qJ4Oh&MMKa2yVeE$#f@Av)ZN=VgDf^>vBQK7=a{y|h6j`sUOl=&)1@>ul4 zOd^>(v$D%y4D|B1vH|N~fu@ilbdB27W=){u>q~(3<|ha#s=|Y=HlaA*hVx$8QsNi; zH^>Q_Fz7i`@Wrq`G47MXLJ4~5=-U_2<0!XrW#A3eLSFmE9F*oWz}U04x3+g4diK`# zv)#R?U01Gv>6MpE^pRYHerZL8NK|R%GJ;gG!XP{prHM|`K9LAo*OG12HPavwpc4n< zamgZHTCan6B)U|tQt|GYxZ*isZDnf@=D(Jy~OQyn0H0U6RE!_?!Da%WI{3S($u(w$L=+1g<2 z>Y(f2g$>Tpx#uB}u2EXLPRLK82S8-ULZ1JH64(~QcccIS4A9cpA1Tj#2^B_SI+f0z zPf-=6g48lxnZs=_=6pXNnERVu-4zmU! z;(-q?f^8d`>H#UB0z(S3DI6SAc}O9sZsB)AA*76n0g28qgmjp&!ML?MxO4gG8uA7# zq+MPz*xJ;G(zwXaK~mCa>0lCf#-CUN(Ggn)_t; z#lyXa4?4R8h%U4WjKdhLoMgW`4&;GaGNv@L^xl`atgd-%y#ApX_bvcLJFsa0uLFY- zQ~{*34`90wkV53J@zm|ip1oNe>ja%t9Cvg;bue2lG&b`<21y4~WpgG+ep#-QXs)1Z z-a?~__07&8OBeG7UFJ1>SX>D|mszfK{?1{!2?vm$Akjg05qYu&V_!k5qOJzc`Jmv< zYcn8y2Q<5DSjEw1sN$~gCmA2b$TxidXcWYiM8fX?WD5vItgEX|dWkuyb3UF6WBa&=bdLlMWmzc6}UOLQ5*8wHD&E+dX%8V$G6bZOgkXxnz^nx(7R01U3d zb%4pExAtz%dOrRW^fciDZixWyE2S%n*Tzeu7vxdzLQ>g@2k<`A(n~i;C`bI#jUw^i zr(D-sJSc+wK#5)j1;XOp)DoS|BIS7orB(HG7j~4GD&C4#$@Ra5tiy;t%L0gsLl{cu We&vF%v1X|z5GbT<4a%r~jsF06tw?_W literal 0 HcmV?d00001 diff --git a/core/controller/__pycache__/crud_controller.cpython-36.pyc b/core/controller/__pycache__/crud_controller.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..050551b157d173a0beb30a5fc237a8c5c7c801ef GIT binary patch literal 2880 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 web.Response: + self.cbpi.bus.fire(event="actor/1/on", id=1, power=99) + return web.Response(status=204) + + @on_event(topic="actor/+/on") + def on(self, id, power=100) -> None: + print("ON-------------", id, power) + if id in self.actors: + i = self.actors[id] + i.on(power) + + @on_event(topic="actor/+/on") + def on2(self, id, **kwargs) -> None: + print("POWERED ON", id, kwargs) + + + + def register(self, name, clazz) -> None: + ''' + Register a new actor type + :param name: actor name + :param clazz: actor class + :return: None + ''' + self._parse_props(clazz) + self.types[name] = clazz + + + + diff --git a/core/controller/crud_controller.py b/core/controller/crud_controller.py new file mode 100644 index 0000000..7079969 --- /dev/null +++ b/core/controller/crud_controller.py @@ -0,0 +1,86 @@ +class CRUDController(object): + + + cache = {} + caching = True + + def __init__(self, core): + self.cbpi = core + self.cache = {} + + async def init(self): + if self.caching is True: + self.cache = await self.model.get_all() + + async def get_all(self, force_db_update=False): + + if self.caching is False or force_db_update: + self.cache = await self.model.get_all() + + return self.cache + + async def get_one(self, id): + + return self.cache.get(id) + + + + + async def _pre_add_callback(self, data): + pass + + async def _post_add_callback(self, m): + pass + + async def add(self, **data): + await self._pre_add_callback(data) + m = await self.model.insert(**data) + await self._post_add_callback(m) + self.cache[m.id] = m + return m + + async def _pre_update_callback(self, id): + pass + + async def _post_update_callback(self, m): + pass + + async def update(self, id, **data): + + await self._pre_update_callback(id) + data["id"] = id + try: + del data["instance"] + except: + pass + m = await self.model.update(**data) + #self.core.push_ws("UPDATE_%s" % self.key, m) + + await self._post_update_callback(m) + if self.caching is True: + self.cache[m.id] = m + return m + + async def _pre_delete_callback(self, m): + pass + + async def _post_delete_callback(self, id): + pass + + async def delete(self, id): + await self._pre_delete_callback(id) + m = await self.model.delete(id) + await self._post_delete_callback(id) + try: + if self.caching is True: + del self.cache[id] + except Exception as e: + pass + + #self.core.push("DELETE_%s" % self.key, id) + + async def delete_all(self): + self.model.delete_all() + if self.caching is True: + self.cache = {} + #self.core.push_ws("DELETE_ALL_%s" % self.key, None) \ No newline at end of file diff --git a/core/controller/fermentation_controller.py b/core/controller/fermentation_controller.py new file mode 100644 index 0000000..e69de29 diff --git a/core/controller/sensor_controller.py b/core/controller/sensor_controller.py new file mode 100644 index 0000000..32f6b41 --- /dev/null +++ b/core/controller/sensor_controller.py @@ -0,0 +1,38 @@ +import logging +from logging.handlers import TimedRotatingFileHandler + + +from core.api.decorator import background_task +from core.controller.crud_controller import CRUDController + +from core.database.model import SensorModel +from core.http_endpoints.http_api import HttpAPI + + +class SensorController(CRUDController, HttpAPI): + + model = SensorModel + + def __init__(self, core): + self.core = core + self.core.register(self, "/sensor") + self.service = self + + self.sensors = {"S1": "S1", "S2": "S2"} + handler = TimedRotatingFileHandler("./logs/first_logfile2.log", when="m", interval=1, backupCount=5) + #handler = RotatingFileHandler("first_logfile.log", mode='a', maxBytes=300, backupCount=2, encoding=None, delay=0) + formatter = logging.Formatter('%(asctime)s,%(sensor)s,%(message)s') + handler.setFormatter(formatter) + + self.logger = logging.getLogger("SensorController") + self.logger.setLevel(logging.INFO) + self.logger.propagate = False + self.logger.addHandler(handler) + + async def pre_get_one(self, id): + pass + + @background_task(name="test", interval=1) + async def hallo(self): + + self.logger.info("WOOHO", extra={"sensor": 1}) diff --git a/core/controller/step_controller.py b/core/controller/step_controller.py new file mode 100644 index 0000000..e69de29 diff --git a/core/controller/system_controller.py b/core/controller/system_controller.py new file mode 100644 index 0000000..d4d7031 --- /dev/null +++ b/core/controller/system_controller.py @@ -0,0 +1,23 @@ +from aiohttp import web +from aiojobs.aiohttp import get_scheduler_from_app + +from core.api.decorator import request_mapping + + +class SystemController(): + name = "Manuel" + + def __init__(self, core): + self.core = core + self.service = core.actor + self.core.register(self, "/system") + + @request_mapping("/jobs", method="GET", name="get_jobs", auth_required=True) + def get_all_jobs(self, request): + scheduler = get_scheduler_from_app(self.core.app) + print(scheduler.active_count, scheduler.pending_limit) + for j in scheduler: + print(j) + + # await j.close() + return web.Response(text="HALLO") \ No newline at end of file diff --git a/core/database/__init__.py b/core/database/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/database/__pycache__/__init__.cpython-36.pyc b/core/database/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de3003f51abef79de27e4784d366825659c1f7f6 GIT binary patch literal 147 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 literal 0 HcmV?d00001 diff --git a/core/database/model.py b/core/database/model.py new file mode 100644 index 0000000..f1c8894 --- /dev/null +++ b/core/database/model.py @@ -0,0 +1,156 @@ +import json + +import aiosqlite + +TEST_DB = "./craftbeerpi.db" + + + +class DBModel(object): + + __priamry_key__ = "id" + __as_array__ = False + __order_by__ = None + __json_fields__ = [] + + def __init__(self, args): + + self.__setattr__(self.__priamry_key__, args[self.__priamry_key__]) + for f in self.__fields__: + if f in self.__json_fields__: + if args[f] is not None: + + if isinstance(args[f], dict) or isinstance(args[f], list): + self.__setattr__(f, args[f]) + else: + self.__setattr__(f, json.loads(args[f])) + else: + self.__setattr__(f, None) + else: + print(f,args[f]) + self.__setattr__(f, args[f]) + + @classmethod + async def test_connection(self): + + print("CREATE DATABSE") + async with aiosqlite.connect(TEST_DB) as db: + print("DB OK") + assert isinstance(db, aiosqlite.Connection) + qry = open('./core/sql/create_table_user.sql', 'r').read() + cursor = await db.executescript(qry) + + + + + + @classmethod + async def get_all(cls): + print("GET ALL") + if cls.__as_array__ is True: + result = [] + else: + result = {} + async with aiosqlite.connect(TEST_DB) as db: + + if cls.__order_by__ is not None: + sql = "SELECT * FROM %s ORDER BY %s.'%s'" % (cls.__table_name__,cls.__table_name__,cls.__order_by__) + else: + sql = "SELECT * FROM %s" % cls.__table_name__ + + db.row_factory = aiosqlite.Row + async with db.execute(sql) as cursor: + async for row in cursor: + if cls.__as_array__ is True: + result.append(cls(row)) + else: + result[row[0]] = cls(row) + await cursor.close() + + return result + + @classmethod + async def get_one(cls, id): + async with aiosqlite.connect(TEST_DB) as db: + db.row_factory = aiosqlite.Row + async with db.execute("SELECT * FROM %s WHERE %s = ?" % (cls.__table_name__, cls.__priamry_key__), (id,)) as cursor: + row = await cursor.fetchone() + if row is not None: + return cls(row) + else: + return None + + @classmethod + async def delete(cls, id): + async with aiosqlite.connect(TEST_DB) as db: + await db.execute("DELETE FROM %s WHERE %s = ? " % (cls.__table_name__, cls.__priamry_key__), (id,)) + await db.commit() + + @classmethod + async def insert(cls, **kwargs): + + async with aiosqlite.connect(TEST_DB) as db: + if cls.__priamry_key__ is not None and cls.__priamry_key__ in kwargs: + query = "INSERT INTO %s (%s, %s) VALUES (?, %s)" % ( + cls.__table_name__, + cls.__priamry_key__, + ', '.join("'%s'" % str(x) for x in cls.__fields__), + ', '.join(['?'] * len(cls.__fields__))) + data = () + data = data + (kwargs.get(cls.__priamry_key__),) + for f in cls.__fields__: + if f in cls.__json_fields__: + data = data + (json.dumps(kwargs.get(f)),) + else: + data = data + (kwargs.get(f),) + else: + + query = 'INSERT INTO %s (%s) VALUES (%s)' % ( + cls.__table_name__, + ', '.join("'%s'" % str(x) for x in cls.__fields__), + ', '.join(['?'] * len(cls.__fields__))) + + data = () + for f in cls.__fields__: + if f in cls.__json_fields__: + data = data + (json.dumps(kwargs.get(f)),) + else: + data = data + (kwargs.get(f),) + + print(query, data) + cursor = await db.execute(query, data) + await db.commit() + + i = cursor.lastrowid + kwargs["id"] = i + + return cls(kwargs) + + @classmethod + async def update(cls, **kwargs): + async with aiosqlite.connect(TEST_DB) as db: + query = 'UPDATE %s SET %s WHERE %s = ?' % (cls.__table_name__, ', '.join("'%s' = ?" % str(x) for x in cls.__fields__), cls.__priamry_key__) + + data = () + for f in cls.__fields__: + if f in cls.__json_fields__: + data = data + (json.dumps(kwargs.get(f)),) + else: + data = data + (kwargs.get(f),) + + data = data + (kwargs.get(cls.__priamry_key__),) + cursor = await db.execute(query, data) + await db.commit() + return cls(kwargs) + + +class ActorModel(DBModel): + __fields__ = ["name","type","config"] + __table_name__ = "actor" + __json_fields__ = ["config"] + + +class SensorModel(DBModel): + __fields__ = ["name","type", "config"] + __table_name__ = "sensor" + __json_fields__ = ["config"] \ No newline at end of file diff --git a/core/database/orm_framework.py b/core/database/orm_framework.py new file mode 100644 index 0000000..e69de29 diff --git a/core/eventbus.py b/core/eventbus.py new file mode 100644 index 0000000..5935bab --- /dev/null +++ b/core/eventbus.py @@ -0,0 +1,92 @@ +import logging + + +class EventBus(object): + class Node(object): + __slots__ = '_children', '_content' + + def __init__(self): + self._children = {} + self._content = None + + def register(self, key, value, doc=None): + + if doc is not None: + self.docs[key] = doc + self.logger.info("key %s", key) + node = self._root + for sym in key.split('/'): + node = node._children.setdefault(sym, self.Node()) + + if not isinstance(node._content, list): + node._content = [] + node._content.append(value) + + def get_callbacks(self, key): + try: + node = self._root + for sym in key.split('/'): + node = node._children[sym] + if node._content is None: + raise KeyError(key) + return node._content + except KeyError: + raise KeyError(key) + + def unregister(self, key, method=None): + + lst = [] + try: + parent, node = None, self._root + for k in key.split('/'): + parent, node = node, node._children[k] + lst.append((parent, k, node)) + # TODO + print(node._content) + if method is not None: + node._content = None + else: + node._content = None + except KeyError: + raise KeyError(key) + else: # cleanup + for parent, k, node in reversed(lst): + if node._children or node._content is not None: + break + del parent._children[k] + + def __init__(self): + self.logger = logging.getLogger(__name__) + self._root = self.Node() + self.docs = {} + + def fire(self, event: str, **kwargs) -> None: + self.logger.info("EMIT EVENT %s", event) + for methods in self.iter_match(event): + for f in methods: + print("METHOD: ", f) + f(**kwargs) + + def iter_match(self, topic): + + lst = topic.split('/') + normal = not topic.startswith('$') + + def rec(node, i=0): + if i == len(lst): + if node._content is not None: + yield node._content + else: + part = lst[i] + if part in node._children: + for content in rec(node._children[part], i + 1): + yield content + if '+' in node._children and (normal or i > 0): + for content in rec(node._children['+'], i + 1): + yield content + if '#' in node._children and (normal or i > 0): + content = node._children['#']._content + if content is not None: + yield content + + return rec(self._root) diff --git a/core/extension/__init__.py b/core/extension/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/extension/__pycache__/__init__.cpython-36.pyc b/core/extension/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..73cfcbefe30008aaa8d3dee1a9252dc709903fb9 GIT binary patch literal 148 zcmXr!<>g8_c{Q2=2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CUyk~r#i>Qb`nidD zrKve-MVTeV$r<|TnI##eN&1PI`SHbxxdl0?`pNl4srsoEC8>GEnfZD8@$s2?nI-Y@ XdIgoYIBatBQ%ZAE?LbBs12F>tSBWM} literal 0 HcmV?d00001 diff --git a/core/extension/dummy/__init__.py b/core/extension/dummy/__init__.py new file mode 100644 index 0000000..e13f96d --- /dev/null +++ b/core/extension/dummy/__init__.py @@ -0,0 +1,45 @@ +from core.database.model import ActorModel +from core.api.decorator import action, background_task +from core.api.property import Property +print("##################") + +from core.api.actor import Actor +import logging + + +class MyActor(Actor): + + + name = Property.Number(label="Test") + name1 = Property.Text(label="Test") + name2 = Property.Kettle(label="Test") + + @background_task("s1", interval=2) + async def bg_job(self): + print("WOOH BG") + + @action(key="name", parameters={}) + def myAction(self): + print("HALLO") + + def state(self): + super().state() + + def off(self): + super().off() + + def on(self, power=100): + super().on(power) + + def __init__(self): + pass + + def __init__(self, core=None): + self.logger = logging.getLogger(__name__) + self.logger.info("WOOHOO MY ACTOR") + self.core = None + + +def setup(cbpi): + + cbpi.actor.register("MyActor", MyActor) \ No newline at end of file diff --git a/core/extension/dummy/__pycache__/__init__.cpython-36.pyc b/core/extension/dummy/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a078627a49790d854e45168f68b921bdc7ed690 GIT binary patch literal 1898 zcmb7FOONA35NwN1In7_-L{;0#W_RF#qi$DswdFZbJvPW+ zz$kx$i4kU`Br`(8K-o;q%nGf{4sE@*QYUjm*C4#X>~(djAx^4UJ>8yL~Vwe9GTo;v_T}2~BQY*vw$&3nO$uc5Ar-vRBJZ z?lX(o%z0rlmo+wIZG;CrU|vF46ZU*|p!ZtO$;@B@Yi+!+t>rfBfZSns^{U7En`YQ$ zhwKO<@3DLA4oF7WdroW;_JN1{s&T&3o-6waFC_+&MpK?DvwV1Cg4-B+l1nariPG4> zXyCy&D*uF01~5rTSd|DcYL2fO-%lowkH0)cdkX>IgJ73Do&8Qk2hRU}I{L2Uq8w#W zzJzU&$TEI9nkVwBYkI=}!grl6tCue7qfgxIO0$y!+ z={TyX3rpo?NF+G<23o0I>26)wDqq1w8ZA7H_9R)83u6u3G6EzTWANB1mr!%?l9A*! zE-=}oG)|+kr1T}exCb`wqcII_T(!2)`s4qFEAE0FWfim84pX4%J+wDr`Su>#!4?fZ zx?!M*wHqMd8;1@QnW_T4epxRVY6WQ)If%#xluhv~7l8j7FoM1dV;iQw1I};7sPlzjHXe^hrl6E1=hCeYfZFBhKz$4 z0a(QeQlxr2?V|n@(M0RpBy8`L+DCzj6IkKeM-9E_;4ah3`>e|0=Xi_g8zeBgK$>U5 Iu(}Wa0YOlY@Bjb+ literal 0 HcmV?d00001 diff --git a/core/helper/__init__.py b/core/helper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/helper/__pycache__/__init__.cpython-36.pyc b/core/helper/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..569e48e3db2c8ef230b6cdbbcf6010719b577118 GIT binary patch literal 145 zcmXr!<>k6^?M5^M5IhDEFu(|8H~?`m3y?@*2xib^^jpbL1QJFNzwGowi&Kk=^>Y*R zN>g*viZV-zlQZ7o2pgX zW+DuBp1vSxLi(igt?h8dv40Qsb>7EK0vZZbPzZ%eQ0+)XR67pWw%dAP^v8>`73c7Y zNQNZaB<>xl%B&b}|pBzk$6*p})8C*G^lP*RolX+s?eJruqAspDri4oVBHs z%s^hXR_9Y~7TV@>*EVWdFGh>wFi`qXE{#v9nA;=;LSTx0kz!2J7YPn=15Y;pWpZ?p zHYSp(`9{{dEJIqBb*q+!@mg7aSW0v5u}pT?@FjJfzx7BBNF1*w!OpIbFdx2|kZw&p zu7^3Uz|)$)(u#;y`fsAjIA({Z3O%07byYI7Yn1ZegCXU(vJ1OI?(SVcdz)}Ju(vpa yTM0Lqv5}HqPNdT#noFB*S>1}d7rLZN^|?dKQ-$QwIS*Srfn#nHToc1+xbX*5@xhS* literal 0 HcmV?d00001 diff --git a/core/helper/jsondump.py b/core/helper/jsondump.py new file mode 100644 index 0000000..762524d --- /dev/null +++ b/core/helper/jsondump.py @@ -0,0 +1,26 @@ +import json +from json import JSONEncoder + +from core.database.model import DBModel, ActorModel + + +class ComplexEncoder(JSONEncoder): + def default(self, obj): + + try: + if isinstance(obj, DBModel): + return obj.__dict__ + + elif isinstance(obj, ActorModel): + return None + + elif hasattr(obj, "callback"): + return obj() + else: + return None + except TypeError as e: + pass + return None + +def json_dumps(obj): + return json.dumps(obj, cls=ComplexEncoder) \ No newline at end of file diff --git a/core/http_endpoints/__init__.py b/core/http_endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/http_endpoints/__pycache__/__init__.cpython-36.pyc b/core/http_endpoints/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05452e47ef679d30124433d9075e24602ccaca83 GIT binary patch literal 143 zcmXr!<>lHbcPp9!2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CUpD%o#i>Qb`nidD zrKve-MVTeV$r<|TnI##eN&1PI`SHbxxdl0?`pNl4srnfuB?bEN@tJvhUfl@_`w3O;z=)zOSn0w{Exd&prFD=M(aoeDipqKY*d1 zf)GT|f~5Fm1ua?1DC%C}m450w-7kVNOhcy!MO4OVOvxWagd#d2B06U2mY}al68{b7 zkx@de_d!nJb9E*S*VDNa%R(xCpz4xmO#?GMCEqWlHoOEouV&!tEOcFQu`C-s#dFS{ z0F(zX^h*$uq*RcU2`bnLNj>QcPxvA@WoI3B^!cR(1jpoSgOL&Cj7vhWtZpvRPwL-YiKz%gvJ z>b)6{_r~Mf&)?pD_-KFpG6`)|)Uz4jvs*yLGti~7G3QlQO3rPFv*7Xb>Y%p%bkgJr zv%Z$a0a&$?e-YJ#>%Tl6zSdIdVVPA+m{hp|R)@3P%$Jj4me*WoWmCu@?itPj4VRT@ z>bx?#HM1rkG=JjNd6gT^JBTaW8x2LHI-aU__7h1k>Cnk&J$lD<+kg} zKuO)ym6kTb63U7~VHqS$b#YC!t{z8DD|XPo?VzuBAaNRxBy80`gZJ%%RWSURi=%Tm z*cRt-eg(roeiu~GT_~X=X4nFA?;k=Ptf2*hIcVOncbq|QQoia1iIq(gL zF%0!1h!#&>$rg|2@Tgs!zK#Ne-UtY`T!A@_0TOnRZh!FDd!}pn_#J*P@JPz zx6pK%{66HF5FB73KW(+L4!!(;?CV9NBvxCn&~`X4Yy9Ithi!BIewh_*zo|=jJu;}S zq4*ia9TZ<_cN!Lx!tRJ+XcRGvgTCJnoj2*I2z)kz&clLg3%3W>qMqo%nHTHHUdEOj vVEYLPYG!KXB1rpgVlInDssYwKc7fx@-LWYo8~@${yH7DL?BN*Om*Myq0&-)> literal 0 HcmV?d00001 diff --git a/core/http_endpoints/__pycache__/http_login.cpython-36.pyc b/core/http_endpoints/__pycache__/http_login.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec92fbac6ca957335ccf586768ab3ae0a344b2e4 GIT binary patch literal 1296 zcmZux&5qne5bhuUWp-xREa4{{5aMPeG6ya>AQXhiZp3IdBFn`bTAu0NT|48Sbhoq0 z$dRHrM|cBXfal;X`ig|aD{!K!ogFq39(B2@y8OBNtIzY*Y&OxKx}X2zg#1ZvTo987 zu*?@=B$0GWDwKHIX2XPlB_BDoCS5E%?C3uO3&q|x6{Pg3gmm0H6s$UA$v!QA!r z4zeN{l_X=5O7@0iTm@w~Vh%KmWGExZ#xe%v#D&Y|qNq3QEfU@XSl_`i_rdhEBqc39 zSWikmK#ThvGzz%@a|kQr-&jvXC<#KZT=4kx$=NPiZ1EM2AAf(gi!o?A>ykD%=Bm*$ zo13mxT3p8|b3td6&L(3X{WNksZ(A2>cvNY3E01t!;&>W!n_B zHDl=Cc&~lo5+RDZutG%078*kDz;8ES;)(BFZ@r;JQs6OIId=NPF6`|2m-lh_>qfpvLyb5tI&buavKq(ck{^|6o7yNBse02$ zl`{PvZp2zW>y)wn{G&O7yqIrt`Camq=~osc+tZ#8Y|l(o#xf`q z83HpAGGn9i)<9l^)PbdVwL3WZcDX$LY|+=|*<=atb3 z7NgW|P(6k45SBsW37yk~enO{oLOa_rw>q*Y66xP0$w}K?pYyqH1KfMSm*9 zvo7C`JNkWq8(W^?zk None: + + self.mqtt_methods[topic] = func + + async def on_message(self): + while True: + + message = await self.client.deliver_message() + matched = False + packet = message.publish_packet + print(message.topic) + #print(message.topic.split('/')) + data = packet.payload.data.decode("utf-8") + + for callback in self.matcher.iter_match(message.topic): + print("MATCH") + callback(data) + matched = True + + if matched == False: + print("NO HANDLER", data) + + async def start_broker(self, app): + + await self.broker.start() + # + await self.client.connect('mqtt://username:manuel@localhost:1885') + # await self.client.connect('mqtt://broker.hivemq.com:1883') + + for k, v in self.mqtt_methods.items(): + print("############MQTT Subscribe:", k, v) + await self.client.subscribe([(k, QOS_1)]) + self.matcher[k] = v + await get_scheduler_from_app(app).spawn(self.on_message()) diff --git a/core/mqtt/mqtt_matcher.py b/core/mqtt/mqtt_matcher.py new file mode 100644 index 0000000..51bb22f --- /dev/null +++ b/core/mqtt/mqtt_matcher.py @@ -0,0 +1,167 @@ +class MQTTMatcher(object): + + + class Node(object): + __slots__ = '_children', '_content' + + def __init__(self): + self._children = {} + self._content = None + + + def register(self, key, value): + node = self._root + for sym in key.split('/'): + node = node._children.setdefault(sym, self.Node()) + + if not isinstance(node._content, list): + node._content = [] + node._content.append(value) + + def get_callbacks(self, key): + try: + node = self._root + for sym in key.split('/'): + node = node._children[sym] + if node._content is None: + raise KeyError(key) + return node._content + except KeyError: + raise KeyError(key) + + def unregister(self, key, method=None): + + lst = [] + try: + parent, node = None, self._root + for k in key.split('/'): + parent, node = node, node._children[k] + lst.append((parent, k, node)) + # TODO + print(node._content) + if method is not None: + node._content = None + else: + node._content = None + except KeyError: + raise KeyError(key) + else: # cleanup + for parent, k, node in reversed(lst): + if node._children or node._content is not None: + break + del parent._children[k] + + def __init__(self): + self._root = self.Node() + + def __setitem__(self, key, value): + print("...",key, value) + node = self._root + for sym in key.split('/'): + print(sym) + node = node._children.setdefault(sym, self.Node()) + print(node) + if not isinstance(node._content, list): + #print("new array") + node._content = [] + node._content.append(value) + #node._content = value + + def __getitem__(self, key): + try: + node = self._root + for sym in key.split('/'): + node = node._children[sym] + if node._content is None: + raise KeyError(key) + return node._content + except KeyError: + raise KeyError(key) + ''' + + def __delitem__(self, thekey): + print("DELETE") + + if isinstance(thekey, tuple): + key = thekey[1] + methods = thekey[0] + print(methods.__module__, methods.__name__) + else: + methods = None + key = thekey + + lst = [] + try: + parent, node = None, self._root + for k in key.split('/'): + parent, node = node, node._children[k] + lst.append((parent, k, node)) + # TODO + print(node._content) + if methods is not None: + + node._content = None + else: + node._content = None + except KeyError: + raise KeyError(key) + else: # cleanup + for parent, k, node in reversed(lst): + if node._children or node._content is not None: + break + del parent._children[k] + ''' + def iter_match(self, topic): + + lst = topic.split('/') + normal = not topic.startswith('$') + def rec(node, i=0): + if i == len(lst): + if node._content is not None: + yield node._content + else: + part = lst[i] + if part in node._children: + for content in rec(node._children[part], i + 1): + yield content + if '+' in node._children and (normal or i > 0): + for content in rec(node._children['+'], i + 1): + yield content + if '#' in node._children and (normal or i > 0): + content = node._children['#']._content + if content is not None: + yield content + return rec(self._root) + + +if __name__ == "__main__": + m = MQTTMatcher() + + def test_name(): + print("actor/1/on") + + def test_name2(): + print("actor/2/on") + + def test_name3(): + print("actor/#") + + def test_name4(): + print("actor/+/on") + + + + m.register("actor/1/on", test_name) + m.register("actor/1/on", test_name) + m.register("actor/1/on", test_name) + + print(m.get_callbacks("actor/1/on")) + + + m.unregister("actor/1/on") + + for methods in m.iter_match("actor/1/on"): + + for f in methods: + f() + diff --git a/core/plugin.py b/core/plugin.py new file mode 100644 index 0000000..cfdab18 --- /dev/null +++ b/core/plugin.py @@ -0,0 +1,46 @@ +from pprint import pprint + +from core.api.property import Property + + +class PluginAPI(): + + + def _parse_props(self, cls): + + name = cls.__name__ + + result = {"name": name, "class": cls, "properties": [], "actions": []} + + + tmpObj = cls() + members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")] + for m in members: + if isinstance(tmpObj.__getattribute__(m), Property.Number): + t = tmpObj.__getattribute__(m) + result["properties"].append( + {"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description, "default_value": t.default_value}) + elif isinstance(tmpObj.__getattribute__(m), Property.Text): + t = tmpObj.__getattribute__(m) + result["properties"].append( + {"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "default_value": t.default_value, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Select): + t = tmpObj.__getattribute__(m) + result["properties"].append( + {"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Actor): + t = tmpObj.__getattribute__(m) + result["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Sensor): + t = tmpObj.__getattribute__(m) + result["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Kettle): + t = tmpObj.__getattribute__(m) + result["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description}) + + for method_name, method in cls.__dict__.items(): + if hasattr(method, "action"): + key = method.__getattribute__("key") + parameters = method.__getattribute__("parameters") + result["actions"].append({"method": method_name, "label": key, "parameters": parameters}) + pprint(result, width=200) \ No newline at end of file diff --git a/core/sql/create_table_user.sql b/core/sql/create_table_user.sql new file mode 100644 index 0000000..8d65c4d --- /dev/null +++ b/core/sql/create_table_user.sql @@ -0,0 +1,104 @@ +CREATE TABLE IF NOT EXISTS dashboard +( + id INTEGER PRIMARY KEY NOT NULL, + name VARCHAR(80) + +); + +CREATE TABLE IF NOT EXISTS dashboard_content +( + id INTEGER PRIMARY KEY NOT NULL, + dbid INTEGER(80), + element_id INTEGER, + type VARCHAR(80), + x INTEGER(5), + y INTEGER(5), + config VARCHAR(3000) +); + +CREATE TABLE IF NOT EXISTS actor +( + id INTEGER PRIMARY KEY NOT NULL, + name VARCHAR(80), + type VARCHAR(80), + config VARCHAR(3000) + +); + +CREATE TABLE IF NOT EXISTS sensor +( + id INTEGER PRIMARY KEY NOT NULL, + name VARCHAR(80), + type VARCHAR(80), + config VARCHAR(3000) + +); + +CREATE TABLE IF NOT EXISTS kettle +( + id INTEGER PRIMARY KEY NOT NULL, + name VARCHAR(80), + sensor VARCHAR(80), + heater VARCHAR(10), + automatic VARCHAR(255), + logic VARCHAR(50), + config VARCHAR(1000), + agitator VARCHAR(10), + target_temp INTEGER, + height INTEGER, + diameter INTEGER +); + +CREATE TABLE IF NOT EXISTS config +( + name VARCHAR(50) PRIMARY KEY NOT NULL, + value VARCHAR(255), + type VARCHAR(50), + description VARCHAR(255), + options VARCHAR(255) +); + +CREATE TABLE IF NOT EXISTS sensor +( + id INTEGER PRIMARY KEY NOT NULL, + type VARCHAR(100), + name VARCHAR(80), + config VARCHAR(3000) +); + +CREATE TABLE IF NOT EXISTS step +( + id INTEGER PRIMARY KEY NOT NULL, + "order" INTEGER, + name VARCHAR(80), + type VARCHAR(100), + stepstate VARCHAR(255), + state VARCHAR(1), + start INTEGER, + end INTEGER, + config VARCHAR(255), + kettleid INTEGER +); + +CREATE TABLE IF NOT EXISTS tank +( + id INTEGER PRIMARY KEY NOT NULL, + name VARCHAR(80), + brewname VARCHAR(80), + sensor VARCHAR(80), + sensor2 VARCHAR(80), + sensor3 VARCHAR(80), + heater VARCHAR(10), + logic VARCHAR(50), + config VARCHAR(1000), + cooler VARCHAR(10), + target_temp INTEGER +); + +CREATE TABLE IF NOT EXISTS translation +( + language_code VARCHAR(3) NOT NULL, + key VARCHAR(80) NOT NULL, + text VARCHAR(100) NOT NULL, + PRIMARY KEY (language_code, key) +); \ No newline at end of file diff --git a/core/test.db b/core/test.db new file mode 100644 index 0000000000000000000000000000000000000000..c6756e40779a0be9a8ed8359db52a48779f52b52 GIT binary patch literal 49152 zcmeI((NEh(9Kdm#5&{OA(h0c{nrf97qE#&+LfhM#w$X|fU`^6(s1K1zt|21WEIC#X z;(?4mVSh}e{Q>(E`mldtf5gr{;>01TgtqP>`Wo3ue&_h^_qjWZ3!(hF*p$L~=eLhs z>Ew)ihG`nl9LF$>wAvTc-rMHXlj+_I^=J+}ANMqEJW1pi7iNw5?tV+iw(E6Tu59|=z|;8` zr9!?^a4Pxd#ey?XV69n>+FGvHIB^@ITJ!6|`7vL5@hV?h%VnIM-HNmGrdWI&o^~kC zqQY<1hfAe6l~Hka{YLo@rLFCJY0vq-u;;ABYJBXdD`%|C=KPGkwQ3qouP#nIzqHgZ zBvtoB`r+&9K(njaffozi=W|JWdD*;bXad(elxnx)Ne2;~ZL{ud?Nkci6-v%vo8q~8 z?onStC94JY+v5G`l8*2?emlxPdWVj0j4R09EI1IZ6#Xk@dv&+`Mza>3zS#@ceD7Ve z5ycgJzr=5ix{!3+4I!&i93A%{tW0-#RwFKkh#e`8gMBWB7({M^_{eY9Mf*{&7Hv4% zPo5q3y@S!CPuA^FAW?!Fo10PDU_9H8wq?9V;YB^JuR3JbzvQ8ivL*Th#L8Sgn@QT~ zwAp7@PisrlQN zA!FU`9PImUyRPoEo)n(E5lF;vZxr9gxxU{Y$ZL_OXo(|LakXEj^NEeO=!2 zcXlJ9M^4mpx!?|DW#pZt{qUiA`E@+;D5L4oiQXo`;eli+@0BS%U6;aY_1#w=@5Cz9 zv42zBr`Sf4sMb9&leTS}-Bj2*x2A?%c$kW{Ee!q7O^b?k5sP+Fsgry%W)Tl`j@|&o5M+KaYsL91&Yru`i|) zhP|>>5goa)eU=YCa5%rXZzhao9gJdw>;KQ47uQDs0R#|0009ILKmY**5I_Kd|5PAY z|F76fL0EH9M{JLTO{wo)ip&M$)XzxvWY8v+O*fB*srAb None: + self.core = core + self._callbacks = defaultdict(set) + self._clients = weakref.WeakSet() + self.logger = logging.getLogger(__name__) + self.core.app.add_routes([web.get('/ws', self.websocket_handler)]) + + def add_callback(self, func: Callable, event: str) -> None: + self._callbacks[event].add(func) + + async def emit(self, event: str, *args, **kwargs) -> None: + for func in self._event_funcs(event): + await func(*args, **kwargs) + + def _event_funcs(self, event: str) -> Iterable[Callable]: + for func in self._callbacks[event]: + yield func + + async def websocket_handler(self, request): + ws = web.WebSocketResponse() + await ws.prepare(request) + + self._clients.add(ws) + + c = len(self._clients) - 1 + + self.logger.info(ws) + self.logger.info(c) + try: + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == 'close': + + await ws.close() + self.logger.info("WS Close") + else: + msg_obj = msg.json() + + + + self.core.bus.fire(msg_obj["topic"], id=1, power=22) + #await self.fire(msg_obj["key"], ws, msg) + + #await ws.send_str(msg.data) + elif msg.type == aiohttp.WSMsgType.ERROR: + self.logger.error('ws connection closed with exception %s' % ws.exception()) + + finally: + self._clients.discard(ws) + + self.logger.info("Web Socket Close") + + return ws + + +async def websocket_handler(request): + ws = web.WebSocketResponse() + await ws.prepare(request) + + _ws.append(ws) + + c = len(_ws) - 1 + + async for msg in ws: + + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == 'close': + await ws.close() + else: + + await ws.send_str(msg.data) + elif msg.type == aiohttp.WSMsgType.ERROR: + print('ws connection closed with exception %s' % + ws.exception()) + + del _ws[c] + print('websocket connection closed') + + return ws \ No newline at end of file diff --git a/craftbeerpi.db b/craftbeerpi.db new file mode 100644 index 0000000000000000000000000000000000000000..eb7b074f63b9f313a5bde99cecc79ad270c39bc3 GIT binary patch literal 49152 zcmeI)Z%^As9KdnAr8qcbWe<>xrm0qWl4#Z16ruK6n|9HL#@LpzO=u4ylU##Eu&Hyj z@Q{>8d$gBRX)k53W6yW?HFoSIlcGs`V0|OmoPU?t_xs!*I3f7y$9-Q4_jMSZdD7i6 zHVo4=UbwDd7;EZSSI6WPU$0Cq)K_z=yr{Tld|BJ5tyhey^})FN`zL?Y{;vJHzEQnb z{mV8ge_9_ZH;X<>903FnKmY**iUQYrw&iSZo8u$t9S?I!Ere?IX9Id*VY^-ML{mcB`w--nMD@L0?>s-VD_bBwg=9 zhRJnzs@dJ<)W!Pv<(lPeZkjg(P2dHmQXO_a={TaZ_51GL!D0LBcE_D=Q$E+gJIf?g zvRdFc67S~Mj6^UBqcs2Y6FUB6QN_+|#fk8w$nMmfJbM@p{9gL@-AT9?2Cw}=8dvaH zO*ou)Bk4s0A-htXolhX_#(1-$5o-zJNQ(3LSj!>Ck!27cgi&8a4<=91hV%X8)p_O} zj~@MI-3|qkCirA`H?5nFH?wFY^G_5(+T;4J1+(myr$Wl1$OeerxPGx}Ia^!i__xGG ze^Q^VoQ;ls)XC+jy6RsB+FNgUF)zCuNZQ+dG3rJBc|5=8h=fVSC|6@QzOYuE=Ua=W zm2P*pslQg#`Vt?;_^Uff-Z#A@Zw;f*tGT>&Y?)D!!zoOZwCQPl(R7Fx2DMe0ni5$z zEwBY<RVJGMIdJaw{uONsa~e}{o`x}sHcWvD9+S_yIGwc2=m1+Cu5*KS+1^T zB6EACAx+D