Compare commits
467 Commits
20230510-f
...
mp-2024_10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acbe4505b9 | ||
|
|
b2193afa46 | ||
|
|
28b130ecd4 | ||
|
|
2ac1182879 | ||
|
|
f2d18fceee | ||
|
|
43c23d754c | ||
|
|
8eee81c682 | ||
|
|
34d395bb0b | ||
|
|
277af02f68 | ||
|
|
68ef24ea9b | ||
|
|
a3d5b33105 | ||
|
|
a7adf15bf6 | ||
|
|
a435b995a8 | ||
|
|
9d71ff27a7 | ||
|
|
090e178ed1 | ||
|
|
a78e354c28 | ||
|
|
9c87c3e5f3 | ||
|
|
01133cc35b | ||
|
|
4dc6031d03 | ||
|
|
c3fd458769 | ||
|
|
433720525d | ||
|
|
375ab592ff | ||
|
|
d2694df67c | ||
|
|
2270163837 | ||
|
|
9282ac3bb2 | ||
|
|
6f858e3909 | ||
|
|
cf26a01bb8 | ||
|
|
2e3705946e | ||
|
|
42f76f9d09 | ||
|
|
bc7a549513 | ||
|
|
f002587aee | ||
|
|
a520b37089 | ||
|
|
4f628a16c6 | ||
|
|
630dc2cecb | ||
|
|
51a585740d | ||
|
|
dab4980a7a | ||
|
|
e847130f0c | ||
|
|
4c88c15874 | ||
|
|
132ec3ce95 | ||
|
|
9178a6fca5 | ||
|
|
eb68e66746 | ||
|
|
b72d474a7f | ||
|
|
2b68bfd3af | ||
|
|
e4a0e8557a | ||
|
|
57bbefdf38 | ||
|
|
7707cb0a82 | ||
|
|
dfad168875 | ||
|
|
7fde61f849 | ||
|
|
8904d33789 | ||
|
|
d28e20b179 | ||
|
|
c5915b5583 | ||
|
|
2626c4365c | ||
|
|
9c35e7a006 | ||
|
|
061438b7c8 | ||
|
|
88035efdf9 | ||
|
|
3546c93d23 | ||
|
|
e232b4adbf | ||
|
|
89019f1e60 | ||
|
|
efc91241d9 | ||
|
|
c90c33ec11 | ||
|
|
aca24183e4 | ||
|
|
1626526714 | ||
|
|
7ad64cd654 | ||
|
|
cc6ed1198b | ||
|
|
fae5b55e82 | ||
|
|
a6af10a32d | ||
|
|
97138bcbe0 | ||
|
|
2b8cabd391 | ||
|
|
85d0992ce9 | ||
|
|
b3199681de | ||
|
|
b78fc0999b | ||
|
|
3cba4a1f7c | ||
|
|
d7705590fe | ||
|
|
adcb037976 | ||
|
|
072ed88102 | ||
|
|
cc1dcc4d7f | ||
|
|
25efeeb244 | ||
|
|
0926ba2381 | ||
|
|
1d08945ae5 | ||
|
|
d2ac801223 | ||
|
|
8f6291ef02 | ||
|
|
21d47b8b7f | ||
|
|
6f5da8ee6c | ||
|
|
9c2001285b | ||
|
|
8199f7c3b0 | ||
|
|
03f9178dd2 | ||
|
|
0566483575 | ||
|
|
3a9bb3d5ec | ||
|
|
2d7459394e | ||
|
|
bb77c6acd1 | ||
|
|
10564ec78f | ||
|
|
ee73bb0f69 | ||
|
|
8aa4143d8a | ||
|
|
c22edcbbec | ||
|
|
8dd9e69bdf | ||
|
|
2014304c73 | ||
|
|
c2d7564e0c | ||
|
|
d70c673b8a | ||
|
|
23489dd5bf | ||
|
|
5767c1307d | ||
|
|
b93ead5e5f | ||
|
|
6fc7f5fc7a | ||
|
|
60c86c7598 | ||
|
|
07f99b7050 | ||
|
|
6676024cb0 | ||
|
|
cf9118e41d | ||
|
|
49d037c040 | ||
|
|
b0b6efb1c3 | ||
|
|
be053b035f | ||
|
|
a839d97140 | ||
|
|
bdcbaa2b46 | ||
|
|
a624331166 | ||
|
|
7e4977f472 | ||
|
|
9adb95d532 | ||
|
|
f729766e6b | ||
|
|
4548b3c225 | ||
|
|
caa7138738 | ||
|
|
91752156f2 | ||
|
|
a1a64fec42 | ||
|
|
9e80636acb | ||
|
|
741dd4fe12 | ||
|
|
5ca1fd4275 | ||
|
|
7590aa3717 | ||
|
|
08399ecf87 | ||
|
|
0e83988904 | ||
|
|
3bec999ae0 | ||
|
|
5b3c813981 | ||
|
|
b490646799 | ||
|
|
f912c537d4 | ||
|
|
3af514d946 | ||
|
|
9a2a1764d9 | ||
|
|
4687a8726b | ||
|
|
7a5900be25 | ||
|
|
2d09e22ec6 | ||
|
|
cdcb4e2b3e | ||
|
|
6ff68b848c | ||
|
|
0f98ed87a4 | ||
|
|
ee94d8a583 | ||
|
|
4ba0e01c9f | ||
|
|
c908eb4840 | ||
|
|
892dc65898 | ||
|
|
0c819bcd19 | ||
|
|
caf04e88f3 | ||
|
|
79f4018341 | ||
|
|
f1fe99673b | ||
|
|
79afc70b92 | ||
|
|
ec033cfd10 | ||
|
|
0107330c32 | ||
|
|
cb43378a2f | ||
|
|
0fafb36100 | ||
|
|
88aea30da1 | ||
|
|
4a20933397 | ||
|
|
a10cd8293b | ||
|
|
c055ee6cc2 | ||
|
|
7fbe9744ea | ||
|
|
0fabc6d613 | ||
|
|
39933a957b | ||
|
|
6308207548 | ||
|
|
2de89ecc96 | ||
|
|
85d7ccf0f2 | ||
|
|
d14363b8f0 | ||
|
|
a298e6845a | ||
|
|
d8985183f7 | ||
|
|
ad34bc8ec3 | ||
|
|
0bc37343a5 | ||
|
|
73f749b5bb | ||
|
|
28882010a9 | ||
|
|
b0afa98387 | ||
|
|
6ba1a18de1 | ||
|
|
c79037a1e1 | ||
|
|
743b33664f | ||
|
|
fd43a89bcd | ||
|
|
9bd376464a | ||
|
|
e70c294d9b | ||
|
|
a456211438 | ||
|
|
1c4d94c5ce | ||
|
|
50546799dc | ||
|
|
9bc837249e | ||
|
|
2215d68544 | ||
|
|
fc6130f4cc | ||
|
|
cf1983d264 | ||
|
|
ed21f4bbfc | ||
|
|
d99787b787 | ||
|
|
5f2da242c5 | ||
|
|
9b724d5a5f | ||
|
|
2fa3e9d4ab | ||
|
|
5e4ca45443 | ||
|
|
090917ea09 | ||
|
|
7e3523ec42 | ||
|
|
12a2cc1b8e | ||
|
|
6b0972d76e | ||
|
|
984cccc25b | ||
|
|
dbad1ba8a1 | ||
|
|
b70e0e0bc2 | ||
|
|
595a140428 | ||
|
|
b94105bf78 | ||
|
|
eec544d1b8 | ||
|
|
cb6e21715a | ||
|
|
026d4a57fb | ||
|
|
7745accfae | ||
|
|
cea3137b5a | ||
|
|
c73fede935 | ||
|
|
b56947dcba | ||
|
|
a23997db39 | ||
|
|
51ba17d43f | ||
|
|
575b0285fe | ||
|
|
277a27516c | ||
|
|
817ff958b9 | ||
|
|
ea2cd6e58e | ||
|
|
1f2f8b574e | ||
|
|
cd6413e7a6 | ||
|
|
425c26cfbb | ||
|
|
f2ab0d8b9f | ||
|
|
e0a6ddd89f | ||
|
|
c02f371350 | ||
|
|
c2a6d33ff2 | ||
|
|
8aeb488e2e | ||
|
|
45cae14f6a | ||
|
|
892d9f5c5a | ||
|
|
65e60c2dec | ||
|
|
6aac577365 | ||
|
|
85a93065a4 | ||
|
|
319cdbce18 | ||
|
|
c800e99dc8 | ||
|
|
2da873bbb9 | ||
|
|
6abac9b5a1 | ||
|
|
ed1f96fdbc | ||
|
|
37a290ce1f | ||
|
|
a3bf403ac0 | ||
|
|
dde9106a5d | ||
|
|
334d0e8096 | ||
|
|
abada7b89b | ||
|
|
69893640a3 | ||
|
|
9f7f5ab0db | ||
|
|
6828438780 | ||
|
|
05fb3d3b0a | ||
|
|
66c583f866 | ||
|
|
2363535fe0 | ||
|
|
9d0037b83d | ||
|
|
f8f4380038 | ||
|
|
ead34f0309 | ||
|
|
1d51ef0259 | ||
|
|
b888524cc3 | ||
|
|
5ec9827f92 | ||
|
|
7ce34b0500 | ||
|
|
516ac4e34e | ||
|
|
36e9909060 | ||
|
|
403392a72e | ||
|
|
2c584bbff9 | ||
|
|
b6e4a5265a | ||
|
|
b473d62cdc | ||
|
|
3e5bff90d1 | ||
|
|
d5b1dbd5ee | ||
|
|
29eb910881 | ||
|
|
bcc7629b1e | ||
|
|
f400104bbc | ||
|
|
a3d0fad984 | ||
|
|
075fbc1cb5 | ||
|
|
c9d82cc88e | ||
|
|
2342dfbe4a | ||
|
|
dbc8fdf35d | ||
|
|
89dd230b8f | ||
|
|
243754c15d | ||
|
|
d17274c6d6 | ||
|
|
9b2b9dccea | ||
|
|
83106327fa | ||
|
|
87114cecea | ||
|
|
f3c68a8bba | ||
|
|
f083fb1c00 | ||
|
|
88d049d68a | ||
|
|
7ee7edffec | ||
|
|
e486a7e69d | ||
|
|
2443fbca9f | ||
|
|
716c1c58df | ||
|
|
7ea260031e | ||
|
|
02c256ffa2 | ||
|
|
02f02b1ad1 | ||
|
|
f4902d5717 | ||
|
|
8bb60fdba7 | ||
|
|
1050ee1c75 | ||
|
|
ec816bddcf | ||
|
|
9468911451 | ||
|
|
61ce363a8a | ||
|
|
563e5f0eff | ||
|
|
ec5aeb9a05 | ||
|
|
9a4eb3c608 | ||
|
|
dd133c7368 | ||
|
|
a7267c061a | ||
|
|
a94ebeca29 | ||
|
|
1b1d2f6c9e | ||
|
|
83cdc8abe3 | ||
|
|
2653b16939 | ||
|
|
ee19014644 | ||
|
|
a479538743 | ||
|
|
2ac4887f01 | ||
|
|
8a7a4c7a64 | ||
|
|
c62165cd92 | ||
|
|
5305aa7fe3 | ||
|
|
e29a32f24b | ||
|
|
50bdefcb4a | ||
|
|
02d12b4209 | ||
|
|
6f9e20095a | ||
|
|
e0476924c1 | ||
|
|
2787bb9b79 | ||
|
|
d92ae455db | ||
|
|
f9a5119d1f | ||
|
|
e162d9564b | ||
|
|
6889d5d851 | ||
|
|
87d22b1e16 | ||
|
|
30522df662 | ||
|
|
ed4fc1852a | ||
|
|
d6494d07d5 | ||
|
|
2c8e57ecff | ||
|
|
d3a6256c8c | ||
|
|
656c9cf66f | ||
|
|
db19019202 | ||
|
|
5712b041fe | ||
|
|
5925bc58b1 | ||
|
|
2e29790be7 | ||
|
|
0545a802de | ||
|
|
a3efa18a61 | ||
|
|
605d78a2b7 | ||
|
|
e7bfa36cab | ||
|
|
dce1b8698a | ||
|
|
e4c753cefd | ||
|
|
9e49e60aa8 | ||
|
|
4c44890d3c | ||
|
|
ef22bd65ea | ||
|
|
1ba263fb13 | ||
|
|
0cf3976fc7 | ||
|
|
eeffe225ec | ||
|
|
de1a975586 | ||
|
|
13d161d119 | ||
|
|
793d12693b | ||
|
|
5888bc9068 | ||
|
|
b6fe1775bd | ||
|
|
90d2467fde | ||
|
|
3c91a83177 | ||
|
|
c7ee9dc18c | ||
|
|
62abfd56e9 | ||
|
|
b818065b9b | ||
|
|
c9b88f2cea | ||
|
|
f0cfbfccc4 | ||
|
|
a3f866f69c | ||
|
|
16e08d623d | ||
|
|
077b367299 | ||
|
|
d1f7a6b730 | ||
|
|
f26c78a5e9 | ||
|
|
0fc18c1da1 | ||
|
|
ddded51f9e | ||
|
|
7b89df6153 | ||
|
|
161dee1667 | ||
|
|
e98afa80d9 | ||
|
|
38ae2d3d1d | ||
|
|
79c71563d5 | ||
|
|
fa12be880a | ||
|
|
dcdb512995 | ||
|
|
7fb4e8b577 | ||
|
|
7f1c66cbe6 | ||
|
|
c90e8c899a | ||
|
|
ab6480ebca | ||
|
|
8613fbdad7 | ||
|
|
b66f3d2ef4 | ||
|
|
f1753eeea7 | ||
|
|
bfed937950 | ||
|
|
4730943931 | ||
|
|
afc0994c38 | ||
|
|
831c94f898 | ||
|
|
0740378ad8 | ||
|
|
f56b25d06f | ||
|
|
eadfead77c | ||
|
|
17d4ce5125 | ||
|
|
253b3862da | ||
|
|
043541f936 | ||
|
|
45da38b64a | ||
|
|
c57472d86e | ||
|
|
1e27223dfa | ||
|
|
0f896c1729 | ||
|
|
66073737a4 | ||
|
|
bf89562d51 | ||
|
|
2adefc4b79 | ||
|
|
f03c078606 | ||
|
|
d6ae79cf81 | ||
|
|
0814cf4af1 | ||
|
|
74789b802f | ||
|
|
5f6581d126 | ||
|
|
8c60c3c8e4 | ||
|
|
cf005fa60c | ||
|
|
9b7d043682 | ||
|
|
161b979e84 | ||
|
|
11798a39d6 | ||
|
|
07abc76a7a | ||
|
|
e1639a9d13 | ||
|
|
71f5ce8c7e | ||
|
|
518a3a53f9 | ||
|
|
2b733a52ca | ||
|
|
3bfb39966f | ||
|
|
f9ae85b9ad | ||
|
|
5fdb33c192 | ||
|
|
51a13f286f | ||
|
|
290967a7c5 | ||
|
|
64938b9cb0 | ||
|
|
590eccf8d9 | ||
|
|
a4c0f2e6fd | ||
|
|
bcd3e3325c | ||
|
|
c1353c056a | ||
|
|
9602471a9b | ||
|
|
f5878f43ff | ||
|
|
edcac1f2b9 | ||
|
|
e25a391fde | ||
|
|
978d3f6f7a | ||
|
|
c5171714b2 | ||
|
|
96c2b9a649 | ||
|
|
487e506a01 | ||
|
|
ec745f5cc9 | ||
|
|
17889fd30b | ||
|
|
23c9e286b1 | ||
|
|
a2c79aa6db | ||
|
|
f716ebd338 | ||
|
|
9b0122e34c | ||
|
|
b9a54b8ffb | ||
|
|
b5916acf79 | ||
|
|
4701a71986 | ||
|
|
fc2c18b489 | ||
|
|
0cc498d830 | ||
|
|
28bc8efac8 | ||
|
|
aafecfa704 | ||
|
|
3378908c93 | ||
|
|
e4135a7bbd | ||
|
|
1efcd09f0c | ||
|
|
6269431467 | ||
|
|
792f167a71 | ||
|
|
897fdffcf9 | ||
|
|
53e1fbae56 | ||
|
|
16ce958964 | ||
|
|
db5d6cb980 | ||
|
|
06b5ab26c8 | ||
|
|
02797ff092 | ||
|
|
3eb0a9afa9 | ||
|
|
5852ad9a1e | ||
|
|
8ee0602f7a | ||
|
|
f8c325e747 | ||
|
|
893ae6867b | ||
|
|
3efb83ecfd | ||
|
|
f30c4895fa | ||
|
|
0fd58567fe | ||
|
|
7a4edb6854 | ||
|
|
c7f232dd98 | ||
|
|
4489314b47 | ||
|
|
08c3875a26 | ||
|
|
39987b31c7 | ||
|
|
43b23b2636 | ||
|
|
2d393630d8 | ||
|
|
5105c0c7f7 | ||
|
|
6f5a26b0cf | ||
|
|
d766a3635a | ||
|
|
b4175f4a89 | ||
|
|
f0917064af | ||
|
|
1751170940 | ||
|
|
3e85dc9bd5 | ||
|
|
54301fed44 | ||
|
|
efcab6f38d | ||
|
|
9f32f206b3 | ||
|
|
6a22fb9956 | ||
|
|
a29a314976 | ||
|
|
226922d3e4 | ||
|
|
84403d07f6 |
18
.gitignore
vendored
18
.gitignore
vendored
@@ -4,3 +4,21 @@ build/
|
||||
aqhome.db
|
||||
aqhome.log
|
||||
aqhomed.vg
|
||||
aqhome-mqttlog.vg
|
||||
aqhome-storage.vg
|
||||
aqhome-storage.pid
|
||||
aqhome-data.vg
|
||||
aqhome-data.pid
|
||||
aqhome-nodes.db
|
||||
aqhome-nodes.log
|
||||
aqhome-nodes.pid
|
||||
aqhome-nodes.vg
|
||||
aqhome-tool.vg
|
||||
aqhome-mqtt.pid
|
||||
aqhome-mqtt.devices
|
||||
|
||||
core.*
|
||||
aqhome.geany
|
||||
aqhome-nodes.db
|
||||
aqhome-nodes.db.*
|
||||
|
||||
|
||||
78
0BUILD
78
0BUILD
@@ -2,7 +2,7 @@
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<project name="aqhome" version="0.0.1" so_current="0" so_age="0" so_revision="0" write_config_h="TRUE">
|
||||
<project name="aqhome" version="0.0.4" so_current="0" so_age="0" so_revision="4" write_config_h="TRUE">
|
||||
<setVar name="package">$(project_name)</setVar>
|
||||
<setVar name="version">
|
||||
$(project_vmajor).$(project_vminor).$(project_vpatchlevel)
|
||||
@@ -44,23 +44,81 @@
|
||||
<setVar name="includedir">$(option_prefix)/include</setVar>
|
||||
<setVar name="datarootdir">$(option_prefix)/share</setVar>
|
||||
<setVar name="datadir">$(option_prefix)/share</setVar>
|
||||
<setVar name="rtdatadir">$(option_prefix)/var/lib</setVar>
|
||||
<setVar name="localedir">$(option_prefix)/share/locale</setVar>
|
||||
|
||||
<setVar name="pkglibdir">$(libdir)/$(package)</setVar>
|
||||
<setVar name="pkgincludedir">$(includedir)/aqhome/$(package)</setVar>
|
||||
<setVar name="pkgdatadir">$(datadir)/$(package)</setVar>
|
||||
|
||||
<option id="enable_testcode" type="string">
|
||||
<default>TRUE</default>
|
||||
<choices>TRUE FALSE</choices>
|
||||
</option>
|
||||
<ifVarMatches name="option_enable_testcode" value="TRUE" >
|
||||
<define name="AQHOME_ENABLE_TESTCODE" value="1" />
|
||||
</ifVarMatches>
|
||||
|
||||
|
||||
<option id="local_install" type="string">
|
||||
<default>FALSE</default>
|
||||
<choices>TRUE FALSE</choices>
|
||||
</option>
|
||||
<ifVarMatches name="option_local_install" value="TRUE" >
|
||||
<define name="ENABLE_LOCAL_INSTALL" value="1" />
|
||||
</ifVarMatches>
|
||||
|
||||
|
||||
<option id="debug" type="string">
|
||||
<default>TRUE</default>
|
||||
<choices>TRUE FALSE</choices>
|
||||
</option>
|
||||
<ifVarMatches name="option_debug" value="TRUE" >
|
||||
<setVar name="CFLAGS">-ggdb -Wall -O0</setVar>
|
||||
<setVar name="CXXFLAGS">-ggdb -Wall -O0</setVar>
|
||||
<setVar name="CFLAGS">
|
||||
-ggdb -Wall -Og -W
|
||||
-Wbad-function-cast -Wmissing-parameter-type
|
||||
-Wnested-externs -Wstringop-overflow=2
|
||||
-Wdeclaration-after-statement -Wpointer-sign
|
||||
-Wunused-parameter
|
||||
</setVar>
|
||||
<setVar name="CXXFLAGS">-ggdb -Wall -Og</setVar>
|
||||
</ifVarMatches>
|
||||
|
||||
|
||||
|
||||
<!-- paths -->
|
||||
<ifVarMatches name="GWBUILD_SYSTEM" value="windows" > <!-- long version of IF statement with THEN and ELSE -->
|
||||
<then>
|
||||
<define name="OS_WIN32" value="1" />
|
||||
<setVar name="aqhome_sys_is_windows">1</setVar>
|
||||
<setVar name="aqhome_cfg_searchdir">etc</setVar>
|
||||
<setVar name="aqhome_locale_searchdir">share/locale</setVar>
|
||||
<setVar name="aqhome_data_searchdir">share"</setVar>
|
||||
<setVar name="aqhome_rtdata_searchdir">var/lib</setVar>
|
||||
</then>
|
||||
<else>
|
||||
<define name="OS_POSIX" value="1" />
|
||||
<setVar name="aqhome_sys_is_windows">0</setVar>
|
||||
<ifVarMatches name="option_local_install" value="TRUE" >
|
||||
<then>
|
||||
<setVar name="aqhome_cfg_searchdir">etc</setVar>
|
||||
<setVar name="aqhome_locale_searchdir">share/locale</setVar>
|
||||
<setVar name="aqhome_data_searchdir">share</setVar>
|
||||
<setVar name="aqhome_rtdata_searchdir">var/lib</setVar>
|
||||
</then>
|
||||
<else>
|
||||
<setVar name="aqhome_cfg_searchdir">$(sysconfdir)</setVar>
|
||||
<setVar name="aqhome_locale_searchdir">$(datadir)/locale</setVar>
|
||||
<setVar name="aqhome_data_searchdir">$(datadir)</setVar>
|
||||
<setVar name="aqhome_rtdata_searchdir">$(rtdatadir)</setVar>
|
||||
</else>
|
||||
</ifVarMatches>
|
||||
</else>
|
||||
</ifVarMatches>
|
||||
<define name="AQHOME_SYS_IS_WINDOWS" value="$(aqhome_sys_is_windows)" />
|
||||
|
||||
|
||||
|
||||
<!-- use "-Owith_avr=TRUE" or "FALSE" to enable or disable assembling AVR code -->
|
||||
<option id="with_avr" type="string">
|
||||
<default>TRUE</default>
|
||||
@@ -88,9 +146,13 @@
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dep id="gwenhywfar" name="gwenhywfar" minversion="5.8.2.1" required="TRUE" >
|
||||
<dep id="gwenhywfar" name="gwenhywfar" minversion="5.11.2" required="TRUE" >
|
||||
<variables>plugindir gwengui-fox16</variables>
|
||||
</dep>
|
||||
<!-- <dep id="aqdatabase" name="aqdatabase" minversion="1.99.1" required="TRUE" >
|
||||
<variables>aqdatabase_typemakerdir</variables>
|
||||
</dep>
|
||||
-->
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -110,6 +172,9 @@
|
||||
<subdirs>
|
||||
aqhome
|
||||
apps
|
||||
devices
|
||||
etc
|
||||
scripts
|
||||
</subdirs>
|
||||
|
||||
<ifVarMatches name="option_with_avr" value="TRUE" >
|
||||
@@ -131,7 +196,10 @@
|
||||
|
||||
<output>
|
||||
</output>
|
||||
|
||||
<!-- see http://eleccelerator.com/fusecalc/fusecalc.php?chip=attiny84 -->
|
||||
<!-- disable divide by 8: -U lfuse:w:0xEA:m default (divide by 8): -U lfuse:w:0x6A:m -->
|
||||
<!-- changes to hfuse: enable EESAVE -->
|
||||
<!-- changes to efuse: enable SELFPRGEN -->
|
||||
<cmd tool="$(avrdude)" checkDates="FALSE" >
|
||||
-p t84 -c stk500 -P /dev/ttyACM0 -B16 -U hfuse:w:0xD7:m -U efuse:w:0xFE:m -U flash:w:avr/att84_temp1.hex
|
||||
</cmd>
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
<gwbuild>
|
||||
|
||||
<subdirs>
|
||||
aqhomed
|
||||
aqhome-tool
|
||||
aqhome-mqttlog
|
||||
aqhome-data
|
||||
aqhome-nodes
|
||||
aqhome-react
|
||||
</subdirs>
|
||||
|
||||
</gwbuild>
|
||||
|
||||
1
apps/aqhome-data/.gitignore
vendored
Normal file
1
apps/aqhome-data/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
test/
|
||||
96
apps/aqhome-data/0BUILD
Normal file
96
apps/aqhome-data/0BUILD
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-data" install="$(sbindir)" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
aqhome_data.h
|
||||
aqhome_data_p.h
|
||||
fini.h
|
||||
init.h
|
||||
loop.h
|
||||
c_connect.h
|
||||
c_updatedata.h
|
||||
c_getvalues.h
|
||||
c_getdevices.h
|
||||
c_getdatapoints.h
|
||||
c_getlastdatapoint.h
|
||||
c_setdata.h
|
||||
c_addvalue.h
|
||||
c_annvalue.h
|
||||
c_moddevice.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
aqhome_data.c
|
||||
fini.c
|
||||
init.c
|
||||
loop.c
|
||||
c_connect.c
|
||||
c_updatedata.c
|
||||
c_getvalues.c
|
||||
c_getdevices.c
|
||||
c_getdatapoints.c
|
||||
c_getlastdatapoint.c
|
||||
c_setdata.c
|
||||
c_addvalue.c
|
||||
c_annvalue.c
|
||||
c_moddevice.c
|
||||
main.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
152
apps/aqhome-data/aqhome_data.c
Normal file
152
apps/aqhome-data/aqhome_data.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQHOME_DATA *AqHomeData_new()
|
||||
{
|
||||
AQHOME_DATA *aqh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHOME_DATA, aqh);
|
||||
aqh->storageMutex=GWEN_Mutex_new();
|
||||
aqh->requestTree=GWEN_MsgRequest_new();
|
||||
|
||||
return aqh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeData_free(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_Mutex_free(aqh->storageMutex);
|
||||
|
||||
GWEN_MsgRequest_free(aqh->requestTree);
|
||||
GWEN_MsgEndpoint_free(aqh->ipcdEndpoint);
|
||||
GWEN_DB_Group_free(aqh->dbArgs);
|
||||
AQH_Storage_free(aqh->storage);
|
||||
free(aqh->pidFile);
|
||||
|
||||
GWEN_FREE_OBJECT(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?(aqh->ipcdEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?(aqh->dbArgs):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?(aqh->storage):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_REQUEST *AqHomeData_GetRequestTree(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?aqh->requestTree:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeData_AddRequestToTree(AQHOME_DATA *aqh, GWEN_MSG_REQUEST *rq)
|
||||
{
|
||||
if (aqh && rq)
|
||||
GWEN_MsgRequest_Tree2_AddChild(aqh->requestTree, rq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeData_GetPidFile(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?aqh->pidFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_GetTimeout(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?aqh->timeout:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_LockStorage(AQHOME_DATA *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Mutex_Lock(aqh->storageMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_UnlockStorage(AQHOME_DATA *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Mutex_Unlock(aqh->storageMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_IpcEndpoint_GetServiceName(ep);
|
||||
if (s && *s && strcasecmp(s, serviceName)==0)
|
||||
return ep;
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
47
apps/aqhome-data/aqhome_data.h
Normal file
47
apps/aqhome-data/aqhome_data.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_H
|
||||
#define AQHOME_DATA_H
|
||||
|
||||
|
||||
#include "aqhome/data/storage.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/request.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQHOME_DATA AQHOME_DATA;
|
||||
|
||||
|
||||
AQHOME_DATA *AqHomeData_new();
|
||||
void AqHomeData_free(AQHOME_DATA *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName);
|
||||
|
||||
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh);
|
||||
|
||||
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh);
|
||||
|
||||
const char *AqHomeData_GetPidFile(const AQHOME_DATA *aqh);
|
||||
|
||||
int AqHomeData_GetTimeout(const AQHOME_DATA *aqh);
|
||||
|
||||
int AqHomeData_LockStorage(AQHOME_DATA *aqh);
|
||||
int AqHomeData_UnlockStorage(AQHOME_DATA *aqh);
|
||||
|
||||
GWEN_MSG_REQUEST *AqHomeData_GetRequestTree(const AQHOME_DATA *aqh);
|
||||
void AqHomeData_AddRequestToTree(AQHOME_DATA *aqh, GWEN_MSG_REQUEST *rq);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
44
apps/aqhome-data/aqhome_data_p.h
Normal file
44
apps/aqhome-data/aqhome_data_p.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_P_H
|
||||
#define AQHOME_DATA_P_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
#include <gwenhywfar/mutex.h>
|
||||
|
||||
|
||||
#define AQHOME_DATA_DEFAULT_PIDFILE "/var/run/aqhome-data.pid"
|
||||
#define AQHOME_DATA_DEFAULT_DATADIR "/var/lib/aqhome-data/data"
|
||||
#define AQHOME_DATA_DEFAULT_IPC_PORT 45456
|
||||
|
||||
#define AQHOME_DATA_STATEFILENAME "statefile"
|
||||
|
||||
|
||||
|
||||
struct AQHOME_DATA {
|
||||
GWEN_MSG_ENDPOINT *ipcdEndpoint;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
AQH_STORAGE *storage;
|
||||
|
||||
char *pidFile;
|
||||
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
|
||||
GWEN_MUTEX *storageMutex;
|
||||
|
||||
GWEN_MSG_REQUEST *requestTree;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
72
apps/aqhome-data/c_addvalue.c
Normal file
72
apps/aqhome-data/c_addvalue.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_addvalue.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
AQH_ValuesDataIpcMsg_Parse(msg, 0);
|
||||
recvdValue=AQH_ValuesDataIpcMsg_ReadFirstValue(msg);
|
||||
if (recvdValue) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
|
||||
if (value==NULL)
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_addvalue.h
Normal file
25
apps/aqhome-data/c_addvalue.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_ADDVALUE_H
|
||||
#define AQHOME_DATA_C_ADDVALUE_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
65
apps/aqhome-data/c_annvalue.c
Normal file
65
apps/aqhome-data/c_annvalue.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_annvalue.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleAnnounceValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
AQH_ValuesDataIpcMsg_Parse(msg, 0);
|
||||
recvdValue=AQH_ValuesDataIpcMsg_ReadFirstValue(msg);
|
||||
if (recvdValue) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
|
||||
if (value==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Could not create announced value");
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_annvalue.h
Normal file
25
apps/aqhome-data/c_annvalue.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_ANNVALUE_H
|
||||
#define AQHOME_DATA_C_ANNVALUE_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleAnnounceValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
93
apps/aqhome-data/c_connect.c
Normal file
93
apps/aqhome-data/c_connect.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_connect.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/data/msg_data_connect.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleConnect(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
char *clientId=NULL;
|
||||
char *userId=NULL;
|
||||
char *passw=NULL;
|
||||
uint32_t flags;
|
||||
|
||||
AQH_ConnectDataIpcMsg_Parse(msg, 0);
|
||||
clientId=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_CLIENTID, NULL);
|
||||
userId=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_USERID, NULL);
|
||||
flags=AQH_Tag16IpcMsg_GetTagDataAsUint32(msg, AQH_MSGDATA_CONNECT_TAGS_FLAGS, 0);
|
||||
passw=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_PASSWORD, NULL);
|
||||
|
||||
if (clientId)
|
||||
AQH_IpcEndpoint_SetServiceName(ep, clientId);
|
||||
if (userId)
|
||||
AQH_IpcEndpoint_SetUserName(ep, userId);
|
||||
|
||||
if (flags & AQH_MSGDATA_CONNECT_FLAGS_WANTUPDATES)
|
||||
GWEN_MsgEndpoint_AddFlags(ep, AQH_IPCENDPOINT_FLAGS_WANTUPDATES);
|
||||
|
||||
/* TODO: add user management, for now we allow all */
|
||||
AQH_IpcEndpoint_SetPermissions(ep,
|
||||
AQH_IPCENDPOINT_PERMS_LISTVALUES |
|
||||
AQH_IPCENDPOINT_PERMS_READVALUE |
|
||||
AQH_IPCENDPOINT_PERMS_ADDVALUE |
|
||||
AQH_IPCENDPOINT_PERMS_LISTDATA |
|
||||
AQH_IPCENDPOINT_PERMS_READDATA |
|
||||
AQH_IPCENDPOINT_PERMS_ADDDATA |
|
||||
AQH_IPCENDPOINT_PERMS_LISTDEVICES |
|
||||
AQH_IPCENDPOINT_PERMS_READDEVICE |
|
||||
AQH_IPCENDPOINT_PERMS_ADDDEVICE |
|
||||
AQH_IPCENDPOINT_PERMS_MODDEVICE);
|
||||
free(passw);
|
||||
free(userId);
|
||||
free(clientId);
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,18 +6,20 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_ENDPOINT_WRITE_H
|
||||
#define AQH_ENDPOINT_WRITE_H
|
||||
#ifndef AQHOME_DATA_C_CONNECT_H
|
||||
#define AQHOME_DATA_C_CONNECT_H
|
||||
|
||||
|
||||
#include "aqhome/msg/endpoint_node.h"
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
|
||||
AQHOME_API GWEN_MSG_ENDPOINT *AQH_WriteEndpoint_new(const char *folder, int groupId);
|
||||
|
||||
void AqHomeData_HandleConnect(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
211
apps/aqhome-data/c_getdatapoints.c
Normal file
211
apps/aqhome-data/c_getdatapoints.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getdatapoints.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/data/msg_data_getdata.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
|
||||
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _getAndSendDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep,
|
||||
const AQH_VALUE *value,
|
||||
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsNoNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
|
||||
uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsWithNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
|
||||
static void _sendDataPointsResponse(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
|
||||
uint32_t refMsgId);
|
||||
static void _getAndSendLastDatapoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
|
||||
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
|
||||
AQH_VALUE *value;
|
||||
char *valueName;
|
||||
uint64_t tsBegin;
|
||||
uint64_t tsEnd;
|
||||
uint64_t numRequested;
|
||||
|
||||
AQH_GetDataDataIpcMsg_Parse(recvdMsg, 0);
|
||||
valueName=AQH_Tag16IpcMsg_GetTagDataAsNewString(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
|
||||
tsBegin=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0);
|
||||
tsEnd=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_END, 0);
|
||||
numRequested=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NUM, 0);
|
||||
|
||||
value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
|
||||
if (value) {
|
||||
resultCode=_getAndSendDataPoints(aqh, ep, value, tsBegin, tsEnd, numRequested, GWEN_IpcMsg_GetMsgId(recvdMsg));
|
||||
if (resultCode==AQH_MSG_IPC_SUCCESS)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Value \"%s\" does not exist", valueName);
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
free(valueName);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
if (num==0)
|
||||
return _getAndSendDataPointsNoNum(aqh, ep, value, tsBegin, tsEnd, refMsgId);
|
||||
else if (num==1) {
|
||||
_getAndSendLastDatapoint(aqh, ep, value, refMsgId);
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else
|
||||
return _getAndSendDataPointsWithNum(aqh, ep, value, num, refMsgId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsNoNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
valueId=AQH_Value_GetId(value);
|
||||
tablePtr=AQH_Storage_GetDataPoints(aqh->storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(aqh, ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSG_IPC_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsWithNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
|
||||
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
|
||||
valueId=AQH_Value_GetId(value);
|
||||
tablePtr=AQH_Storage_GetLastNDataPoints(aqh->storage, valueId, num);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(aqh, ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSG_IPC_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataPointsResponse(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
int numTableEntries;
|
||||
int numDataPoints;
|
||||
GWEN_MSG *outMsg;
|
||||
|
||||
numTableEntries=(int)(tablePtr[0]);
|
||||
numDataPoints=numTableEntries/2;
|
||||
outMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
value, &(tablePtr[1]), numDataPoints);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _getAndSendLastDatapoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint32_t refMsgId)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
int rv;
|
||||
uint64_t timestamp=0;
|
||||
double data=0.0;
|
||||
|
||||
rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(value), ×tamp, &data);
|
||||
if (rv<0) {
|
||||
switch(rv) {
|
||||
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
|
||||
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
|
||||
default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
outMsg=AQH_MultiDataDataIpcMsg_newForOne(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
value, timestamp, data);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_getdatapoints.h
Normal file
25
apps/aqhome-data/c_getdatapoints.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETDATAPOINTS_H
|
||||
#define AQHOME_DATA_C_GETDATAPOINTS_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
106
apps/aqhome-data/c_getdevices.c
Normal file
106
apps/aqhome-data/c_getdevices.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getdevices.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_devices.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_DEVICESPERMSG 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendDeviceList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleGetDevices(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
const AQH_DEVICE_LIST *origDeviceList;
|
||||
|
||||
DBG_INFO(NULL, "HandleGetDevices");
|
||||
origDeviceList=AQH_Storage_GetDeviceList(aqh->storage);
|
||||
if (origDeviceList) {
|
||||
DBG_INFO(NULL, "Have a list of %d devices", AQH_Device_List_GetCount(origDeviceList));
|
||||
if (AQH_Device_List_GetCount(origDeviceList)<AQHOMEDATA_DEVICESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending all entries in one message");
|
||||
_sendDeviceList(aqh, ep, origDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
else {
|
||||
AQH_DEVICE_LIST *tmpDeviceList;
|
||||
const AQH_DEVICE *v;
|
||||
|
||||
DBG_INFO(NULL, "Sending entries in multiple messages");
|
||||
tmpDeviceList=AQH_Device_List_new();
|
||||
v=AQH_Device_List_First(origDeviceList);
|
||||
while(v) {
|
||||
const AQH_DEVICE *next;
|
||||
AQH_DEVICE *copyOfDevice;
|
||||
|
||||
next=AQH_Device_List_Next(v);
|
||||
copyOfDevice=AQH_Device_dup(v);
|
||||
AQH_Device_List_Add(copyOfDevice, tmpDeviceList);
|
||||
if (AQH_Device_List_GetCount(tmpDeviceList)>=AQHOMEDATA_DEVICESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
|
||||
_sendDeviceList(aqh, ep, tmpDeviceList, next?0:AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
AQH_Device_List_Clear(tmpDeviceList);
|
||||
}
|
||||
v=next;
|
||||
}
|
||||
if (AQH_Device_List_GetCount(tmpDeviceList)) {
|
||||
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
|
||||
_sendDeviceList(aqh, ep, tmpDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg)); /* send remaining */
|
||||
}
|
||||
AQH_Device_List_free(tmpDeviceList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
_sendDeviceList(aqh, ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDeviceList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
msg=AQH_DevicesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
flags, vl);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_getdevices.h
Normal file
25
apps/aqhome-data/c_getdevices.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETDEVICES_H
|
||||
#define AQHOME_DATA_C_GETDEVICES_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetDevices(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
107
apps/aqhome-data/c_getlastdatapoint.c
Normal file
107
apps/aqhome-data/c_getlastdatapoint.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getlastdatapoint.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_getdata.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
|
||||
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
|
||||
char *valueName;
|
||||
|
||||
AQH_GetDataDataIpcMsg_Parse(recvdMsg, 0);
|
||||
valueName=AQH_Tag16IpcMsg_GetTagDataAsNewString(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
|
||||
if (valueName && *valueName) {
|
||||
const AQH_VALUE *storedValue;
|
||||
|
||||
storedValue=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
|
||||
if (storedValue) {
|
||||
uint64_t timestamp=0;
|
||||
double data=0.0;
|
||||
int rv;
|
||||
|
||||
rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(storedValue), ×tamp, &data);
|
||||
if (rv<0) {
|
||||
switch(rv) {
|
||||
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
|
||||
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
|
||||
default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
outMsg=AQH_MultiDataDataIpcMsg_newForOne(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
storedValue, timestamp, data);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
free(valueName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Value \"%s\" not found", valueName);
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
free(valueName);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No name for value");
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_getlastdatapoint.h
Normal file
25
apps/aqhome-data/c_getlastdatapoint.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETLASTDATAPOINT_H
|
||||
#define AQHOME_DATA_C_GETLASTDATAPOINT_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
106
apps/aqhome-data/c_getvalues.c
Normal file
106
apps/aqhome-data/c_getvalues.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getvalues.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_VALUESPERMSG 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
const AQH_VALUE_LIST *origValueList;
|
||||
|
||||
DBG_INFO(NULL, "HandleGetValues");
|
||||
origValueList=AQH_Storage_GetValueList(aqh->storage);
|
||||
if (origValueList) {
|
||||
DBG_INFO(NULL, "Have a list of %d values", AQH_Value_List_GetCount(origValueList));
|
||||
if (AQH_Value_List_GetCount(origValueList)<AQHOMEDATA_VALUESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending all entries in one message");
|
||||
_sendValueList(aqh, ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
else {
|
||||
AQH_VALUE_LIST *tmpValueList;
|
||||
const AQH_VALUE *v;
|
||||
|
||||
DBG_INFO(NULL, "Sending entries in multiple messages");
|
||||
tmpValueList=AQH_Value_List_new();
|
||||
v=AQH_Value_List_First(origValueList);
|
||||
while(v) {
|
||||
const AQH_VALUE *next;
|
||||
AQH_VALUE *copyOfValue;
|
||||
|
||||
next=AQH_Value_List_Next(v);
|
||||
copyOfValue=AQH_Value_dup(v);
|
||||
AQH_Value_List_Add(copyOfValue, tmpValueList);
|
||||
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
|
||||
_sendValueList(aqh, ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
AQH_Value_List_Clear(tmpValueList);
|
||||
}
|
||||
v=next;
|
||||
}
|
||||
if (AQH_Value_List_GetCount(tmpValueList)) {
|
||||
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
|
||||
_sendValueList(aqh, ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg)); /* send remaining */
|
||||
}
|
||||
AQH_Value_List_free(tmpValueList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
_sendValueList(aqh, ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
msg=AQH_ValuesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
flags, vl);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_getvalues.h
Normal file
25
apps/aqhome-data/c_getvalues.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETVALUES_H
|
||||
#define AQHOME_DATA_C_GETVALUES_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
114
apps/aqhome-data/c_moddevice.c
Normal file
114
apps/aqhome-data/c_moddevice.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getlastdatapoint.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_devices.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
|
||||
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_MODDEVICE) {
|
||||
AQH_DEVICE *device;
|
||||
|
||||
AQH_DevicesDataIpcMsg_Parse(recvdMsg, 0);
|
||||
device=AQH_DevicesDataIpcMsg_ReadFirstDevice(recvdMsg);
|
||||
if (device) {
|
||||
const char *deviceNameForSystem;
|
||||
|
||||
deviceNameForSystem=AQH_Device_GetNameForSystem(device);
|
||||
if (deviceNameForSystem && *deviceNameForSystem) {
|
||||
AQH_DEVICE *storedDevice;
|
||||
|
||||
storedDevice=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, deviceNameForSystem);
|
||||
if (storedDevice) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_Device_GetNameForGui(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetNameForGui(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetRoomName(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetRoomName(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetLocation(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetLocation(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetDescription(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetDescription(storedDevice, s);
|
||||
|
||||
AQH_Storage_AddRuntimeFlags(aqh->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
|
||||
resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device \"%s\" not found", deviceNameForSystem);
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No name for value");
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No device info in message");
|
||||
resultCode=AQH_MSG_IPC_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_moddevice.h
Normal file
25
apps/aqhome-data/c_moddevice.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_MODDEVICE_H
|
||||
#define AQHOME_DATA_C_MODDEVICE_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
258
apps/aqhome-data/c_setdata.c
Normal file
258
apps/aqhome-data/c_setdata.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_setdata.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_set.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
|
||||
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epSrc, uint32_t requestMsgId,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *v, const char *data);
|
||||
static void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason);
|
||||
static void _rqAbort(GWEN_MSG_REQUEST *rq, int reason);
|
||||
|
||||
static GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const AQH_VALUE *v, const char *data);
|
||||
static int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg);
|
||||
static void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
uint32_t msgId;
|
||||
AQH_VALUE *recvdValue;
|
||||
const char *valueName;
|
||||
char *valueDataFreeable;
|
||||
AQH_VALUE *systemValue;
|
||||
|
||||
msgId=GWEN_IpcMsg_GetMsgId(recvdMsg);
|
||||
DBG_INFO(NULL, "Received IPC SetDataRequest message (msgId=%d)", msgId);
|
||||
|
||||
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||
valueName=recvdValue?AQH_Value_GetNameForSystem(recvdValue):NULL;
|
||||
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||
|
||||
systemValue=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
|
||||
if (systemValue) {
|
||||
if (AQH_Value_GetValueType(systemValue)==AQH_ValueType_Actor) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=AQH_Value_GetDriver(systemValue);
|
||||
if (driverName && *driverName) {
|
||||
GWEN_MSG_ENDPOINT *epDriver;
|
||||
|
||||
epDriver=AqHomeData_GetIpcEndpointByServiceName(aqh, driverName);
|
||||
if (epDriver) {
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
|
||||
DBG_DEBUG(NULL, "Creating SETDATA request for driver endpoint (%s)", GWEN_MsgEndpoint_GetName(epDriver));
|
||||
rq=_mkRequest_SetData(aqh, epSrc, msgId, epDriver, systemValue, valueDataFreeable);
|
||||
AqHomeData_AddRequestToTree(aqh, rq);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Driver \"%s\" not available", driverName);
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No driver name");
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Value \"%s\" is not an actor", valueName);
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unknown value \"%s\"", valueName);
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_NOTFOUND);
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
free(valueDataFreeable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* IPC Request SETDATA
|
||||
*/
|
||||
|
||||
GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epSrc, uint32_t requestMsgId,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *v, const char *data)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
GWEN_MSG_REQUEST *subRq;
|
||||
|
||||
rq=GWEN_MsgRequest_new();
|
||||
GWEN_MsgRequest_SetPrivateData(rq, aqh);
|
||||
GWEN_MsgRequest_SetEndpoint(rq, epSrc);
|
||||
GWEN_MsgRequest_SetRequestMsgId(rq, requestMsgId);
|
||||
GWEN_MsgRequest_SetSubRequestFinishedFn(rq, _rqSubRequestFinished);
|
||||
GWEN_MsgRequest_SetAbortFn(rq, _rqAbort);
|
||||
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_REQUEST_EXPIRE_SECS);
|
||||
|
||||
subRq=_mkSubRequest_SetData(aqh, epDriver, v, data);
|
||||
GWEN_MsgRequest_Tree2_AddChild(rq, subRq);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
uint32_t refMsgId;
|
||||
int result;
|
||||
|
||||
DBG_DEBUG(NULL, "SubRequest finished (reason: %d)", reason);
|
||||
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=GWEN_MsgRequest_GetEndpoint(rq);
|
||||
result=GWEN_MsgRequest_GetResult(subRq);
|
||||
|
||||
if (reason==GWEN_MSG_REQUEST_REASON_ABORTED)
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
else
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, result);
|
||||
|
||||
GWEN_MsgRequest_SetResult(rq, result);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqAbort(GWEN_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
uint32_t refMsgId;
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=GWEN_MsgRequest_GetEndpoint(rq);
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Driver Request SETDATA
|
||||
*/
|
||||
|
||||
|
||||
GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const AQH_VALUE *v, const char *data)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
uint16_t msgId;
|
||||
GWEN_MSG *driverMsg;
|
||||
|
||||
rq=GWEN_MsgRequest_new();
|
||||
GWEN_MsgRequest_SetPrivateData(rq, aqh);
|
||||
GWEN_MsgRequest_SetEndpoint(rq, epDriver);
|
||||
|
||||
GWEN_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
|
||||
GWEN_MsgRequest_SetAbortFn(rq, _subRqAbort);
|
||||
|
||||
msgId=GWEN_MsgEndpoint_GetNextMessageId(epDriver);
|
||||
GWEN_MsgRequest_SetRequestMsgId(rq, msgId);
|
||||
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
|
||||
|
||||
driverMsg=AQH_SetDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_SETDATA, msgId, 0, v, data);
|
||||
GWEN_MsgEndpoint_AddSendMessage(epDriver, driverMsg);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg)
|
||||
{
|
||||
DBG_DEBUG(NULL, "Checking message from driver");
|
||||
if (GWEN_IpcMsg_GetCode(msg)==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||
uint32_t result;
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
result=AQH_ResultIpcMsg_GetResultCode(msg);
|
||||
DBG_INFO(NULL, "Received result for request: %d", result);
|
||||
GWEN_MsgRequest_SetResult(rq, result);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, GWEN_MSG_REQUEST_REASON_DONE);
|
||||
return GWEN_MSG_REQUEST_RESULT_HANDLED;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unexpected response message %d", GWEN_IpcMsg_GetCode(msg));
|
||||
}
|
||||
|
||||
return GWEN_MSG_REQUEST_RESULT_NOT_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
|
||||
GWEN_MsgRequest_SetResult(rq, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_setdata.h
Normal file
25
apps/aqhome-data/c_setdata.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_SETDATA_H
|
||||
#define AQHOME_DATA_C_SETDATA_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
153
apps/aqhome-data/c_updatedata.c
Normal file
153
apps/aqhome-data/c_updatedata.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_updatedata.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues);
|
||||
static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
|
||||
const uint64_t *dataPoints, uint32_t numValues);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
const GWEN_TAG16 *tag;
|
||||
AQH_VALUE *recvdValue;
|
||||
const char *valueName;
|
||||
const uint64_t *dataPoints=NULL;
|
||||
unsigned int numberOfPoints=0;
|
||||
|
||||
AQH_MultiDataDataIpcMsg_Parse(recvdMsg, 0);
|
||||
|
||||
recvdValue=AQH_MultiDataDataIpcMsg_ReadValue(recvdMsg);
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
tag=AQH_Tag16IpcMsg_FindFirstTagByType(recvdMsg, AQH_MSGDATA_MULTIDATA_TAGS_DATA);
|
||||
dataPoints=tag?((const uint64_t*)GWEN_Tag16_GetTagData(tag)):NULL;
|
||||
numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t));
|
||||
|
||||
if (numberOfPoints>0) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
|
||||
if (value) {
|
||||
resultCode=_storeDataPoints(aqh, value, dataPoints, numberOfPoints);
|
||||
if (resultCode==AQH_MSG_IPC_SUCCESS)
|
||||
_sendDataChangedMsgToAllClients(aqh, ep, value, dataPoints, numberOfPoints);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No permissions to add datapoint for value \"%s\"", valueName);
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No datapoints");
|
||||
resultCode=AQH_MSG_IPC_ERROR_INVALID;
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i=0; i<numValues; i++) {
|
||||
uint64_t timestamp;
|
||||
union {double f; uint64_t i;} u;
|
||||
int rv;
|
||||
|
||||
timestamp=*(dataPoints++);
|
||||
u.i=*(dataPoints++);
|
||||
rv=AQH_Storage_AddDatapoint(aqh->storage, AQH_Value_GetId(v), timestamp, u.f);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return AQH_MSG_IPC_ERROR_GENERIC;
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
|
||||
}
|
||||
} /* for */
|
||||
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
|
||||
const uint64_t *dataPoints, uint32_t numValues)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
if (ep!=epSrc) {
|
||||
if (GWEN_MsgEndpoint_GetFlags(ep) & AQH_IPCENDPOINT_FLAGS_WANTUPDATES) {
|
||||
GWEN_MSG *msg;
|
||||
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
|
||||
msg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
|
||||
v, dataPoints, numValues);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
|
||||
}
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/c_updatedata.h
Normal file
25
apps/aqhome-data/c_updatedata.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_UPDATEDATA_H
|
||||
#define AQHOME_DATA_C_UPDATEDATA_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
80
apps/aqhome-data/fini.c
Normal file
80
apps/aqhome-data/fini.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./fini.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_Fini(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
if (aqh->ipcdEndpoint) {
|
||||
_disconnectTree(aqh->ipcdEndpoint);
|
||||
GWEN_MsgEndpoint_Disconnect(aqh->ipcdEndpoint);
|
||||
}
|
||||
GWEN_MsgEndpoint_free(aqh->ipcdEndpoint);
|
||||
aqh->ipcdEndpoint=NULL;
|
||||
|
||||
if (aqh->pidFile)
|
||||
remove(aqh->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epChild;
|
||||
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
||||
while(epChild) {
|
||||
_disconnectTree(epChild);
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
||||
} /* while */
|
||||
|
||||
GWEN_MsgEndpoint_Disconnect(ep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-data/fini.h
Normal file
23
apps/aqhome-data/fini.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_FINI_H
|
||||
#define AQHOME_DATA_FINI_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
|
||||
void AqHomeData_Fini(AQHOME_DATA *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
341
apps/aqhome-data/init.c
Normal file
341
apps/aqhome-data/init.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./init.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_msgio.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _setupStorage(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static void _setupIpc(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
||||
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AqHomeData_Init(AQHOME_DATA *aqh, int argc, char **argv)
|
||||
{
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
int rv;
|
||||
const char *s;
|
||||
|
||||
dbArgs=GWEN_DB_Group_new("args");
|
||||
rv=_readArgs(argc, argv, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
|
||||
aqh->dbArgs=dbArgs;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_LOGGER_LEVEL ll;
|
||||
|
||||
ll=GWEN_Logger_Name2Level(s);
|
||||
GWEN_Logger_SetLevel(NULL, ll);
|
||||
}
|
||||
|
||||
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_DATA_DEFAULT_PIDFILE);
|
||||
if (s && *s) {
|
||||
free(aqh->pidFile);
|
||||
aqh->pidFile=strdup(s);
|
||||
rv=_createPidFile(s);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv=_setupStorage(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
_setupIpc(aqh, dbArgs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupStorage(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *dataFolder;
|
||||
GWEN_BUFFER *nameBuf;
|
||||
AQH_STORAGE *sto;
|
||||
int rv;
|
||||
|
||||
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_DATA_DEFAULT_DATADIR);
|
||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(nameBuf, "%s%s%s", dataFolder, GWEN_DIR_SEPARATOR_S, AQHOME_DATA_STATEFILENAME);
|
||||
|
||||
sto=AQH_Storage_new();
|
||||
AQH_Storage_SetStateFile(sto, GWEN_Buffer_GetStart(nameBuf));
|
||||
AQH_Storage_SetDataFileFolder(sto, dataFolder);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
|
||||
rv=AQH_Storage_Init(sto);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQH_Storage_free(sto);
|
||||
return rv;
|
||||
}
|
||||
aqh->storage=sto;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupIpc(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
|
||||
if (!(tcpAddress && *tcpAddress))
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, NULL);
|
||||
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
|
||||
if (tcpPort<0)
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_DATA_DEFAULT_IPC_PORT);
|
||||
|
||||
if (tcpAddress && *tcpAddress && tcpPort>0) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
DBG_INFO(NULL, "Starting TCP service on \"%s\":%d", tcpAddress, tcpPort);
|
||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
|
||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
|
||||
|
||||
aqh->ipcdEndpoint=ep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
|
||||
GWEN_SOCKET *sk,
|
||||
const GWEN_INETADDRESS *addr,
|
||||
GWEN_UNUSED void *data)
|
||||
{
|
||||
/* AQHOME_DATA *aqh;
|
||||
*
|
||||
* aqh=(AQHOME_DATA*) data;
|
||||
*/
|
||||
DBG_INFO(NULL, "Incoming IPC connection");
|
||||
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
int pidfd;
|
||||
|
||||
if (remove(pidFilename)==0) {
|
||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (pidfd < 0) {
|
||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
f = fdopen(pidfd, "w");
|
||||
#else /* HAVE_STAT_H */
|
||||
f=fopen(pidFilename,"w+");
|
||||
#endif /* HAVE_STAT_H */
|
||||
|
||||
/* write pid */
|
||||
#ifdef HAVE_GETPID
|
||||
fprintf(f,"%d\n",getpid());
|
||||
#else
|
||||
fprintf(f,"-1\n");
|
||||
#endif
|
||||
if (fclose(f)) {
|
||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
int rv;
|
||||
const GWEN_ARGS args[]= {
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"loglevel", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"L", /* short option */
|
||||
"loglevel", /* long option */
|
||||
I18S("Specify loglevel"), /* short description */
|
||||
I18S("Specify loglevel") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"tcpAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"t", /* short option */
|
||||
"tcpaddress", /* long option */
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)"),
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"tcpPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"P", /* short option */
|
||||
"tcpport", /* long option */
|
||||
I18S("Specify the TCP port to listen on"),
|
||||
I18S("Specify the TCP port to listen on")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"datafolder", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"datafolder", /* long option */
|
||||
I18S("Folder where data files are stored"),
|
||||
I18S("Folder where data files are stored")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"pidfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"p", /* short option */
|
||||
"pidfile", /* long option */
|
||||
I18S("Specify the PID file"),
|
||||
I18S("Specify the PID file")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"timeout", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"T", /* short option */
|
||||
"timeout", /* long option */
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"help", /* name */
|
||||
0, /* minnum */
|
||||
0, /* maxnum */
|
||||
"h", /* short option */
|
||||
"help",
|
||||
I18S("Show this help screen."),
|
||||
I18S("Show this help screen.")
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
||||
GWEN_BUFFER *ubuf;
|
||||
|
||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(ubuf,
|
||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
||||
AQHOME_VERSION_STRING,
|
||||
argv[0]);
|
||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
||||
return 1;
|
||||
}
|
||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
||||
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-data/init.h
Normal file
23
apps/aqhome-data/init.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_INIT_H
|
||||
#define AQHOME_DATA_INIT_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeData_Init(AQHOME_DATA *aqh, int argc, char **argv);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
260
apps/aqhome-data/loop.c
Normal file
260
apps/aqhome-data/loop.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop.h"
|
||||
#include "./c_connect.h"
|
||||
#include "./c_updatedata.h"
|
||||
#include "./c_getdatapoints.h"
|
||||
#include "./c_getlastdatapoint.h"
|
||||
#include "./c_getvalues.h"
|
||||
#include "./c_getdevices.h"
|
||||
#include "./c_setdata.h"
|
||||
#include "./c_addvalue.h"
|
||||
#include "./c_annvalue.h"
|
||||
#include "./c_moddevice.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/data/msg_data_datapoints.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/msg_ipc.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _readAndHandleIpcMessages(AQHOME_DATA *aqh);
|
||||
static void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep);
|
||||
static void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
static AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const char *nameForDriver);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_Loop(AQHOME_DATA *aqh, int timeoutInMsecs)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgEndpoint_IoLoop(aqh->ipcdEndpoint, timeoutInMsecs);
|
||||
_readAndHandleIpcMessages(aqh);
|
||||
|
||||
AQH_Requests_CheckTimeouts(aqh->requestTree);
|
||||
AQH_Requests_Cleanup(aqh->requestTree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_WriteStorageIfChanged(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (AQH_Storage_GetRuntimeFlags(aqh->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Storage modified, writing statefile");
|
||||
rv=AqHomeData_LockStorage(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error locking storage (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
rv=AQH_Storage_WriteState(aqh->storage);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing state file (%d)", rv);
|
||||
AqHomeData_UnlockStorage(aqh);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AqHomeData_UnlockStorage(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_VALUE *AqHomeData_GetOrCreateValueForDriverWithTemplate(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *valueTemplate)
|
||||
{
|
||||
const char *serviceName;
|
||||
AQH_VALUE *v;
|
||||
GWEN_BUFFER *buf;
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
serviceName=AQH_IpcEndpoint_GetServiceName(epDriver);
|
||||
valueName=AQH_Value_GetName(valueTemplate);
|
||||
deviceName=AQH_Value_GetDeviceName(valueTemplate);
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
if (deviceName && *deviceName)
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName, valueName);
|
||||
else
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", valueName);
|
||||
|
||||
v=AQH_Storage_GetValueByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
|
||||
if (v==NULL) {
|
||||
if (AQH_IpcEndpoint_GetPermissions(epDriver) & AQH_IPCENDPOINT_PERMS_ADDVALUE) {
|
||||
AQH_DEVICE *device;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
device=(deviceName && *deviceName)?_getOrCreateDeviceForDriver(aqh, epDriver, deviceName):NULL;
|
||||
|
||||
v=AQH_Value_new();
|
||||
AQH_Value_SetDriver(v, serviceName);
|
||||
AQH_Value_SetName(v, AQH_Value_GetName(valueTemplate));
|
||||
AQH_Value_SetNameForSystem(v, GWEN_Buffer_GetStart(buf));
|
||||
AQH_Value_SetValueUnits(v, AQH_Value_GetValueUnits(valueTemplate));
|
||||
AQH_Value_SetValueType(v, AQH_Value_GetValueType(valueTemplate));
|
||||
AQH_Value_SetModality(v, AQH_Value_GetModality(valueTemplate));
|
||||
AQH_Value_SetTimestampCreation(v, (uint64_t) time(NULL));
|
||||
if (device) {
|
||||
AQH_Value_SetDeviceNameForSystem(v, AQH_Device_GetNameForSystem(device));
|
||||
AQH_Value_SetDeviceName(v, AQH_Device_GetName(device));
|
||||
}
|
||||
AQH_Storage_AddValue(aqh->storage, v);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create value \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const char *deviceName)
|
||||
{
|
||||
const char *serviceName;
|
||||
AQH_DEVICE *device;
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
serviceName=AQH_IpcEndpoint_GetServiceName(epDriver);
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName);
|
||||
|
||||
device=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
|
||||
if (device==NULL) {
|
||||
if (AQH_IpcEndpoint_GetPermissions(epDriver) & AQH_IPCENDPOINT_PERMS_ADDDEVICE) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Creating device \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
device=AQH_Device_new();
|
||||
AQH_Device_SetDriver(device, serviceName);
|
||||
AQH_Device_SetName(device, deviceName);
|
||||
AQH_Device_SetNameForSystem(device, GWEN_Buffer_GetStart(buf));
|
||||
AQH_Device_SetTimestampCreation(device, (uint64_t) time(NULL));
|
||||
AQH_Storage_AddDevice(aqh->storage, device);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create device \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _readAndHandleIpcMessages(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (aqh->ipcdEndpoint) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
_handleIpcEndpoint(aqh, ep);
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
|
||||
DBG_INFO(NULL, "Got IPS message %d (msgId=%d, refMsgId=%d) [%s]",
|
||||
GWEN_IpcMsg_GetCode(msg),
|
||||
GWEN_IpcMsg_GetMsgId(msg),
|
||||
GWEN_IpcMsg_GetRefMsgId(msg),
|
||||
GWEN_MsgEndpoint_GetName(ep));
|
||||
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, ep, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
|
||||
_handleIpcMsg(aqh, ep, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
uint16_t code;
|
||||
uint8_t protoId;
|
||||
|
||||
/* exec IPC message */
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
protoId=GWEN_IpcMsg_GetProtoId(msg);
|
||||
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeData_HandleConnect(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeData_HandleUpdateData(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeData_HandleGetValues(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeData_HandleGetDataPoints(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ: AqHomeData_HandleGetLastDataPoint(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeData_HandleSetData(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeData_HandleAddValue(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: AqHomeData_HandleAnnounceValue(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeData_HandleGetDevices(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeData_HandleModDevice(aqh, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
30
apps/aqhome-data/loop.h
Normal file
30
apps/aqhome-data/loop.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_LOOP_H
|
||||
#define AQHOME_DATA_LOOP_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_Loop(AQHOME_DATA *aqh, int timeoutInMsecs);
|
||||
|
||||
int AqHomeData_WriteStorageIfChanged(AQHOME_DATA *aqh);
|
||||
|
||||
AQH_VALUE *AqHomeData_GetOrCreateValueForDriverWithTemplate(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *valueTemplate);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
253
apps/aqhome-data/main.c
Normal file
253
apps/aqhome-data/main.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
#include "./init.h"
|
||||
#include "./fini.h"
|
||||
#include "./loop.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
//#define WRITE_INTERVAL_IN_SECS (5*60)
|
||||
|
||||
#define WRITE_INTERVAL_IN_SECS 60
|
||||
#define PING_INTERVAL 120
|
||||
#define CONNCLEAN_INTERVAL_IN_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
#endif
|
||||
|
||||
static void _runService(AQHOME_DATA *aqh);
|
||||
static void _writeCurrentState(AQHOME_DATA *aqh);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
||||
#endif
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
AQHOME_DATA *aqh;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhome-data", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
aqh=AqHomeData_new();
|
||||
rv=AqHomeData_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
_runService(aqh);
|
||||
|
||||
AqHomeData_Fini(aqh);
|
||||
AqHomeData_free(aqh);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _runService(AQHOME_DATA *aqh)
|
||||
{
|
||||
time_t timeStart;
|
||||
time_t timeLastWrite;
|
||||
time_t timeLastConnectionCleanup;
|
||||
int timeout;
|
||||
|
||||
timeout=AqHomeData_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastWrite=time(NULL);
|
||||
timeLastConnectionCleanup=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
time_t now;
|
||||
|
||||
DBG_DEBUG(NULL, "Next loop");
|
||||
AqHomeData_Loop(aqh, 2000);
|
||||
|
||||
now=time(NULL);
|
||||
|
||||
if (((int)difftime(now, timeLastConnectionCleanup))>CONNCLEAN_INTERVAL_IN_SECS) {
|
||||
DBG_DEBUG(NULL, "Cleanup connections");
|
||||
GWEN_MsgEndpoint_RemoveUnconnectedAndEmptyChildren(AqHomeData_GetIpcdEndpoint(aqh));
|
||||
timeLastConnectionCleanup=now;
|
||||
}
|
||||
|
||||
if (((int)difftime(now, timeLastWrite))>WRITE_INTERVAL_IN_SECS) {
|
||||
DBG_DEBUG(NULL, "Write time");
|
||||
_writeCurrentState(aqh);
|
||||
timeLastWrite=now;
|
||||
}
|
||||
|
||||
if (timeout && ((int)difftime(now, timeStart))>timeout) {
|
||||
DBG_INFO(NULL, "Timeout");
|
||||
_writeCurrentState(aqh);
|
||||
break;
|
||||
}
|
||||
} /* while */
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeCurrentState(AQHOME_DATA *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=AqHomeData_WriteStorageIfChanged(aqh);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "ATTENTION: Could not write storage statefile (%d)", rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
|
||||
stopService=1;
|
||||
break;
|
||||
default:
|
||||
DBG_WARN(0, "Unknown signal %d",s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
89
apps/aqhome-mqttlog/0BUILD
Normal file
89
apps/aqhome-mqttlog/0BUILD
Normal file
@@ -0,0 +1,89 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-mqttlog" install="$(sbindir)" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
init.h
|
||||
fini.h
|
||||
loop.h
|
||||
loop_ipc.h
|
||||
loop_mqtt.h
|
||||
aqhome_mqtt.h
|
||||
aqhome_mqtt_p.h
|
||||
xmlread.h
|
||||
xmlwrite.h
|
||||
c_setdata.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
aqhome_mqtt.c
|
||||
init.c
|
||||
fini.c
|
||||
loop.c
|
||||
loop_ipc.c
|
||||
loop_mqtt.c
|
||||
main.c
|
||||
xmlread.c
|
||||
xmlwrite.c
|
||||
c_setdata.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
aqhmqtt_types
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
types
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
189
apps/aqhome-mqttlog/aqhome_mqtt.c
Normal file
189
apps/aqhome-mqttlog/aqhome_mqtt.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/endpoint_ipcclient.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQHOME_MQTT *AqHomeMqtt_new(void)
|
||||
{
|
||||
AQHOME_MQTT *aqh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHOME_MQTT, aqh);
|
||||
|
||||
return aqh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_free(AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->availableDeviceList);
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
GWEN_DB_Group_free(aqh->dbArgs);
|
||||
free(aqh->pidFile);
|
||||
|
||||
GWEN_FREE_OBJECT(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetBrokerEndpoint(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?(aqh->brokerEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetMqttEndpoint(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?(aqh->mqttEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomeMqtt_GetDbArgs(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?(aqh->dbArgs):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeMqtt_GetPidFile(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->pidFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->pidFile);
|
||||
aqh->pidFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->timeout:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->deviceFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->deviceFile);
|
||||
aqh->deviceFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->availableDeviceList:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->availableDeviceList);
|
||||
aqh->availableDeviceList=dl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
aqh->registeredDeviceList=dl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId)
|
||||
{
|
||||
if (aqh && aqh->registeredDeviceList) {
|
||||
return AQHMQTT_Device_List_GetById(aqh->registeredDeviceList, wantedDeviceId);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No registered devices");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh && aqh->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
|
||||
if (device) {
|
||||
fprintf(stderr, "Registered Devices:\n");
|
||||
while(device) {
|
||||
const char *sDeviceName;
|
||||
const char *sDeviceId;
|
||||
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
fprintf(stderr, " %s (%s)\n", sDeviceId?sDeviceId:"<no id>", sDeviceName?sDeviceName:"<no name>");
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "No registered devices\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "No registered devices\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
51
apps/aqhome-mqttlog/aqhome_mqtt.h
Normal file
51
apps/aqhome-mqttlog/aqhome_mqtt.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTT_H
|
||||
#define AQHOME_MQTT_H
|
||||
|
||||
|
||||
//#include "./mqttvalue.h"
|
||||
//#include "./mqtttopic.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQHOME_MQTT AQHOME_MQTT;
|
||||
|
||||
|
||||
AQHOME_MQTT *AqHomeMqtt_new(void);
|
||||
void AqHomeMqtt_free(AQHOME_MQTT *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetBrokerEndpoint(const AQHOME_MQTT *aqh);
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetMqttEndpoint(const AQHOME_MQTT *aqh);
|
||||
|
||||
GWEN_DB_NODE *AqHomeMqtt_GetDbArgs(const AQHOME_MQTT *aqh);
|
||||
|
||||
const char *AqHomeMqtt_GetPidFile(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s);
|
||||
|
||||
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh);
|
||||
|
||||
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s);
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
||||
|
||||
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
||||
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId);
|
||||
|
||||
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh);
|
||||
|
||||
#endif
|
||||
|
||||
45
apps/aqhome-mqttlog/aqhome_mqtt_p.h
Normal file
45
apps/aqhome-mqttlog/aqhome_mqtt_p.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTT_P_H
|
||||
#define AQHOME_MQTT_P_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/mutex.h>
|
||||
|
||||
|
||||
#define AQHOME_MQTT_DEFAULT_PIDFILE "/var/run/aqhome-mqtt.pid"
|
||||
#define AQHOME_MQTT_DEFAULT_DATADIR "/var/lib/aqhome-mqtt"
|
||||
#define AQHOME_MQTT_DEFAULT_DEVICEFILE "mqttlog/registereddevices.xml"
|
||||
|
||||
#define AQHOME_MQTT_DEFAULT_BROKER_PORT 1899
|
||||
#define AQHOME_MQTT_DEFAULT_BROKER_CLIENTID "mqtt"
|
||||
|
||||
|
||||
|
||||
|
||||
struct AQHOME_MQTT {
|
||||
GWEN_MSG_ENDPOINT *rootEndpoint;
|
||||
GWEN_MSG_ENDPOINT *brokerEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
|
||||
GWEN_MSG_ENDPOINT *mqttEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
char *pidFile;
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
|
||||
AQHMQTT_DEVICE_LIST *availableDeviceList;
|
||||
AQHMQTT_DEVICE_LIST *registeredDeviceList;
|
||||
|
||||
char *deviceFile;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
160
apps/aqhome-mqttlog/c_setdata.c
Normal file
160
apps/aqhome-mqttlog/c_setdata.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./c_setdata.h"
|
||||
#include "aqhome/data/value.h"
|
||||
#include "aqhome/ipc/data/msg_data_set.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const char *valueName, const char *valueData);
|
||||
static void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData);
|
||||
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
DBG_ERROR(NULL, "Received SETDATA request");
|
||||
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||
if (recvdValue) {
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
|
||||
if (valueName && deviceName) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AqHomeMqtt_FindRegisteredDevice(aqh, deviceName);
|
||||
if (device) {
|
||||
char *valueDataFreeable;
|
||||
|
||||
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
|
||||
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||
_sendDataForDevice(aqh, device, valueName, valueDataFreeable);
|
||||
free(valueDataFreeable);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
|
||||
AqHomeMqtt_DumpRegisteredDevices(aqh);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either value name or device name missing in request");
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Request does not contain a value object");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const char *valueName, const char *valueData)
|
||||
{
|
||||
const char *deviceId;
|
||||
|
||||
deviceId=AQHMQTT_Device_GetId(device);
|
||||
if (deviceId && *deviceId) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
AQHMQTT_VALUE *value;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
|
||||
if (value) {
|
||||
/* found value, create publish msg, send */
|
||||
DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
|
||||
_sendValueToMqtt(aqh, deviceId, topic, valueData);
|
||||
}
|
||||
} /* if out */
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
} /* while topic */
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device has no id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
ep=AqHomeMqtt_GetMqttEndpoint(aqh);
|
||||
buf=_createBufferForTopic(deviceId, topic);
|
||||
DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
|
||||
msgOut=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(buf),
|
||||
(const uint8_t*) (valueData?valueData:NULL),
|
||||
valueData?strlen(valueData):0);
|
||||
if (msgOut) {
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Error creating message");
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
const char *s;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
s=AQHMQTT_Topic_GetBeforeId(topic);
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
GWEN_Buffer_AppendString(buf, deviceId);
|
||||
s=AQHMQTT_Topic_GetAfterId(topic);
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-mqttlog/c_setdata.h
Normal file
25
apps/aqhome-mqttlog/c_setdata.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTTLOG_C_SETDATA_H
|
||||
#define AQHOME_MQTTLOG_C_SETDATA_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
|
||||
void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
85
apps/aqhome-mqttlog/fini.c
Normal file
85
apps/aqhome-mqttlog/fini.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./fini.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqtt_Fini(AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
if (aqh->rootEndpoint)
|
||||
_disconnectTree(aqh->rootEndpoint);
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
aqh->rootEndpoint=NULL;
|
||||
aqh->brokerEndpoint=NULL;
|
||||
aqh->mqttEndpoint=NULL;
|
||||
|
||||
AQHMQTT_Device_List_free(aqh->availableDeviceList);
|
||||
aqh->availableDeviceList=NULL;
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
aqh->registeredDeviceList=NULL;
|
||||
|
||||
if (aqh->pidFile)
|
||||
remove(aqh->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epChild;
|
||||
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
||||
while(epChild) {
|
||||
_disconnectTree(epChild);
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
||||
} /* while */
|
||||
|
||||
GWEN_MsgEndpoint_Disconnect(ep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-mqttlog/fini.h
Normal file
23
apps/aqhome-mqttlog/fini.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_FINI_H
|
||||
#define AQHOMEMQTT_FINI_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_Fini(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
489
apps/aqhome-mqttlog/init.c
Normal file
489
apps/aqhome-mqttlog/init.c
Normal file
@@ -0,0 +1,489 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./init.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "./xmlread.h"
|
||||
#include "./xmlwrite.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/endpoint_ipcclient.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
static int _setupBroker(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static int _setupMqtt(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
const char *s;
|
||||
|
||||
dbArgs=GWEN_DB_Group_new("args");
|
||||
rv=_readArgs(argc, argv, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
aqh->dbArgs=dbArgs;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_LOGGER_LEVEL ll;
|
||||
|
||||
ll=GWEN_Logger_Name2Level(s);
|
||||
GWEN_Logger_SetLevel(NULL, ll);
|
||||
}
|
||||
|
||||
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_MQTT_DEFAULT_PIDFILE);
|
||||
if (s && *s) {
|
||||
AqHomeMqtt_SetPidFile(aqh, s);
|
||||
rv=_createPidFile(s);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "devicefile", 0, NULL);
|
||||
if (s && *s) {
|
||||
AqHomeMqtt_SetDeviceFile(aqh, s);
|
||||
}
|
||||
else {
|
||||
GWEN_BUFFER *bufFilename;
|
||||
|
||||
bufFilename=AQH_GetRuntimeFilePath(AQHOME_MQTT_DEFAULT_DEVICEFILE);
|
||||
if (bufFilename) {
|
||||
AqHomeMqtt_SetDeviceFile(aqh, GWEN_Buffer_GetStart(bufFilename));
|
||||
GWEN_Buffer_free(bufFilename);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Could not setup filename for devices, please specify via command line argument");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
|
||||
|
||||
rv=_setupMqtt(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_setupBroker(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
AqHomeMqtt_LoadRuntimeDeviceFiles(aqh);
|
||||
|
||||
AqHomeMqtt_ReloadDeviceFiles(aqh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
DBG_ERROR(NULL, "Loading devices description files");
|
||||
deviceList=AqHomeMqttLog_ReadDataDeviceFiles(aqh);
|
||||
if (deviceList)
|
||||
AqHomeMqtt_SetAvailableDeviceList(aqh, deviceList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
DBG_ERROR(NULL, "Loading registered devices from file \"%s\"", aqh->deviceFile);
|
||||
deviceList=AqHomeMqttLog_ReadDeviceFile(aqh, aqh->deviceFile);
|
||||
if (deviceList)
|
||||
AqHomeMqtt_SetRegisteredDeviceList(aqh, deviceList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=AqHomeMqttLog_WriteDevicesFile(aqh, aqh->registeredDeviceList, aqh->deviceFile);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing devices to \"%s\" (%d)", aqh->deviceFile, rv);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
int pidfd;
|
||||
|
||||
if (remove(pidFilename)==0) {
|
||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (pidfd < 0) {
|
||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
f = fdopen(pidfd, "w");
|
||||
#else /* HAVE_STAT_H */
|
||||
f=fopen(pidFilename,"w+");
|
||||
#endif /* HAVE_STAT_H */
|
||||
|
||||
/* write pid */
|
||||
#ifdef HAVE_GETPID
|
||||
fprintf(f,"%d\n",getpid());
|
||||
#else
|
||||
fprintf(f,"-1\n");
|
||||
#endif
|
||||
if (fclose(f)) {
|
||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupBroker(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *brokerAddress;
|
||||
int brokerPort;
|
||||
const char *brokerClientId;
|
||||
|
||||
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL);
|
||||
if (!(brokerAddress && *brokerAddress))
|
||||
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
|
||||
|
||||
brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, -1);
|
||||
if (brokerPort<0)
|
||||
brokerPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_MQTT_DEFAULT_BROKER_PORT);
|
||||
|
||||
brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOME_MQTT_DEFAULT_BROKER_CLIENTID);
|
||||
|
||||
if (brokerAddress && *brokerAddress && brokerPort) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
GWEN_MSG_ENDPOINT *ipcBaseEndpoint;
|
||||
int rv;
|
||||
|
||||
ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0);
|
||||
ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0);
|
||||
AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId);
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
||||
aqh->brokerEndpoint=ep;
|
||||
|
||||
rv=GWEN_MultilayerEndpoint_StartConnect(ep);
|
||||
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
|
||||
DBG_ERROR(NULL, "Error connecting to broker server %s:%d (%d), will retry later", brokerAddress, brokerPort, rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupMqtt(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *mqttAddress;
|
||||
int mqttPort;
|
||||
const char *mqttClientId;
|
||||
int mqttKeepAlive;
|
||||
|
||||
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL);
|
||||
if (!(mqttAddress && *mqttAddress))
|
||||
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/mqttAddr", 0, "127.0.0.1");
|
||||
|
||||
mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, 1883);
|
||||
if (mqttPort<0)
|
||||
mqttPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/mqttPort", 0, 1883);
|
||||
|
||||
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, "aqhome-mqttlog");
|
||||
if (!(mqttClientId && *mqttClientId))
|
||||
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/mqttClientId", 0, "aqhome-mqttlog");
|
||||
|
||||
mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, 600);
|
||||
|
||||
if (mqttAddress && *mqttAddress && mqttPort) {
|
||||
GWEN_MSG_ENDPOINT *epMqtt;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Connecting to %s (port %d)", mqttAddress, mqttPort);
|
||||
epMqtt=AQH_MqttClientEndpoint_new(mqttClientId, mqttAddress, mqttPort, NULL, 0);
|
||||
if (epMqtt==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint TCP");
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
AQH_MqttClientEndpoint_SetKeepAliveTime(epMqtt, mqttKeepAlive);
|
||||
GWEN_MsgEndpoint_AddFlags(epMqtt, AQH_ENDPOINT2_MQTTCLIENT_FLAGS_SUBSCRIBEALL);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, epMqtt);
|
||||
aqh->mqttEndpoint=epMqtt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
int rv;
|
||||
const GWEN_ARGS args[]= {
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"loglevel", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"L", /* short option */
|
||||
"loglevel", /* long option */
|
||||
I18S("Specify loglevel"), /* short description */
|
||||
I18S("Specify loglevel") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"cfgdir", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"D", /* short option */
|
||||
"cfgdir", /* long option */
|
||||
I18S("Specify the configuration folder"),
|
||||
I18S("Specify the configuration folder")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"charset", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
0, /* short option */
|
||||
"charset", /* long option */
|
||||
I18S("Specify the output character set"), /* short description */
|
||||
I18S("Specify the output character set") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"brokerAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"ba", /* short option */
|
||||
"brokeraddress", /* long option */
|
||||
I18S("Specify the address of the broker server to connect to (disabled if missing)"),
|
||||
I18S("Specify the address of the broker server to connect to (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"brokerPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"bp", /* short option */
|
||||
"brokerport", /* long option */
|
||||
I18S("Specify the port of the broker server (default: 1899)"),
|
||||
I18S("Specify the port of the broker server (default: 1899)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"brokerClientId", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"brokerclientid", /* long option */
|
||||
I18S("Specify client id for the broker server (default: \"nodes\")"),
|
||||
I18S("Specify client id for the broker server (default: \"nodes\")")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"mqttAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"ma", /* short option */
|
||||
"mqttaddress", /* long option */
|
||||
I18S("Specify the address of the MQTT server to connect to (disabled if missing)"),
|
||||
I18S("Specify the address of the MQTT server to connect to (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"mqttPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"mp", /* short option */
|
||||
"mqttport", /* long option */
|
||||
I18S("Specify the port of the MQTT server (default: 1883)"),
|
||||
I18S("Specify the port of the MQTT server (default: 1883)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"mqttClientId", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"mqttclientid", /* long option */
|
||||
I18S("Specify client id for the MQTT server (default: \"aqhomed\")"),
|
||||
I18S("Specify client id for the MQTT server (default: \"aqhomed\")")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"mqttKeepAlive", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"mk", /* short option */
|
||||
"mqttkeepalive", /* long option */
|
||||
I18S("Specify keepalive time in seconds (defaults: 600)"),
|
||||
I18S("Specify keepalive time in seconds (defaults: 600)")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"pidfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"p", /* short option */
|
||||
"pidfile", /* long option */
|
||||
I18S("Specify the PID file"),
|
||||
I18S("Specify the PID file")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"timeout", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"T", /* short option */
|
||||
"timeout", /* long option */
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"devicefile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"d", /* short option */
|
||||
"devicefile", /* long option */
|
||||
I18S("Specify the device file"),
|
||||
I18S("Specify the device file")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"help", /* name */
|
||||
0, /* minnum */
|
||||
0, /* maxnum */
|
||||
"h", /* short option */
|
||||
"help",
|
||||
I18S("Show this help screen."),
|
||||
I18S("Show this help screen.")
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
||||
GWEN_BUFFER *ubuf;
|
||||
|
||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(ubuf,
|
||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
||||
AQHOME_VERSION_STRING,
|
||||
argv[0]);
|
||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
||||
return 1;
|
||||
}
|
||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
||||
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-mqttlog/init.h
Normal file
27
apps/aqhome-mqttlog/init.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_INIT_H
|
||||
#define AQHOMEMQTT_INIT_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv);
|
||||
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh);
|
||||
|
||||
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
57
apps/aqhome-mqttlog/loop.c
Normal file
57
apps/aqhome-mqttlog/loop.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./loop.h"
|
||||
#include "./loop_ipc.h"
|
||||
#include "./loop_mqtt.h"
|
||||
#include "./c_setdata.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/json_read.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
|
||||
|
||||
//#define FULL_DEBUG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqttLog_Loop(AQHOME_MQTT *aqh, int timeoutInMsecs)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
|
||||
AqHomeMqttLog_ReadAndHandleMqttMessages(aqh);
|
||||
AqHomeMqttLog_ReadAndHandleIpcMessages(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,17 +6,21 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_ENDPOINT_NODE_IPC_TCPD_H
|
||||
#define AQH_ENDPOINT_NODE_IPC_TCPD_H
|
||||
#ifndef AQHOMEMQTT_LOOP_H
|
||||
#define AQHOMEMQTT_LOOP_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
AQHOME_API GWEN_MSG_ENDPOINT *AQH_TcpdIpcNodeEndpoint_new(const char *host, int port, const char *name, int groupId);
|
||||
void AqHomeMqttLog_Loop(AQHOME_MQTT *aqh, int timeoutInMsecs);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
87
apps/aqhome-mqttlog/loop_ipc.c
Normal file
87
apps/aqhome-mqttlog/loop_ipc.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./loop_ipc.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "./c_setdata.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/json_read.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
|
||||
|
||||
#define FULL_DEBUG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleIpcMessages(AQHOME_MQTT *aqh)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
epTcp=aqh->brokerEndpoint;
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
|
||||
_handleIpcMsg(aqh, epTcp, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
uint16_t code;
|
||||
uint8_t protoId;
|
||||
|
||||
/* exec IPC message */
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
protoId=GWEN_IpcMsg_GetProtoId(msg);
|
||||
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeMqttLog_HandleSetData(aqh, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if (protoId==0 && code==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||
/* result received */
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
26
apps/aqhome-mqttlog/loop_ipc.h
Normal file
26
apps/aqhome-mqttlog/loop_ipc.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_LOOP_IPC_H
|
||||
#define AQHOMEMQTT_LOOP_IPC_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleIpcMessages(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
501
apps/aqhome-mqttlog/loop_mqtt.c
Normal file
501
apps/aqhome-mqttlog/loop_mqtt.c
Normal file
@@ -0,0 +1,501 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./loop_mqtt.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/json_read.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
|
||||
|
||||
//#define FULL_DEBUG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleMqttMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
static void _handlePublishMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
static int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *topic, const char *value);
|
||||
static void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *dev, AQHMQTT_TOPIC *t, const char *rcvdValue);
|
||||
static void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *dev, AQHMQTT_TOPIC *t, const char *rcvdValue);
|
||||
static void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue);
|
||||
static void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device);
|
||||
static void _sendAnnounceValueMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
|
||||
static AQH_VALUE *_mkMessageValue(const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
|
||||
static int _mqttValueTypeMessageValueType(int t);
|
||||
static int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue);
|
||||
static AQHMQTT_TOPIC *_findMaskMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir);
|
||||
static AQHMQTT_TOPIC *_findTopicMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir);
|
||||
static GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleMqttMessages(AQHOME_MQTT *aqh)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
epTcp=aqh->mqttEndpoint;
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
|
||||
#ifdef FULL_DEBUG
|
||||
DBG_ERROR(NULL, "Received this message:");
|
||||
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
|
||||
#endif
|
||||
_handleMqttMsg(aqh, epTcp, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeMqttLog_SendPing(AQHOME_MQTT *aqh)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Sending PING");
|
||||
epTcp=aqh->mqttEndpoint;
|
||||
msgOut=GWEN_MqttMsg_new(AQH_MQTTMSG_MSGTYPE_PINGREQ, 0, NULL);
|
||||
if (msgOut==NULL) {
|
||||
DBG_ERROR(NULL, "Error creating message");
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMqttMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PUBLISH & 0xf0)) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "PUBLISH message received");
|
||||
#ifdef FULL_DEBUG
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQH_PublishMqttMsg_DumpToBuffer(msg, buf, "received");
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
#endif
|
||||
_handlePublishMsg(aqh, ep, msg);
|
||||
}
|
||||
else if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PINGRESP & 0xf0)) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "PING response received");
|
||||
}
|
||||
else {
|
||||
#ifdef FULL_DEBUG
|
||||
DBG_ERROR(NULL, "Received this message:");
|
||||
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handlePublishMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
char *topic;
|
||||
char *value;
|
||||
|
||||
topic=AQH_PublishMqttMsg_ExtractTopic(msg);
|
||||
value=AQH_PublishMqttMsg_ExtractValue(msg);
|
||||
|
||||
if (topic && value) {
|
||||
int rv;
|
||||
|
||||
rv=_handlePublish(aqh, ep, topic, value);
|
||||
if (rv!=1) {
|
||||
DBG_INFO(NULL, "New topic \"%s\", trying to register", topic);
|
||||
rv=_registerNewDeviceForTopic(aqh, ep, topic, value);
|
||||
if (rv==1) {
|
||||
rv=_handlePublish(aqh, ep, topic, value);
|
||||
if (rv!=1) {
|
||||
DBG_ERROR(NULL, "Topic \"%s\" still not handled, SNH!", topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
|
||||
}
|
||||
free(value);
|
||||
free(topic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue)
|
||||
{
|
||||
if (rcvdTopic && *rcvdTopic) {
|
||||
if (aqh->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
|
||||
while(device) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
const char *sDeviceName;
|
||||
const char *sDeviceId;
|
||||
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=_findTopicMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
#if 0
|
||||
if (topic==NULL) {
|
||||
topic=_findMaskMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
if (topic)
|
||||
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
|
||||
}
|
||||
#endif
|
||||
if (topic) {
|
||||
DBG_INFO(AQH_LOGDOMAIN,
|
||||
"Handling topic \"%s\" for device type %s (id: %s)",
|
||||
rcvdTopic,
|
||||
sDeviceName, sDeviceId?sDeviceId:"<no id>");
|
||||
if (AQHMQTT_Topic_GetTopicType(topic)==AQHMQTT_TopicType_Json)
|
||||
_handleJsonTopic(aqh, ep, device, topic, rcvdValue);
|
||||
else
|
||||
_handleNumTopic(aqh, ep, device, topic, rcvdValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *device, AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
{
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList)
|
||||
_sendMessage(aqh, device, AQHMQTT_Value_List_First(valueList), rcvdValue);
|
||||
else {
|
||||
DBG_INFO(NULL, "No value list in device \"%s\"", AQHMQTT_Device_GetId(device));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *device, AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
{
|
||||
GWEN_JSON_ELEM *jeRoot;
|
||||
|
||||
jeRoot=GWEN_JsonElement_fromString(rcvdValue);
|
||||
if (jeRoot==NULL) {
|
||||
DBG_INFO(NULL, "Could not parse JSON value: %s", rcvdValue);
|
||||
}
|
||||
else {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList) {
|
||||
AQHMQTT_VALUE *value;
|
||||
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
const char *path;
|
||||
|
||||
path=AQHMQTT_Value_GetPath(value);
|
||||
if (path && *path) {
|
||||
GWEN_JSON_ELEM *je;
|
||||
|
||||
je=GWEN_JsonElement_GetElementByPath(jeRoot, path, 0);
|
||||
if (je) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_JsonElement_GetData(je);
|
||||
if (s && *s)
|
||||
_sendMessage(aqh, device, value, s);
|
||||
}
|
||||
}
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
} /* while */
|
||||
}
|
||||
GWEN_JsonElement_free(jeRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue)
|
||||
{
|
||||
int rv;
|
||||
union {double f; uint64_t i;} u;
|
||||
const char *deviceName;
|
||||
|
||||
deviceName=AQHMQTT_Device_GetId(device);
|
||||
rv=GWEN_Text_StringToDouble(rcvdValue, &(u.f));
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Invalid value received from MQTT server (%s)", rcvdValue?rcvdValue:"<empty>");
|
||||
}
|
||||
else {
|
||||
GWEN_MSG *pubMsg;
|
||||
uint64_t arrayToSend[2];
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
arrayToSend[0]=(uint64_t) time(NULL);
|
||||
arrayToSend[1]=u.i;
|
||||
|
||||
msgValue=_mkMessageValue(device, value);
|
||||
|
||||
pubMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
|
||||
msgValue, arrayToSend, 1);
|
||||
if (pubMsg) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "BROKER UPDATE_DATA %s/%s: %f",
|
||||
deviceName?deviceName:"<no device name>",
|
||||
AQH_Value_GetName(msgValue), u.f);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
|
||||
}
|
||||
AQH_Value_free(msgValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
|
||||
{
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList) {
|
||||
const AQHMQTT_VALUE *value;
|
||||
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
_sendAnnounceValueMessage(aqh, device, value);
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
}
|
||||
}
|
||||
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendAnnounceValueMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
|
||||
{
|
||||
GWEN_MSG *pubMsg;
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
msgValue=_mkMessageValue(device, value);
|
||||
pubMsg=AQH_ValuesDataIpcMsg_newForOneValue(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
|
||||
0, msgValue);
|
||||
if (pubMsg) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "BROKER ANNOUNCE_VALUE %s", AQH_Value_GetName(msgValue));
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
|
||||
}
|
||||
AQH_Value_free(msgValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_VALUE *_mkMessageValue(const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
|
||||
{
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
msgValue=AQH_Value_new();
|
||||
AQH_Value_SetDeviceName(msgValue, AQHMQTT_Device_GetId(device));
|
||||
AQH_Value_SetName(msgValue, AQHMQTT_Value_GetName(value));
|
||||
AQH_Value_SetValueUnits(msgValue, AQHMQTT_Value_GetValueUnits(value));
|
||||
AQH_Value_SetValueType(msgValue, _mqttValueTypeMessageValueType(AQHMQTT_Value_GetValueType(value)));
|
||||
return msgValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _mqttValueTypeMessageValueType(int t)
|
||||
{
|
||||
switch(t){
|
||||
case AQHMQTT_ValueType_Sensor: return AQH_ValueType_Sensor;
|
||||
case AQHMQTT_ValueType_Actor: return AQH_ValueType_Actor;
|
||||
default: break;
|
||||
}
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Invalid mqtt value type %d", t);
|
||||
return AQH_ValueType_Sensor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue)
|
||||
{
|
||||
if (rcvdTopic && *rcvdTopic) {
|
||||
if (aqh->availableDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->availableDeviceList);
|
||||
while(device) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=_findMaskMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
if (topic) {
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=_extractDeviceId(topic, rcvdTopic);
|
||||
if (buf) {
|
||||
AQHMQTT_DEVICE *newDevice;
|
||||
|
||||
newDevice=AQHMQTT_Device_dup(device);
|
||||
AQHMQTT_Device_SetId(newDevice, GWEN_Buffer_GetStart(buf));
|
||||
topic=_findMaskMatchingTopic(AQHMQTT_Device_GetTopicList(newDevice), rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
|
||||
if (aqh->registeredDeviceList==NULL)
|
||||
aqh->registeredDeviceList=AQHMQTT_Device_List_new();
|
||||
DBG_ERROR(NULL, "Registered device \"%s\" (%s)", AQHMQTT_Device_GetId(newDevice), AQHMQTT_Device_GetName(newDevice));
|
||||
AQHMQTT_Device_List_Add(newDevice, aqh->registeredDeviceList);
|
||||
_announceDeviceToBroker(aqh, newDevice);
|
||||
GWEN_Buffer_free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC *_findMaskMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir)
|
||||
{
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==dir) {
|
||||
const char *sMask;
|
||||
|
||||
sMask=AQHMQTT_Topic_GetMask(topic);
|
||||
if (sMask && *sMask && GWEN_Text_ComparePattern(rcvdTopic, sMask, 0)!=-1) {
|
||||
/* found a matching topic */
|
||||
return topic;
|
||||
}
|
||||
}
|
||||
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC *_findTopicMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir)
|
||||
{
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==dir) {
|
||||
const char *sTopic;
|
||||
|
||||
sTopic=AQHMQTT_Topic_GetTopic(topic);
|
||||
if (sTopic && *sTopic && strcasecmp(rcvdTopic, sTopic)==0) {
|
||||
return topic;
|
||||
}
|
||||
}
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic)
|
||||
{
|
||||
const char *sBefore;
|
||||
const char *sAfter;
|
||||
|
||||
sBefore=AQHMQTT_Topic_GetBeforeId(topic);
|
||||
sAfter=AQHMQTT_Topic_GetAfterId(topic);
|
||||
|
||||
if (sBefore && *sBefore && sAfter && *sAfter) {
|
||||
GWEN_BUFFER *buf;
|
||||
int rv;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(buf, rcvdTopic);
|
||||
rv=GWEN_Buffer_KeepTextBetweenStrings(buf, sBefore, sAfter, 1);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Could not extract id from [%s] (beforeId=%s, afterId=%s)", rcvdTopic, sBefore, sAfter);
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,19 +6,22 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_ENDPOINT_NODE_IPC_H
|
||||
#define AQH_ENDPOINT_NODE_IPC_H
|
||||
#ifndef AQHOMEMQTT_LOOP_MQTT_H
|
||||
#define AQHOMEMQTT_LOOP_MQTT_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
AQHOME_API GWEN_MSG_ENDPOINT *AQH_IpcNodeEndpoint_new(const char *name, int groupId);
|
||||
void AqHomeMqttLog_ReadAndHandleMqttMessages(AQHOME_MQTT *aqh);
|
||||
int AqHomeMqttLog_SendPing(AQHOME_MQTT *aqh);
|
||||
|
||||
AQHOME_API int AQH_IpcNodeEndpointMgr_LoopOnce(GWEN_MSG_ENDPOINT_MGR *emgr);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
279
apps/aqhome-mqttlog/main.c
Normal file
279
apps/aqhome-mqttlog/main.c
Normal file
@@ -0,0 +1,279 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./init.h"
|
||||
#include "./fini.h"
|
||||
#include "./loop.h"
|
||||
#include "./loop_mqtt.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
#define AQHOME_MQTTLOG_PING_INTERVAL 120
|
||||
#define AQHOME_MQTTLOG_SAVE_INTERVAL 60
|
||||
|
||||
#define FULL_DEBUG
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _serve(AQHOME_MQTT *aqh);
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
AQHOME_MQTT *aqh;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
int rv;
|
||||
GWEN_GUI *gui;
|
||||
const char *s;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhome-mqttlog", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
aqh=AqHomeMqtt_new();
|
||||
rv=AqHomeMqtt_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
if (rv==GWEN_ERROR_CLOSE)
|
||||
return 1;
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL);
|
||||
if (s && *s)
|
||||
GWEN_Gui_SetCharSet(gui, s);
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
_serve(aqh);
|
||||
|
||||
AqHomeMqtt_Fini(aqh);
|
||||
AqHomeMqtt_free(aqh);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _serve(AQHOME_MQTT *aqh)
|
||||
{
|
||||
int rv;
|
||||
int timeout;
|
||||
time_t startTime;
|
||||
time_t lastPingSendTime;
|
||||
time_t lastSaveTime;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
startTime=time(NULL);
|
||||
lastSaveTime=time(NULL);
|
||||
|
||||
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting signal handlers (%d)", rv);
|
||||
return;
|
||||
}
|
||||
|
||||
timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
lastPingSendTime=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
DBG_DEBUG(NULL, "Next loop");
|
||||
AqHomeMqttLog_Loop(aqh, 2000);
|
||||
|
||||
if (timeout) {
|
||||
time_t now;
|
||||
|
||||
now=time(NULL);
|
||||
if ((now-startTime)>timeout) {
|
||||
DBG_ERROR(NULL, "Timeout, stopping service");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (1){
|
||||
time_t now;
|
||||
|
||||
now=time(NULL);
|
||||
if (now-lastPingSendTime>AQHOME_MQTTLOG_PING_INTERVAL) {
|
||||
rv=AqHomeMqttLog_SendPing(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error sending PING");
|
||||
}
|
||||
lastPingSendTime=time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (1){
|
||||
time_t now;
|
||||
|
||||
now=time(NULL);
|
||||
if (now-lastSaveTime>AQHOME_MQTTLOG_SAVE_INTERVAL) {
|
||||
DBG_ERROR(NULL, "Writing device files");
|
||||
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
lastSaveTime=time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} /* while */
|
||||
|
||||
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
|
||||
stopService=1;
|
||||
break;
|
||||
default:
|
||||
DBG_WARN(0, "Unknown signal %d",s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
81
apps/aqhome-mqttlog/types/0BUILD
Normal file
81
apps/aqhome-mqttlog/types/0BUILD
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhmqtt_types" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
device.t2d
|
||||
value.t2d
|
||||
topic.t2d
|
||||
translation.t2d
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
device.c
|
||||
value.c
|
||||
topic.c
|
||||
translation.c
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
device.h
|
||||
device_p.h
|
||||
value.h
|
||||
value_p.h
|
||||
topic.h
|
||||
topic_p.h
|
||||
translation.h
|
||||
translation_p.h
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
75
apps/aqhome-mqttlog/types/device.t2d
Normal file
75
apps/aqhome-mqttlog/types/device.t2d
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_DEVICE" type="pointer">
|
||||
<descr>
|
||||
This object and its objects are used to store registered devices and definitions for possible new devices.
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_DEVICE</identifier>
|
||||
<prefix>AQHMQTT_Device</prefix>
|
||||
<baseFileName>device</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-mqttlog/types/topic.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="char_ptr" maxlen="128">
|
||||
<descr>Only set for registered devices</descr>
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="driver" type="char_ptr" maxlen="64">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="topicList" type="AQHMQTT_TOPIC_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own noconst</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
114
apps/aqhome-mqttlog/types/topic.t2d
Normal file
114
apps/aqhome-mqttlog/types/topic.t2d
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_TOPIC" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_TOPIC</identifier>
|
||||
<prefix>AQHMQTT_Topic</prefix>
|
||||
<baseFileName>topic</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-mqttlog/types/value.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
|
||||
<enum id="AQHMQTT_TOPIC_TYPE" prefix="AQHMQTT_TopicType_">
|
||||
<item name="num" value="0">
|
||||
<descr>numeric type</descr>
|
||||
</item>
|
||||
<item name="json" >
|
||||
<descr>JSON type</descr>
|
||||
</item>
|
||||
</enum>
|
||||
|
||||
<enum id="AQHMQTT_TOPIC_DIR" prefix="AQHMQTT_TopicDir_">
|
||||
<item name="in" value="0"/>
|
||||
<item name="out" />
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="topic" type="char_ptr" maxlen="128">
|
||||
<descr>Only set for registered devices</descr>
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="topicType" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="direction" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="mask" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="beforeId" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="afterId" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="valueList" type="AQHMQTT_VALUE_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
55
apps/aqhome-mqttlog/types/translation.t2d
Normal file
55
apps/aqhome-mqttlog/types/translation.t2d
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_TRANSLATION" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_TRANSLATION</identifier>
|
||||
<prefix>AQHMQTT_Translation</prefix>
|
||||
<baseFileName>translation</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_db
|
||||
with_list1
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="aqhValue" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="driverValue" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
92
apps/aqhome-mqttlog/types/value.t2d
Normal file
92
apps/aqhome-mqttlog/types/value.t2d
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_VALUE" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_VALUE</identifier>
|
||||
<prefix>AQHMQTT_Value</prefix>
|
||||
<baseFileName>value</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-mqttlog/types/translation.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
|
||||
<enum id="AQHMQTT_VALUE_TYPE" prefix="AQHMQTT_ValueType_">
|
||||
<item name="sensor" value="0">
|
||||
<descr>sensor</descr>
|
||||
</item>
|
||||
<item name="actor" >
|
||||
<descr>actor</descr>
|
||||
</item>
|
||||
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="valueType" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="valueUnits" type="char_ptr" maxlen="32">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="path" type="char_ptr" maxlen="256">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="translationList" type="AQHMQTT_TRANSLATION_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
467
apps/aqhome-mqttlog/xmlread.c
Normal file
467
apps/aqhome-mqttlog/xmlread.c
Normal file
@@ -0,0 +1,467 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./xmlread.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "aqhome-mqttlog/types/topic.h"
|
||||
#include "aqhome-mqttlog/types/value.h"
|
||||
#include "aqhome-mqttlog/types/translation.h"
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/xml.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl);
|
||||
static int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList);
|
||||
static int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList);
|
||||
static AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode);
|
||||
static AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
|
||||
static AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode);
|
||||
static AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
|
||||
static AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode);
|
||||
static AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
|
||||
static AQHMQTT_TRANSLATION *_readXmlTranslation(AQHOME_MQTT *aqh, GWEN_XMLNODE *translationNode);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHMQTT_Device_List_new();
|
||||
rv=_readDeviceFileToList(aqh, sFilename, deviceList);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" not found", sFilename);
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDataDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/mqtt", "*.xml");
|
||||
if (sl) {
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=_readDeviceFiles(aqh, sl);
|
||||
GWEN_StringList_free(sl);
|
||||
if (deviceList==NULL) {
|
||||
DBG_INFO(NULL, "Error reading data device files");
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No data device files");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl)
|
||||
{
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHMQTT_Device_List_new();
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
while(se) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Reading device file \"%s\"", s);
|
||||
rv=_readDeviceFileToList(aqh, s, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
|
||||
}
|
||||
}
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
}
|
||||
|
||||
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_XMLNODE *deviceListNode;
|
||||
int rv;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
||||
rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL);
|
||||
if (deviceListNode==NULL)
|
||||
deviceListNode=rootNode;
|
||||
|
||||
rv=_readXmlDevices(aqh, deviceListNode, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *deviceNode;
|
||||
|
||||
deviceNode=GWEN_XMLNode_FindFirstTag(deviceListNode, "device", NULL, NULL);
|
||||
if (deviceNode) {
|
||||
while(deviceNode) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL);
|
||||
if (driverName && *driverName && strcasecmp(driverName, "mqtt")==0) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=_readXmlDevice(aqh, deviceNode);
|
||||
if (device==NULL) {
|
||||
DBG_INFO(NULL, "Error reading device from XML");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
else {
|
||||
const char *sDeviceId;
|
||||
const char *sDeviceName;
|
||||
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
if (sDeviceId && *sDeviceId) {
|
||||
DBG_ERROR(NULL, "Adding device \"%s\" (%s) to list", sDeviceId, sDeviceName?sDeviceName:"<no type name>");
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Adding device type \"%s\" to list", sDeviceName?sDeviceName:"<no type name>");
|
||||
}
|
||||
AQHMQTT_Device_List_Add(device, deviceList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device is not an MQTT device, ignoring");
|
||||
}
|
||||
deviceNode=GWEN_XMLNode_FindNextTag(deviceNode, "device", NULL, NULL);
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <device> element found");
|
||||
return GWEN_ERROR_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
AQHMQTT_DEVICE *device;
|
||||
GWEN_XMLNODE *topicsNode;
|
||||
|
||||
device=AQHMQTT_Device_new();
|
||||
AQHMQTT_Device_SetId(device, GWEN_XMLNode_GetProperty(deviceNode, "id", NULL));
|
||||
AQHMQTT_Device_SetName(device, GWEN_XMLNode_GetProperty(deviceNode, "name", NULL));
|
||||
AQHMQTT_Device_SetDriver(device, GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL));
|
||||
|
||||
topicsNode=GWEN_XMLNode_FindFirstTag(deviceNode, "mqtttopics", NULL, NULL);
|
||||
if (topicsNode) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=_readXmlTopicList(aqh, topicsNode);
|
||||
if (topicList)
|
||||
AQHMQTT_Device_SetTopicList(device, topicList);
|
||||
else {
|
||||
DBG_INFO(NULL, "No mqtt topics read");
|
||||
AQHMQTT_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <mqtttopics> element");
|
||||
AQHMQTT_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode)
|
||||
{
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
GWEN_XMLNODE *topicNode;
|
||||
|
||||
topicList=AQHMQTT_Topic_List_new();
|
||||
topicNode=GWEN_XMLNode_FindFirstTag(parentNode, "mqtttopic", NULL, NULL);
|
||||
while(topicNode) {
|
||||
AQHMQTT_TOPIC *topic=_readXmlTopic(aqh, topicNode);
|
||||
if (topic)
|
||||
AQHMQTT_Topic_List_Add(topic, topicList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <mqtttopic> element");
|
||||
AQHMQTT_Topic_List_free(topicList);
|
||||
return NULL;
|
||||
}
|
||||
topicNode=GWEN_XMLNode_FindNextTag(topicNode, "mqtttopic", NULL, NULL);
|
||||
}
|
||||
if (AQHMQTT_Topic_List_GetCount(topicList)<1) {
|
||||
AQHMQTT_Topic_List_free(topicList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return topicList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode)
|
||||
{
|
||||
AQHMQTT_TOPIC *topic;
|
||||
GWEN_XMLNODE *valuesNode;
|
||||
int i;
|
||||
const char *s;
|
||||
|
||||
topic=AQHMQTT_Topic_new();
|
||||
s=GWEN_XMLNode_GetProperty(topicNode, "type", NULL);
|
||||
i=AQHMQTT_TopicType_fromString(s);
|
||||
if (i==AQHMQTT_TopicType_Unknown) {
|
||||
DBG_ERROR(NULL, "Invalid topic type \"%s\"", s?s:"<empty>");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
AQHMQTT_Topic_SetTopicType(topic, i);
|
||||
|
||||
s=GWEN_XMLNode_GetProperty(topicNode, "direction", NULL);
|
||||
i=AQHMQTT_TopicDir_fromString(s);
|
||||
if (i==AQHMQTT_TopicDir_Unknown) {
|
||||
DBG_ERROR(NULL, "Invalid topic direction \"%s\"", s?s:"<empty>");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
AQHMQTT_Topic_SetDirection(topic, i);
|
||||
|
||||
AQHMQTT_Topic_SetName(topic, GWEN_XMLNode_GetProperty(topicNode, "name", NULL));
|
||||
AQHMQTT_Topic_SetTopic(topic, GWEN_XMLNode_GetCharValue(topicNode, "topic", NULL));
|
||||
AQHMQTT_Topic_SetMask(topic, GWEN_XMLNode_GetCharValue(topicNode, "mask", NULL));
|
||||
AQHMQTT_Topic_SetBeforeId(topic, GWEN_XMLNode_GetCharValue(topicNode, "beforeId", NULL));
|
||||
AQHMQTT_Topic_SetAfterId(topic, GWEN_XMLNode_GetCharValue(topicNode, "afterId", NULL));
|
||||
|
||||
valuesNode=GWEN_XMLNode_FindFirstTag(topicNode, "values", NULL, NULL);
|
||||
if (valuesNode) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=_readXmlValueList(aqh, valuesNode);
|
||||
if (valueList)
|
||||
AQHMQTT_Topic_SetValueList(topic, valueList);
|
||||
else {
|
||||
DBG_INFO(NULL, "No values read");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <values> element");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return topic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode)
|
||||
{
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
GWEN_XMLNODE *valueNode;
|
||||
|
||||
valueList=AQHMQTT_Value_List_new();
|
||||
valueNode=GWEN_XMLNode_FindFirstTag(parentNode, "value", NULL, NULL);
|
||||
while(valueNode) {
|
||||
AQHMQTT_VALUE *value=_readXmlValue(aqh, valueNode);
|
||||
if (value)
|
||||
AQHMQTT_Value_List_Add(value, valueList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <value> element");
|
||||
AQHMQTT_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
valueNode=GWEN_XMLNode_FindNextTag(valueNode, "value", NULL, NULL);
|
||||
}
|
||||
if (AQHMQTT_Value_List_GetCount(valueList)<1) {
|
||||
AQHMQTT_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return valueList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode)
|
||||
{
|
||||
AQHMQTT_VALUE *value;
|
||||
GWEN_XMLNODE *translationNode;
|
||||
const char *s;
|
||||
int i;
|
||||
|
||||
value=AQHMQTT_Value_new();
|
||||
AQHMQTT_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL));
|
||||
AQHMQTT_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL));
|
||||
AQHMQTT_Value_SetPath(value, GWEN_XMLNode_GetProperty(valueNode, "path", NULL));
|
||||
|
||||
s=GWEN_XMLNode_GetProperty(valueNode, "type", NULL);
|
||||
i=AQHMQTT_ValueType_fromString(s);
|
||||
if (i==AQHMQTT_ValueType_Unknown) {
|
||||
DBG_ERROR(NULL, "Invalid value type \"%s\"", s?s:"<empty>");
|
||||
AQHMQTT_Value_free(value);
|
||||
return NULL;
|
||||
}
|
||||
AQHMQTT_Value_SetValueType(value, i);
|
||||
|
||||
translationNode=GWEN_XMLNode_FindFirstTag(valueNode, "translations", NULL, NULL);
|
||||
if (translationNode) {
|
||||
AQHMQTT_TRANSLATION_LIST *translationList;
|
||||
|
||||
translationList=_readXmlTranslationList(aqh, translationNode);
|
||||
if (translationList) {
|
||||
DBG_INFO(NULL, "Translations read");
|
||||
AQHMQTT_Value_SetTranslationList(value, translationList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <translations> element");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode)
|
||||
{
|
||||
AQHMQTT_TRANSLATION_LIST *translationList;
|
||||
GWEN_XMLNODE *translationNode;
|
||||
|
||||
translationList=AQHMQTT_Translation_List_new();
|
||||
translationNode=GWEN_XMLNode_FindFirstTag(parentNode, "translation", NULL, NULL);
|
||||
while(translationNode) {
|
||||
AQHMQTT_TRANSLATION *translation=_readXmlTranslation(aqh, translationNode);
|
||||
if (translation)
|
||||
AQHMQTT_Translation_List_Add(translation, translationList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <translation> element");
|
||||
AQHMQTT_Translation_List_free(translationList);
|
||||
return NULL;
|
||||
}
|
||||
translationNode=GWEN_XMLNode_FindNextTag(translationNode, "translation", NULL, NULL);
|
||||
}
|
||||
if (AQHMQTT_Translation_List_GetCount(translationList)<1) {
|
||||
AQHMQTT_Translation_List_free(translationList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return translationList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TRANSLATION *_readXmlTranslation(AQHOME_MQTT *aqh, GWEN_XMLNODE *translationNode)
|
||||
{
|
||||
const char *sAqhValue;
|
||||
const char *sDriverValue;
|
||||
|
||||
sAqhValue=GWEN_XMLNode_GetProperty(translationNode, "aqhValue", NULL);
|
||||
sDriverValue=GWEN_XMLNode_GetProperty(translationNode, "driverValue", NULL);
|
||||
if (sAqhValue && *sAqhValue && sDriverValue && *sDriverValue) {
|
||||
AQHMQTT_TRANSLATION *translation;
|
||||
|
||||
translation=AQHMQTT_Translation_new();
|
||||
AQHMQTT_Translation_SetAqhValue(translation, sAqhValue);
|
||||
AQHMQTT_Translation_SetDriverValue(translation, sDriverValue);
|
||||
return translation;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Either AqhValue or DriverValue missing in device description file");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
26
apps/aqhome-mqttlog/xmlread.h
Normal file
26
apps/aqhome-mqttlog/xmlread.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTTLOG_XMLREAD_H
|
||||
#define AQHOME_MQTTLOG_XMLREAD_H
|
||||
|
||||
|
||||
#include "aqhome-mqttlog/aqhome_mqtt.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDataDeviceFiles(AQHOME_MQTT *aqh);
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
249
apps/aqhome-mqttlog/xmlwrite.c
Normal file
249
apps/aqhome-mqttlog/xmlwrite.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./xmlwrite.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "aqhome-mqttlog/types/topic.h"
|
||||
#include "aqhome-mqttlog/types/value.h"
|
||||
#include "aqhome-mqttlog/types/translation.h"
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/xml.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _writeDevicesToXml(const AQHMQTT_DEVICE_LIST *deviceList, GWEN_XMLNODE *node);
|
||||
static void _writeDeviceToXml(const AQHMQTT_DEVICE *device, GWEN_XMLNODE *node);
|
||||
static void _writeTopicToXml(const AQHMQTT_TOPIC *topic, GWEN_XMLNODE *node);
|
||||
static void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node);
|
||||
static void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation);
|
||||
static void _setXmlPropertyIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value);
|
||||
static void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int AqHomeMqttLog_WriteDevicesFile(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Could not access file \"%s\"", sFilename);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
else {
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_BUFFER *nbuf;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "root");
|
||||
_writeDevicesToXml(deviceList, rootNode);
|
||||
|
||||
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(nbuf, sFilename);
|
||||
GWEN_Buffer_AppendString(nbuf, ".tmp");
|
||||
unlink(GWEN_Buffer_GetStart(nbuf));
|
||||
rv=GWEN_XMLNode_WriteFile(rootNode,
|
||||
GWEN_Buffer_GetStart(nbuf),
|
||||
GWEN_XML_FLAGS_SIMPLE | GWEN_XML_FLAGS_HANDLE_HEADERS | GWEN_XML_FLAGS_INDENT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error writing XML file \"%s\": %d", GWEN_Buffer_GetStart(nbuf), rv);
|
||||
GWEN_Buffer_free(nbuf);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
if (rename(GWEN_Buffer_GetStart(nbuf), sFilename)<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error renaming \"%s\"->\"%s\": %d (%s)",
|
||||
GWEN_Buffer_GetStart(nbuf), sFilename, errno, strerror(errno));
|
||||
GWEN_Buffer_free(nbuf);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
GWEN_Buffer_free(nbuf);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeDevicesToXml(const AQHMQTT_DEVICE_LIST *deviceList, GWEN_XMLNODE *node)
|
||||
{
|
||||
if (deviceList && AQHMQTT_Device_List_GetCount(deviceList)) {
|
||||
GWEN_XMLNODE *nDevices;
|
||||
const AQHMQTT_DEVICE *device;
|
||||
|
||||
nDevices=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "devices");
|
||||
device=AQHMQTT_Device_List_First(deviceList);
|
||||
while(device) {
|
||||
GWEN_XMLNODE *nDevice;
|
||||
|
||||
nDevice=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "device");
|
||||
_writeDeviceToXml(device, nDevice);
|
||||
GWEN_XMLNode_AddChild(nDevices, nDevice);
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nDevices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _writeDeviceToXml(const AQHMQTT_DEVICE *device, GWEN_XMLNODE *node)
|
||||
{
|
||||
const AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
_setXmlPropertyIfNotNull(node, "id", AQHMQTT_Device_GetId(device));
|
||||
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Device_GetName(device));
|
||||
_setXmlPropertyIfNotNull(node, "driver", AQHMQTT_Device_GetDriver(device));
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList && AQHMQTT_Topic_List_GetCount(topicList)) {
|
||||
GWEN_XMLNODE *nTopics;
|
||||
const AQHMQTT_TOPIC *topic;
|
||||
|
||||
nTopics=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "mqtttopics");
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
GWEN_XMLNODE *nTopic;
|
||||
|
||||
nTopic=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "mqtttopic");
|
||||
_writeTopicToXml(topic, nTopic);
|
||||
GWEN_XMLNode_AddChild(nTopics, nTopic);
|
||||
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nTopics);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void _writeTopicToXml(const AQHMQTT_TOPIC *topic, GWEN_XMLNODE *node)
|
||||
{
|
||||
const AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
GWEN_XMLNode_SetProperty(node, "type", AQHMQTT_TopicType_toString(AQHMQTT_Topic_GetTopicType(topic)));
|
||||
GWEN_XMLNode_SetProperty(node, "direction", AQHMQTT_TopicDir_toString(AQHMQTT_Topic_GetDirection(topic)));
|
||||
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Topic_GetName(topic));
|
||||
_setXmlCharValueIfNotNull(node, "topic", AQHMQTT_Topic_GetTopic(topic));
|
||||
_setXmlCharValueIfNotNull(node, "mask", AQHMQTT_Topic_GetMask(topic));
|
||||
_setXmlCharValueIfNotNull(node, "beforeId", AQHMQTT_Topic_GetBeforeId(topic));
|
||||
_setXmlCharValueIfNotNull(node, "afterId", AQHMQTT_Topic_GetAfterId(topic));
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList && AQHMQTT_Value_List_GetCount(valueList)) {
|
||||
GWEN_XMLNODE *nValues;
|
||||
const AQHMQTT_VALUE *value;
|
||||
|
||||
nValues=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "values");
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
GWEN_XMLNODE *nValue;
|
||||
|
||||
nValue=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "value");
|
||||
_writeValueToXml(value, nValue);
|
||||
GWEN_XMLNode_AddChild(nValues, nValue);
|
||||
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node)
|
||||
{
|
||||
const AQHMQTT_TRANSLATION_LIST *translationList;
|
||||
|
||||
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Value_GetName(value));
|
||||
_setXmlPropertyIfNotNull(node, "units", AQHMQTT_Value_GetValueUnits(value));
|
||||
_setXmlPropertyIfNotNull(node, "path", AQHMQTT_Value_GetPath(value));
|
||||
GWEN_XMLNode_SetProperty(node, "type", AQHMQTT_ValueType_toString(AQHMQTT_Value_GetValueType(value)));
|
||||
|
||||
translationList=AQHMQTT_Value_GetTranslationList(value);
|
||||
if (translationList && AQHMQTT_Translation_List_GetCount(translationList)) {
|
||||
GWEN_XMLNODE *nTranslations;
|
||||
const AQHMQTT_TRANSLATION *translation;
|
||||
|
||||
nTranslations=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "translations");
|
||||
translation=AQHMQTT_Translation_List_First(translationList);
|
||||
while(translation) {
|
||||
GWEN_XMLNODE *nTranslation;
|
||||
|
||||
nTranslation=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "transaction");
|
||||
_writeTranslationToXml(translation, nTranslation);
|
||||
GWEN_XMLNode_AddChild(nTranslations, nTranslation);
|
||||
|
||||
translation=AQHMQTT_Translation_List_Next(translation);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nTranslations);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation)
|
||||
{
|
||||
_setXmlPropertyIfNotNull(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t));
|
||||
_setXmlPropertyIfNotNull(nTranslation, "driverValue", AQHMQTT_Translation_GetDriverValue(t));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setXmlPropertyIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value)
|
||||
{
|
||||
if (value && *value)
|
||||
GWEN_XMLNode_SetProperty(n, name, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value)
|
||||
{
|
||||
if (value && *value)
|
||||
GWEN_XMLNode_SetCharValue(n, name, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-mqttlog/xmlwrite.h
Normal file
24
apps/aqhome-mqttlog/xmlwrite.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTTLOG_XMLWRITE_H
|
||||
#define AQHOME_MQTTLOG_XMLWRITE_H
|
||||
|
||||
|
||||
#include "aqhome-mqttlog/aqhome_mqtt.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeMqttLog_WriteDevicesFile(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
95
apps/aqhome-nodes/0BUILD
Normal file
95
apps/aqhome-nodes/0BUILD
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-nodes" install="$(sbindir)" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
aqhomed.h
|
||||
aqhomed_p.h
|
||||
init.h
|
||||
fini.h
|
||||
loop.h
|
||||
loop_broker.h
|
||||
loop_tty.h
|
||||
loop_tty_ipc.h
|
||||
loop_tty_broker.h
|
||||
loop_ipc.h
|
||||
db.h
|
||||
tty_log.h
|
||||
devicesread.h
|
||||
devicesdump.h
|
||||
r_setdata.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
main.c
|
||||
aqhomed.c
|
||||
init.c
|
||||
fini.c
|
||||
loop.c
|
||||
loop_broker.c
|
||||
loop_tty.c
|
||||
loop_tty_ipc.c
|
||||
loop_tty_broker.c
|
||||
loop_ipc.c
|
||||
db.c
|
||||
tty_log.c
|
||||
devicesread.c
|
||||
devicesdump.c
|
||||
r_setdata.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhnodes_types
|
||||
aqhome
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
types
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
221
apps/aqhome-nodes/aqhomed.c
Normal file
221
apps/aqhome-nodes/aqhomed.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQHOMED *AqHomed_new(void)
|
||||
{
|
||||
AQHOMED *aqh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHOMED, aqh);
|
||||
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
|
||||
aqh->nodeDb=AQH_NodeDb_new();
|
||||
aqh->requestTree=GWEN_MsgRequest_new();
|
||||
|
||||
return aqh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomed_free(AQHOMED *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgRequest_free(aqh->requestTree);
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
aqh->rootEndpoint=NULL;
|
||||
aqh->ttyEndpoint=NULL;
|
||||
aqh->ipcdEndpoint=NULL;
|
||||
aqh->brokerEndpoint=NULL;
|
||||
GWEN_DB_Group_free(aqh->dbArgs);
|
||||
AQH_NodeDb_free(aqh->nodeDb);
|
||||
aqh->dbArgs=NULL;
|
||||
free(aqh->logFile);
|
||||
free(aqh->pidFile);
|
||||
free(aqh->dbFile);
|
||||
|
||||
GWEN_FREE_OBJECT(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomed_GetTtyEndpoint(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->ttyEndpoint:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->ipcdEndpoint:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomed_GetBrokerEndpoint(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->brokerEndpoint:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->dbArgs:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomed_GetLogFile(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->logFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomed_SetLogFile(AQHOMED *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->logFile);
|
||||
aqh->logFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomed_GetPidFile(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->pidFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomed_SetPidFile(AQHOMED *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->pidFile);
|
||||
aqh->pidFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomed_GetDbFile(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->dbFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomed_SetDbFile(AQHOMED *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->dbFile);
|
||||
aqh->dbFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomed_GetTimeout(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->timeout:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_REQUEST *AqHomed_GetRequestTree(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->requestTree:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomed_AddRequestToTree(AQHOMED *aqh, GWEN_MSG_REQUEST *rq)
|
||||
{
|
||||
if (aqh && rq)
|
||||
GWEN_MsgRequest_Tree2_AddChild(aqh->requestTree, rq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AQHNODE_DEVICE_LIST *AqHomed_GetDeviceDefList(const AQHOMED *aqh)
|
||||
{
|
||||
return aqh?aqh->deviceDefList:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AQHNODE_DEVICE *AqHomed_FindDeviceDef(const AQHOMED *aqh, uint32_t manufacturer, uint16_t deviceType, uint16_t deviceVersion)
|
||||
{
|
||||
if (aqh && aqh->deviceDefList) {
|
||||
const AQHNODE_DEVICE *device;
|
||||
|
||||
device=AQHNODE_Device_List_First(aqh->deviceDefList);
|
||||
while(device) {
|
||||
if (AQHNODE_Device_GetManufacturer(device)==manufacturer &&
|
||||
AQHNODE_Device_GetDeviceType(device)==deviceType &&
|
||||
AQHNODE_Device_GetDeviceVersion(device)==(deviceVersion & 0xff00))
|
||||
return device;
|
||||
device=AQHNODE_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AQHNODE_DEVICE *AqHomed_GetDeviceDefByName(const AQHOMED *aqh, const char *name)
|
||||
{
|
||||
if (aqh && aqh->deviceDefList && name)
|
||||
return AQHNODE_Device_List_GetByName(aqh->deviceDefList, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
59
apps/aqhome-nodes/aqhomed.h
Normal file
59
apps/aqhome-nodes/aqhomed.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_H
|
||||
#define AQHOMED_H
|
||||
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/request.h>
|
||||
|
||||
|
||||
#define AQHOME_ENDPOINTGROUP_NODE 1
|
||||
#define AQHOME_ENDPOINTGROUP_IPC 2
|
||||
#define AQHOME_ENDPOINTGROUP_MQTT 4
|
||||
|
||||
|
||||
typedef struct AQHOMED AQHOMED;
|
||||
|
||||
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
|
||||
AQHOMED *AqHomed_new(void);
|
||||
void AqHomed_free(AQHOMED *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomed_GetTtyEndpoint(const AQHOMED *aqh);
|
||||
GWEN_MSG_ENDPOINT *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh);
|
||||
GWEN_MSG_ENDPOINT *AqHomed_GetBrokerEndpoint(const AQHOMED *aqh);
|
||||
|
||||
GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh);
|
||||
|
||||
const char *AqHomed_GetLogFile(const AQHOMED *aqh);
|
||||
void AqHomed_SetLogFile(AQHOMED *aqh, const char *s);
|
||||
|
||||
const char *AqHomed_GetPidFile(const AQHOMED *aqh);
|
||||
void AqHomed_SetPidFile(AQHOMED *aqh, const char *s);
|
||||
|
||||
const char *AqHomed_GetDbFile(const AQHOMED *aqh);
|
||||
void AqHomed_SetDbFile(AQHOMED *aqh, const char *s);
|
||||
|
||||
int AqHomed_GetTimeout(const AQHOMED *aqh);
|
||||
|
||||
GWEN_MSG_REQUEST *AqHomed_GetRequestTree(const AQHOMED *aqh);
|
||||
void AqHomed_AddRequestToTree(AQHOMED *aqh, GWEN_MSG_REQUEST *rq);
|
||||
|
||||
const AQHNODE_DEVICE_LIST *AqHomed_GetDeviceDefList(const AQHOMED *aqh);
|
||||
const AQHNODE_DEVICE *AqHomed_FindDeviceDef(const AQHOMED *aqh, uint32_t manufacturer, uint16_t deviceType, uint16_t deviceVersion);
|
||||
const AQHNODE_DEVICE *AqHomed_GetDeviceDefByName(const AQHOMED *aqh, const char *name);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
53
apps/aqhome-nodes/aqhomed_p.h
Normal file
53
apps/aqhome-nodes/aqhomed_p.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_P_H
|
||||
#define AQHOMED_P_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
#include "aqhome/nodes/nodedb.h"
|
||||
|
||||
|
||||
/* default values */
|
||||
#define AQHOMED_DEFAULT_NODEADDR 240
|
||||
#define AQHOMED_DEFAULT_PIDFILE "/var/run/aqhomed-node.pid"
|
||||
#define AQHOMED_DEFAULT_DEVICE "/dev/ttyUSB0"
|
||||
#define AQHOMED_DEFAULT_IPC_PORT 45454
|
||||
#define AQHOMED_DEFAULT_BROKER_PORT 1899
|
||||
#define AQHOMED_DEFAULT_BROKER_CLIENTID "nodes"
|
||||
|
||||
|
||||
|
||||
struct AQHOMED {
|
||||
GWEN_MSG_ENDPOINT *rootEndpoint;
|
||||
|
||||
GWEN_MSG_ENDPOINT *ttyEndpoint;
|
||||
GWEN_MSG_ENDPOINT *ipcdEndpoint;
|
||||
|
||||
GWEN_MSG_ENDPOINT *brokerEndpoint;
|
||||
|
||||
AQH_NODE_DB *nodeDb;
|
||||
AQHNODE_DEVICE_LIST *deviceDefList;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
char *dbFile;
|
||||
char *logFile;
|
||||
char *pidFile;
|
||||
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
|
||||
int nodeAddress;
|
||||
|
||||
GWEN_MSG_REQUEST *requestTree;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
442
apps/aqhome-nodes/db.c
Normal file
442
apps/aqhome-nodes/db.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./db.h"
|
||||
#include "./aqhomed_p.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_sendstats.h"
|
||||
#include "aqhome/msg/msg_recvstats.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_value3.h"
|
||||
#include "aqhome/msg/msg_needaddr.h"
|
||||
#include "aqhome/msg/msg_claimaddr.h"
|
||||
#include "aqhome/msg/msg_haveaddr.h"
|
||||
#include "aqhome/msg/msg_device.h"
|
||||
#include "aqhome/msg/msg_flashready.h"
|
||||
|
||||
#include "aqhome/data/value.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/timestamp.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgValue3(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
static void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid);
|
||||
static void _updateTimestampLastChange(AQH_NODE_INFO *ni);
|
||||
static void _assignDeviceId(AQHOMED *aqh, AQH_NODE_INFO *ni, uint32_t uid);
|
||||
|
||||
static void _announceNodeValues(AQHOMED *aqh, const AQH_NODE_INFO *ni);
|
||||
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
|
||||
static void _announceValue(AQHOMED *aqh, uint32_t uid, const AQHNODE_VALUE *v);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
int msgIsValid;
|
||||
uint8_t msgType;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN,
|
||||
" - msg %d (%s) from %d to %d",
|
||||
AQH_NodeMsg_GetMsgType(msg),
|
||||
AQH_NodeMsg_MsgTypeToChar(AQH_NodeMsg_GetMsgType(msg)),
|
||||
AQH_NodeMsg_GetSourceAddress(msg),
|
||||
AQH_NodeMsg_GetDestAddress(msg));
|
||||
|
||||
msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg));
|
||||
msgType=AQH_NodeMsg_GetMsgType(msg);
|
||||
|
||||
if (msgIsValid) {
|
||||
switch(msgType) {
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: _handleMsgComSendStat(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: _handleMsgComRecvStat(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_VALUE2: _handleMsgValue2(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_VALUE_REPORT: _handleMsgValue3(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_NEED_ADDRESS: _handleMsgNeedAddress(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleMsgClaimAddress(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_HAVE_ADDRESS: _handleMsgHaveAddress(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(aqh, msg); break;
|
||||
case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(aqh, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomed_WriteNodeDb(AQHOMED *aqh)
|
||||
{
|
||||
if (aqh->dbFile) {
|
||||
GWEN_DB_NODE *dbNodeDb;
|
||||
|
||||
AQH_NodeDb_ClearModified(aqh->nodeDb);
|
||||
dbNodeDb=GWEN_DB_Group_new("nodeDb");
|
||||
AQH_NodeDb_toDb(aqh->nodeDb, dbNodeDb);
|
||||
GWEN_DB_WriteFile(dbNodeDb, aqh->dbFile, GWEN_DB_FLAGS_DEFAULT);
|
||||
GWEN_DB_Group_free(dbNodeDb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_Value2Msg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgValue3(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_Value3Msg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_NeedAddrMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_ClaimAddrMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_HaveAddrMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_SendStatsMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
AQH_NodeInfo_SetStatsPacketsOut(ni, AQH_SendStatsMsg_GetPacketsOut(msg));
|
||||
AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMsg_GetCollisions(msg));
|
||||
AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMsg_GetBusyErrors(msg));
|
||||
AQH_NodeDb_SetModified(aqh->nodeDb);
|
||||
_updateTimestampLastChange(ni);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_RecvStatsMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
AQH_NodeInfo_SetStatsPacketsIn(ni, AQH_RecvStatsMsg_GetPacketsIn(msg));
|
||||
AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMsg_GetCrcErrors(msg));
|
||||
AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMsg_GetIoErrors(msg));
|
||||
AQH_NodeDb_SetModified(aqh->nodeDb);
|
||||
_updateTimestampLastChange(ni);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_DeviceMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni) {
|
||||
const char *s;
|
||||
|
||||
AQH_NodeInfo_SetManufacturer(ni, AQH_DeviceMsg_GetManufacturer(msg));
|
||||
AQH_NodeInfo_SetDeviceType(ni, AQH_DeviceMsg_GetDeviceType(msg));
|
||||
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_DeviceMsg_GetDeviceVersion(msg)<<8)+AQH_DeviceMsg_GetDeviceRevision(msg));
|
||||
AQH_NodeInfo_SetFirmwareVersion(ni,
|
||||
(AQH_DeviceMsg_GetFirmwareVariant(msg)<<24) |
|
||||
(AQH_DeviceMsg_GetFirmwareVersionMajor(msg)<<16) |
|
||||
(AQH_DeviceMsg_GetFirmwareVersionMinor(msg)<<8) |
|
||||
AQH_DeviceMsg_GetFirmwareVersionPatchlevel(msg));
|
||||
s=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (!(s && *s))
|
||||
_assignDeviceId(aqh, ni, uid);
|
||||
_updateTimestampLastChange(ni);
|
||||
AQH_NodeDb_SetModified(aqh->nodeDb);
|
||||
if (uid!=0x00000000L && uid!=0xffffffff)
|
||||
_announceNodeValues(aqh, ni);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _announceNodeValues(AQHOMED *aqh, const AQH_NODE_INFO *ni)
|
||||
{
|
||||
const char *devName;
|
||||
|
||||
devName=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (devName) {
|
||||
const AQHNODE_DEVICE *devInfo;
|
||||
|
||||
devInfo=AqHomed_GetDeviceDefByName(aqh, devName);
|
||||
if (devInfo) {
|
||||
const AQHNODE_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHNODE_Device_GetValueList(devInfo);
|
||||
if (valueList) {
|
||||
const AQHNODE_VALUE *v;
|
||||
|
||||
v=AQHNODE_Value_List_First(valueList);
|
||||
while(v) {
|
||||
DBG_INFO(NULL, "Announcing value \"%08x/%s\" (%d=%s)",
|
||||
AQH_NodeInfo_GetUid(ni), AQHNODE_Value_GetName(v),
|
||||
AQHNODE_Value_GetModality(v),
|
||||
AQH_ValueModality_toString(AQHNODE_Value_GetModality(v)));
|
||||
_announceValue(aqh, AQH_NodeInfo_GetUid(ni), v);
|
||||
v=AQHNODE_Value_List_Next(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Node type \"%s\" not in database", devName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Node type not in database");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setDeviceName(AQH_VALUE *value, uint32_t uid)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 64, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(buf, "%08x", uid);
|
||||
AQH_Value_SetDeviceName(value, GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _announceValue(AQHOMED *aqh, uint32_t uid, const AQHNODE_VALUE *v)
|
||||
{
|
||||
AQH_VALUE *value;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
value=AQH_Value_new();
|
||||
_setDeviceName(value, uid);
|
||||
AQH_Value_SetDriver(value, "nodes");
|
||||
AQH_Value_SetName(value, AQHNODE_Value_GetName(v));
|
||||
AQH_Value_SetValueUnits(value, AQHNODE_Value_GetValueUnits(v));
|
||||
AQH_Value_SetValueType(value, AQHNODE_Value_GetValueType(v));
|
||||
AQH_Value_SetModality(value, AQHNODE_Value_GetModality(v));
|
||||
|
||||
msg=AQH_ValuesDataIpcMsg_newForOneValue(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
|
||||
0, value);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, msg);
|
||||
AQH_Value_free(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_FlashReadyMsg_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
|
||||
if (ni) {
|
||||
const char *s;
|
||||
|
||||
AQH_NodeInfo_SetManufacturer(ni, AQH_FlashReadyMsg_GetManufacturer(msg));
|
||||
AQH_NodeInfo_SetDeviceType(ni, AQH_FlashReadyMsg_GetDeviceType(msg));
|
||||
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_FlashReadyMsg_GetDeviceVersion(msg)<<8)+AQH_FlashReadyMsg_GetDeviceRevision(msg));
|
||||
AQH_NodeInfo_SetFirmwareVersion(ni,
|
||||
(AQH_FlashReadyMsg_GetFirmwareVariant(msg)<<24) |
|
||||
(AQH_FlashReadyMsg_GetFirmwareVersionMajor(msg)<<16) |
|
||||
(AQH_FlashReadyMsg_GetFirmwareVersionMinor(msg)<<8) |
|
||||
AQH_FlashReadyMsg_GetFirmwareVersionPatchlevel(msg));
|
||||
s=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (!(s && *s))
|
||||
_assignDeviceId(aqh, ni, uid);
|
||||
_updateTimestampLastChange(ni);
|
||||
AQH_NodeDb_SetModified(aqh->nodeDb);
|
||||
if (uid!=0x00000000L && uid!=0xffffffff)
|
||||
_announceNodeValues(aqh, ni);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid)
|
||||
{
|
||||
uint8_t busAddr;
|
||||
AQH_NODE_INFO *ni;
|
||||
|
||||
busAddr=AQH_NodeMsg_GetSourceAddress(msg);
|
||||
ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid);
|
||||
if (ni) {
|
||||
uint8_t storedBusAddr;
|
||||
|
||||
storedBusAddr=AQH_NodeInfo_GetBusAddress(ni);
|
||||
if (busAddr!=0 && storedBusAddr!=busAddr) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Changed busaddr for %08x from %02x to %02x", uid, storedBusAddr, busAddr);
|
||||
AQH_NodeInfo_SetBusAddress(ni, busAddr);
|
||||
_updateTimestampLastChange(ni);
|
||||
AQH_NodeDb_SetModified(aqh->nodeDb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int rv;
|
||||
|
||||
ni=AQH_NodeInfo_new();
|
||||
AQH_NodeInfo_SetBusAddress(ni, busAddr);
|
||||
AQH_NodeInfo_SetUid(ni, uid);
|
||||
_updateTimestampLastChange(ni);
|
||||
rv=AQH_NodeDb_AddNodeInfo(aqh->nodeDb, ni);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
AQH_NodeInfo_free(ni);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Added node %08x (%02x)", uid, busAddr);
|
||||
}
|
||||
}
|
||||
return ni;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _assignDeviceId(AQHOMED *aqh, AQH_NODE_INFO *ni, uint32_t uid)
|
||||
{
|
||||
const AQHNODE_DEVICE *dev;
|
||||
|
||||
dev=AqHomed_FindDeviceDef(aqh,
|
||||
AQH_NodeInfo_GetManufacturer(ni),
|
||||
AQH_NodeInfo_GetDeviceType(ni),
|
||||
AQH_NodeInfo_GetDeviceVersion(ni));
|
||||
if (dev==NULL) {
|
||||
DBG_ERROR(NULL,
|
||||
"Unknown NODE device encountered (%08x, %04x, %04x)",
|
||||
AQH_NodeInfo_GetManufacturer(ni),
|
||||
AQH_NodeInfo_GetDeviceType(ni),
|
||||
AQH_NodeInfo_GetDeviceVersion(ni));
|
||||
}
|
||||
else {
|
||||
const char *s;
|
||||
|
||||
s=AQHNODE_Device_GetName(dev);
|
||||
DBG_ERROR(NULL, "Found device \"%s\" (%08x)", s?s:"<no name>", uid);
|
||||
AQH_NodeInfo_SetDeviceId(ni, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _updateTimestampLastChange(AQH_NODE_INFO *ni)
|
||||
{
|
||||
GWEN_TIMESTAMP *t;
|
||||
|
||||
t=GWEN_Timestamp_NowInLocalTime();
|
||||
AQH_NodeInfo_SetTimestampLastChange(ni, t);
|
||||
GWEN_Timestamp_free(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-nodes/db.h
Normal file
25
apps/aqhome-nodes/db.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_DB_H
|
||||
#define AQHOMED_DB_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
void AqHomed_WriteNodeDb(AQHOMED *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
128
apps/aqhome-nodes/devicesdump.c
Normal file
128
apps/aqhome-nodes/devicesdump.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./devicesdump.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _dumpDevice(const AQHNODE_DEVICE *dev, GWEN_BUFFER *dbuf, int indent);
|
||||
static void _dumpValue(const AQHNODE_VALUE *value, GWEN_BUFFER *dbuf, int indent);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeNodes_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
|
||||
if (devList && AQHNODE_Device_List_GetCount(devList)) {
|
||||
const AQHNODE_DEVICE *dev;
|
||||
|
||||
GWEN_Buffer_AppendString(dbuf, "Devices:\n");
|
||||
dev=AQHNODE_Device_List_First(devList);
|
||||
while(dev) {
|
||||
_dumpDevice(dev, dbuf, 2);
|
||||
dev=AQHNODE_Device_List_Next(dev);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _dumpDevice(const AQHNODE_DEVICE *dev, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
const char *name;
|
||||
const char *driver;
|
||||
uint32_t manufacturer;
|
||||
uint16_t deviceType;
|
||||
uint16_t deviceVersion;
|
||||
const AQHNODE_VALUE_LIST *valueList;
|
||||
|
||||
name=AQHNODE_Device_GetName(dev);
|
||||
driver=AQHNODE_Device_GetDriver(dev);
|
||||
manufacturer=AQHNODE_Device_GetManufacturer(dev);
|
||||
deviceType=AQHNODE_Device_GetDeviceType(dev);
|
||||
deviceVersion=AQHNODE_Device_GetDeviceVersion(dev);
|
||||
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "Device: %s (%s, %08x, %04x, %04x)\n",
|
||||
name?name:"<empty name>",
|
||||
driver?driver:"<empty driver>",
|
||||
manufacturer,
|
||||
deviceType,
|
||||
deviceVersion);
|
||||
valueList=AQHNODE_Device_GetValueList(dev);
|
||||
if (valueList && AQHNODE_Value_List_GetCount(valueList)) {
|
||||
const AQHNODE_VALUE *value;
|
||||
|
||||
value=AQHNODE_Value_List_First(valueList);
|
||||
while(value) {
|
||||
_dumpValue(value, dbuf, indent+2);
|
||||
value=AQHNODE_Value_List_Next(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _dumpValue(const AQHNODE_VALUE *value, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
int id;
|
||||
const char *name;
|
||||
const char *descr;
|
||||
int valueType;
|
||||
int dataType;
|
||||
int modality;
|
||||
const char *units;
|
||||
int denom;
|
||||
|
||||
id=AQHNODE_Value_GetId(value);
|
||||
name=AQHNODE_Value_GetName(value);
|
||||
descr=AQHNODE_Value_GetDescription(value);
|
||||
valueType=AQHNODE_Value_GetValueType(value);
|
||||
dataType=AQHNODE_Value_GetDataType(value);
|
||||
modality=AQHNODE_Value_GetModality(value);
|
||||
units=AQHNODE_Value_GetValueUnits(value);
|
||||
denom=AQHNODE_Value_GetDenom(value);
|
||||
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "Value: %d[%02x] (%s, %s, %s, %s, %s, %s, %d)\n",
|
||||
id, id,
|
||||
name?name:"<empty name>",
|
||||
AQH_ValueType_toString(valueType),
|
||||
AQH_ValueDataType_toString(dataType),
|
||||
AQH_ValueModality_toString(modality),
|
||||
units?units:"<empty units>",
|
||||
descr?descr:"<empty descr>",
|
||||
denom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-nodes/devicesdump.h
Normal file
24
apps/aqhome-nodes/devicesdump.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_NODES_DEVICESDUMP_H
|
||||
#define AQHOME_NODES_DEVICESDUMP_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
|
||||
|
||||
void AqHomeNodes_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
397
apps/aqhome-nodes/devicesread.c
Normal file
397
apps/aqhome-nodes/devicesread.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./devicesread.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _readDeviceFileToList(const char *sFilename, AQHNODE_DEVICE_LIST *deviceList);
|
||||
static AQHNODE_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl);
|
||||
static int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHNODE_DEVICE_LIST *deviceList);
|
||||
static AQHNODE_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode);
|
||||
static AQHNODE_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *valuesNode);
|
||||
static AQHNODE_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode);
|
||||
static int _readManufacturer(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
|
||||
static int _readDeviceType(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
|
||||
static int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDeviceFile(const char *sFilename)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHNODE_Device_List_new();
|
||||
rv=_readDeviceFileToList(sFilename, deviceList);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" not found", sFilename);
|
||||
AQHNODE_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AQHNODE_Device_List_GetCount(deviceList)<1) {
|
||||
AQHNODE_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDataDeviceFiles()
|
||||
{
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/nodes", "*.xml");
|
||||
if (sl) {
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=_readDeviceFiles(sl);
|
||||
GWEN_StringList_free(sl);
|
||||
if (deviceList==NULL) {
|
||||
DBG_INFO(NULL, "Error reading data device files");
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No data device files");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl)
|
||||
{
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHNODE_Device_List_new();
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
while(se) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Reading device file \"%s\"", s);
|
||||
rv=_readDeviceFileToList(s, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
|
||||
}
|
||||
}
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
}
|
||||
|
||||
if (AQHNODE_Device_List_GetCount(deviceList)<1) {
|
||||
AQHNODE_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceFileToList(const char *sFilename, AQHNODE_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_XMLNODE *deviceListNode;
|
||||
int rv;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
||||
rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL);
|
||||
if (deviceListNode==NULL)
|
||||
deviceListNode=rootNode;
|
||||
|
||||
rv=_readXmlDevices(deviceListNode, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHNODE_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *deviceNode;
|
||||
|
||||
deviceNode=GWEN_XMLNode_FindFirstTag(deviceListNode, "device", NULL, NULL);
|
||||
if (deviceNode) {
|
||||
while(deviceNode) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL);
|
||||
if (driverName && *driverName && strcasecmp(driverName, "nodes")==0) {
|
||||
AQHNODE_DEVICE *device;
|
||||
|
||||
device=_readXmlDevice(deviceNode);
|
||||
if (device==NULL) {
|
||||
DBG_INFO(NULL, "Error reading device from XML");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
else {
|
||||
const char *sDeviceName;
|
||||
|
||||
sDeviceName=AQHNODE_Device_GetName(device);
|
||||
if (sDeviceName && *sDeviceName) {
|
||||
DBG_ERROR(NULL, "Adding device type \"%s\" to list", sDeviceName?sDeviceName:"<no type name>");
|
||||
AQHNODE_Device_List_Add(device, deviceList);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device with no name, not adding");
|
||||
AQHNODE_Device_free(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device is not an NODES device, ignoring");
|
||||
}
|
||||
deviceNode=GWEN_XMLNode_FindNextTag(deviceNode, "device", NULL, NULL);
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <device> element found");
|
||||
return GWEN_ERROR_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
AQHNODE_DEVICE *device;
|
||||
GWEN_XMLNODE *valuesNode;
|
||||
int rv;
|
||||
|
||||
device=AQHNODE_Device_new();
|
||||
AQHNODE_Device_SetName(device, GWEN_XMLNode_GetProperty(deviceNode, "name", NULL));
|
||||
AQHNODE_Device_SetDriver(device, GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL));
|
||||
rv=_readManufacturer(device, deviceNode);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
rv=_readDeviceType(device, deviceNode);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
rv=_readDeviceVersion(device, deviceNode);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read values */
|
||||
valuesNode=GWEN_XMLNode_FindFirstTag(deviceNode, "values", NULL, NULL);
|
||||
if (valuesNode) {
|
||||
AQHNODE_VALUE_LIST *valueList;
|
||||
|
||||
valueList=_readXmlValueList(valuesNode);
|
||||
if (valueList==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
AQHNODE_Device_SetValueList(device, valueList);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <values> element");
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *valuesNode)
|
||||
{
|
||||
AQHNODE_VALUE_LIST *valueList;
|
||||
GWEN_XMLNODE *node;
|
||||
|
||||
valueList=AQHNODE_Value_List_new();
|
||||
node=GWEN_XMLNode_FindFirstTag(valuesNode, "value", NULL, NULL);
|
||||
while(node) {
|
||||
AQHNODE_VALUE *value;
|
||||
|
||||
value=_readXmlValue(node);
|
||||
if (value)
|
||||
AQHNODE_Value_List_Add(value, valueList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <value> element");
|
||||
AQHNODE_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
node=GWEN_XMLNode_FindNextTag(node, "value", NULL, NULL);
|
||||
}
|
||||
if (AQHNODE_Value_List_GetCount(valueList)<1) {
|
||||
DBG_INFO(NULL, "No <value> element in <values> element");
|
||||
AQHNODE_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
return valueList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode)
|
||||
{
|
||||
AQHNODE_VALUE *value;
|
||||
|
||||
value=AQHNODE_Value_new();
|
||||
AQHNODE_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL));
|
||||
AQHNODE_Value_SetId(value, GWEN_XMLNode_GetIntProperty(valueNode, "id", 0));
|
||||
AQHNODE_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL));
|
||||
AQHNODE_Value_SetValueType(value, AQH_ValueType_fromString(GWEN_XMLNode_GetProperty(valueNode, "type", NULL)));
|
||||
AQHNODE_Value_SetDataType(value, AQH_ValueDataType_fromString(GWEN_XMLNode_GetProperty(valueNode, "dataType", NULL)));
|
||||
AQHNODE_Value_SetModality(value, AQH_ValueModality_fromString(GWEN_XMLNode_GetProperty(valueNode, "modality", NULL)));
|
||||
AQHNODE_Value_SetDenom(value, GWEN_XMLNode_GetIntProperty(valueNode, "denom", 1));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readManufacturer(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
const char *s;
|
||||
uint32_t v;
|
||||
|
||||
s=GWEN_XMLNode_GetCharValue(deviceNode, "manufacturer", NULL);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(NULL, "Missing manufacturer");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
if (strlen(s)>4) {
|
||||
DBG_ERROR(NULL, "Bad manufacturer string (too long): \"%s\"", s);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
v=0;
|
||||
while(*s) {
|
||||
v<<=8;
|
||||
v|=*s & 0xff;
|
||||
s++;
|
||||
}
|
||||
v=((v>>24) & 0x000000ffL) |
|
||||
((v>>8) & 0x0000ff00L) |
|
||||
((v<<8) & 0x00ff0000L) |
|
||||
((v<<24) & 0xff000000L);
|
||||
|
||||
AQHNODE_Device_SetManufacturer(device, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceType(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
const char *s;
|
||||
uint16_t v;
|
||||
|
||||
s=GWEN_XMLNode_GetCharValue(deviceNode, "devicetype", NULL);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(NULL, "Missing device type");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
if (strlen(s)>2) {
|
||||
DBG_ERROR(NULL, "Bad devicetype string (too long): \"%s\"", s);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
v=0;
|
||||
while(*s) {
|
||||
v<<=8;
|
||||
v|=*s & 0xff;
|
||||
s++;
|
||||
}
|
||||
|
||||
AQHNODE_Device_SetDeviceType(device, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
int v;
|
||||
|
||||
v=GWEN_XMLNode_GetIntValue(deviceNode, "deviceversion", -1);
|
||||
if (v<0) {
|
||||
DBG_ERROR(NULL, "Missing device version");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
AQHNODE_Device_SetDeviceVersion(device, v<<8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-nodes/devicesread.h
Normal file
25
apps/aqhome-nodes/devicesread.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_NODES_DEVICESREAD_H
|
||||
#define AQHOME_NODES_DEVICESREAD_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDeviceFile(const char *sFilename);
|
||||
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDataDeviceFiles(void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
89
apps/aqhome-nodes/fini.c
Normal file
89
apps/aqhome-nodes/fini.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./fini.h"
|
||||
#include "./db.h"
|
||||
#include "./aqhomed_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_Fini(AQHOMED *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
if (aqh->rootEndpoint) {
|
||||
_disconnectTree(aqh->rootEndpoint);
|
||||
GWEN_MsgEndpoint_Disconnect(aqh->rootEndpoint);
|
||||
}
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
aqh->rootEndpoint=NULL;
|
||||
aqh->ttyEndpoint=NULL;
|
||||
aqh->ipcdEndpoint=NULL;
|
||||
aqh->brokerEndpoint=NULL;
|
||||
|
||||
AqHomed_WriteNodeDb(aqh);
|
||||
|
||||
if (aqh->pidFile)
|
||||
remove(aqh->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epChild;
|
||||
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
||||
while(epChild) {
|
||||
_disconnectTree(epChild);
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
||||
} /* while */
|
||||
|
||||
GWEN_MsgEndpoint_Disconnect(ep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/fini.h
Normal file
23
apps/aqhome-nodes/fini.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_FINI_H
|
||||
#define AQHOMED_FINI_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_Fini(AQHOMED *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
540
apps/aqhome-nodes/init.c
Normal file
540
apps/aqhome-nodes/init.c
Normal file
@@ -0,0 +1,540 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./init.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./devicesread.h"
|
||||
#include "./devicesdump.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/endpoint_ipcclient.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static void _setupIpcd(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static void _setupBroker(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
||||
static void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static int _loadDeviceList(AQHOMED *aqh);
|
||||
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AqHomed_Init(AQHOMED *aqh, int argc, char **argv)
|
||||
{
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
int rv;
|
||||
const char *s;
|
||||
|
||||
dbArgs=GWEN_DB_Group_new("args");
|
||||
rv=_readArgs(argc, argv, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
aqh->dbArgs=dbArgs;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_LOGGER_LEVEL ll;
|
||||
|
||||
ll=GWEN_Logger_Name2Level(s);
|
||||
GWEN_Logger_SetLevel(NULL, ll);
|
||||
}
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOMED_DEFAULT_PIDFILE);
|
||||
if (s && *s) {
|
||||
AqHomed_SetPidFile(aqh, s);
|
||||
rv=_createPidFile(s);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
aqh->nodeAddress=GWEN_DB_GetIntValue(dbArgs, "nodeAddress", 0, AQHOMED_DEFAULT_NODEADDR);
|
||||
|
||||
rv=_loadDeviceList(aqh);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error loading device list(%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
#if 0
|
||||
else {
|
||||
GWEN_BUFFER *dbuf;
|
||||
|
||||
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AqHomeNodes_DumpDevices(aqh->deviceDefList, dbuf);
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
_setupDb(aqh, dbArgs);
|
||||
|
||||
rv=_setupTty(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting up TTY endpoint (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
_setupIpcd(aqh, dbArgs);
|
||||
_setupBroker(aqh, dbArgs);
|
||||
_setupLog(aqh, dbArgs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *devicePath;
|
||||
|
||||
devicePath=GWEN_DB_GetCharValue(dbArgs, "device", 0, AQHOMED_DEFAULT_DEVICE);
|
||||
if (devicePath && *devicePath) {
|
||||
GWEN_MSG_ENDPOINT *epTty;
|
||||
|
||||
epTty=AQH_TtyEndpoint_new(devicePath, AQHOME_ENDPOINTGROUP_NODE);
|
||||
if (epTty==NULL) {
|
||||
DBG_ERROR(NULL, "Error creating endpoint TTY");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, epTty);
|
||||
aqh->ttyEndpoint=epTty;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Missing device path");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupIpcd(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
|
||||
if (!(tcpAddress && *tcpAddress))
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/nodesAddress", 0, NULL);
|
||||
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
|
||||
if (tcpPort<0)
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/nodesPort", 0, AQHOMED_DEFAULT_IPC_PORT);
|
||||
|
||||
if (tcpAddress && *tcpAddress && tcpPort) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, AQHOME_ENDPOINTGROUP_IPC);
|
||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
||||
aqh->ipcdEndpoint=ep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupBroker(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *brokerAddress;
|
||||
int brokerPort;
|
||||
const char *brokerClientId;
|
||||
|
||||
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL);
|
||||
if (!(brokerAddress && *brokerAddress))
|
||||
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
|
||||
|
||||
brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, -1);
|
||||
if (brokerPort<0)
|
||||
brokerPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOMED_DEFAULT_BROKER_PORT);
|
||||
|
||||
brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOMED_DEFAULT_BROKER_CLIENTID);
|
||||
|
||||
if (brokerAddress && *brokerAddress && brokerPort) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
GWEN_MSG_ENDPOINT *ipcBaseEndpoint;
|
||||
int rv;
|
||||
|
||||
ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0);
|
||||
ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0);
|
||||
AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId);
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
||||
aqh->brokerEndpoint=ep;
|
||||
|
||||
rv=GWEN_MultilayerEndpoint_StartConnect(ep);
|
||||
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
|
||||
DBG_ERROR(NULL, "Error connecting to broker server %s:%d (%d), will retry later", brokerAddress, brokerPort, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_UNUSED GWEN_MSG_ENDPOINT *ep,
|
||||
GWEN_SOCKET *sk,
|
||||
GWEN_UNUSED const GWEN_INETADDRESS *addr,
|
||||
GWEN_UNUSED void *data)
|
||||
{
|
||||
/* AQHOMED *aqh;
|
||||
*
|
||||
* aqh=(AQHOMED*) data;
|
||||
*/
|
||||
DBG_INFO(NULL, "Incoming IPC connection");
|
||||
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, AQHOME_ENDPOINTGROUP_IPC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *logFile;
|
||||
|
||||
logFile=GWEN_DB_GetCharValue(dbArgs, "logfile", 0, NULL);
|
||||
if (logFile && *logFile)
|
||||
AqHomed_SetLogFile(aqh, logFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "dbfile", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *dbNodeDb;
|
||||
int rv;
|
||||
|
||||
AqHomed_SetDbFile(aqh, s);
|
||||
|
||||
dbNodeDb=GWEN_DB_Group_new("dbNodes");
|
||||
rv=GWEN_DB_ReadFile(dbNodeDb, s, GWEN_DB_FLAGS_DEFAULT|GWEN_PATH_FLAGS_CREATE_GROUP);
|
||||
if (rv==0) {
|
||||
AQH_NodeDb_fromDb(aqh->nodeDb, dbNodeDb);
|
||||
}
|
||||
GWEN_DB_Group_free(dbNodeDb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _loadDeviceList(AQHOMED *aqh)
|
||||
{
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AqHomeNodes_ReadDataDeviceFiles();
|
||||
if (deviceList==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading device list");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
aqh->deviceDefList=deviceList;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
int pidfd;
|
||||
|
||||
if (remove(pidFilename)==0) {
|
||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (pidfd < 0) {
|
||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
f = fdopen(pidfd, "w");
|
||||
#else /* HAVE_STAT_H */
|
||||
f=fopen(pidFilename,"w+");
|
||||
#endif /* HAVE_STAT_H */
|
||||
|
||||
/* write pid */
|
||||
#ifdef HAVE_GETPID
|
||||
fprintf(f,"%d\n",getpid());
|
||||
#else
|
||||
fprintf(f,"-1\n");
|
||||
#endif
|
||||
if (fclose(f)) {
|
||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
int rv;
|
||||
const GWEN_ARGS args[]= {
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"loglevel", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"L", /* short option */
|
||||
"loglevel", /* long option */
|
||||
I18S("Specify loglevel"), /* short description */
|
||||
I18S("Specify loglevel") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"cfgdir", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"D", /* short option */
|
||||
"cfgdir", /* long option */
|
||||
I18S("Specify the configuration folder"),
|
||||
I18S("Specify the configuration folder")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"charset", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
0, /* short option */
|
||||
"charset", /* long option */
|
||||
I18S("Specify the output character set"), /* short description */
|
||||
I18S("Specify the output character set") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"device", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"d", /* short option */
|
||||
"device", /* long option */
|
||||
I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)"),
|
||||
I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"nodeAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"n", /* short option */
|
||||
"node", /* long option */
|
||||
I18S("Specify the node address for the AqHome node adaptor (default 240)"),
|
||||
I18S("Specify the node address for the AqHome node adaptor (default 240)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"logFile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"l", /* short option */
|
||||
"logfile", /* long option */
|
||||
I18S("Specify a logfile to log received messages to"),
|
||||
I18S("Specify a logfile to log received messages to")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"tcpAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"t", /* short option */
|
||||
"tcpaddress", /* long option */
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)"),
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"tcpPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"P", /* short option */
|
||||
"tcpport", /* long option */
|
||||
I18S("Specify the TCP port to listen on (default: 45454)"),
|
||||
I18S("Specify the TCP port to listen on (default: 45454)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"brokerAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"ba", /* short option */
|
||||
"brokeraddress", /* long option */
|
||||
I18S("Specify the address of the broker server to connect to (disabled if missing)"),
|
||||
I18S("Specify the address of the broker server to connect to (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"brokerPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"bp", /* short option */
|
||||
"brokerport", /* long option */
|
||||
I18S("Specify the port of the broker server (default: 1899)"),
|
||||
I18S("Specify the port of the broker server (default: 1899)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"brokerClientId", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"brokerclientid", /* long option */
|
||||
I18S("Specify client id for the broker server (default: \"nodes\")"),
|
||||
I18S("Specify client id for the broker server (default: \"nodes\")")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"dbfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"db", /* short option */
|
||||
"dbfile", /* long option */
|
||||
I18S("Specify DB file to read/write node database"),
|
||||
I18S("Specify DB file to read/write node database")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"pidfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"p", /* short option */
|
||||
"pidfile", /* long option */
|
||||
I18S("Specify the PID file"),
|
||||
I18S("Specify the PID file")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"timeout", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"T", /* short option */
|
||||
"timeout", /* long option */
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"help", /* name */
|
||||
0, /* minnum */
|
||||
0, /* maxnum */
|
||||
"h", /* short option */
|
||||
"help",
|
||||
I18S("Show this help screen."),
|
||||
I18S("Show this help screen.")
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
||||
GWEN_BUFFER *ubuf;
|
||||
|
||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(ubuf,
|
||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
||||
AQHOME_VERSION_STRING,
|
||||
argv[0]);
|
||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
||||
return 1;
|
||||
}
|
||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
||||
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/init.h
Normal file
23
apps/aqhome-nodes/init.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_INIT_H
|
||||
#define AQHOMED_INIT_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
int AqHomed_Init(AQHOMED *aqh, int argc, char **argv);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/ipc.h
Normal file
23
apps/aqhome-nodes/ipc.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_IPC_H
|
||||
#define AQHOMED_LOOP_IPC_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
91
apps/aqhome-nodes/loop.c
Normal file
91
apps/aqhome-nodes/loop.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop.h"
|
||||
#include "./loop_tty.h"
|
||||
#include "./loop_ipc.h"
|
||||
#include "./loop_broker.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./db.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_value.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
|
||||
AqHomed_ReadAndHandleTtyMessages(aqh);
|
||||
AqHomed_ReadAndHandleIpcMessages(aqh);
|
||||
AqHomed_ReadAndHandleBrokerMessages(aqh);
|
||||
|
||||
AQH_Requests_CheckTimeouts(aqh->requestTree);
|
||||
AQH_Requests_Cleanup(aqh->requestTree);
|
||||
|
||||
#if 0
|
||||
DBG_ERROR(NULL, "Messages in TTY queue: %d in, %d out",
|
||||
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetReceivedMessageList(aqh->ttyEndpoint)),
|
||||
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetSendMessageList(aqh->ttyEndpoint)));
|
||||
|
||||
DBG_ERROR(NULL, "Messages in IPC queue: %d in, %d out",
|
||||
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetReceivedMessageList(aqh->ipcdEndpoint)),
|
||||
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetSendMessageList(aqh->ipcdEndpoint)));
|
||||
|
||||
DBG_ERROR(NULL, "Messages in Broker queue: %d in, %d out",
|
||||
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetReceivedMessageList(aqh->brokerEndpoint)),
|
||||
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetSendMessageList(aqh->brokerEndpoint)));
|
||||
#endif
|
||||
|
||||
if (AQH_NodeDb_IsModified(aqh->nodeDb))
|
||||
AqHomed_WriteNodeDb(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/loop.h
Normal file
23
apps/aqhome-nodes/loop.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_H
|
||||
#define AQHOMED_LOOP_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
101
apps/aqhome-nodes/loop_broker.c
Normal file
101
apps/aqhome-nodes/loop_broker.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_broker.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./db.h"
|
||||
#include "./r_setdata.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_ping.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
static void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomed_ReadAndHandleBrokerMessages(AQHOMED *aqh)
|
||||
{
|
||||
if (aqh->brokerEndpoint) {
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
epTcp=aqh->brokerEndpoint;
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
|
||||
uint16_t code;
|
||||
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
|
||||
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, epTcp, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
|
||||
_handleIpcMsg(aqh, epTcp, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
uint16_t code;
|
||||
|
||||
/* exec IPC message */
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet");
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeNodes_HandleSetData(aqh, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-nodes/loop_broker.h
Normal file
25
apps/aqhome-nodes/loop_broker.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_BROKER_H
|
||||
#define AQHOMED_LOOP_BROKER_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle messageexchange with the broker (aqhome-data).
|
||||
*/
|
||||
void AqHomed_ReadAndHandleBrokerMessages(AQHOMED *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
197
apps/aqhome-nodes/loop_ipc.c
Normal file
197
apps/aqhome-nodes/loop_ipc.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_ipc.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./db.h"
|
||||
#include "./r_setdata.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_value3.h"
|
||||
#include "aqhome/msg/msg_ping.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/nodes/ipc_nodes.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_value.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_ping.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_setaccmsggrps.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_getdevices_rsp.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_set.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleIpcEndpoint(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep);
|
||||
static void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
void _handleIpcMsgPing(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
void _handleIpcMsgSetAccMsgGrps(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
void _handleIpcMsgForward(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
void _handleIpcMsgGetDevicesReq(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomed_ReadAndHandleIpcMessages(AQHOMED *aqh)
|
||||
{
|
||||
if (aqh->ipcdEndpoint) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
_handleIpcEndpoint(aqh, ep);
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcEndpoint(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
|
||||
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, ep, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
|
||||
_handleIpcMsg(aqh, ep, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
uint16_t code;
|
||||
|
||||
/* exec IPC message */
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Received IPC packet (%d, %04x)", code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_NODES_PING: _handleIpcMsgPing(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_NODES_SETACCMSGGRPS: _handleIpcMsgSetAccMsgGrps(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_NODES_FORWARD: _handleIpcMsgForward(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_NODES_GETDEVICES_REQ: _handleIpcMsgGetDevicesReq(aqh, ep, msg); break;
|
||||
// case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeNodes_HandleNodeSetData(aqh, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsgPing(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC PING message");
|
||||
msgOut=AQH_PingMsg_new(aqh->nodeAddress, AQH_PingIpcMsg_GetDestAddr(msg), AQH_MSG_TYPE_PING);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsgSetAccMsgGrps(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
uint32_t groups;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Received IPC SET_ACCEPTED_MSG_GROUPS message");
|
||||
groups=AQH_SetAcceptedMsgGroupsIpcMsg_GetMsgGroups(msg);
|
||||
AQH_IpcEndpoint_SetAcceptedMsgGroups(ep, groups);
|
||||
// TODO: send response?
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsgForward(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC FORWARD message");
|
||||
msgOut=AQH_ForwardIpcMsg_GetCopyOfNodeMsg(msg);
|
||||
if (msgOut)
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsgGetDevicesReq(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
AQH_NODE_INFO_LIST *nodeInfoList;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Received IPC GetDevicesRequest message");
|
||||
nodeInfoList=AQH_NodeDb_GetAllNodeInfos(aqh->nodeDb);
|
||||
if (nodeInfoList && AQH_NodeInfo_List_GetCount(nodeInfoList)) {
|
||||
const AQH_NODE_INFO *ni;
|
||||
|
||||
ni=AQH_NodeInfo_List_First(nodeInfoList);
|
||||
while(ni) {
|
||||
const AQH_NODE_INFO *niNext;
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
niNext=AQH_NodeInfo_List_Next(ni);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Sending response for node %02x (%08x)", AQH_NodeInfo_GetBusAddress(ni), AQH_NodeInfo_GetUid(ni));
|
||||
msgOut=AQH_GetDevicesResponseIpcMsg_new(AQH_MSGTYPE_IPC_NODES_GETDEVICES_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
|
||||
niNext?0:AQH_MSGIPC_GETDEVICES_RSP_FLAGS_LAST, ni);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||
ni=niNext;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No nodes");
|
||||
msgOut=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_NODES_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
|
||||
AQH_MSG_IPC_ERROR_NODATA);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/loop_ipc.h
Normal file
23
apps/aqhome-nodes/loop_ipc.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_IPC_H
|
||||
#define AQHOMED_LOOP_IPC_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_ReadAndHandleIpcMessages(AQHOMED *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
87
apps/aqhome-nodes/loop_tty.c
Normal file
87
apps/aqhome-nodes/loop_tty.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_tty.h"
|
||||
#include "./loop_tty_ipc.h"
|
||||
#include "./loop_tty_broker.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./db.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_value.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomed_ReadAndHandleTtyMessages(AQHOMED *aqh)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->ttyEndpoint)) ) {
|
||||
_handleTtyMsg(aqh, msg);
|
||||
AQH_Requests_HandleTtyMsg(aqh->requestTree, aqh->ttyEndpoint, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
if (aqh->logFile)
|
||||
AqHomed_LogTtyMsg(aqh, msg);
|
||||
if (aqh->nodeDb)
|
||||
AqHomed_NodeMsgToDb(aqh, msg);
|
||||
if (aqh->ipcdEndpoint)
|
||||
AqHomed_ForwardTtyMsgToIpcClients(aqh, msg);
|
||||
if (aqh->brokerEndpoint)
|
||||
AqHomed_ForwardTtyMsgToBroker(aqh, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/loop_tty.h
Normal file
23
apps/aqhome-nodes/loop_tty.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_TTY_H
|
||||
#define AQHOMED_LOOP_TTY_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_ReadAndHandleTtyMessages(AQHOMED *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
234
apps/aqhome-nodes/loop_tty_broker.c
Normal file
234
apps/aqhome-nodes/loop_tty_broker.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_tty_broker.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./db.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_value3.h"
|
||||
#include "aqhome/msg/msg_sendstats.h"
|
||||
#include "aqhome/msg/msg_recvstats.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _processValue3Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
static void _publishInt(AQHOMED *aqh, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v);
|
||||
static void _publishDouble(AQHOMED *aqh, uint32_t uid, const char *vPath, int vType, const char *vUnits, double v);
|
||||
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_ForwardTtyMsgToBroker(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
if (GWEN_MsgEndpoint_GetState(aqh->brokerEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message");
|
||||
switch(AQH_NodeMsg_GetMsgType(nodeMsg)) {
|
||||
case AQH_MSG_TYPE_VALUE_REPORT:
|
||||
_processValue3Message(aqh, nodeMsg);
|
||||
break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS:
|
||||
_processSendStatsMessage(aqh, nodeMsg);
|
||||
break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS:
|
||||
_processRecvStatsMessage(aqh, nodeMsg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _processValue3Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
uint32_t uid;
|
||||
uint8_t valueId;
|
||||
AQH_NODE_INFO *ni;
|
||||
double v;
|
||||
|
||||
uid=AQH_Value3Msg_GetUid(nodeMsg);
|
||||
valueId=AQH_Value3Msg_GetValueId(nodeMsg);
|
||||
v=AQH_Value3Msg_GetValue(nodeMsg);
|
||||
ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid);
|
||||
if (ni) {
|
||||
const char *devName;
|
||||
|
||||
devName=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (devName) {
|
||||
const AQHNODE_DEVICE *devInfo;
|
||||
|
||||
devInfo=AqHomed_GetDeviceDefByName(aqh, devName);
|
||||
if (devInfo) {
|
||||
const AQHNODE_VALUE *value;
|
||||
|
||||
value=AQHNODE_Value_List_GetById(AQHNODE_Device_GetValueList(devInfo), valueId);
|
||||
if (value) {
|
||||
const char *vname;
|
||||
|
||||
vname=AQHNODE_Value_GetName(value);
|
||||
if (vname && *vname)
|
||||
_publishDouble(aqh, uid, vname, AQHNODE_Value_GetModality(value), AQHNODE_Value_GetValueUnits(value), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
uint16_t packetsOutInt;
|
||||
|
||||
packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg);
|
||||
if (packetsOutInt) {
|
||||
uint32_t uid;
|
||||
double packetsOut;
|
||||
double collisions;
|
||||
double busy;
|
||||
double collisionsPercentage=0.0;
|
||||
double busyPercentage=0.0;
|
||||
|
||||
uid=AQH_SendStatsMsg_GetUid(nodeMsg);
|
||||
packetsOut=/*(double)*/ packetsOutInt;
|
||||
collisions=/*(double)*/ AQH_SendStatsMsg_GetCollisions(nodeMsg);
|
||||
busy=/*(double)*/ AQH_SendStatsMsg_GetBusyErrors(nodeMsg);
|
||||
|
||||
collisionsPercentage=collisions*100.0/packetsOut;
|
||||
busyPercentage=busy*100.0/packetsOut;
|
||||
|
||||
_publishInt( aqh, uid, "net/packetsOut", 0, NULL, packetsOutInt);
|
||||
_publishInt( aqh, uid, "net/collisions", 0, NULL, (int) AQH_SendStatsMsg_GetCollisions(nodeMsg));
|
||||
_publishDouble(aqh, uid, "net/collisionsPercent", 0, "%", collisionsPercentage);
|
||||
_publishDouble(aqh, uid, "net/busyPercent", 0, "%", busyPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
uint16_t packetsInInt;
|
||||
|
||||
packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg);
|
||||
if (packetsInInt) {
|
||||
uint32_t uid;
|
||||
double packetsIn;
|
||||
double crcErrors;
|
||||
double ioErrors;
|
||||
double crcErrorsPercentage=0.0;
|
||||
double ioErrorsPercentage=0.0;
|
||||
|
||||
uid=AQH_SendStatsMsg_GetUid(nodeMsg);
|
||||
packetsIn=/*(double)*/ packetsInInt;
|
||||
crcErrors=/*(double)*/AQH_RecvStatsMsg_GetCrcErrors(nodeMsg);
|
||||
ioErrors=/*(double)*/AQH_RecvStatsMsg_GetIoErrors(nodeMsg);
|
||||
|
||||
crcErrorsPercentage=crcErrors*100.0/packetsIn;
|
||||
ioErrorsPercentage=ioErrors*100.0/packetsIn;
|
||||
|
||||
_publishInt( aqh, uid, "net/packetsIn", 0, NULL, packetsInInt);
|
||||
_publishInt( aqh, uid, "net/crcerrors", 0, NULL, (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg));
|
||||
_publishInt( aqh, uid, "net/ioerrors", 0, NULL, (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg));
|
||||
_publishDouble(aqh, uid, "net/crcerrorsPercent", 0, "%", crcErrorsPercentage);
|
||||
_publishDouble(aqh, uid, "net/ioerrorsPercent", 0, "%", ioErrorsPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishInt(AQHOMED *aqh, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v)
|
||||
{
|
||||
_publishDouble(aqh, uid, vPath, vModality, vUnits, /*(double)*/ v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishDouble(AQHOMED *aqh, uint32_t uid, const char *vPath, int vModality, const char *vUnits, double v)
|
||||
{
|
||||
GWEN_MSG *pubMsg;
|
||||
union {double f; uint64_t i;} u;
|
||||
uint64_t arrayToSend[2];
|
||||
AQH_VALUE *value;
|
||||
|
||||
u.f=v;
|
||||
arrayToSend[0]=(uint64_t) time(NULL);
|
||||
arrayToSend[1]=u.i;
|
||||
|
||||
value=AQH_Value_new();
|
||||
_setDeviceName(value, uid);
|
||||
AQH_Value_SetName(value, vPath);
|
||||
AQH_Value_SetValueUnits(value, vUnits);
|
||||
AQH_Value_SetValueType(value, AQH_ValueType_Sensor);
|
||||
AQH_Value_SetModality(value, vModality);
|
||||
|
||||
pubMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
|
||||
value, arrayToSend, 1);
|
||||
if (pubMsg) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "BROKER PUBLISH %s: %f", AQH_Value_GetName(value), v);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
|
||||
}
|
||||
AQH_Value_free(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setDeviceName(AQH_VALUE *value, uint32_t uid)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 64, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(buf, "%08x", uid);
|
||||
AQH_Value_SetDeviceName(value, GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/loop_tty_broker.h
Normal file
23
apps/aqhome-nodes/loop_tty_broker.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_TTY_BROKER_H
|
||||
#define AQHOMED_LOOP_TTY_BROKER_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_ForwardTtyMsgToBroker(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
120
apps/aqhome-nodes/loop_tty_ipc.c
Normal file
120
apps/aqhome-nodes/loop_tty_ipc.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_tty_ipc.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./db.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_value.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg);
|
||||
static void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
uint32_t msgGroup;
|
||||
|
||||
msgGroup=AQH_NodeMsg_GetMsgGroup(AQH_NodeMsg_GetMsgType(msg));
|
||||
if (msgGroup) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
if (msgGroup & AQH_IpcEndpoint_GetAcceptedMsgGroups(ep)) {
|
||||
DBG_INFO(NULL, "Endpoint accepts msg group %d", msgGroup);
|
||||
switch(AQH_NodeMsg_GetMsgType(msg)) {
|
||||
case AQH_MSG_TYPE_VALUE2:
|
||||
_forwardValue2MsgToIpc(ep, msg);
|
||||
break;
|
||||
default:
|
||||
_forwardAnyMsgToIpc(ep, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Message type %d not in any message group, ignoring message", AQH_NodeMsg_GetMsgType(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
GWEN_MSG *ipcMsg;
|
||||
|
||||
ipcMsg=AQH_ValueIpcMsg_new(AQH_MSGTYPE_IPC_NODES_VALUE,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
|
||||
AQH_Value2Msg_GetUid(nodeMsg),
|
||||
AQH_Value2Msg_GetValueId(nodeMsg),
|
||||
AQH_Value2Msg_GetValueType(nodeMsg),
|
||||
AQH_Value2Msg_GetValueNom(nodeMsg),
|
||||
AQH_Value2Msg_GetValueDenom(nodeMsg));
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, ipcMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
GWEN_MSG *ipcMsg;
|
||||
|
||||
ipcMsg=AQH_ForwardIpcMsg_new(AQH_MSGTYPE_IPC_NODES_FORWARD,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
|
||||
GWEN_Msg_GetConstBuffer(nodeMsg), GWEN_Msg_GetBytesInBuffer(nodeMsg));
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, ipcMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/loop_tty_ipc.h
Normal file
23
apps/aqhome-nodes/loop_tty_ipc.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_TTY_IPC_H
|
||||
#define AQHOMED_LOOP_TTY_IPC_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
215
apps/aqhome-nodes/loop_tty_mqtt.c
Normal file
215
apps/aqhome-nodes/loop_tty_mqtt.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop_tty_mqtt.h"
|
||||
#include "./aqhomed_p.h"
|
||||
#include "./tty_log.h"
|
||||
#include "./tty_write.h"
|
||||
#include "./db.h"
|
||||
|
||||
#include "aqhome/msg/endpoint_tty.h"
|
||||
#include "aqhome/msg/msg_node.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_sendstats.h"
|
||||
#include "aqhome/msg/msg_recvstats.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
|
||||
#include "aqhome/ipc/nodes/msg_ipc_value.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
|
||||
static void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v);
|
||||
static void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v);
|
||||
static void _publishString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void AqHomed_ForwardTtyMsgToMqttServer(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
if (GWEN_MsgEndpoint_GetState(aqh->mqttEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message");
|
||||
switch(AQH_NodeMsg_GetMsgType(nodeMsg)) {
|
||||
case AQH_MSG_TYPE_VALUE2:
|
||||
_processValue2Message(aqh, nodeMsg);
|
||||
break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS:
|
||||
_processSendStatsMessage(aqh, nodeMsg);
|
||||
break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS:
|
||||
_processRecvStatsMessage(aqh, nodeMsg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
if (AQH_Value2Msg_GetValueType(nodeMsg)==AQH_MSG_VALUE2_TYPE_DOOR)
|
||||
_publishString(aqh,
|
||||
AQH_Value2Msg_GetUid(nodeMsg),
|
||||
AQH_Value2Msg_GetValueId(nodeMsg),
|
||||
AQH_Value2Msg_GetValueTypeName(nodeMsg),
|
||||
AQH_Value2Msg_GetValueAsWindowStateString(nodeMsg));
|
||||
else
|
||||
_publishDouble(aqh,
|
||||
AQH_Value2Msg_GetUid(nodeMsg),
|
||||
AQH_Value2Msg_GetValueId(nodeMsg),
|
||||
AQH_Value2Msg_GetValueTypeName(nodeMsg),
|
||||
AQH_Value2Msg_GetValue(nodeMsg));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
uint16_t packetsOutInt;
|
||||
|
||||
packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg);
|
||||
if (packetsOutInt) {
|
||||
double packetsOut;
|
||||
double collisions;
|
||||
double busy;
|
||||
double collisionsPercentage=0.0;
|
||||
double busyPercentage=0.0;
|
||||
|
||||
packetsOut=(double) packetsOutInt;
|
||||
collisions=(double)AQH_SendStatsMsg_GetCollisions(nodeMsg);
|
||||
busy=(double)AQH_SendStatsMsg_GetBusyErrors(nodeMsg);
|
||||
|
||||
collisionsPercentage=collisions*100.0/packetsOut;
|
||||
busyPercentage=busy*100.0/packetsOut;
|
||||
|
||||
_publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/packetsOut", packetsOutInt);
|
||||
_publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisions", (int) AQH_SendStatsMsg_GetCollisions(nodeMsg));
|
||||
_publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisionsPercent", collisionsPercentage);
|
||||
_publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/busyPercent", busyPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
|
||||
{
|
||||
uint16_t packetsInInt;
|
||||
|
||||
packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg);
|
||||
if (packetsInInt) {
|
||||
double packetsIn;
|
||||
double crcErrors;
|
||||
double ioErrors;
|
||||
double crcErrorsPercentage=0.0;
|
||||
double ioErrorsPercentage=0.0;
|
||||
|
||||
packetsIn=(double) packetsInInt;
|
||||
crcErrors=(double)AQH_RecvStatsMsg_GetCrcErrors(nodeMsg);
|
||||
ioErrors=(double)AQH_RecvStatsMsg_GetIoErrors(nodeMsg);
|
||||
|
||||
crcErrorsPercentage=crcErrors*100.0/packetsIn;
|
||||
ioErrorsPercentage=ioErrors*100.0/packetsIn;
|
||||
|
||||
_publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/packetsIn", packetsInInt);
|
||||
_publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrors", (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg));
|
||||
_publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrors", (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg));
|
||||
_publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrorsPercent", crcErrorsPercentage);
|
||||
_publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrorsPercent", ioErrorsPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v)
|
||||
{
|
||||
char numBuf[16];
|
||||
|
||||
snprintf(numBuf, sizeof(numBuf)-1, "%f", v);
|
||||
numBuf[sizeof(numBuf)-1]=0;
|
||||
_publishString(aqh, uid, valueId, valuePath, numBuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v)
|
||||
{
|
||||
char numBuf[16];
|
||||
|
||||
snprintf(numBuf, sizeof(numBuf)-1, "%d", v);
|
||||
numBuf[sizeof(numBuf)-1]=0;
|
||||
_publishString(aqh, uid, valueId, valuePath, numBuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v)
|
||||
{
|
||||
GWEN_BUFFER *bufTopic;
|
||||
GWEN_MSG *pubMsg;
|
||||
|
||||
bufTopic=GWEN_Buffer_new(0, 64, 0, 1);
|
||||
if (valueId>0)
|
||||
GWEN_Buffer_AppendArgs(bufTopic, "%s/%08x/%d/%s",
|
||||
aqh->mqttTopicPrefix,
|
||||
uid,
|
||||
valueId,
|
||||
valuePath);
|
||||
else
|
||||
GWEN_Buffer_AppendArgs(bufTopic, "%s/%08x/%s",
|
||||
aqh->mqttTopicPrefix,
|
||||
uid,
|
||||
valuePath);
|
||||
|
||||
pubMsg=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(bufTopic), (const uint8_t*) v, strlen(v));
|
||||
if (pubMsg) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "MQTT PUBLISH %s: %s", GWEN_Buffer_GetStart(bufTopic), v);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, pubMsg);
|
||||
}
|
||||
GWEN_Buffer_free(bufTopic);
|
||||
}
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/loop_tty_mqtt.h
Normal file
23
apps/aqhome-nodes/loop_tty_mqtt.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_LOOP_TTY_MQTT_H
|
||||
#define AQHOMED_LOOP_TTY_MQTT_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_ForwardTtyMsgToMqttServer(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
212
apps/aqhome-nodes/main.c
Normal file
212
apps/aqhome-nodes/main.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include "./aqhomed.h"
|
||||
#include "./init.h"
|
||||
#include "./fini.h"
|
||||
#include "./loop.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _runService(AQHOMED *aqh);
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
||||
#endif
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
AQHOMED *aqh;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhomed", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
aqh=AqHomed_new();
|
||||
rv=AqHomed_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
_runService(aqh);
|
||||
|
||||
AqHomed_Fini(aqh);
|
||||
AqHomed_free(aqh);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _runService(AQHOMED *aqh)
|
||||
{
|
||||
time_t timeStart;
|
||||
int timeout;
|
||||
|
||||
timeout=AqHomed_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
AqHomed_Loop(aqh, 2000);
|
||||
if (timeout) {
|
||||
time_t now;
|
||||
|
||||
now=time(NULL);
|
||||
if (timeout && ((int)difftime(now, timeStart))>timeout) {
|
||||
DBG_INFO(NULL, "Timeout");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* while */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
|
||||
stopService=1;
|
||||
break;
|
||||
default:
|
||||
DBG_WARN(0, "Unknown signal %d",s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
344
apps/aqhome-nodes/r_setdata.c
Normal file
344
apps/aqhome-nodes/r_setdata.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./r_setdata.h"
|
||||
#include "./aqhomed_p.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/data/msg_data_set.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/msg/msg_value3.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* definitions
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
|
||||
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQH_NODE_INFO *_getNodeInfoFromValue(AQHOMED *aqh, const AQH_VALUE *value);
|
||||
|
||||
static GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOMED *aqh,
|
||||
GWEN_MSG_ENDPOINT *ep, uint32_t requestMsgId,
|
||||
int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom);
|
||||
|
||||
static void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason);
|
||||
static void _rqAbort(GWEN_MSG_REQUEST *rq, int reason);
|
||||
|
||||
static GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOMED *aqh, int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom);
|
||||
static int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg);
|
||||
static void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeNodes_HandleSetData(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
uint32_t msgId;
|
||||
|
||||
DBG_INFO(NULL, "Received IPC SetDataRequest message");
|
||||
msgId=GWEN_IpcMsg_GetMsgId(recvdMsg);
|
||||
|
||||
if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||
value=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||
if (value) {
|
||||
const char *varName;
|
||||
|
||||
varName=AQH_Value_GetName(value);
|
||||
if (varName) {
|
||||
char *data;
|
||||
|
||||
data=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||
if (data) {
|
||||
AQH_NODE_INFO *nodeInfo;
|
||||
|
||||
nodeInfo=_getNodeInfoFromValue(aqh, value);
|
||||
if (nodeInfo) {
|
||||
const char *devName;
|
||||
|
||||
devName=AQH_NodeInfo_GetDeviceId(nodeInfo);
|
||||
if (devName) {
|
||||
const AQHNODE_DEVICE *devInfo;
|
||||
|
||||
devInfo=AqHomed_GetDeviceDefByName(aqh, devName);
|
||||
if (devInfo) {
|
||||
const AQHNODE_VALUE *devValue;
|
||||
|
||||
devValue=AQHNODE_Value_List_GetByName(AQHNODE_Device_GetValueList(devInfo), varName);
|
||||
if (devValue) {
|
||||
uint16_t dataVal=0;
|
||||
uint16_t dataDenom=0;
|
||||
|
||||
if (AQH_ReadDataFromString(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) {
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
int destAddr;
|
||||
|
||||
destAddr=AQH_NodeInfo_GetBusAddress(nodeInfo);
|
||||
DBG_DEBUG(NULL, "Creating SETDATA request");
|
||||
|
||||
rq=_mkRequest_SetData(aqh, ep, msgId, destAddr, AQHNODE_Value_GetId(devValue), dataVal, dataDenom);
|
||||
AqHomed_AddRequestToTree(aqh, rq);
|
||||
/* done */
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Bad data \"%s\"", data);
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_BADDATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid value name \"%s\"", varName);
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unknown node \"%s\"", devName);
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Node not yet fully identified, come back later");
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_TRYAGAIN);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No matching nodeinfo");
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_INVALID);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No data");
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_NODATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No var name");
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_NODATA);
|
||||
}
|
||||
AQH_Value_free(value);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Could not read value from message");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "TTY endpoint not connected");
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_IO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* IPC Request SETDATA
|
||||
*/
|
||||
|
||||
GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOMED *aqh,
|
||||
GWEN_MSG_ENDPOINT *ep, uint32_t requestMsgId,
|
||||
int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
GWEN_MSG_REQUEST *subRq;
|
||||
|
||||
rq=GWEN_MsgRequest_new();
|
||||
GWEN_MsgRequest_SetPrivateData(rq, aqh);
|
||||
GWEN_MsgRequest_SetEndpoint(rq, ep);
|
||||
GWEN_MsgRequest_SetRequestMsgId(rq, requestMsgId);
|
||||
GWEN_MsgRequest_SetSubRequestFinishedFn(rq, _rqSubRequestFinished);
|
||||
GWEN_MsgRequest_SetAbortFn(rq, _rqAbort);
|
||||
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_REQUEST_EXPIRE_SECS);
|
||||
|
||||
subRq=_mkSubRequest_SetData(aqh, destAddr, valueId, dataVal, dataDenom);
|
||||
GWEN_MsgRequest_Tree2_AddChild(rq, subRq);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
uint32_t refMsgId;
|
||||
int result;
|
||||
|
||||
DBG_INFO(NULL, "SubRequest finished (reason: %d)", reason);
|
||||
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=GWEN_MsgRequest_GetEndpoint(rq);
|
||||
result=GWEN_MsgRequest_GetResult(subRq);
|
||||
|
||||
if (reason==GWEN_MSG_REQUEST_REASON_ABORTED)
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
else
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, result);
|
||||
|
||||
GWEN_MsgRequest_SetResult(rq, result);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqAbort(GWEN_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
uint32_t refMsgId;
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=GWEN_MsgRequest_GetEndpoint(rq);
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* TTY Request SETDATA
|
||||
*/
|
||||
|
||||
|
||||
GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOMED *aqh, int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
uint16_t msgId;
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
rq=GWEN_MsgRequest_new();
|
||||
GWEN_MsgRequest_SetPrivateData(rq, aqh);
|
||||
GWEN_MsgRequest_SetEndpoint(rq, aqh->ttyEndpoint);
|
||||
|
||||
GWEN_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
|
||||
GWEN_MsgRequest_SetAbortFn(rq, _subRqAbort);
|
||||
|
||||
msgId=GWEN_MsgEndpoint_GetNextMessageId(aqh->ttyEndpoint) & 0xffff;
|
||||
GWEN_MsgRequest_SetRequestMsgId(rq, msgId);
|
||||
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
|
||||
|
||||
msgOut=AQH_Value3Msg_new(aqh->nodeAddress, destAddr, AQH_MSG_TYPE_VALUE_SET, msgId, valueId, dataVal, dataDenom);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg)
|
||||
{
|
||||
AQHOMED *aqh;
|
||||
uint8_t destAddr;
|
||||
|
||||
DBG_DEBUG(NULL, "Checking message from %02x", AQH_NodeMsg_GetSourceAddress(msg));
|
||||
aqh=(AQHOMED*)GWEN_MsgRequest_GetPrivateData(rq);
|
||||
|
||||
destAddr=AQH_NodeMsg_GetDestAddress(msg);
|
||||
if (destAddr==0xff || destAddr==aqh->nodeAddress) {
|
||||
uint8_t msgCode;
|
||||
|
||||
msgCode=AQH_NodeMsg_GetMsgType(msg);
|
||||
if (msgCode==AQH_MSG_TYPE_VALUE_SET_ACK || msgCode==AQH_MSG_TYPE_VALUE_SET_NACK) {
|
||||
uint16_t msgId;
|
||||
|
||||
msgId=AQH_Value3Msg_GetMsgId(msg);
|
||||
if (msgId==GWEN_MsgRequest_GetRequestMsgId(rq)) {
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL,
|
||||
"Received response (%02x) for msg id %04x from %02x",
|
||||
msgCode, msgId, AQH_NodeMsg_GetSourceAddress(msg));
|
||||
GWEN_MsgRequest_SetResult(rq, (msgCode==AQH_MSG_TYPE_VALUE_SET_ACK)?AQH_MSG_IPC_SUCCESS:AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, GWEN_MSG_REQUEST_REASON_DONE);
|
||||
return GWEN_MSG_REQUEST_RESULT_HANDLED;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, " Non-matching message id");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, " Non-matching message code");
|
||||
}
|
||||
}
|
||||
return GWEN_MSG_REQUEST_RESULT_NOT_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
|
||||
GWEN_MsgRequest_SetResult(rq, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_NODE_INFO *_getNodeInfoFromValue(AQHOMED *aqh, const AQH_VALUE *value)
|
||||
{
|
||||
const char *s;
|
||||
unsigned long int uid;
|
||||
|
||||
s=AQH_Value_GetDeviceName(value);
|
||||
if (s && *s && 1==sscanf(s, "%lx", &uid)) {
|
||||
AQH_NODE_INFO *ni;
|
||||
|
||||
ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_ERROR(NULL, "Node \"%08lx\" not found", uid);
|
||||
return NULL;
|
||||
}
|
||||
return ni;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/r_setdata.h
Normal file
27
apps/aqhome-nodes/r_setdata.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_R_SETDATA_H
|
||||
#define AQHOMED_R_SETDATA_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
#include <gwenhywfar/request.h>
|
||||
|
||||
|
||||
|
||||
void AqHomeNodes_HandleSetData(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
136
apps/aqhome-nodes/tty_log.c
Normal file
136
apps/aqhome-nodes/tty_log.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./tty_log.h"
|
||||
#include "./aqhomed_p.h"
|
||||
|
||||
#include "aqhome/msg/msg_value.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_value3.h"
|
||||
#include "aqhome/msg/msg_sendstats.h"
|
||||
#include "aqhome/msg/msg_recvstats.h"
|
||||
#include "aqhome/msg/msg_memstats.h"
|
||||
#include "aqhome/msg/msg_sysstats.h"
|
||||
#include "aqhome/msg/msg_ping.h"
|
||||
#include "aqhome/msg/msg_pong.h"
|
||||
#include "aqhome/msg/msg_needaddr.h"
|
||||
#include "aqhome/msg/msg_claimaddr.h"
|
||||
#include "aqhome/msg/msg_haveaddr.h"
|
||||
#include "aqhome/msg/msg_denyaddr.h"
|
||||
#include "aqhome/msg/msg_device.h"
|
||||
#include "aqhome/msg/msg_flashready.h"
|
||||
#include "aqhome/msg/msg_flashstart.h"
|
||||
#include "aqhome/msg/msg_flashresponse.h"
|
||||
#include "aqhome/msg/msg_flashend.h"
|
||||
#include "aqhome/msg/msg_flashdata.h"
|
||||
#include "aqhome/msg/msg_reboot.h"
|
||||
|
||||
#include <gwenhywfar/list.h>
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/gwentime.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _writeToLogFile(const char *filename, const char *txt);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
if (aqh && aqh->logFile) {
|
||||
uint8_t msgType;
|
||||
int msgIsValid;
|
||||
GWEN_BUFFER *dbuf;
|
||||
GWEN_TIME *ti;
|
||||
|
||||
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
ti=GWEN_CurrentTime();
|
||||
GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss ", dbuf);
|
||||
GWEN_Time_free(ti);
|
||||
ti=NULL;
|
||||
|
||||
msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg));
|
||||
msgType=AQH_NodeMsg_GetMsgType(msg);
|
||||
|
||||
if (msgIsValid) {
|
||||
switch(msgType) {
|
||||
case AQH_MSG_TYPE_PING: AQH_PingMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_PONG: AQH_PongMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_TWIBUSMEMBER: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_DEBUG: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_VALUE: AQH_ValueMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_VALUE2: AQH_Value2Msg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_NEED_ADDRESS: AQH_NeedAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_CLAIM_ADDRESS: AQH_ClaimAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_HAVE_ADDRESS: AQH_HaveAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_DENY_ADDRESS: AQH_DenyAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_DEVICE: AQH_DeviceMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_MEMSTATS: AQH_MemStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_SYSSTATS: AQH_SysStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_READY: AQH_FlashReadyMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_START: AQH_FlashStartMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_RSP: AQH_FlashResponseMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_END: AQH_FlashEndMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_DATA: AQH_FlashDataMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_REBOOT_REQ: AQH_RebootRequestMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_REBOOT_RSP: AQH_RebootResponseMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_VALUE_REPORT:
|
||||
case AQH_MSG_TYPE_VALUE_SET:
|
||||
case AQH_MSG_TYPE_VALUE_SET_ACK:
|
||||
case AQH_MSG_TYPE_VALUE_SET_NACK: AQH_Value3Msg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
default: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
AQH_NodeMsg_DumpToBuffer(msg, dbuf, "(invalid) received");
|
||||
}
|
||||
_writeToLogFile(aqh->logFile, GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeToLogFile(const char *filename, const char *txt)
|
||||
{
|
||||
if (txt && *txt) {
|
||||
FILE *f;
|
||||
|
||||
f=fopen(filename, "a+");
|
||||
if (f) {
|
||||
if (1!=fwrite(txt, strlen(txt), 1, f)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error logging.");
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-nodes/tty_log.h
Normal file
23
apps/aqhome-nodes/tty_log.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_TTY_LOG_H
|
||||
#define AQHOMED_TTY_LOG_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
73
apps/aqhome-nodes/types/0BUILD
Normal file
73
apps/aqhome-nodes/types/0BUILD
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhnodes_types" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
device.t2d
|
||||
value.t2d
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
device.c
|
||||
value.c
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
device.h
|
||||
device_p.h
|
||||
value.h
|
||||
value_p.h
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
87
apps/aqhome-nodes/types/device.t2d
Normal file
87
apps/aqhome-nodes/types/device.t2d
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHNODE_DEVICE" type="pointer">
|
||||
<descr>
|
||||
This object and its objects are used to store registered devices and definitions for possible new devices.
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHNODE_DEVICE</identifier>
|
||||
<prefix>AQHNODE_Device</prefix>
|
||||
<baseFileName>device</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-nodes/types/value.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="driver" type="char_ptr" maxlen="64">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="manufacturer" type="uint32_t" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="deviceType" type="uint16_t" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="deviceVersion" type="uint16_t" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="valueList" type="AQHNODE_VALUE_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
94
apps/aqhome-nodes/types/value.t2d
Normal file
94
apps/aqhome-nodes/types/value.t2d
Normal file
@@ -0,0 +1,94 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHNODE_VALUE" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHNODE_VALUE</identifier>
|
||||
<prefix>AQHNODE_Value</prefix>
|
||||
<baseFileName>value</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="32">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="description" type="char_ptr" maxlen="256">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="valueType" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="dataType" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="modality" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="valueUnits" type="char_ptr" maxlen="32">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="denom" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
88
apps/aqhome-react/0BUILD
Normal file
88
apps/aqhome-react/0BUILD
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-react" install="$(sbindir)" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
aqhome_react.h
|
||||
aqhome_react_p.h
|
||||
init.h
|
||||
fini.h
|
||||
loop.h
|
||||
net_read.h
|
||||
suntimes.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
aqhome_react.c
|
||||
init.c
|
||||
fini.c
|
||||
loop.c
|
||||
net_read.c
|
||||
suntimes.c
|
||||
main.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
aqhreact_types
|
||||
aqhreact_units
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
-lm
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
types
|
||||
units
|
||||
networks
|
||||
examples
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
385
apps/aqhome-react/aqhome_react.c
Normal file
385
apps/aqhome-react/aqhome_react.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./aqhome_react_p.h"
|
||||
#include "./net_read.h"
|
||||
#include "aqhome-react/units/u_logical.h"
|
||||
#include "aqhome-react/units/u_valuefilter.h"
|
||||
#include "aqhome-react/units/u_valueset.h"
|
||||
#include "aqhome-react/units/u_varset.h"
|
||||
#include "aqhome-react/units/u_stabilize.h"
|
||||
#include "aqhome-react/units/u_lowpass.h"
|
||||
#include "aqhome-react/units/u_highpass.h"
|
||||
#include "aqhome-react/units/u_zeroposnegstring.h"
|
||||
#include "aqhome-react/units/u_suntime.h"
|
||||
#include "aqhome-react/units/u_varchanges.h"
|
||||
#include "aqhome-react/units/u_timeprogram.h"
|
||||
#include "aqhome-react/units/u_statfns.h"
|
||||
|
||||
#include "aqhome/data/vars_dbwrite.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
AQHOME_REACT *AqHomeReact_new()
|
||||
{
|
||||
AQHOME_REACT *aqh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHOME_REACT, aqh);
|
||||
aqh->unitList=AQHREACT_Unit_List_new();
|
||||
|
||||
return aqh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeReact_free(AQHOME_REACT *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHREACT_Unit_List_free(aqh->unitList);
|
||||
GWEN_MsgEndpoint_free(aqh->brokerEndpoint);
|
||||
GWEN_DB_Group_free(aqh->dbArgs);
|
||||
free(aqh->varsFile);
|
||||
free(aqh->pidFile);
|
||||
|
||||
GWEN_FREE_OBJECT(aqh);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeReact_GetBrokerEndpoint(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?(aqh->brokerEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomeReact_GetDbArgs(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?(aqh->dbArgs):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeReact_GetPidFile(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->pidFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeReact_SetPidFile(AQHOME_REACT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->pidFile);
|
||||
aqh->pidFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeReact_GetVarsFile(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->varsFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeReact_SetVarsFile(AQHOME_REACT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->varsFile);
|
||||
aqh->varsFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_GetTimeout(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->timeout:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
time_t AqHomeReact_GetLatestNetworkFileTime(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->latestNetworkFileTime:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeReact_SetLatestNetworkFileTime(AQHOME_REACT *aqh, time_t t)
|
||||
{
|
||||
if (aqh)
|
||||
aqh->latestNetworkFileTime=t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHREACT_UNIT *AqHomeReact_GetTimerUnit(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->timerUnit:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHREACT_UNIT *AqHomeReact_GetServerVarChangeUnit(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->serverVarChangeUnit:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHREACT_UNIT *AqHomeReact_FindUnitByUnitId(const AQHOME_REACT *aqh, const char *unitId)
|
||||
{
|
||||
if (aqh && unitId && *unitId) {
|
||||
AQHREACT_UNIT *unit;
|
||||
|
||||
unit=AQHREACT_Unit_List_GetById(aqh->unitList, unitId);
|
||||
if (unit==NULL) {
|
||||
DBG_ERROR(NULL, "Unit \"%s\" not found", unitId);
|
||||
return NULL;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeReact_AddUnit(AQHOME_REACT *aqh, AQHREACT_UNIT *unit)
|
||||
{
|
||||
if (aqh && unit)
|
||||
AQHREACT_Unit_List_Add(unit, aqh->unitList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_VARS *AqHomeReact_GetLocalVars(const AQHOME_REACT *aqh)
|
||||
{
|
||||
return aqh?aqh->localVars:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_SetCharValue(AQHOME_REACT *aqh, const char *path, const char *value)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
int rv;
|
||||
uint64_t timestamp;
|
||||
|
||||
timestamp=(uint64_t) time(NULL);
|
||||
rv=AQH_Vars_SetCharValue(aqh->localVars, AQH_VARS_PATHFLAGS_OVERWRITE_VARS, path, value);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AqHomeReact_UnitVarChanges_StringVarUpdated(aqh->localVarChangeUnit, path, timestamp, value);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeReact_GetCharValue(AQHOME_REACT *aqh, const char *path, int idx, const char *defaultValue)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
return AQH_Vars_GetCharValue(aqh->localVars, path, idx, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_SetDoubleValue(AQHOME_REACT *aqh, const char *path, double value)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
int rv;
|
||||
uint64_t timestamp;
|
||||
|
||||
timestamp=(uint64_t) time(NULL);
|
||||
rv=AQH_Vars_SetDoubleValue(aqh->localVars, AQH_VARS_PATHFLAGS_OVERWRITE_VARS, path, value);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AqHomeReact_UnitVarChanges_DoubleVarUpdated(aqh->localVarChangeUnit, path, timestamp, value);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double AqHomeReact_GetDoubleValue(AQHOME_REACT *aqh, const char *path, int idx, double defaultValue)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
return AQH_Vars_GetDoubleValue(aqh->localVars, path, idx, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_SetIntValue(AQHOME_REACT *aqh, const char *path, int value)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
int rv;
|
||||
uint64_t timestamp;
|
||||
|
||||
timestamp=(uint64_t) time(NULL);
|
||||
rv=AQH_Vars_SetIntValue(aqh->localVars, AQH_VARS_PATHFLAGS_OVERWRITE_VARS, path, value);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AqHomeReact_UnitVarChanges_IntVarUpdated(aqh->localVarChangeUnit, path, timestamp, value);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_GetIntValue(AQHOME_REACT *aqh, const char *path, int idx, int defaultValue)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
return AQH_Vars_GetIntValue(aqh->localVars, path, idx, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_IncIntValue(AQHOME_REACT *aqh, const char *path, int startValue, int defaultValue)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
int v;
|
||||
|
||||
v=AQH_Vars_GetIntValue(aqh->localVars, path, 0, startValue);
|
||||
v++;
|
||||
AqHomeReact_SetIntValue(aqh, path, v);
|
||||
return v;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_DecIntValue(AQHOME_REACT *aqh, const char *path, int startValue, int defaultValue)
|
||||
{
|
||||
if (aqh && aqh->localVars && path && *path) {
|
||||
int v;
|
||||
|
||||
v=AQH_Vars_GetIntValue(aqh->localVars, path, 0, startValue);
|
||||
v--;
|
||||
AqHomeReact_SetIntValue(aqh, path, v);
|
||||
return v;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeReact_WriteVarsFile(AQHOME_REACT *aqh)
|
||||
{
|
||||
if (aqh && aqh->localVars && aqh->varsFile) {
|
||||
int rv;
|
||||
|
||||
rv=AQH_Vars_WriteDbFile(aqh->localVars, aqh->varsFile);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHREACT_UNIT *AqHomeReact_CreateUnitByName(AQHOME_REACT *aqh, const char *unitType)
|
||||
{
|
||||
/* this does not include u_timer and u_varchanges, because those are only created once globally in init.c */
|
||||
if (aqh && unitType && *unitType) {
|
||||
if (strcasecmp(unitType, "or")==0)
|
||||
return AqHomeReact_UnitOr_new(aqh);
|
||||
else if (strcasecmp(unitType, "and")==0)
|
||||
return AqHomeReact_UnitAnd_new(aqh);
|
||||
else if (strcasecmp(unitType, "xor")==0)
|
||||
return AqHomeReact_UnitXor_new(aqh);
|
||||
else if (strcasecmp(unitType, "valueFilter")==0)
|
||||
return AqHomeReact_UnitValueFilter_new(aqh);
|
||||
else if (strcasecmp(unitType, "valueSet")==0)
|
||||
return AqHomeReact_UnitValueSet_new(aqh);
|
||||
else if (strcasecmp(unitType, "varSet")==0)
|
||||
return AqHomeReact_UnitVarSet_new(aqh);
|
||||
else if (strcasecmp(unitType, "stabilize")==0)
|
||||
return AqHomeReact_UnitStabilize_new(aqh);
|
||||
else if (strcasecmp(unitType, "lowPass")==0)
|
||||
return AqHomeReact_UnitLowPass_new(aqh);
|
||||
else if (strcasecmp(unitType, "highPass")==0)
|
||||
return AqHomeReact_UnitHighPass_new(aqh);
|
||||
else if (strcasecmp(unitType, "zeroPosNegString")==0)
|
||||
return AqHomeReact_UnitZeroPosNegString_new(aqh);
|
||||
else if (strcasecmp(unitType, "suntime")==0)
|
||||
return AqHomeReact_UnitSuntime_new(aqh);
|
||||
else if (strcasecmp(unitType, "timeraction")==0)
|
||||
return AqHomeReact_UnitTimeProgram_new(aqh);
|
||||
else if (strcasecmp(unitType, "average")==0)
|
||||
return AqHomeReact_UnitAverage_new(aqh);
|
||||
else if (strcasecmp(unitType, "minvalue")==0)
|
||||
return AqHomeReact_UnitMinValue_new(aqh);
|
||||
else if (strcasecmp(unitType, "maxvalue")==0)
|
||||
return AqHomeReact_UnitMaxValue_new(aqh);
|
||||
else {
|
||||
AQHREACT_UNIT *unit;
|
||||
|
||||
DBG_INFO(NULL, "Trying to load network \"%s\"", unitType);
|
||||
unit=AQHomeReact_FindAndReadDataDirNetwork(aqh, unitType);
|
||||
if (unit==NULL) {
|
||||
DBG_ERROR(NULL, "Unknown unit type \"%s\"", unitType);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
const char *s;
|
||||
|
||||
s=AQHREACT_Unit_GetTypeName(unit);
|
||||
if (!(s && *s && strcasecmp(s, unitType)==0)) {
|
||||
DBG_ERROR(NULL, "ERROR: Network file for type \"%s\" contains type \"%s\" instead", unitType, s?s:"<no name>");
|
||||
AQHREACT_Unit_free(unit);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user