fhem configuration in sql-DB ablegen - besteht Interesse?

Begonnen von betateilchen, 12 Februar 2014, 11:09:56

Vorheriges Thema - Nächstes Thema

Wzut

Zitat von: betateilchen am 18 Februar 2014, 11:17:25
Variante aus dem Test-Thread schon mehrmals runtergeladen (die letzte Version zwei Mal)
Also wenns recht ist wären es heute Abend dann drei Downloads, da ich an dem Thema grossses Interessse habe.
Ich möchte allerdings nicht sql-lite benutzen sondern wie bisher bei allen meinen Projekten mysql.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

betateilchen

Welchen Datenbanktyp Du verwendest, ist meiner Erweiterung eigentlich egal, Postgresql, Sqlite, MySQL - solange Du das entsprechende perl-DBD Modul auf Deinem System hast und die Konfig-Datei für die DB-Connection stimmt, sollte es funktionieren.

für MySQL muss der Verbindungseintrag so aussehen:


%dbconfig= (
connection => "mysql:database=<datenbankName>;host=<hostAdresse>db;port=3306",
user => "datenbankUser",
password => "datenbanUserkPasswort",
);

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Wzut

ging alles nach deiner Anleitung im Testforum problemlos , alle .cfg Zeilen wurden in die Tabelle übernommen und nach einem save verdoppelt :

Datensätze COMMAND
             1 #
             2 #created
         342 attr
         183 define

Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

betateilchen

#18
Ist doch perfekt :)

Mach mal ein {cfgDB_Info} dann siehst Du noch ein bißchen mehr.


--------------------------------------------------------------------------------
configDB Database Information
--------------------------------------------------------------------------------
dbconn: SQLite:dbname=/opt/fhem/configDB.db
dbuser:
dbpass:
dbtype: SQLITE
--------------------------------------------------------------------------------
fhemconfig: 11908 entries

Ver 0 saved: Tue Feb 18 22:05:52 2014 def: 286 attr: 1202
Ver 1 saved: Tue Feb 18 21:41:09 2014 def: 286 attr: 1202
Ver 2 saved: Tue Feb 18 21:40:01 2014 def: 286 attr: 1202
Ver 3 saved: Tue Feb 18 20:16:41 2014 def: 286 attr: 1202
Ver 4 saved: Tue Feb 18 20:15:13 2014 def: 286 attr: 1201
Ver 5 saved: Tue Feb 18 20:08:09 2014 def: 286 attr: 1201
Ver 6 saved: Tue Feb 18 18:39:49 2014 def: 286 attr: 1201
Ver 7 saved: Tue Feb 18 07:52:07 2014 def: 286 attr: 1201
--------------------------------------------------------------------------------
fhemstate: 1520 entries saved: Tue Feb 18 22:05:52 2014
--------------------------------------------------------------------------------
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Zitat von: rudolfkoenig am 18 Februar 2014, 08:07:45
Sicher, ich wollte nur abwarten, dass deine Baustelle sich beruhigt.
...
Und hat ausser dir sonst jemand diese Erweiterung schon getestet?

Meine Baustelle hat sich beruhigt und die Konfiguration aus der Datenbank läuft hier ohne jeder Änderung/Korrektur seit zwei Wochen störungsfrei auf insgesamt drei fhem Installationen (zwei mit SQLITE, eine mit MySQL) auf unterschiedlichen Plattformen (Mac OSX, RaspberryPi und Beaglebone Black)

Und von Testern wurden mir bisher auch keinerlei Probleme gemeldet.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

Kannst du mir bitte zusammenfassen, welche Aenderungen ich wo einbauen soll? Ich will nichts uebersehen.

betateilchen

ja, mach ich gerne. Ich werde eine Patchdatei bauen, dann kannst Du Dir das nochmal anschauen.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen


Hier die diff für die fhem.pl. Das Prinzip ist eigentlich immer das gleiche: Feststellen, ob configDB gesetzt ist, wenn ja, die zugehörige Funktion ausführen, wenn nein, das originale Coding verwenden.



