98_configdb.pm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. # $Id: 98_configdb.pm 16477 2018-03-24 17:58:10Z betateilchen $
  2. #
  3. package main;
  4. use strict;
  5. use warnings;
  6. use feature qw/say switch/;
  7. use POSIX;
  8. use configDB;
  9. no if $] >= 5.017011, warnings => 'experimental';
  10. sub CommandConfigdb($$);
  11. sub _cfgDB_readConfig();
  12. my @pathname;
  13. sub configdb_Initialize($$) {
  14. my %hash = ( Fn => "CommandConfigdb",
  15. Hlp => "help ,access additional functions from configDB" );
  16. $cmds{configdb} = \%hash;
  17. }
  18. sub CommandConfigdb($$) {
  19. my ($cl, $param) = @_;
  20. my @a = split("[ \t][ \t]*", $param);
  21. my ($cmd, $param1, $param2) = @a;
  22. $cmd //= "";
  23. $param1 //= "";
  24. $param2 //= "";
  25. my $configfile = $attr{global}{configfile};
  26. return "\n error: configDB not used!" unless($configfile eq 'configDB' || $cmd eq 'migrate');
  27. my $ret;
  28. given ($cmd) {
  29. when ('attr') {
  30. Log3('configdb', 4, "configdb: attr $param1 $param2 requested.");
  31. if ($param1 eq "" && $param2 eq "") {
  32. # list attributes
  33. foreach my $c (sort keys %{$configDB{attr}}) {
  34. my $val = $configDB{attr}{$c};
  35. $val =~ s/;/;;/g;
  36. $val =~ s/\n/\\\n/g;
  37. $ret .= "configdb attr $c $val\n";
  38. }
  39. } elsif($param2 eq "") {
  40. # delete attribute
  41. delete $configDB{attr}{$param1};
  42. $ret = " attribute $param1 deleted";
  43. } else {
  44. # set attribute
  45. $configDB{attr}{$param1} = $param2;
  46. $ret = " attribute $param1 set to value $param2";
  47. }
  48. }
  49. when ('dump') {
  50. return _cfgDB_dump($param1);
  51. }
  52. when ('diff') {
  53. return "\n Syntax: configdb diff <device> <version>" if @a != 3;
  54. Log3('configdb', 4, "configdb: diff requested for device: $param1 in version $param2.");
  55. $ret = _cfgDB_Diff($param1, $param2);
  56. }
  57. when ('filedelete') {
  58. return "\n Syntax: configdb filedelete <pathToFile>" if @a != 2;
  59. my $filename;
  60. if($param1 =~ m,^[./],) {
  61. $filename = $param1;
  62. } else {
  63. $filename = $attr{global}{modpath};
  64. $filename .= "/$param1";
  65. }
  66. $ret = "File $filename ";
  67. $ret .= defined(_cfgDB_Filedelete($filename)) ? "deleted from" : "not found in";
  68. $ret .= " database.";
  69. }
  70. when ('fileexport') {
  71. return "\n Syntax: configdb fileexport <pathToFile>" if @a != 2;
  72. if ($param1 ne 'all') {
  73. my $filename;
  74. if($param1 =~ m,^[./],) {
  75. $filename = $param1;
  76. } else {
  77. $filename = $attr{global}{modpath};
  78. $filename .= "/$param1";
  79. }
  80. $ret = _cfgDB_Fileexport $filename;
  81. } else { # start export all
  82. my $flist = _cfgDB_Filelist(1);
  83. my @filelist = split(/\n/,$flist);
  84. undef $flist;
  85. foreach my $f (@filelist) {
  86. Log3 (4,undef,"configDB: exporting $f");
  87. my ($path,$file) = $f =~ m|^(.*[/\\])([^/\\]+?)$|;
  88. $path = "/tmp/$path";
  89. eval qx(mkdir -p $path) unless (-e "$path");
  90. $ret .= _cfgDB_Fileexport $f;
  91. $ret .= "\n";
  92. }
  93. } # end export all
  94. }
  95. when ('fileimport') {
  96. return "\n Syntax: configdb fileimport <pathToFile>" if @a != 2;
  97. my $filename;
  98. if($param1 =~ m,^[./],) {
  99. $filename = $param1;
  100. } else {
  101. $filename = $attr{global}{modpath};
  102. $filename .= "/$param1";
  103. }
  104. if ( -r $filename ) {
  105. my $filesize = -s $filename;
  106. $ret = _cfgDB_binFileimport($filename,$filesize);
  107. } elsif ( -e $filename) {
  108. $ret = "\n Read error on file $filename";
  109. } else {
  110. $ret = "\n File $filename not found.";
  111. }
  112. }
  113. when ('filelist') {
  114. return _cfgDB_Filelist;
  115. }
  116. when ('filemove') {
  117. return "\n Syntax: configdb filemove <pathToFile>" if @a != 2;
  118. my $filename;
  119. if($param1 =~ m,^[./],) {
  120. $filename = $param1;
  121. } else {
  122. $filename = $attr{global}{modpath};
  123. $filename .= "/$param1";
  124. }
  125. if ( -r $filename ) {
  126. my $filesize = -s $filename;
  127. $ret = _cfgDB_binFileimport ($filename,$filesize,1);
  128. $ret .= "\nFile $filename deleted from local filesystem.";
  129. } elsif ( -e $filename) {
  130. $ret = "\n Read error on file $filename";
  131. } else {
  132. $ret = "\n File $filename not found.";
  133. }
  134. }
  135. when ('fileshow') {
  136. return "\n Syntax: configdb fileshow <pathToFile>" if @a != 2;
  137. my @rets = cfgDB_FileRead($param1);
  138. my $r = (int(@rets)) ? join "\n",@rets : "File $param1 not found in database.";
  139. return $r;
  140. }
  141. when ('info') {
  142. Log3('configdb', 4, "info requested.");
  143. $ret = _cfgDB_Info('$Id: 98_configdb.pm 16477 2018-03-24 17:58:10Z betateilchen $');
  144. }
  145. when ('list') {
  146. $param1 = $param1 ? $param1 : '%';
  147. $param2 = $param2 ? $param2 : 0;
  148. $ret = "list not allowed for configDB itself.";
  149. break if($param1 =~ m/configdb/i);
  150. Log3('configdb', 4, "configdb: list requested for device: $param1 in version $param2.");
  151. $ret = _cfgDB_Search($param1,$param2,1);
  152. }
  153. when ('migrate') {
  154. return "\n Migration not possible. Already running with configDB!" if $configfile eq 'configDB';
  155. Log3('configdb', 4, "configdb: migration requested.");
  156. $ret = _cfgDB_Migrate;
  157. }
  158. when ('recover') {
  159. return "\n Syntax: configdb recover <version>" if @a != 2;
  160. Log3('configdb', 4, "configdb: recover for version $param1 requested.");
  161. $ret = _cfgDB_Recover($param1);
  162. }
  163. when ('reorg') {
  164. # $param1 = $param1 ? $param1 : 3;
  165. $param1 //= 3;
  166. Log3('configdb', 4, "configdb: reorg requested with keep: $param1.");
  167. $ret = _cfgDB_Reorg($a[1]);
  168. }
  169. when ('search') {
  170. return "\n Syntax: configdb search <searchTerm> [searchVersion]" if @a < 2;
  171. $param1 = $param1 ? $param1 : '%';
  172. $param2 = $param2 ? $param2 : 0;
  173. Log3('configdb', 4, "configdb: list requested for device: $param1 in version $param2.");
  174. $ret = _cfgDB_Search($param1,$param2);
  175. }
  176. when ('uuid') {
  177. $param1 = _cfgDB_Uuid;
  178. Log3('configdb', 4, "configdb: uuid requested: $param1");
  179. $ret = $param1;
  180. }
  181. default {
  182. $ret = "\n Syntax:\n".
  183. " configdb attr [attribute] [value]\n".
  184. " configdb diff <device> <version>\n".
  185. " configdb dump\n".
  186. " configDB filedelete <pathToFilename>\n".
  187. " configDB fileimport <pathToFilename>\n".
  188. " configDB fileexport <pathToFilename>\n".
  189. " configDB filelist\n".
  190. " configDB filemove <pathToFilename>\n".
  191. " configDB fileshow <pathToFilename>\n".
  192. " configdb info\n".
  193. " configdb list [device] [version]\n".
  194. " configdb migrate\n".
  195. " configdb recover <version>\n".
  196. " configdb reorg [keepVersions]\n".
  197. " configdb search <searchTerm> [version]\n".
  198. " configdb uuid\n".
  199. "";
  200. }
  201. }
  202. return $ret;
  203. }
  204. sub _cfgDB_readConfig() {
  205. if(!open(CONFIG, 'configDB.conf')) {
  206. Log3('configDB', 1, 'Cannot open database configuration file configDB.conf');
  207. return 0;
  208. }
  209. my @config=<CONFIG>;
  210. close(CONFIG);
  211. use vars qw(%configDB);
  212. my %dbconfig;
  213. eval join("", @config);
  214. my $cfgDB_dbconn = $dbconfig{connection};
  215. my $cfgDB_dbuser = $dbconfig{user};
  216. my $cfgDB_dbpass = $dbconfig{password};
  217. my $cfgDB_dbtype;
  218. %dbconfig = ();
  219. @config = ();
  220. if($cfgDB_dbconn =~ m/pg:/i) {
  221. $cfgDB_dbtype ="POSTGRESQL";
  222. } elsif ($cfgDB_dbconn =~ m/mysql:/i) {
  223. $cfgDB_dbtype = "MYSQL";
  224. } elsif ($cfgDB_dbconn =~ m/sqlite:/i) {
  225. $cfgDB_dbtype = "SQLITE";
  226. } else {
  227. $cfgDB_dbtype = "unknown";
  228. }
  229. return($cfgDB_dbconn,$cfgDB_dbuser,$cfgDB_dbpass,$cfgDB_dbtype);
  230. }
  231. 1;
  232. =pod
  233. =item command
  234. =item summary frontend command for configDB configuration
  235. =item summary_DE Befehl zur Konfiguration der configDB
  236. =begin html
  237. <a name="configdb"></a>
  238. <h3>configdb</h3>
  239. <ul>
  240. <a href="https://forum.fhem.de/index.php?board=46.0">Link to FHEM forum</a><br/><br/>
  241. Starting with version 5079, fhem can be used with a configuration database instead of a plain text file (e.g. fhem.cfg).<br/>
  242. This offers the possibility to completely waive all cfg-files, "include"-problems and so on.<br/>
  243. Furthermore, configDB offers a versioning of several configuration together with the possibility to restore a former configuration.<br/>
  244. Access to database is provided via perl's database interface DBI.<br/>
  245. <br/>
  246. <b>Interaction with other modules</b><br/>
  247. <ul><br/>
  248. Currently the fhem modules<br/>
  249. <br/>
  250. <li>02_RSS.pm</li>
  251. <li>55_InfoPanel.pm</li>
  252. <li>91_eventTypes</li>
  253. <li>93_DbLog.pm</li>
  254. <li>95_holiday.pm</li>
  255. <li>98_SVG.pm</li>
  256. <br/>
  257. will use configDB to read their configuration data from database<br/>
  258. instead of formerly used configuration files inside the filesystem.<br/>
  259. <br/>
  260. This requires you to import your configuration files from filesystem into database.<br/>
  261. <br/>
  262. Example:<br/>
  263. <code>configdb fileimport FHEM/nrw.holiday</code><br/>
  264. <code>configdb fileimport FHEM/myrss.layout</code><br/>
  265. <code>configdb fileimport www/gplot/xyz.gplot</code><br/>
  266. <br/>
  267. <b>This does not affect the definitons of your holiday or RSS entities.</b><br/>
  268. <br/>
  269. <b>During migration all external configfiles used in current configuration<br/>
  270. will be imported aufmatically.</b><br>
  271. <br/>
  272. Each fileimport into database will overwrite the file if it already exists in database.<br/>
  273. <br/>
  274. </ul><br/>
  275. <br/>
  276. <b>Prerequisits / Installation</b><br/>
  277. <ul><br/>
  278. <li>Please install perl package Text::Diff if not already installed on your system.</li><br/>
  279. <li>You must have access to a SQL database. Supported database types are SQLITE, MYSQL and POSTGRESQL.</li><br/>
  280. <li>The corresponding DBD module must be available in your perl environment,<br/>
  281. e.g. sqlite3 running on a Debian systems requires package libdbd-sqlite3-perl</li><br/>
  282. <li>Create an empty database, e.g. with sqlite3:<br/>
  283. <pre>
  284. mba:fhem udo$ sqlite3 configDB.db
  285. SQLite version 3.7.13 2012-07-17 17:46:21
  286. Enter ".help" for instructions
  287. Enter SQL statements terminated with a ";"
  288. sqlite> pragma auto_vacuum=2;
  289. sqlite> .quit
  290. mba:fhem udo$
  291. </pre></li>
  292. <li>The database tables will be created automatically.</li><br/>
  293. <li>Create a configuration file containing the connection string to access database.<br/>
  294. <br/>
  295. <b>IMPORTANT:</b>
  296. <ul><br/>
  297. <li>This file <b>must</b> be named "configDB.conf"</li>
  298. <li>This file <b>must</b> be located in the same directory containing fhem.pl and configDB.pm, e.g. /opt/fhem</li>
  299. </ul>
  300. <br/>
  301. <pre>
  302. ## for MySQL
  303. ################################################################
  304. #%dbconfig= (
  305. # connection => "mysql:database=configDB;host=db;port=3306",
  306. # user => "fhemuser",
  307. # password => "fhempassword",
  308. #);
  309. ################################################################
  310. #
  311. ## for PostgreSQL
  312. ################################################################
  313. #%dbconfig= (
  314. # connection => "Pg:database=configDB;host=localhost",
  315. # user => "fhemuser",
  316. # password => "fhempassword"
  317. #);
  318. ################################################################
  319. #
  320. ## for SQLite (username and password stay empty for SQLite)
  321. ################################################################
  322. #%dbconfig= (
  323. # connection => "SQLite:dbname=/opt/fhem/configDB.db",
  324. # user => "",
  325. # password => ""
  326. #);
  327. ################################################################
  328. </pre></li><br/>
  329. </ul>
  330. <b>Start with a complete new "fresh" fhem Installation</b><br/>
  331. <ul><br/>
  332. It's easy... simply start fhem by issuing following command:<br/><br/>
  333. <ul><code>perl fhem.pl configDB</code></ul><br/>
  334. <b>configDB</b> is a keyword which is recognized by fhem to use database for configuration.<br/>
  335. <br/>
  336. <b>That's all.</b> Everything (save, rereadcfg etc) should work as usual.
  337. </ul>
  338. <br/>
  339. <b>or:</b><br/>
  340. <br/>
  341. <b>Migrate your existing fhem configuration into the database</b><br/>
  342. <ul><br/>
  343. It's easy, too... <br/>
  344. <br/>
  345. <li>start your fhem the last time with fhem.cfg<br/><br/>
  346. <ul><code>perl fhem.pl fhem.cfg</code></ul></li><br/>
  347. <br/>
  348. <li>transfer your existing configuration into the database<br/><br/>
  349. <ul>enter<br/><br/><code>configdb migrate</code><br/>
  350. <br/>
  351. into frontend's command line</ul><br/></br>
  352. Be patient! Migration can take some time, especially on mini-systems like RaspberryPi or Beaglebone.<br/>
  353. Completed migration will be indicated by showing database statistics.<br/>
  354. Your original configfile will not be touched or modified by this step.</li><br/>
  355. <li>shutdown fhem</li><br/>
  356. <li>restart fhem with keyword configDB<br/><br/>
  357. <ul><code>perl fhem.pl configDB</code></ul></li><br/>
  358. <b>configDB</b> is a keyword which is recognized by fhem to use database for configuration.<br/>
  359. <br/>
  360. <b>That's all.</b> Everything (save, rereadcfg etc) should work as usual.
  361. </ul>
  362. <br/><br/>
  363. <b>Additional functions provided</b><br/>
  364. <ul><br/>
  365. A new command <code>configdb</code> is propagated to fhem.<br/>
  366. This command can be used with different parameters.<br/>
  367. <br/>
  368. <li><code>configdb attr [attribute] [value]</code></li><br/>
  369. Provides the possibility to pass attributes to backend and frontend.<br/>
  370. <br/>
  371. <code> configdb attr private 1</code> - set the attribute named 'private' to value 1.<br/>
  372. <br/>
  373. <code> configdb attr private</code> - delete the attribute named 'private'<br/>
  374. <br/>
  375. <code> configdb attr</code> - show all defined attributes.<br/>
  376. <br/>
  377. <ul>Supported attributes:</ul>
  378. <br/>
  379. <ul><b>deleteimported</b> if set to 1 files will always be deleted from filesystem after import to database.<br/></ul><br/>
  380. <ul><b>maxversions</b> set the maximum number of configurations stored in database. <br/>
  381. The oldest version will be dropped in a "save config" if it would exceed this number.</ul><br/>
  382. <ul><b>private</b> if set to 0 the database user and password info will be shown in 'configdb info' output.</ul><br/>
  383. <br/>
  384. <li><code>configdb diff &lt;device&gt; &lt;version&gt;</code></li><br/>
  385. Compare configuration dataset for device &lt;device&gt;
  386. from current version 0 with version &lt;version&gt;<br/>
  387. Example for valid request:<br/>
  388. <br/>
  389. <code>configdb diff telnetPort 1</code><br/>
  390. <br/>
  391. will show a result like this:
  392. <pre>
  393. compare device: telnetPort in current version 0 (left) to version: 1 (right)
  394. +--+--------------------------------------+--+--------------------------------------+
  395. | 1|define telnetPort telnet 7072 global | 1|define telnetPort telnet 7072 global |
  396. * 2|attr telnetPort room telnet * | |
  397. +--+--------------------------------------+--+--------------------------------------+</pre>
  398. <b>Special: configdb diff all current</b><br/>
  399. <br/>
  400. Will show a diff table containing all changes between saved version 0<br/>
  401. and UNSAVED version from memory (currently running installation).<br/>
  402. <br/>
  403. <li><code>configdb dump [unzipped]</code></li><br/>
  404. Create a gzipped dump file from from database.<br/>
  405. If optional parameter 'unzipped' provided, dump file will be written unzipped.<br/>
  406. <br/>
  407. <br/>
  408. <li><code>configdb filedelete &lt;Filename&gt;</code></li><br/>
  409. Delete file from database.<br/>
  410. <br/>
  411. <br/>
  412. <li><code>configdb fileexport &lt;targetFilename&gt;|all</code></li><br/>
  413. Exports specified file (or all files) from database into filesystem.<br/>
  414. Example:<br/>
  415. <br/>
  416. <code>configdb fileexport FHEM/99_myUtils.pm</code><br/>
  417. <br/>
  418. <br/>
  419. <li><code>configdb fileimport &lt;sourceFilename&gt;</code></li><br/>
  420. Imports specified text file from from filesystem into database.<br/>
  421. Example:<br/>
  422. <br/>
  423. <code>configdb fileimport FHEM/99_myUtils.pm</code><br/>
  424. <br/>
  425. <br/>
  426. <li><code>configdb filelist</code></li><br/>
  427. Show a list with all filenames stored in database.<br/>
  428. <br/>
  429. <br/>
  430. <li><code>configdb filemove &lt;sourceFilename&gt;</code></li><br/>
  431. Imports specified fhem file from from filesystem into database and<br/>
  432. deletes the file from local filesystem afterwards.<br/>
  433. Example:<br/>
  434. <br/>
  435. <code>configdb filemove FHEM/99_myUtils.pm</code><br/>
  436. <br/>
  437. <br/>
  438. <li><code>configdb fileshow &lt;Filename&gt;</code></li><br/>
  439. Show content of specified file stored in database.<br/>
  440. <br/>
  441. <br/>
  442. <li><code>configdb info</code></li><br/>
  443. Returns some database statistics<br/>
  444. <pre>
  445. --------------------------------------------------------------------------------
  446. configDB Database Information
  447. --------------------------------------------------------------------------------
  448. dbconn: SQLite:dbname=/opt/fhem/configDB.db
  449. dbuser:
  450. dbpass:
  451. dbtype: SQLITE
  452. --------------------------------------------------------------------------------
  453. fhemconfig: 7707 entries
  454. Ver 0 saved: Sat Mar 1 11:37:00 2014 def: 293 attr: 1248
  455. Ver 1 saved: Fri Feb 28 23:55:13 2014 def: 293 attr: 1248
  456. Ver 2 saved: Fri Feb 28 23:49:01 2014 def: 293 attr: 1248
  457. Ver 3 saved: Fri Feb 28 22:24:40 2014 def: 293 attr: 1247
  458. Ver 4 saved: Fri Feb 28 22:14:03 2014 def: 293 attr: 1246
  459. --------------------------------------------------------------------------------
  460. fhemstate: 1890 entries saved: Sat Mar 1 12:05:00 2014
  461. --------------------------------------------------------------------------------
  462. </pre>
  463. Ver 0 always indicates the currently running configuration.<br/>
  464. <br/>
  465. <li><code>configdb list [device] [version]</code></li><br/>
  466. Search for device named [device] in configuration version [version]<br/>
  467. in database archive.<br/>
  468. Default value for [device] = % to show all devices.<br/>
  469. Default value for [version] = 0 to show devices from current version.<br/>
  470. Examples for valid requests:<br/>
  471. <br/>
  472. <code>get configDB list</code><br/>
  473. <code>get configDB list global</code><br/>
  474. <code>get configDB list '' 1</code><br/>
  475. <code>get configDB list global 1</code><br/>
  476. <br/>
  477. <li><code>configdb recover &lt;version&gt;</code></li><br/>
  478. Restores an older version from database archive.<br/>
  479. <code>configdb recover 3</code> will <b>copy</b> version #3 from database
  480. to version #0.<br/>
  481. Original version #0 will be lost.<br/><br/>
  482. <b>Important!</b><br/>
  483. The restored version will <b>NOT</b> be activated automatically!<br/>
  484. You must do a <code>rereadcfg</code> or - even better - <code>shutdown restart</code> yourself.<br/>
  485. <br/>
  486. <li><code>configdb reorg [keep]</code></li><br/>
  487. Deletes all stored versions with version number higher than [keep].<br/>
  488. Default value for optional parameter keep = 3.<br/>
  489. This function can be used to create a nightly running job for<br/>
  490. database reorganisation when called from an at-Definition.<br/>
  491. <br/>
  492. <li><code>configdb search <searchTerm> [searchVersion]</code></li><br/>
  493. Search for specified searchTerm in any given version (default=0)<br/>
  494. <pre>
  495. Example:
  496. configdb search %2286BC%
  497. Result:
  498. search result for: %2286BC% in version: 0
  499. --------------------------------------------------------------------------------
  500. define az_RT CUL_HM 2286BC
  501. define az_RT_Clima CUL_HM 2286BC04
  502. define az_RT_Climate CUL_HM 2286BC02
  503. define az_RT_ClimaTeam CUL_HM 2286BC05
  504. define az_RT_remote CUL_HM 2286BC06
  505. define az_RT_Weather CUL_HM 2286BC01
  506. define az_RT_WindowRec CUL_HM 2286BC03
  507. attr Melder_FAl peerIDs 00000000,2286BC03,
  508. attr Melder_FAr peerIDs 00000000,2286BC03,
  509. </pre>
  510. <br/>
  511. <li><code>configdb uuid</code></li><br/>
  512. Returns a uuid that can be used for own purposes.<br/>
  513. <br/>
  514. </ul>
  515. <br/>
  516. <br/>
  517. <b>Author's notes</b><br/>
  518. <br/>
  519. <ul>
  520. <li>You can find two template files for datebase and configfile (sqlite only!) for easy installation.<br/>
  521. Just copy them to your fhem installation directory (/opt/fhem) and have fun.</li>
  522. <br/>
  523. <li>The frontend option "Edit files"-&gt;"config file" will be removed when running configDB.</li>
  524. <br/>
  525. <li>Please be patient when issuing a "save" command
  526. (either manually or by clicking on "save config").<br/>
  527. This will take some moments, due to writing version informations.<br/>
  528. Finishing the save-process will be indicated by a corresponding message in frontend.</li>
  529. <br/>
  530. <li>There still will be some more (planned) development to this extension,
  531. especially regarding some perfomance issues.</li>
  532. <br/>
  533. <li>Have fun!</li>
  534. </ul>
  535. </ul>
  536. =end html
  537. =cut