;
close(CONFIG);
my %dbconfig;
eval join("", @config);
my $cfgDB_dbconn = $dbconfig{connection};
my $cfgDB_dbuser = $dbconfig{user};
my $cfgDB_dbpass = $dbconfig{password};
my $cfgDB_dbtype;
(%dbconfig, @config) = (undef,undef);
if($cfgDB_dbconn =~ m/pg:/i) {
$cfgDB_dbtype ="POSTGRESQL";
} elsif ($cfgDB_dbconn =~ m/mysql:/i) {
$cfgDB_dbtype = "MYSQL";
# } elsif ($cfgDB_dbconn =~ m/oracle:/i) {
# $cfgDB_dbtype = "ORACLE";
} elsif ($cfgDB_dbconn =~ m/sqlite:/i) {
$cfgDB_dbtype = "SQLITE";
} else {
$cfgDB_dbtype = "unknown";
}
sub cfgDB_svnId {
return "# ".'$Id$'
}
sub cfgDB_Connect {
my $fhem_dbh = DBI->connect(
"dbi:$cfgDB_dbconn",
$cfgDB_dbuser,
$cfgDB_dbpass,
{ AutoCommit => 0, RaiseError => 1 },
) or die $DBI::errstr;
return $fhem_dbh;
}
sub cfgDB_Uuid{
my $fhem_dbh = cfgDB_Connect;
my $uuid;
$uuid = $fhem_dbh->selectrow_array('select lower(hex(randomblob(16)))') if($cfgDB_dbtype eq 'SQLITE');
$uuid = $fhem_dbh->selectrow_array('select uuid()') if($cfgDB_dbtype eq 'MYSQL');
$uuid = $fhem_dbh->selectrow_array('select uuid_generate_v4()') if($cfgDB_dbtype eq 'POSTGRESQL');
$fhem_dbh->disconnect();
return $uuid;
}
sub cfgDB_Init {
##################################################
# Create non-existing database tables
# Create default config entries if necessary
#
my $fhem_dbh = cfgDB_Connect;
eval { $fhem_dbh->do("CREATE EXTENSION \"uuid-ossp\"") if($cfgDB_dbtype eq 'POSTGRESQL'); };
# create TABLE fhemversions ifnonexistent
$fhem_dbh->do("CREATE TABLE IF NOT EXISTS fhemversions(VERSION INT, VERSIONUUID CHAR(50))");
# create TABLE fhemconfig if nonexistent
$fhem_dbh->do("CREATE TABLE IF NOT EXISTS fhemconfig(COMMAND CHAR(32), DEVICE CHAR(32), P1 CHAR(50), P2 TEXT, VERSION INT, VERSIONUUID CHAR(50))");
# check TABLE fhemconfig already populated
my $count = $fhem_dbh->selectrow_array('SELECT count(*) FROM fhemconfig');
if($count < 1) {
# insert default entries to get fhem running
my $uuid = cfgDB_Uuid;
$fhem_dbh->do("INSERT INTO fhemversions values (0, '$uuid')");
cfgDB_InsertLine($fhem_dbh, $uuid, '#created by cfgDB_Init');
cfgDB_InsertLine($fhem_dbh, $uuid, 'attr global logfile ./log/fhem-%Y-%m-%d.log');
cfgDB_InsertLine($fhem_dbh, $uuid, 'attr global modpath .');
cfgDB_InsertLine($fhem_dbh, $uuid, 'attr global userattr devStateIcon devStateStyle icon sortby webCmd');
cfgDB_InsertLine($fhem_dbh, $uuid, 'attr global verbose 3');
cfgDB_InsertLine($fhem_dbh, $uuid, 'define telnetPort telnet 7072 global');
cfgDB_InsertLine($fhem_dbh, $uuid, 'define WEB FHEMWEB 8083 global');
cfgDB_InsertLine($fhem_dbh, $uuid, 'define Logfile FileLog ./log/fhem-%Y-%m-%d.log fakelog');
}
# create TABLE fhemstate if nonexistent
$fhem_dbh->do("CREATE TABLE IF NOT EXISTS fhemstate(stateString TEXT)");
# close database connection
$fhem_dbh->commit();
$fhem_dbh->disconnect();
return;
}
sub cfgDB_Info {
my $l = '--------------------';
$l .= $l;
$l .= $l;
$l .= "\n";
my $r = $l;
$r .= " configDB Database Information\n";
$r .= $l;
$r .= " dbconn: $cfgDB_dbconn\n";
$r .= " dbuser: $cfgDB_dbuser\n";
$r .= " dbpass: $cfgDB_dbpass\n";
$r .= " dbtype: $cfgDB_dbtype\n";
$r .= " Unknown dbmodel type in configuration file.\n" if $dbtype eq 'unknown';
$r .= " Only Mysql, Postgresql, SQLite are fully supported.\n" if $dbtype eq 'unknown';
$r .= $l;
my $fhem_dbh = cfgDB_Connect;
my ($sql, $sth, @line, $row);
# read versions table statistics
my $count;
$count = $fhem_dbh->selectrow_array('SELECT count(*) FROM fhemconfig');
$r .= " fhemconfig: $count entries\n\n";
# read versions creation time
$sql = "SELECT * FROM fhemconfig as c join fhemversions as v on v.versionuuid=c.versionuuid ".
"WHERE COMMAND like '#created%' ORDER by v.VERSION";
$sth = $fhem_dbh->prepare( $sql );
$sth->execute();
while (@line = $sth->fetchrow_array()) {
$row = " Ver $line[6] saved: $line[1] $line[2] $line[3] def: ".
$fhem_dbh->selectrow_array("SELECT COUNT(*) from fhemconfig where COMMAND = 'define' and VERSIONUUID = '$line[5]'");
$row .= " attr: ".
$fhem_dbh->selectrow_array("SELECT COUNT(*) from fhemconfig where COMMAND = 'attr' and VERSIONUUID = '$line[5]'");
$r .= "$row\n";
}
$r .= $l;
# read state table statistics
$count = $fhem_dbh->selectrow_array('SELECT count(*) FROM fhemstate');
$r .= " fhemstate: $count entries saved: ";
# read state table creation time
$sth = $fhem_dbh->prepare( "SELECT * FROM fhemstate WHERE STATESTRING like '#%'" );
$sth->execute();
while ($row = $sth->fetchrow_array()) {
(undef,$row) = split(/#/,$row);
$r .= "$row\n";
}
$r .= $l;
$fhem_dbh->disconnect();
return $r;
}
sub cfgDB_Recover($) {
my ($version) = @_;
my ($cmd, $count, $ret);
if($version > 0) {
my $fhem_dbh = cfgDB_Connect;
$cmd = "SELECT count(*) FROM fhemconfig WHERE VERSIONUUID in (select versionuuid from fhemversions where version = $version)";
$count = $fhem_dbh->selectrow_array($cmd);
if($count > 0) {
my $fromuuid = $fhem_dbh->selectrow_array("select versionuuid from fhemversions where version = $version");
my $touuid = cfgDB_Uuid;
# Delete current version 0
$fhem_dbh->do("DELETE FROM fhemconfig WHERE VERSIONUUID in (select versionuuid from fhemversions where version = 0)");
$fhem_dbh->do("update fhemversions set versionuuid = '$touuid' where version = 0");
# Copy selected version to version 0
my ($sth, $sth2, @line);
$cmd = "SELECT * FROM fhemconfig WHERE VERSIONUUID = '$fromuuid'";
$sth = $fhem_dbh->prepare($cmd);
$sth->execute();
$sth2 = $fhem_dbh->prepare('INSERT INTO fhemconfig values (?, ?, ?, ?, ?, ?)');
while (@line = $sth->fetchrow_array()) {
$sth2->execute($line[0], $line[1], $line[2], $line[3], -1, $touuid);
}
$fhem_dbh->commit();
$fhem_dbh->disconnect();
# Inform user about restart or rereadcfg needed
$ret = "Version 0 deleted.\n";
$ret .= "Version $version copied to version 0\n\n";
$ret .= "Please use rereadcfg or restart to activate configuration.";
} else {
$fhem_dbh->disconnect();
$ret = "No entries found in version $version.\nNo changes committed to database.";
}
} else {
$ret = 'Please select version 1..n for recovery.';
}
return $ret;
}
sub cfgDB_Reorg(;$) {
my ($lastversion) = @_;
$lastversion = ($lastversion > 0) ? $lastversion : 3;
Log3('configDB', 4, "DB Reorg started, keeping last $lastversion versions.");
my $fhem_dbh = cfgDB_Connect;
$fhem_dbh->do("delete FROM fhemconfig where versionuuid in (select versionuuid from fhemversions where version > $lastversion)");
$fhem_dbh->do("delete from fhemversions where version > $lastversion");
$fhem_dbh->commit();
$fhem_dbh->disconnect();
return " Result after database reorg:\n".cfgDB_Info;
}
sub cfgDB_InsertLine($$$) {
my ($fhem_dbh, $uuid, $line) = @_;
my ($c,$d,$p1,$p2) = split(/ /, $line, 4);
my $sth = $fhem_dbh->prepare('INSERT INTO fhemconfig values (?, ?, ?, ?, ?, ?)');
$sth->execute($c, $d, $p1, $p2, -1, $uuid);
return;
}
sub cfgDB_Execute($@) {
my ($cl, @dbconfig) = @_;
my $ret;
foreach (@dbconfig){
my $l = $_;
$l =~ s/[\r\n]//g;
$ret .= AnalyzeCommandChain($cl, $l);
}
return $ret if($ret);
return undef;
}
sub cfgDB_SaveCfg {
my (%devByNr, @rowList);
map { $devByNr{$defs{$_}{NR}} = $_ } keys %defs;
for(my $i = 0; $i < $devcount; $i++) {
my ($h, $d);
if($comments{$i}) {
$h = $comments{$i};
} else {
$d = $devByNr{$i};
next if(!defined($d) ||
$defs{$d}{TEMPORARY} || # e.g. WEBPGM connections
$defs{$d}{VOLATILE}); # e.g at, will be saved to the statefile
$h = $defs{$d};
}
if(!defined($d)) {
push @rowList, $h->{TEXT};
next;
}
if($d ne "global") {
my $def = $defs{$d}{DEF};
if(defined($def)) {
$def =~ s/;/;;/g;
$def =~ s/\n/\\\n/g;
} else {
$dev = "";
}
push @rowList, "define $d $defs{$d}{TYPE} $def";
}
foreach my $a (sort keys %{$attr{$d}}) {
next if($d eq "global" &&
($a eq "configfile" || $a eq "version"));
my $val = $attr{$d}{$a};
$val =~ s/;/;;/g;
$val =~ s/\n/\\\n/g;
push @rowList, "attr $d $a $val";
}
}
# Insert @rowList into database table
my $fhem_dbh = cfgDB_Connect;
my $uuid = cfgDB_Rotate($fhem_dbh);
$t = localtime;
$out = "#created $t";
push @rowList, $out;
foreach (@rowList) { cfgDB_InsertLine($fhem_dbh, $uuid, $_); }
$fhem_dbh->commit();
$fhem_dbh->disconnect();
return 'configDB saved.';
}
sub cfgDB_SaveState {
my ($out,$val,$r,$rd,$t,@rowList);
$t = localtime;
$out = "#$t";
push @rowList, $out;
foreach my $d (sort keys %defs) {
next if($defs{$d}{TEMPORARY});
if($defs{$d}{VOLATILE}) {
$out = "define $d $defs{$d}{TYPE} $defs{$d}{DEF}";
push @rowList, $out;
}
$val = $defs{$d}{STATE};
if(defined($val) &&
$val ne "unknown" &&
$val ne "Initialized" &&
$val ne "???") {
$val =~ s/;/;;/g;
$val =~ s/\n/\\\n/g;
$out = "setstate $d $val";
push @rowList, $out;
}
$r = $defs{$d}{READINGS};
if($r) {
foreach my $c (sort keys %{$r}) {
$rd = $r->{$c};
if(!defined($rd->{TIME})) {
Log3(undef, 4, "WriteStatefile $d $c: Missing TIME, using current time");
$rd->{TIME} = TimeNow();
}
if(!defined($rd->{VAL})) {
Log3(undef, 4, "WriteStatefile $d $c: Missing VAL, setting it to 0");
$rd->{VAL} = 0;
}
$val = $rd->{VAL};
$val =~ s/;/;;/g;
$val =~ s/\n/\\\n/g;
$out = "setstate $d $rd->{TIME} $c $val";
push @rowList, $out;
}
}
}
my $fhem_dbh = cfgDB_Connect;
$fhem_dbh->do("DELETE FROM fhemstate");
my $sth = $fhem_dbh->prepare('INSERT INTO fhemstate values ( ? )');
foreach (@rowList) { $sth->execute( $_ ); }
$fhem_dbh->commit();
$fhem_dbh->disconnect();
return;
}
sub cfgDB_ReadCfg(@) {
my (@dbconfig) = @_;
my $fhem_dbh = cfgDB_Connect;
my ($sth, @line, $row);
# using a join would be much nicer, but does not work due to sort of join's result
my $uuid = $fhem_dbh->selectrow_array('SELECT versionuuid FROM fhemversions WHERE version = 0');
$sth = $fhem_dbh->prepare( "SELECT * FROM fhemconfig WHERE versionuuid = '$uuid'" );
$sth->execute();
while (@line = $sth->fetchrow_array()) {
$row = "$line[0] $line[1] $line[2] $line[3]";
push @dbconfig, $row;
}
$fhem_dbh->disconnect();
return @dbconfig;
}
sub cfgDB_ReadState(@) {
my (@dbconfig) = @_;
my $fhem_dbh = cfgDB_Connect;
my ($sth, $row);
$sth = $fhem_dbh->prepare( "SELECT * FROM fhemstate" );
$sth->execute();
while ($row = $sth->fetchrow_array()) {
push @dbconfig, $row;
}
$fhem_dbh->disconnect();
return @dbconfig;
}
sub cfgDB_GlobalAttr {
my ($sth, @line, $row, @dbconfig);
my $fhem_dbh = cfgDB_Connect;
$sth = $fhem_dbh->prepare( "SELECT * FROM fhemconfig WHERE DEVICE = 'global'" );
$sth->execute();
while (@line = $sth->fetchrow_array()) {
$row = "$line[0] $line[1] $line[2] $line[3]";
$line[3] =~ s/#.*//;
$line[3] =~ s/ .*$//;
$attr{global}{$line[2]} = $line[3];
}
$fhem_dbh->disconnect();
return;
}
sub cfgDB_Rotate($) {
my ($fhem_dbh) = @_;
my $uuid = cfgDB_Uuid;
# $fhem_dbh->do("UPDATE fhemconfig SET VERSION = VERSION+1");
$fhem_dbh->do("UPDATE fhemversions SET VERSION = VERSION+1");
$fhem_dbh->do("INSERT INTO fhemversions values (0, '$uuid')");
return $uuid;
}
sub cfgDB_ReadAll($){
my ($cl) = @_;
my $ret;
# add Config Rows to commandfile
my @dbconfig = cfgDB_ReadCfg(@dbconfig);
# add State Rows to commandfile
@dbconfig = cfgDB_ReadState(@dbconfig);
# AnalyzeCommandChain for all entries
$ret .= cfgDB_Execute($cl, @dbconfig);
return $ret if($ret);
return undef;
}
sub cfgDB_Migrate {
Log3('configDB',4,'Starting migration.');
Log3('configDB',4,'Processing: cfgDB_Init.');
cfgDB_Init;
Log3('configDB',4,'Processing: cfgDB_SaveCfg.');
cfgDB_SaveCfg;
Log3('configDB',4,'Processing: cfgDB_SaveState.');
cfgDB_SaveState;
Log3('configDB',4,'Migration finished.');
return " Result after migration:\n".cfgDB_Info;
}
sub cfgDB_List(;$$) {
my ($search,$searchversion) = @_;
$search = $search ? $search : "%";
$searchversion = $searchversion ? $searchversion : 0;
my $fhem_dbh = cfgDB_Connect;
my ($sql, $sth, @line, $row, @result, $ret);
$sql = "SELECT command, device, p1, p2 FROM fhemconfig as c join fhemversions as v ON v.versionuuid=c.versionuuid ".
"WHERE v.version = '$searchversion' AND command not like '#create%' AND device like '$search%' ORDER BY lower(device),command DESC";
$sth = $fhem_dbh->prepare( $sql);
$sth->execute();
push @result, "search result for device: $search in version: $searchversion";
push @result, "--------------------------------------------------------------------------------";
while (@line = $sth->fetchrow_array()) {
$row = "$line[0] $line[1] $line[2] $line[3]";
push @result, "$row";
}
$fhem_dbh->disconnect();
$ret = join("\n", @result);
return $ret;
}
sub cfgDB_Diff($$){
my ($search,$searchversion) = @_;
eval {use Text::Diff};
return "error: Please install Text::Diff!" if($@);
my ($sql, $sth, @line, $row, @result, $ret, $v0, $v1);
my $fhem_dbh = cfgDB_Connect;
$sql = "SELECT command, device, p1, p2 FROM fhemconfig as c join fhemversions as v ON v.versionuuid=c.versionuuid ".
"WHERE v.version = 0 AND device = '$search' ORDER BY command DESC";
$sth = $fhem_dbh->prepare( $sql);
$sth->execute();
while (@line = $sth->fetchrow_array()) {
$v0 .= "$line[0] $line[1] $line[2] $line[3]\n";
}
$sql = "SELECT command, device, p1, p2 FROM fhemconfig as c join fhemversions as v ON v.versionuuid=c.versionuuid ".
"WHERE v.version = '$searchversion' AND device = '$search' ORDER BY command DESC";
$sth = $fhem_dbh->prepare( $sql);
$sth->execute();
while (@line = $sth->fetchrow_array()) {
$v1 .= "$line[0] $line[1] $line[2] $line[3]\n";
}
$fhem_dbh->disconnect();
$ret = "compare device: $search in current version 0 (left) to version: $searchversion (right)\n";
$ret .= diff \$v0, \$v1, { STYLE => "Table" }; #, \%options;
return $ret;
}
1;
=pod
=begin html
configDB
Starting with version 5079, fhem can be used with a configuration database instead of a plain text file (e.g. fhem.cfg).
This offers the possibility to completely waive all cfg-files, "include"-problems and so on.
Furthermore, configDB offers a versioning of several configuration together with the possibility to restore a former configuration.
Access to database is provided via perl's database interface DBI.
Prerequisits / Installation
- You must have access to a SQL database. Supported database types are SQLITE, MYSQL and POSTGRESQL.
- The corresponding DBD module must be available in your perl environment,
e.g. sqlite3 running on a Debian systems requires package libdbd-sqlite3-perl
- Create an empty database, e.g. with sqlite3:
mba:fhem udo$ sqlite3 configDB.db
SQLite version 3.7.13 2012-07-17 17:46:21
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> pragma auto_vacuum=2;
sqlite> .quit
mba:fhem udo$
- The database tables will be created automatically.
- Create a configuration file containing the connection string to access database.
IMPORTANT:
- This file must be named "configDB.conf"
- This file must be located in your fhem main directory, e.g. /opt/fhem
## for MySQL
################################################################
#%dbconfig= (
# connection => "mysql:database=configDB;host=db;port=3306",
# user => "fhemuser",
# password => "fhempassword",
#);
################################################################
#
## for PostgreSQL
################################################################
#%dbconfig= (
# connection => "Pg:database=configDB;host=localhost",
# user => "fhemuser",
# password => "fhempassword"
#);
################################################################
#
## for SQLite (username and password stay empty for SQLite)
################################################################
#%dbconfig= (
# connection => "SQLite:dbname=/opt/fhem/configDB.db",
# user => "",
# password => ""
#);
################################################################
Start with a complete new "fresh" fhem Installation
It's easy... simply start fhem by issuing following command:
configDB is a keyword which is recognized by fhem to use database for configuration.
That's all. Everything (save, rereadcfg etc) should work as usual.
or:
Migrate your existing fhem configuration into the database
It's easy, too...
- start your fhem the last time with fhem.cfg
- transfer your existing configuration into the database
enter {use configDB;; cfgDB_Migrate}
into frontend's command line
Be patient! Migration can take some time, especially on mini-systems like RaspberryPi or Beaglebone.
Completed migration will be indicated by showing database statistics.
Your original configfile will not be touched or modified by this step.
- shutdown fhem
- restart fhem with keyword configDB
configDB is a keyword which is recognized by fhem to use database for configuration.
That's all. Everything (save, rereadcfg etc) should work as usual.
Additional functions provided
All functions are called from fhem commandline!
{cfgDB_Info}
Returns some database statistics
--------------------------------------------------------------------------------
configDB Database Information
--------------------------------------------------------------------------------
dbconn: SQLite:dbname=/opt/fhem/configDB.db
dbuser:
dbpass:
dbtype: SQLITE
--------------------------------------------------------------------------------
fhemconfig: 7707 entries
Ver 0 saved: Sat Mar 1 11:37:00 2014 def: 293 attr: 1248
Ver 1 saved: Fri Feb 28 23:55:13 2014 def: 293 attr: 1248
Ver 2 saved: Fri Feb 28 23:49:01 2014 def: 293 attr: 1248
Ver 3 saved: Fri Feb 28 22:24:40 2014 def: 293 attr: 1247
Ver 4 saved: Fri Feb 28 22:14:03 2014 def: 293 attr: 1246
--------------------------------------------------------------------------------
fhemstate: 1890 entries saved: Sat Mar 1 12:05:00 2014
--------------------------------------------------------------------------------
Ver 0 always indicates the currently running configuration.
{cfgDB_List [device],[version]}
Search for device named [device] in configuration version [version]
in database archive.
Default value for [device] = % to show all devices.
Default value for [version] = 0 to show devices from current version.
Examples for valid requests:
{cfgDB_List}
{cfgDB_List 'global'}
{cfgDB_List '',1}
{cfgDB_List 'global',1}
{cfgDB_Diff <device>,<version>}
Compare configuration dataset for device <device> from current version 0 with version <version>
Example for valid request:
{cfgDB_Diff 'telnetPort',1}
will show a result like this:
compare device: telnetPort in current version 0 (left) to version: 1 (right)
+--+--------------------------------------+--+--------------------------------------+
| 1|define telnetPort telnet 7072 global | 1|define telnetPort telnet 7072 global |
* 2|attr telnetPort room telnet * | |
+--+--------------------------------------+--+--------------------------------------+
{cfgDB_Reorg [keep]}
Deletes all stored versions with version number higher than [keep].
Default value for optional parameter keep = 3.
In above example. {cfgDB_Reorg 2}
will delete versions #3 and #4.
This function can be used to create a nightly running job for
database reorganisation when called from an at-Definition.
{cfgDB_Recover <version>}
Restores an older version from database archive.
{cfgDB_Recover 3}
will copy version #3 from database
to version #0.
Original version #0 will be lost.
Important!
The restored version will NOT be activated automatically!
You must do a rereadcfg
or - even better - shutdown restart
yourself.
Author's notes
- You can find two template files for datebase and configfile (sqlite only!) for easy installation.
Just copy them to your fhem installation directory (/opt/fhem) and have fun.
- The frontend option "Edit files"->"config file" will be removed when running configDB.
- Please be patient when issuing a "save" command
(either manually or by clicking on "save config").
This will take some moments, due to writing version informations.
Finishing the save-process will be indicated by a corresponding message in frontend.
- You may need to install perl package Text::Diff to use cfgDB_Diff()
- There still will be some more (planned) development to this extension,
especially regarding some perfomance issues.
- Have fun!
=end html
=begin html_DE
configDB
Seit version 5079 unterstützt fhem die Verwendung einer SQL Datenbank zum Abspeichern der kompletten Konfiguration
Dadurch kann man auf alle cfg Dateien, includes usw. verzichten und die daraus immer wieder resultierenden Probleme vermeiden.
Desweiteren gibt es damit eine Versionierung von Konfigurationen und die Möglichkeit,
jederzeit eine ältere Version wiederherstellen zu können.
Der Zugriff auf die Datenbank erfolgt über die perl-eigene Datenbankschnittstelle DBI.
Voraussetzungen / Installation
- Es muss eine SQL Datenbank verfügbar sein, untsrstützt werden SQLITE, MYSQL und POSTGRESQLL.
- Das zum Datenbanktype gehörende DBD Modul muss in perl installiert sein,
für sqlite3 auf einem Debian System z.B. das Paket libdbd-sqlite3-perl
- Eine leere Datenbank muss angelegt werden, z.B. in sqlite3:
mba:fhem udo$ sqlite3 configDB.db
SQLite version 3.7.13 2012-07-17 17:46:21
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> pragma auto_vacuum=2;
sqlite> .quit
mba:fhem udo$
- Die benötigten Datenbanktabellen werden automatisch angelegt.
- Eine Konfigurationsdatei für die Verbindung zur Datenbank muss angelegt werden.
WICHTIG:
- Diese Datei muss den Namen "configDB.conf" haben
- Diese Datei muss im fhem Verzeichnis liegen, z.B. /opt/fhem
## für MySQL
################################################################
#%dbconfig= (
# connection => "mysql:database=configDB;host=db;port=3306",
# user => "fhemuser",
# password => "fhempassword",
#);
################################################################
#
## für PostgreSQL
################################################################
#%dbconfig= (
# connection => "Pg:database=configDB;host=localhost",
# user => "fhemuser",
# password => "fhempassword"
#);
################################################################
#
## für SQLite (username and password bleiben bei SQLite leer)
################################################################
#%dbconfig= (
# connection => "SQLite:dbname=/opt/fhem/configDB.db",
# user => "",
# password => ""
#);
################################################################
Aufruf mit einer vollständig neuen fhem Installation
Sehr einfach... fhem muss lediglich folgendermassen gestartet werden:
configDB ist das Schlüsselwort, an dem fhem erkennt,
dass eine Datenbank für die Konfiguration verwendet werden soll.
Das war es schon. Alle Befehle (save, rereadcfg etc) arbeiten wie gewohnt.
oder:
übertragen einer bestehenden fhem Konfiguration in die Datenbank
Auch sehr einfach...
- fhem wird zum letzten Mal mit der fhem.cfg gestartet
- Bestehende Konfiguration in die Datenbank übertragen
{use configDB;; cfgDB_Migrate}
in die Befehlszeile der fhem-Oberfläche eingeben
Nicht die Geduld verlieren! Die Migration eine Weile dauern, speziell bei Mini-Systemen wie
RaspberryPi or Beaglebone.
Am Ende der Migration wird eine aktuelle Datenbankstatistik angezeigt.
Die ursprüngliche Konfigurationsdatei wird bei diesem Vorgang nicht angetastet.
- fhem beenden.
- fhem mit dem Schlüsselwort configDB starten
configDB ist das Schlüsselwort, an dem fhem erkennt,
dass eine Datenbank für die Konfiguration verwendet werden soll.
Das war es schon. Alle Befehle (save, rereadcfg etc) arbeiten wie gewohnt.
Zusätzliche Funktionen
Alle Funktionen werden in der Befehelszeile aufgerufen!
{cfgDB_Info}
Liefert eine Datenbankstatistik
--------------------------------------------------------------------------------
configDB Database Information
--------------------------------------------------------------------------------
dbconn: SQLite:dbname=/opt/fhem/configDB.db
dbuser:
dbpass:
dbtype: SQLITE
--------------------------------------------------------------------------------
fhemconfig: 7707 entries
Ver 0 saved: Sat Mar 1 11:37:00 2014 def: 293 attr: 1248
Ver 1 saved: Fri Feb 28 23:55:13 2014 def: 293 attr: 1248
Ver 2 saved: Fri Feb 28 23:49:01 2014 def: 293 attr: 1248
Ver 3 saved: Fri Feb 28 22:24:40 2014 def: 293 attr: 1247
Ver 4 saved: Fri Feb 28 22:14:03 2014 def: 293 attr: 1246
--------------------------------------------------------------------------------
fhemstate: 1890 entries saved: Sat Mar 1 12:05:00 2014
--------------------------------------------------------------------------------
Ver 0 bezeichnet immer die aktuell geladene Konfiguration.
{cfgDB_List [device],[version]}
Sucht das Gerät [device] in der Konfiguration der Version [version]
in der Datenbank.
Standardwert für [device] = % um alle Geräte anzuzeigen
Standardwert für [version] = 0 Geräte in der aktuellen Version anzuzeigen.
Beispiele für gültige Aufrufe:
{cfgDB_List}
{cfgDB_List 'global'}
{cfgDB_List '',1}
{cfgDB_List 'global',1}
{cfgDB_Diff <device>,<version>}
Vergleicht die Konfigurationsdaten des Gerätes <device> aus der aktuellen Version 0 mit den Daten aus Version <version>
Beispielaufruf:
{cfgDB_Diff 'telnetPort',1}
liefert ein Ergebnis ähnlich dieser Ausgabe:
compare device: telnetPort in current version 0 (left) to version: 1 (right)
+--+--------------------------------------+--+--------------------------------------+
| 1|define telnetPort telnet 7072 global | 1|define telnetPort telnet 7072 global |
* 2|attr telnetPort room telnet * | |
+--+--------------------------------------+--+--------------------------------------+
{cfgDB_Reorg [keep]}
Löscht alle gespeicherten Versionen mit Versionsnummer > [keep].
Standardwert für den optionalen Parameter keep = 3.
Im obigen Beispiel würde {cfgDB_Reorg 2}
die Versionen #3 und #4 löschen.
Diese Funktion kann z.B. verwendet werden, um eine regelmäßige nächtliche
Datenbankreorganisation mit Hilfe einer at-Definition einzuplanen.
{cfgDB_Recover <version>}
Stellt eine ältere Version aus dem Datenbankarchiv wieder her.
{cfgDB_Recover 3}
kopiert die Version #3 aus der Datenbank
zur Version #0.
Die ursprüngliche Version #0 wird dabei gelöscht.
Wichtig!
Die zurückgeholte Version wird NICHT automatisch aktiviert!
Ein rereadcfg
oder - besser - shutdown restart
muss manuell erfolgen.
Hinweise
- Im Verzeichnis contrib/configDB befinden sich zwei Vorlagen für Datenbank und Konfiguration,
die durch einfaches Kopieren in das fhem Verzeichnis sofort verwendet werden können (Nur für sqlite!).
- Der Menüpunkt "Edit files"->"config file" wird bei Verwendung von configDB nicht mehr angezeigt.
- Beim Speichern einer Konfiguration nicht ungeduldig werden (egal ob manuell oder durch Klicken auf "save config")
Durch das Schreiben der Versionsinformationen dauert das ein paar Sekunden.
Der Abschluss des Speichern wird durch eine entsprechende Meldung angezeigt.
- Für die Nutzung von cfgDB_Diff() wird das perl Paket Text::Diff benötigt.
- Diese Erweiterung wird laufend weiterentwickelt. Speziell an der Verbesserung der Performance wird gearbeitet.
- Viel Spass!
=end html_DE
=cut