Index: fhem.pl
===================================================================
--- fhem.pl (revision 4891)
+++ fhem.pl (working copy)
@@ -37,6 +37,21 @@


##################################################
+# We need the forward declarations in case of
+# configDB.pm can not be loaded.
+
+sub cfgDB_Init;
+sub cfgDB_ReadAll($);
+sub cfgDB_SaveState;
+sub cfgDB_SaveCfg;
+sub cfgDB_GlobalAttr;
+eval "use configDB";
+
+#
+##################################################
+
+
+##################################################
# Forward declarations
#
sub AddDuplicate($$);
@@ -365,6 +380,8 @@
# Server initialization
doGlobalDef($ARGV[0]);

+cfgDB_Init if $attr{global}{configfile} eq 'configDB';
+
# As newer Linux versions reset serial parameters after fork, we parse the
# config file after the fork. But we need some global attr parameters before, so we
# read them here.
@@ -389,14 +406,17 @@
   sleep(5);
}

-my $ret = CommandInclude(undef, $attr{global}{configfile});
-Log 1, "configfile: $ret" if($ret);
+if($attr{global}{configfile} eq 'configDB') {
+ cfgDB_ReadAll(undef);
+} else {
+ my $ret = CommandInclude(undef, $attr{global}{configfile});
+ Log 1, "configfile: $ret" if($ret);

-if($attr{global}{statefile} && -r $attr{global}{statefile}) {
-  $ret = CommandInclude(undef, $attr{global}{statefile});
-  Log 1, "statefile: $ret" if($ret);
+ if($attr{global}{statefile} && -r $attr{global}{statefile}) {
+ $ret = CommandInclude(undef, $attr{global}{statefile});
+ Log 1, "statefile: $ret" if($ret);
+ }
}
-
SignalHandling();

my $pfn = $attr{global}{pidfilename};
@@ -1068,7 +1088,7 @@
   my ($cl, $param) = @_;
   my $name = ($cl ? $cl->{NAME} : "__anonymous__");
   my $cfgfile = ($param ? $param : $attr{global}{configfile});
-  return "Cannot open $cfgfile: $!" if(! -f $cfgfile);
+  return "Cannot open $cfgfile: $!" if(! -f $cfgfile && $attr{global}{configfile} ne 'configDB');

   $attr{global}{configfile} = $cfgfile;
   WriteStatefile();
@@ -1090,20 +1110,27 @@
   %readyfnlist = ();
   %inform = ();

-  doGlobalDef($cfgfile);
-  setGlobalAttrBeforeFork($cfgfile);
+ doGlobalDef($cfgfile);
+ my $ret;
+
+ if($attr{global}{configfile} eq 'configDB') {
+ cfgDB_ReadAll($cl);
+ } else {
+ setGlobalAttrBeforeFork($cfgfile);

-  my $ret = CommandInclude($cl, $cfgfile);
-  if($attr{global}{statefile} && -r $attr{global}{statefile}) {
-    my $ret2 = CommandInclude($cl, $attr{global}{statefile});
-    $ret = (defined($ret) ? "$ret\n$ret2" : $ret2) if(defined($ret2));
-  }
-  DoTrigger("global", "REREADCFG", 1);
-  $defs{$name} = $selectlist{$name} = $cl if($name && $name ne "__anonymous__");
+ $ret = CommandInclude($cl, $cfgfile);
+ if($attr{global}{statefile} && -r $attr{global}{statefile}) {
+ my $ret2 = CommandInclude($cl, $attr{global}{statefile});
+ $ret = (defined($ret) ? "$ret\n$ret2" : $ret2) if(defined($ret2));
+ }
+ }

-  $init_done = 1;
-  $reread_active=0;
-  return $ret;
+ DoTrigger("global", "REREADCFG", 1);
+ $defs{$name} = $selectlist{$name} = $cl if($name && $name ne "__anonymous__");
+
+ $init_done = 1;
+ $reread_active=0;
+ return $ret;
}

#####################################
@@ -1125,6 +1152,9 @@
sub
WriteStatefile()
{
+ if($attr{global}{configfile} eq 'configDB') {
+ cfgDB_SaveState;
+ } else {
   return "No statefile specified" if(!$attr{global}{statefile});
   if(!open(SFH, ">$attr{global}{statefile}")) {
     my $msg = "WriteStateFile: Cannot open $attr{global}{statefile}: $!";
@@ -1175,6 +1205,7 @@
   }

   close(SFH);
+ }
   return "";
}

@@ -1190,6 +1221,11 @@
   WriteStatefile();

   $param = $attr{global}{configfile} if(!$param);
+
+ if($attr{global}{configfile} eq 'configDB') {
+ $ret = cfgDB_SaveCfg;
+ } else {
+
   return "No configfile attribute set and no argument specified" if(!$param);
   if(!open(SFH, ">$param")) {
     return "Cannot open $param: $!";
@@ -1257,6 +1293,7 @@
   foreach my $fh (values %fh) {
     close($fh) if($fh ne "1");
   }
+ } # if !configDB
   return ($ret ? $ret : "Wrote configuration to $param");
}

@@ -1591,7 +1628,7 @@
       delete($defs{$sdev}{'.userReadings'});
     }

-    $ret = CallFn($sdev, "AttrFn", "del", @a);
+    my $ret = CallFn($sdev, "AttrFn", "del", @a);
     if($ret) {
       push @rets, $ret;
       next;
@@ -3036,17 +3073,21 @@
sub
setGlobalAttrBeforeFork($)
{
-  my ($f) = @_;
-  open(FH, $f) || die("Cant open $f: $!\n");
-  while(my $l = <FH>) {
-    $l =~ s/[\r\n]//g;
-    next if($l !~ m/^attr\s+global\s+([^\s]+)\s+(.*)$/);
-    my ($n,$v) = ($1,$2);
-    $v =~ s/#.*//;
-    $v =~ s/ .*$//;
-    $attr{global}{$n} = $v;
-  }
-  close(FH);
+ my ($f) = @_;
+ if($f eq 'configDB') {
+ cfgDB_GlobalAttr;
+ } else {
+ open(FH, $f) || die("Cant open $f: $!\n");
+ while(my $l = <FH>) {
+ $l =~ s/[\r\n]//g;
+ next if($l !~ m/^attr\s+global\s+([^\s]+)\s+(.*)$/);
+ my ($n,$v) = ($1,$2);
+ $v =~ s/#.*//;
+ $v =~ s/ .*$//;
+ $attr{global}{$n} = $v;
+ }
+ close(FH);
+ }
}




Hier noch die einzige Änderung in der 01_FHEMWEB, da wird lediglich in "Edit files" die fhem.cfg komplett ausgeblendet.



Index: 01_FHEMWEB.pm
===================================================================
--- 01_FHEMWEB.pm (revision 4920)
+++ 01_FHEMWEB.pm (working copy)
@@ -1507,7 +1507,7 @@

     $attr{global}{configfile} =~ m,([^/]*)$,;
     my $cfgFileName = $1;
-    FW_displayFileList("config file", $cfgFileName);
+    FW_displayFileList("config file", $cfgFileName) unless $attr{global}{configfile} eq 'configDB';
     FW_displayFileList("Own modules and helper files",
         FW_fileList("$MW_dir/^(.*sh|[0-9][0-9].*Util.*pm|.*cfg|.*holiday".
                                   "|.*layout)\$"));



Sämtliche Konfigurationsfunktionen sind in die Datei configDB.pm ausgelagert, was den Vorteil hat, dass für Änderungen an diesen Funktionen die fhem.pl nicht angefasst werden muss.

Diese Erweiterungsdatei muss derzeit im gleichen Verzeichnis liegen wie fhem.pl, da es zum Startzeitpunkt noch keinen modpath gibt und der Pfad ./FHEM im Gegensatz zum aktuellen Pfad nicht in @INC enthalten ist.

Unabhängig davon habe ich die Funktionsfähigkeit von fhem in Kombination mit der bisherigen fhem.cfg auch komplett ohne diese Datei getestet und keine Probleme festgestellt.

Wenn ich die Doku als pod in die configDB.pm schreibe, wird die dann von commandref_join berücksichtigt?

Viele Grüße
Udo
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

Habs etwas umformatiert und eingecheckt. Bemerkungen:
- das eval habe ich verschoben, damit es nur dann ausgefuehrt wird, falls noetig ist. Bitte testen.
- cfgDB_ReadAll() usw. sollten die gesammelten Fehlermeldungen zurueckliefern. Danach muessen wir fhem.pl wieder anpassen.
- doku kommt zwar nicht automatisch ins commandref, ich kann aber commandref_join.pl entsprechend erweitern
- ich gehe davon aus, dass die doku auch bootstrapping enthaelt.
- configDB.pm bitte in MAINTAINER.txt eintragen und auch einchecken.

betateilchen

Zitat von: rudolfkoenig am 01 März 2014, 09:08:48Habs etwas umformatiert und eingecheckt.

danke!

Zitat von: rudolfkoenig am 01 März 2014, 09:08:48- das eval habe ich verschoben, damit es nur dann ausgefuehrt wird, falls noetig ist. Bitte testen.

ich werde testen und berichten.

Zitat von: rudolfkoenig am 01 März 2014, 09:08:48- cfgDB_ReadAll() usw. sollten die gesammelten Fehlermeldungen zurueckliefern. Danach muessen wir fhem.pl wieder anpassen.

schau ich mir an.

Zitat von: rudolfkoenig am 01 März 2014, 09:08:48- doku kommt zwar nicht automatisch ins commandref, ich kann aber commandref_join.pl entsprechend erweitern

Wenn Du einen anderen Weg, die Doku bereitzustellen hast, können wir das gerne auch anders machen.

Zitat von: rudolfkoenig am 01 März 2014, 09:08:48- ich gehe davon aus, dass die doku auch bootstrapping enthaelt.

was meinst Du damit genau?

Zitat von: rudolfkoenig am 01 März 2014, 09:08:48- configDB.pm bitte in MAINTAINER.txt eintragen und auch einchecken.

sowieso :)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

ZitatWenn Du einen anderen Weg, die Doku bereitzustellen hast, können wir das gerne auch anders machen.
Ich habe keine besseren Alternativen, deswegen bleibt es erstmal so.

Mit bootstrapping meine ich die Erstinstallation, was jemand machen muss, um nach "configDB" umzuziehen.

betateilchen

Zitat von: rudolfkoenig am 01 März 2014, 10:06:42
Mit bootstrapping meine ich die Erstinstallation, was jemand machen muss, um nach "configDB" umzuziehen.

Ok, da werde ich die Installationsanleitung aus dem "Tester"-Thread übernehmen, die hat sich bewährt.

Die Tests der letzten halben Stunde haben ergeben, dass die eingebauten Änderungen alle funktionieren. Die noch offenen Punkte sind in Arbeit.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen


  • configDB.pm eingecheckt, Doku (englisch) enthalten
  • MAINTAINER.txt ergänzt
  • CHANGED ergänzt
  • commandref_frame angepasst, um die Doku in den helper modules zu verankern

Vielleicht kann mal jemand die Doku in der commandref querlesen, ob das einigermaßen verständlich beschrieben ist.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

Ja, es ist einigermassen verstaendlich :)
Habe commandref_join.pl modifiziert, und die Doku online gestellt.

betateilchen

#29
Danke.

Man könnte für SQLITE die gesamte Installation sogar noch soweit vereinfachen, dass der Anwender, abgesehen von der Installation der Datenbanksoftware nebst passendem DBI überhaupt keinen Aufwand mehr hat, indem man eine leere Datenbankdatei und eine passende Verbindungsdatei mit ausliefert. Dadurch entfielen die beiden größten Fehlerquellen bei der Installation. Ich denke, ich werde diese Dateien in ./contrib bereitstellen.

Gibt es eigentlich Plattformen, für die sqlite nicht zur Verfügung steht?


-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!