2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

feature: DbLog: jokers "%" in device/reading definition are now possible

feature: Text2Speech: Definition of mp3files with a custom templatedefinition.


git-svn-id: https://svn.fhem.de/fhem/trunk@4747 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
tobiasfaust 2014-01-26 13:09:51 +00:00
parent 8fdbb1abe3
commit 23ea60a1c6
4 changed files with 465 additions and 232 deletions

View File

@ -1,6 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- SVN
- feature: DbLog: jokers "%" in device/reading definition are now possible
- feature: SYSMON: new CPU Statistics and Plots
- feature: changed 10_OWServer.pm and 11_OWDevice.pm to use
NOTIFYDEV (justme1968)

View File

@ -6,7 +6,7 @@
# written by Dr. Boris Neubert 2007-12-30
# e-mail: omega at online dot de
#
# modified by Tobias Faust 2012-06-26
# modified and maintained by Tobias Faust since 2012-06-26
# e-mail: tobias dot faust at online dot de
#
##############################################
@ -17,11 +17,8 @@ use warnings;
use DBI;
use Data::Dumper;
sub DbLog($$$);
################################################################
sub
DbLog_Initialize($)
sub DbLog_Initialize($)
{
my ($hash) = @_;
@ -36,8 +33,7 @@ DbLog_Initialize($)
}
###############################################################
sub
DbLog_Define($@)
sub DbLog_Define($@)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
@ -64,8 +60,7 @@ DbLog_Define($@)
}
#####################################
sub
DbLog_Undef($$)
sub DbLog_Undef($$)
{
my ($hash, $name) = @_;
my $dbh= $hash->{DBH};
@ -79,8 +74,7 @@ DbLog_Undef($$)
# DbLog-Instanz aufgerufen
#
################################################################
sub
DbLog_Attr(@)
sub DbLog_Attr(@)
{
my @a = @_;
my $do = 0;
@ -101,8 +95,7 @@ DbLog_Attr(@)
# Parsefunktion, abhaengig vom Devicetyp
#
################################################################
sub
DbLog_ParseEvent($$$)
sub DbLog_ParseEvent($$$)
{
my ($device, $type, $event)= @_;
my @result;
@ -159,6 +152,14 @@ DbLog_ParseEvent($$$)
}
}
# FBDECT
elsif (($type eq "FBDECT")) {
if ( $value=~/([\.\d]+)\s([a-z])/i ) {
$value = $1;
$unit = $2;
}
}
# MAX
elsif(($type eq "MAX")) {
$unit= "°C" if(lc($reading) =~ m/temp/);
@ -339,6 +340,60 @@ DbLog_ParseEvent($$$)
return @result;
}
################################################################
#
# param1: hash
# param2: DbLogType -> Current oder History oder Current/History
# param4: Timestamp
# param5: Device
# param6: Type
# param7: Event
# param8: Reading
# param9: Value
# param10: Unit
#
################################################################
sub DbLog_Push(@) {
my ($hash, $DbLogType, $timestamp, $device, $type, $event, $reading, $value, $unit) = @_;
my $dbh= $hash->{DBH};
$dbh->{RaiseError} = 1;
$dbh->begin_work();
my $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)") if (lc($DbLogType) =~ m(history) );
my $sth_ic = $dbh->prepare_cached("INSERT INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)") if (lc($DbLogType) =~ m(current) );
my $sth_uc = $dbh->prepare_cached("UPDATE current SET TIMESTAMP=?, TYPE=?, EVENT=?, VALUE=?, UNIT=? WHERE (DEVICE=?) AND (READING=?)") if (lc($DbLogType) =~ m(current) );
# insert into history
if (lc($DbLogType) =~ m(history) ) {
my $rv_ih = $sth_ih->execute(($timestamp, $device, $type, $event, $reading, $value, $unit));
}
# update or insert current
if (lc($DbLogType) =~ m(current) ) {
my $rv_uc = $sth_uc->execute(($timestamp, $type, $event, $value, $unit, $device, $reading));
if ($rv_uc == 0) {
my $rv_ic = $sth_ic->execute(($timestamp, $device, $type, $event, $reading, $value, $unit));
}
}
$dbh->commit();
if ($@) {
Log3 $hash->{NAME}, 2, "DbLog: Failed to insert new readings into database: $@";
$dbh->{RaiseError} = 0;
$dbh->rollback();
# reconnect
$dbh->disconnect();
DbLog_Connect($hash);
}
else {
$dbh->{RaiseError} = 0;
}
return $dbh->{RaiseError};
}
################################################################
#
@ -346,13 +401,11 @@ DbLog_ParseEvent($$$)
# aufgerufen
#
################################################################
sub
DbLog_Log($$)
{
sub DbLog_Log($$) {
# Log is my entry, Dev is the entry of the changed device
my ($log, $dev) = @_;
my ($hash, $dev) = @_;
return undef if($log->{STATE} eq "disabled");
return undef if($hash->{STATE} eq "disabled");
# name and type required for parsing
my $n= $dev->{NAME};
@ -362,25 +415,15 @@ DbLog_Log($$)
#my ($sec,$min,$hr,$day,$mon,$yr,$wday,$yday,$isdst)= localtime(time);
#my $ts= sprintf("%04d-%02d-%02d %02d:%02d:%02d", $yr+1900,$mon+1,$day,$hr,$min,$sec);
my $re = $log->{REGEXP};
my $re = $hash->{REGEXP};
my $max = int(@{$dev->{CHANGED}});
my $ts_0 = TimeNow();
my $now = gettimeofday(); # get timestamp in seconds since epoch
my $DbLogExclude = AttrVal($dev->{NAME}, "DbLogExclude", undef);
my $dbh= $log->{DBH};
$dbh->{RaiseError} = 1;
my $DbLogType = AttrVal($log->{NAME}, "DbLogType", "Current/History");
my $DbLogType = AttrVal($hash->{NAME}, "DbLogType", "Current/History");
#one Transaction
eval {
$dbh->begin_work();
my $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)") if ($DbLogType =~ m(History) );
my $sth_uc = $dbh->prepare_cached("UPDATE current SET TIMESTAMP=?, TYPE=?, EVENT=?, VALUE=?, UNIT=? WHERE (DEVICE=?) AND (READING=?)") if ($DbLogType =~ m(Current) );
my $sth_ic = $dbh->prepare_cached("INSERT INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)") if ($DbLogType =~ m(Current) );
#eval {
for (my $i = 0; $i < $max; $i++) {
my $s = $dev->{CHANGED}[$i];
$s = "" if(!defined($s));
@ -409,8 +452,8 @@ DbLog_Log($$)
$DoIt = 0 if(!$v2[1] && $reading =~ m/^$v2[0]$/); #Reading matcht auf Regexp, kein MinIntervall angegeben
if(($v2[1] && $reading =~ m/^$v2[0]$/) && ($v2[1] =~ m/^(\d+)$/)) {
#Regexp matcht und MinIntervall ist angegeben
my $lt = $defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$log->{NAME}}{TIME};
my $lv = $defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$log->{NAME}}{VALUE};
my $lt = $defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{TIME};
my $lv = $defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{VALUE};
$lt = 0 if(!$lt);
$lv = "" if(!$lv);
@ -423,39 +466,14 @@ DbLog_Log($$)
}
next if($DoIt == 0);
$defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$log->{NAME}}{TIME} = $now;
$defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$log->{NAME}}{VALUE} = $value;
$defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{TIME} = $now;
$defs{$dev->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{VALUE} = $value;
my @is= ($ts, $n, $t, $s, $reading, $value, $unit);
# insert into history
if ($DbLogType =~ m(History) ) {
my $rv_ih = $sth_ih->execute(@is);
}
if ($DbLogType =~ m(Current) ) {
# update or insert current
my $rv_uc = $sth_uc->execute(($ts, $t, $s, $value, $unit, $n, $reading));
if ($rv_uc == 0) {
my $rv_ic = $sth_ic->execute(@is);
}
}
DbLog_Push($hash, $DbLogType, $ts, $n, $t, $s, $reading, $value, $unit)
}
}
$dbh->commit();
};
if ($@) {
Log3 $dev->{NAME}, 2, "DbLog: Failed to insert new readings into database: $@";
$dbh->{RaiseError} = 0;
$dbh->rollback();
# reconnect
$dbh->disconnect();
DbLog_Connect($log);
}
else {
$dbh->{RaiseError} = 0;
}
#};
return "";
}
@ -467,8 +485,7 @@ DbLog_Log($$)
# uebergebenes SQL-Format: YYYY-MM-DD HH24:MI:SS
#
################################################################
sub
DbLog_explode_datetime($%) {
sub DbLog_explode_datetime($%) {
my ($t, %def) = @_;
my %retv;
@ -489,20 +506,19 @@ DbLog_explode_datetime($%) {
return %retv
}
sub
DbLog_implode_datetime($$$$$$) {
sub DbLog_implode_datetime($$$$$$) {
my ($year, $month, $day, $hour, $minute, $second) = @_;
my $retv = $year."-".$month."-".$day." ".$hour.":".$minute.":".$second;
return $retv;
}
################################################################
#
# Verbindung zur DB aufbauen
#
################################################################
sub
DbLog_Connect($)
sub DbLog_Connect($)
{
my ($hash)= @_;
@ -575,6 +591,9 @@ DbLog_Connect($)
#
# Prozeduren zum Ausfuehren des SQLs
#
# param1: hash
# param2: pointer : DBFilehandle
# param3: string : SQL
################################################################
sub
DbLog_ExecSQL1($$$)
@ -618,6 +637,8 @@ DbLog_ExecSQL($$)
#
# GET Funktion
# wird zb. zur Generierung der Plots implizit aufgerufen
# infile : [-|current|history]
# outfile: [-|ALL|INT|WEBCHART]
#
################################################################
sub
@ -632,16 +653,22 @@ DbLog_Get($@)
" <out> is a prefix, - means stdout\n"
if(int(@a) < 5);
shift @a;
my $inf = shift @a;
my $outf = shift @a;
my $inf = lc(shift @a);
my $outf = lc(shift @a);
my $from = shift @a;
my $to = shift @a; # Now @a contains the list of column_specs
my ($internal, @fld);
if($outf eq "INT") {
if($inf eq "-") {
$inf = "history";
}
if($outf eq "int") {
$outf = "-";
$internal = 1;
} elsif (uc($outf) eq "WEBCHART") {
} elsif($outf eq "array"){
} elsif(uc($outf) eq "webchart") {
# redirect the get request to the chartQuery function
return chartQuery($hash, @_);
}
@ -659,7 +686,8 @@ DbLog_Get($@)
$to = $to_datetime{datetime};
my ($retval,$sql_timestamp,$sql_value, $type, $event, $unit) = "";
my ($retval,$sql_timestamp, $sql_device, $sql_reading, $sql_value, $type, $event, $unit) = "";
my @ReturnArray;
my $writeout = 0;
my (@min, @max, @sum, @cnt, @lastv, @lastd);
my (%tstamp, %lasttstamp, $out_tstamp, $out_value, $minval, $maxval); #fuer delta-h/d Berechnung
@ -672,6 +700,8 @@ DbLog_Get($@)
$readings[$i][2] = $fld[2]; # Default
$readings[$i][3] = $fld[3]; # function
$readings[$i][4] = $fld[4]; # regexp
$readings[$i][1] = "%" if(length($readings[$i][1])==0); #falls Reading nicht gefüllt setze Joker
}
#create new connection for plotfork
@ -687,7 +717,7 @@ DbLog_Get($@)
$sqlspec{get_timestamp} = "TO_CHAR(TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS')";
$sqlspec{from_timestamp} = "TO_TIMESTAMP('$from', 'YYYY-MM-DD HH24:MI:SS')";
$sqlspec{to_timestamp} = "TO_TIMESTAMP('$to', 'YYYY-MM-DD HH24:MI:SS')";
$sqlspec{reading_clause} = "(DEVICE || '|' || READING)";
#$sqlspec{reading_clause} = "(DEVICE || '|' || READING)";
} elsif ($hash->{DBMODEL} eq "ORACLE") {
$sqlspec{get_timestamp} = "TO_CHAR(TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS')";
$sqlspec{from_timestamp} = "TO_TIMESTAMP('$from', 'YYYY-MM-DD HH24:MI:SS')";
@ -706,7 +736,7 @@ DbLog_Get($@)
$sqlspec{to_timestamp} = "'$to'";
}
if(uc($outf) eq "ALL") {
if($outf =~ m/(all|array)/) {
$sqlspec{all} = ",TYPE,EVENT,UNIT";
} else {
$sqlspec{all} = "";
@ -724,35 +754,48 @@ DbLog_Get($@)
$minval = 999999;
$maxval = -999999;
my $stm= "SELECT
my $stm;
$stm = "SELECT
$sqlspec{get_timestamp},
DEVICE,
READING,
VALUE
$sqlspec{all}
FROM history
WHERE
DEVICE = '".$readings[$i]->[0]."'
AND READING = '".$readings[$i]->[1]."'
AND TIMESTAMP > $sqlspec{from_timestamp}
$sqlspec{all} ";
$stm .= "FROM current " if($inf eq "current");
$stm .= "FROM history " if($inf eq "history");
$stm .= "WHERE 1=1 ";
$stm .= "AND DEVICE = '".$readings[$i]->[0]."' " if ($readings[$i]->[0] !~ m(\%));
$stm .= "AND DEVICE LIKE '".$readings[$i]->[0]."' " if(($readings[$i]->[0] !~ m(^\%$)) && ($readings[$i]->[0] =~ m(\%)));
$stm .= "AND READING = '".$readings[$i]->[1]."' " if ($readings[$i]->[1] !~ m(\%));
$stm .= "AND READING LIKE '".$readings[$i]->[1]."' " if(($readings[$i]->[1] !~ m(^%$)) && ($readings[$i]->[1] =~ m(\%)));
$stm .= "AND TIMESTAMP > $sqlspec{from_timestamp}
AND TIMESTAMP < $sqlspec{to_timestamp}
ORDER BY TIMESTAMP";
Log3 $hash->{NAME}, 5, "Executing $stm";
Log3 $hash->{NAME}, 4, "Processing Statement: $stm";
my $sth= $dbh->prepare($stm) ||
return "Cannot prepare statement $stm: $DBI::errstr";
my $rc= $sth->execute() ||
return "Cannot execute statement $stm: $DBI::errstr";
if(uc($outf) eq "ALL") {
$sth->bind_columns(undef, \$sql_timestamp, \$sql_value, \$type, \$event, \$unit);
$retval .= "Timestamp: Device, Type, Event, Reading, Value, Unit\n";
$retval .= "=====================================================\n";
if($outf =~ m/(all|array)/) {
$sth->bind_columns(undef, \$sql_timestamp, \$sql_device, \$sql_reading, \$sql_value, \$type, \$event, \$unit);
}
else {
$sth->bind_columns(undef, \$sql_timestamp, \$sql_value);
}
if ($outf =~ m/(all)/) {
$retval .= "Timestamp: Device, Type, Event, Reading, Value, Unit\n";
$retval .= "=====================================================\n";
}
while($sth->fetch()) {
$writeout = 0;
$out_value = "";
@ -840,8 +883,13 @@ DbLog_Get($@)
###################### Ausgabe ###########################
if($writeout) {
if(uc($outf) eq "ALL") {
$retval .= sprintf("%s: %s, %s, %s, %s, %s, %s\n", $out_tstamp, $readings[$i]->[0], $type, $event, $readings[$i]->[1], $out_value, $unit);
if ($outf =~ m/(all)/) {
# Timestamp: Device, Type, Event, Reading, Value, Unit
$retval .= sprintf("%s: %s, %s, %s, %s, %s, %s\n", $out_tstamp, $sql_device, $type, $event, $sql_reading, $out_value, $unit);
} elsif ($outf =~ m/(array)/) {
push(@ReturnArray, {"tstamp" => $out_tstamp, "device" => $sql_device, "type" => $type, "event" => $event, "reading" => $sql_reading, "value" => $out_value, "unit" => $unit});
} else {
$out_tstamp =~ s/\ /_/g; #needed by generating plots
$retval .= "$out_tstamp $out_value\n";
@ -873,8 +921,13 @@ DbLog_Get($@)
$out_value = sprintf("%g", $maxval - $minval);
$out_tstamp = DbLog_implode_datetime($lasttstamp{year}, $lasttstamp{month}, $lasttstamp{day}, $lasttstamp{hour}, "30", "00") if($readings[$i]->[3] eq "delta-h");
$out_tstamp = DbLog_implode_datetime($lasttstamp{year}, $lasttstamp{month}, $lasttstamp{day}, "00", "00", "00") if($readings[$i]->[3] eq "delta-d");
if(uc($outf) eq "ALL") {
$retval .= sprintf("%s: %s %s %s %s %s %s\n", $out_tstamp, $readings[$i]->[0], $type, $event, $readings[$i]->[1], $out_value, $unit);
if($outf =~ m/(all)/) {
$retval .= sprintf("%s: %s %s %s %s %s %s\n", $out_tstamp, $sql_device, $type, $event, $sql_reading, $out_value, $unit);
} elsif ($outf =~ m/(array)/) {
push(@ReturnArray, {"tstamp" => $out_tstamp, "device" => $sql_device, "type" => $type, "event" => $event, "reading" => $sql_reading, "value" => $out_value, "unit" => $unit});
} else {
$out_tstamp =~ s/\ /_/g; #needed by generating plots
$retval .= "$out_tstamp $out_value\n";
@ -911,8 +964,13 @@ DbLog_Get($@)
if($internal) {
$internal_data = \$retval;
return undef;
}
} elsif($outf =~ m/(array)/) {
return @ReturnArray;
} else {
return $retval;
}
}
################################################################
@ -1240,7 +1298,6 @@ sub chartQuery($@) {
contains the last event for any given reading and device.
The columns have the following meaning:
<ol>
<li>TIMESTAMP: timestamp of event, e.g. <code>2007-12-30 21:45:22</code></li>
<li>DEVICE: device name, e.g. <code>Wetterstation</code></li>
<li>TYPE: device type, e.g. <code>KS300</code></li>
@ -1284,11 +1341,25 @@ sub chartQuery($@) {
<ul>
<li>&lt;in&gt;<br>
A dummy parameter for FileLog compatibility. Always set to <code>-</code></li>
A dummy parameter for FileLog compatibility. Sessing by defaultto <code>-</code><br>
<ul>
<li>current: reading actual readings from table "current"</li>
<li>history: reading history readings from table "history"</li>
<li>-: identical to "history"</li>
</ul>
</li>
<li>&lt;out&gt;<br>
A dummy parameter for FileLog compatibility. Set it to <code>-</code>
to check the output for plot-computing.<br>Set it to the special keyword
<code>all</code> to get all columns from Database.</li>
A dummy parameter for FileLog compatibility. Setting by default to <code>-</code>
to check the output for plot-computing.<br>
Set it to the special keyword
<code>all</code> to get all columns from Database.
<ul>
<li>ALL: get all colums from table, including a header</li>
<li>Array: get the columns as array of hashes</li>
<li>INT: internally used by generating plots</li>
<li>-: default</li>
</ul>
</li>
<li>&lt;from&gt; / &lt;to&gt;<br>
Used to select the data. Please use the following timeformat or
an initial substring of it:<br>
@ -1299,9 +1370,9 @@ sub chartQuery($@) {
Syntax: &lt;device&gt;:&lt;reading&gt;:&lt;default&gt;:&lt;fn&gt;:&lt;regexp&gt;<br>
<ul>
<li>&lt;device&gt;<br>
The name of the device. Case sensitive</li>
The name of the device. Case sensitive. Using a the joker "%" is supported.</li>
<li>&lt;reading&gt;<br>
The reading of the given device to select. Case sensitive.
The reading of the given device to select. Case sensitive. Using a the joker "%" is supported.
</li>
<li>&lt;default&gt;<br>
no implemented yet
@ -1344,6 +1415,9 @@ sub chartQuery($@) {
Examples:
<ul>
<li><code>get myDbLog - - 2012-11-10 2012-11-20 KS300:temperature</code></li>
<li><code>get myDbLog current ALL - - %:temperature</code></li><br>
you will get all actual readings "temperature" from all logged devices.
Be carful by using "history" as inputfile because a long execution time will be expected!
<li><code>get myDbLog - - 2012-11-10_10 2012-11-10_20 KS300:temperature::int1</code><br>
like from 10am until 08pm at 10.11.2012</li>
<li><code>get myDbLog - all 2012-11-10 2012-11-20 KS300:temperature</code></li>
@ -1472,13 +1546,13 @@ sub chartQuery($@) {
definiert in <code>&lt;configfilename&gt;</code>. (Vergleiche
Beipspielkonfigurationsdatei in <code>contrib/dblog/db.conf</code>).<br>
Die Konfiguration ist in einer sparaten Datei abgelegt um das Datenbankpasswort
nicht in Klartext in der FHEM-Haupt-Konfigurationsdatei speichern zu müssen.
Ansonsten wäre es mittels des <a href="../docs/commandref.html#list">list</a>
nicht in Klartext in der FHEM-Haupt-Konfigurationsdatei speichern zu m&ouml;ssen.
Ansonsten w&auml;re es mittels des <a href="../docs/commandref.html#list">list</a>
Befehls einfach auslesbar.
<br><br>
Die Perl-Module <code>DBI</code> and <code>DBD::&lt;dbtype&gt;</code>
müssen installiert werden (use <code>cpan -i &lt;module&gt;</code>
m&ouml;ssen installiert werden (use <code>cpan -i &lt;module&gt;</code>
falls die eigene Distribution diese nicht schon mitbringt).
<br><br>
@ -1487,7 +1561,7 @@ sub chartQuery($@) {
Ein Beispielcode zum Erstellen einer MySQL/PostGreSQL Datenbak ist in
<code>contrib/dblog/&lt;DBType&gt;_create.sql</code> zu finden.
Die Datenbank beinhaltet 2 Tabellen: <code>current</code> und
<code>history</code>. Die Tabelle <code>current</code> enthält den letzten Stand
<code>history</code>. Die Tabelle <code>current</code> enth&auml;lt den letzten Stand
pro Device und Reading. In der Tabelle <code>history</code> sind alle
Events historisch gespeichert.
@ -1505,10 +1579,10 @@ sub chartQuery($@) {
z.B. <code>71</code></li>
<li>UNIT: Einheit, ermittelt aus dem Event, z.B. <code>%</code></li>
</ol>
Der Wert des Rreadings ist optimiert für eine automatisierte Nachverarbeitung
Der Wert des Rreadings ist optimiert f&ouml;r eine automatisierte Nachverarbeitung
z.B. <code>yes</code> ist transformiert nach <code>1</code>
<br><br>
Die gespeicherten Werte können mittels GET Funktion angezeigt werden:
Die gespeicherten Werte k&ouml;nnen mittels GET Funktion angezeigt werden:
<ul>
<code>get myDbLog - - 2012-11-10 2012-11-10 KS300:temperature</code>
</ul>
@ -1516,7 +1590,6 @@ sub chartQuery($@) {
<b>Beispiel:</b>
<ul>
<code>Speichert alles in der Datenbank</code><br>
<code>define myDbLog DbLog /etc/fhem/db.conf .*:.*</code>
</ul>
</ul>
@ -1531,37 +1604,49 @@ sub chartQuery($@) {
<code>get &lt;name&gt; &lt;infile&gt; &lt;outfile&gt; &lt;from&gt;
&lt;to&gt; &lt;column_spec&gt; </code>
<br><br>
Ließt Daten aus der Datenbank. Wird durch die Frontends benutzt um Plots
zu generieren ohne selbst auf die Datenank zugreifen zu müssen.
Liesst Daten aus der Datenbank. Wird durch die Frontends benutzt um Plots
zu generieren ohne selbst auf die Datenank zugreifen zu m&ouml;ssen.
<br>
<ul>
<li>&lt;in&gt;<br>
Ein Dummy Parameter um eine Kompatibilität zum Filelog herzustellen.
Dieser Parameter ist immer auf <code>-</code> zu setzen.
Ein Parameter um eine Kompatibilit&auml;t zum Filelog herzustellen.
Dieser Parameter ist per default immer auf <code>-</code> zu setzen.<br>
Folgende Auspr&auml;gungen sind zugelassen:<br>
<ul>
<li>current: die aktuellen Werte aus der Tabelle "current" werden gelesen.</li>
<li>history: die historischen Werte aus der Tabelle "history" werden gelesen.</li>
<li>-: identisch wie "history"</li>
</ul>
</li>
<li>&lt;out&gt;<br>
Ein Dummy Parameter um eine Kompatibilität zum Filelog herzustellen.
Dieser Parameter ist immer auf <code>-</code> zu setzen um die
Ermittlung der Daten aus der Datenbank für die Plotgenerierung zu prüfen.<br>
Durchd ie Angabe des Schlüsselworts <code>all</code> werden alle
Spalten der Datenbank ausgegeben.
Ein Parameter um eine Kompatibilit&auml;t zum Filelog herzustellen.
Dieser Parameter ist per default immer auf <code>-</code> zu setzen um die
Ermittlung der Daten aus der Datenbank f&ouml;r die Plotgenerierung zu pr&ouml;fen.<br>
Folgende Auspr&auml;gungen sind zugelassen:<br>
<ul>
<li>ALL: Es werden alle Spalten der Datenbank ausgegeben. Inclusive einer &Uuml;berschrift.</li>
<li>Array: Es werden alle Spalten der Datenbank als Hash ausgegeben. Alle Datens&auml;tze als Array zusammengefasst.</li>
<li>INT: intern zur Plotgenerierung verwendet</li>
<li>-: default</li>
</ul>
</li>
<li>&lt;from&gt; / &lt;to&gt;<br>
Wird benutzt um den Zeitraum der Daten einzugrenzen. Es ist das folgende
Zeitformat oder ein Teilstring davon zu benutzen:<br>
<ul><code>YYYY-MM-DD_HH24:MI:SS</code></ul></li>
<li>&lt;column_spec&gt;<br>
Für jede column_spec Gruppe wird ein Datenset zurückgegeben welches
durch einen Kommentar getrennt wird. Dieser Kommentar repräsentiert
F&ouml;r jede column_spec Gruppe wird ein Datenset zur&ouml;ckgegeben welches
durch einen Kommentar getrennt wird. Dieser Kommentar repr&auml;sentiert
die column_spec.<br>
Syntax: &lt;device&gt;:&lt;reading&gt;:&lt;default&gt;:&lt;fn&gt;:&lt;regexp&gt;<br>
<ul>
<li>&lt;device&gt;<br>
Der Name des Devices. Achtung: Groß/Kleinschreibung beachten!</li>
Der Name des Devices. Achtung: Gross/Kleinschreibung beachten!<br>
Es kann ein % als Jokerzeichen angegeben werden.</li>
<li>&lt;reading&gt;<br>
Das REading des angegebenen Devices zur Datenselektion.
Achtung: Groß/Kleinschreibung beachten!
Das Reading des angegebenen Devices zur Datenselektion.<br>
Es kann ein % als Jokerzeichen angegeben werden.<br>
Achtung: Gross/Kleinschreibung beachten!
</li>
<li>&lt;default&gt;<br>
Zur Zeit noch nicht implementiert.
@ -1571,17 +1656,17 @@ sub chartQuery($@) {
<ul>
<li>int<br>
Ermittelt den Zahlenwert ab dem Anfang der Zeichenkette aus der
Spalte "VALUE". Benutzt z.B. für Ausprägungen wie 10%.
Spalte "VALUE". Benutzt z.B. f&ouml;r Auspr&auml;gungen wie 10%.
</li>
<li>int&lt;digit&gt;<br>
Ermittelt den Zahlenwert ab dem Anfang der Zeichenkette aus der
Spalte "VALUE", inclusive negativen Vorzeichen und Dezimaltrenner.
Benutzt z.B. für Ausprägungen wie -5.7&deg;C.
Benutzt z.B. f&ouml;r Auspr&auml;gungen wie -5.7&deg;C.
</li>
<li>delta-h / delta-d<br>
Ermittelt die relative Veränderung eines Zahlenwertes pro Stunde
oder pro Tag. Wird benutzt z.B. für Spalten die einen
hochlaufenden Zähler enthalten wie im Falle für ein KS300 Regenzähler
Ermittelt die relative Ver&auml;nderung eines Zahlenwertes pro Stunde
oder pro Tag. Wird benutzt z.B. f&ouml;r Spalten die einen
hochlaufenden Z&auml;hler enthalten wie im Falle f&ouml;r ein KS300 Regenz&auml;hler
oder dem 1-wire Modul OWCOUNT.
</li>
<li>delta-ts<br>
@ -1590,19 +1675,19 @@ sub chartQuery($@) {
</li>
</ul></li>
<li>&lt;regexp&gt;<br>
Diese Zeichenkette wird als Perl Befehl ausgewertet. Die regexp wird vor dem angegebenen &lt;fn&gt; Parameter ausgeführt.
Diese Zeichenkette wird als Perl Befehl ausgewertet. Die regexp wird vor dem angegebenen &lt;fn&gt; Parameter ausgef&ouml;hrt.
<br>
Bitte zur Beachtung: Diese Zeichenkette darf keine Leerzeichen
enthalten da diese sonst als &lt;column_spec&gt; Trennung
interpretiert werden und alles nach dem Leerzeichen als neue
&lt;column_spec&gt; gesehen wird.<br>
<b>Schlüsselwörter</b>
<li>$val ist der aktuelle Wert die die Datenbank für ein Device/Reading ausgibt.</li>
<b>Schl&ouml;sselw&ouml;rter</b>
<li>$val ist der aktuelle Wert die die Datenbank f&ouml;r ein Device/Reading ausgibt.</li>
<li>$ts ist der aktuelle Timestamp des Logeintrages.</li>
<li>Wird als $val das Schlüsselwort "hide" zurückgegeben, so wird dieser Logeintrag nicht
ausgegeben, trotzdem aber für die Zeitraumberechnung verwendet.</li>
<li>Wird als $val das Schlüsselwort "ignore" zurückgegeben, so wird dieser Logeintrag
nicht für eine Folgeberechnung verwendet.</li>
<li>Wird als $val das Schl&ouml;sselwort "hide" zur&ouml;ckgegeben, so wird dieser Logeintrag nicht
ausgegeben, trotzdem aber f&ouml;r die Zeitraumberechnung verwendet.</li>
<li>Wird als $val das Schl&ouml;sselwort "ignore" zur&ouml;ckgegeben, so wird dieser Logeintrag
nicht f&ouml;r eine Folgeberechnung verwendet.</li>
</li>
</ul></li>
</ul>
@ -1610,39 +1695,42 @@ sub chartQuery($@) {
<b>Beispiele:</b>
<ul>
<li><code>get myDbLog - - 2012-11-10 2012-11-20 KS300:temperature</code></li>
<li><code>get myDbLog current ALL - - %:temperature</code></li><br>
Damit erhält man alle aktuellen Readings "temperature" von allen in der DB geloggten Devices.
Achtung: bei Nutzung von Jokerzeichen auf die historyTabelle kann man sein FHEM aufgrund langer Laufzeit lahmlegen!
<li><code>get myDbLog - - 2012-11-10_10 2012-11-10_20 KS300:temperature::int1</code><br>
gibt Daten aus von 10Uhr bis 20Uhr am 10.11.2012</li>
<li><code>get myDbLog - all 2012-11-10 2012-11-20 KS300:temperature</code></li>
<li><code>get myDbLog - - 2012-11-10 2012-11-20 KS300:temperature KS300:rain::delta-h KS300:rain::delta-d</code></li>
<li><code>get myDbLog - - 2012-11-10 2012-11-20 MyFS20:data:::$val=~s/(on|off).*/$1eq"on"?1:0/eg</code><br>
gibt 1 zurück für alle Ausprägungen von on* (on|on-for-timer etc) und 0 für alle off*</li>
gibt 1 zur&ouml;ck f&ouml;r alle Auspr&auml;gungen von on* (on|on-for-timer etc) und 0 f&ouml;r alle off*</li>
<li><code>get myDbLog - - 2012-11-10 2012-11-20 Bodenfeuchte:data:::$val=~s/.*B:\s([-\.\d]+).*/$1/eg</code><br>
Beispiel von OWAD: Ein Wert wie z.B.: <code>"A: 49.527 % B: 66.647 % C: 9.797 % D: 0.097 V"</code><br>
und die Ausgabe ist für das Reading B folgende: <code>2012-11-20_10:23:54 66.647</code></li>
und die Ausgabe ist f&ouml;r das Reading B folgende: <code>2012-11-20_10:23:54 66.647</code></li>
<li><code>get DbLog - - 2013-05-26 2013-05-28 Pumpe:data::delta-ts:$val=~s/on/hide/</code><br>
Realisierung eines Betriebsstundenzählers.Durch delta-ts wird die Zeit in Sek zwischen den Log-
einträgen ermittelt. Die Zeiten werden bei den on-Meldungen nicht ausgegeben welche einer Abschaltzeit
entsprechen würden.</li>
Realisierung eines Betriebsstundenz&auml;hlers.Durch delta-ts wird die Zeit in Sek zwischen den Log-
eintr&auml;gen ermittelt. Die Zeiten werden bei den on-Meldungen nicht ausgegeben welche einer Abschaltzeit
entsprechen w&ouml;rden.</li>
</ul>
<br><br>
</ul>
<b>Get</b> für die Nutzung von webcharts
<b>Get</b> f&ouml;r die Nutzung von webcharts
<ul>
<code>get &lt;name&gt; &lt;infile&gt; &lt;outfile&gt; &lt;from&gt;
&lt;to&gt; &lt;device&gt; &lt;querytype&gt; &lt;xaxis&gt; &lt;yaxis&gt; &lt;savename&gt; </code>
<br><br>
Liest Daten aus der Datenbank aus und gibt diese in JSON formatiert aus. Wird für das Charting Frontend genutzt
Liest Daten aus der Datenbank aus und gibt diese in JSON formatiert aus. Wird f&ouml;r das Charting Frontend genutzt
<br>
<ul>
<li>&lt;name&gt;<br>
Der Name des definierten DbLogs, so wie er in der fhem.cfg angegeben wurde.</li>
<li>&lt;in&gt;<br>
Ein Dummy Parameter um eine Kompatibilität zum Filelog herzustellen.
Ein Dummy Parameter um eine Kompatibilit&auml;t zum Filelog herzustellen.
Dieser Parameter ist immer auf <code>-</code> zu setzen.</li>
<li>&lt;out&gt;<br>
Ein Dummy Parameter um eine Kompatibilität zum Filelog herzustellen.
Ein Dummy Parameter um eine Kompatibilit&auml;t zum Filelog herzustellen.
Dieser Parameter ist auf <code>webchart</code> zu setzen um die Charting Get Funktion zu nutzen.
</li>
<li>&lt;from&gt; / &lt;to&gt;<br>
@ -1652,32 +1740,32 @@ sub chartQuery($@) {
<li>&lt;device&gt;<br>
Ein String, der das abzufragende Device darstellt.</li>
<li>&lt;querytype&gt;<br>
Ein String, der die zu verwendende Abfragemethode darstellt. Zur Zeit unterstützte Werte sind: <br>
<code>getreadings</code> um für ein bestimmtes device alle Readings zu erhalten<br>
<code>getdevices</code> um alle verfügbaren devices zu erhalten<br>
<code>timerange</code> um Chart-Daten abzufragen. Es werden die Parameter 'xaxis', 'yaxis', 'device', 'to' und 'from' benötigt<br>
<code>savechart</code> um einen Chart unter Angabe eines 'savename' und seiner zugehörigen Konfiguration abzuspeichern<br>
<code>deletechart</code> um einen zuvor gespeicherten Chart unter Angabe einer id zu löschen<br>
Ein String, der die zu verwendende Abfragemethode darstellt. Zur Zeit unterst&ouml;tzte Werte sind: <br>
<code>getreadings</code> um f&ouml;r ein bestimmtes device alle Readings zu erhalten<br>
<code>getdevices</code> um alle verf&ouml;gbaren devices zu erhalten<br>
<code>timerange</code> um Chart-Daten abzufragen. Es werden die Parameter 'xaxis', 'yaxis', 'device', 'to' und 'from' ben&ouml;tigt<br>
<code>savechart</code> um einen Chart unter Angabe eines 'savename' und seiner zugeh&ouml;rigen Konfiguration abzuspeichern<br>
<code>deletechart</code> um einen zuvor gespeicherten Chart unter Angabe einer id zu l&ouml;schen<br>
<code>getcharts</code> um eine Liste aller gespeicherten Charts zu bekommen.<br>
<code>getTableData</code> um Daten aus der Datenbank abzufragen und in einer Tabelle darzustellen. Benötigt paging Parameter wie start und limit.<br>
<code>hourstats</code> um Statistiken für einen Wert (yaxis) für eine Stunde abzufragen.<br>
<code>daystats</code> um Statistiken für einen Wert (yaxis) für einen Tag abzufragen.<br>
<code>weekstats</code> um Statistiken für einen Wert (yaxis) für eine Woche abzufragen.<br>
<code>monthstats</code> um Statistiken für einen Wert (yaxis) für einen Monat abzufragen.<br>
<code>yearstats</code> um Statistiken für einen Wert (yaxis) für ein Jahr abzufragen.<br>
<code>getTableData</code> um Daten aus der Datenbank abzufragen und in einer Tabelle darzustellen. Ben&ouml;tigt paging Parameter wie start und limit.<br>
<code>hourstats</code> um Statistiken f&ouml;r einen Wert (yaxis) f&ouml;r eine Stunde abzufragen.<br>
<code>daystats</code> um Statistiken f&ouml;r einen Wert (yaxis) f&ouml;r einen Tag abzufragen.<br>
<code>weekstats</code> um Statistiken f&ouml;r einen Wert (yaxis) f&ouml;r eine Woche abzufragen.<br>
<code>monthstats</code> um Statistiken f&ouml;r einen Wert (yaxis) f&ouml;r einen Monat abzufragen.<br>
<code>yearstats</code> um Statistiken f&ouml;r einen Wert (yaxis) f&ouml;r ein Jahr abzufragen.<br>
</li>
<li>&lt;xaxis&gt;<br>
Ein String, der die X-Achse repräsentiert</li>
Ein String, der die X-Achse repr&auml;sentiert</li>
<li>&lt;yaxis&gt;<br>
Ein String, der die Y-Achse repräsentiert</li>
Ein String, der die Y-Achse repr&auml;sentiert</li>
<li>&lt;savename&gt;<br>
Ein String, unter dem ein Chart in der Datenbank gespeichert werden soll</li>
<li>&lt;chartconfig&gt;<br>
Ein jsonstring der den zu speichernden Chart repräsentiert</li>
Ein jsonstring der den zu speichernden Chart repr&auml;sentiert</li>
<li>&lt;pagingstart&gt;<br>
Ein Integer um den Startwert für die Abfrage 'getTableData' festzulegen</li>
Ein Integer um den Startwert f&ouml;r die Abfrage 'getTableData' festzulegen</li>
<li>&lt;paginglimit&gt;<br>
Ein Integer um den Limitwert für die Abfrage 'getTableData' festzulegen</li>
Ein Integer um den Limitwert f&ouml;r die Abfrage 'getTableData' festzulegen</li>
</ul>
<br><br>
Beispiele:
@ -1685,16 +1773,16 @@ sub chartQuery($@) {
<li><code>get logdb - webchart "" "" "" getcharts</code><br>
Liefert alle gespeicherten Charts aus der Datenbank</li>
<li><code>get logdb - webchart "" "" "" getdevices</code><br>
Liefert alle verfügbaren Devices aus der Datenbank</li>
Liefert alle verf&ouml;gbaren Devices aus der Datenbank</li>
<li><code>get logdb - webchart "" "" ESA2000_LED_011e getreadings</code><br>
Liefert alle verfügbaren Readings aus der Datenbank unter Angabe eines Gerätes</li>
Liefert alle verf&ouml;gbaren Readings aus der Datenbank unter Angabe eines Ger&auml;tes</li>
<li><code>get logdb - webchart 2013-02-11_00:00:00 2013-02-12_00:00:00 ESA2000_LED_011e timerange TIMESTAMP day_kwh</code><br>
Liefert Chart-Daten, die auf folgenden Parametern basieren: 'xaxis', 'yaxis', 'device', 'to' und 'from'<br>
Die Ausgabe erfolgt als JSON, z.B.: <code>[{'TIMESTAMP':'2013-02-11 00:10:10','VALUE':'0.22431388090756'},{'TIMESTAMP'.....}]</code></li>
<li><code>get logdb - webchart 2013-02-11_00:00:00 2013-02-12_00:00:00 ESA2000_LED_011e savechart TIMESTAMP day_kwh tageskwh</code><br>
Speichert einen Chart unter Angabe eines 'savename' und seiner zugehörigen Konfiguration</li>
Speichert einen Chart unter Angabe eines 'savename' und seiner zugeh&ouml;rigen Konfiguration</li>
<li><code>get logdb - webchart "" "" "" deletechart "" "" 7</code><br>
Löscht einen zuvor gespeicherten Chart unter Angabe einer id</li>
L&ouml;scht einen zuvor gespeicherten Chart unter Angabe einer id</li>
</ul>
<br><br>
</ul>
@ -1709,11 +1797,11 @@ sub chartQuery($@) {
</ul>
<br>
Wenn DbLog genutzt wird, wird in alle Devices das Attribut <i>DbLogExclude</i>
propagiert. Der Wert des Attributes wird als Regexp ausgewertet und schließt die
propagiert. Der Wert des Attributes wird als Regexp ausgewertet und schliesst die
damit matchenden Readings von einem Logging aus. Einzelne Regexp werden durch
Kommata getrennt. Ist MinIntervall angegeben, so wird der Logeintrag nur
dann nicht geloggt, wenn das Intervall noch nicht erreicht und der Wert des
Readings sich nicht verändert hat.
Readings sich nicht ver&auml;ndert hat.
<br>
<b>Beispiele</b>
<ul>

View File

@ -62,6 +62,8 @@ sub Text2Speech_Initialize($)
" TTS_UseMP3Wrap:0,1".
" TTS_MplayerCall".
" TTS_SentenceAppendix".
" TTS_FileMapping".
" TTS_FileTemplateDir".
" ".$readingFnAttributes;
}
@ -145,6 +147,10 @@ sub Text2Speech_Attr(@) {
my $hash = $defs{$a[1]};
my $value = $a[3];
my $TTS_FileTemplateDir = AttrVal($hash->{NAME}, "TTS_FileTemplateDir", "templates");
my $TTS_CacheFileDir = AttrVal($hash->{NAME}, "TTS_CacheFileDir", "cache");
my $TTS_FileMapping = AttrVal($hash->{NAME}, "TTS_FileMapping", ""); # zb, silence:silence.mp3 ring:myringtone.mp3;
if($a[2] eq "TTS_Delemiter" && $a[0] ne "del") {
return "wrong delemiter syntax: [+-]a[lfn]. \n".
" Example 1: +an~\n".
@ -166,8 +172,23 @@ sub Text2Speech_Attr(@) {
return "This Attribute is only available in direct mode" if($hash->{MODE} ne "DIRECT");
return "Attribute TTS_UseMP3Wrap is required!" unless(AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", undef));
my $file = AttrVal($hash->{NAME}, "TTS_CacheFileDir", "cache") ."/". $value;
my $file = $TTS_CacheFileDir ."/". $value;
return "File <".$file."> does not exists in CacheFileDir" if(! -e $file);
} elsif ($a[2] eq "TTS_FileTemplateDir") {
unless(-e ($TTS_CacheFileDir ."/". $value) or mkdir ($TTS_CacheFileDir ."/". $value)) {
#Verzeichnis anlegen gescheitert
return "Could not create directory: <$value>";
}
} elsif ($a[2] eq "TTS_FileMapping") {
#ueberpruefen, ob mp3 Template existiert
my @FileTpl = split(" ", $TTS_FileMapping);
for(my $j=0; $j<(@FileTpl); $j++) {
my @FileTplPc = split(/:/, $FileTpl[$j]);
return "file does not exist: <".$TTS_CacheFileDir ."/". $TTS_FileTemplateDir ."/". $FileTplPc[1] .">"
unless (-e $TTS_CacheFileDir ."/". $TTS_FileTemplateDir ."/". $FileTplPc[1]);
}
}
if($a[0] eq "set" && $a[2] eq "disable") {
@ -319,6 +340,8 @@ sub Text2Speech_PrepareSpeech($$) {
my $TTS_Ressource = AttrVal($hash->{NAME}, "TTS_Ressource", "Google");
my $TTS_Delemiter = AttrVal($hash->{NAME}, "TTS_Delemiter", undef);
my $TTS_FileTpl = AttrVal($hash->{NAME}, "TTS_FileMapping", ""); # zb, silence:silence.mp3 ring:myringtone.mp3; im Text: mein Klingelton :ring: ist laut.
my $TTS_FileTemplateDir = AttrVal($hash->{NAME}, "TTS_FileTemplateDir", "templates");
my $TTS_ForceSplit = 0;
my $TTS_AddDelemiter;
@ -351,12 +374,30 @@ sub Text2Speech_PrepareSpeech($$) {
@text = $hash->{helper}{Text2Speech} if($hash->{helper}{Text2Speech}[0]);
push(@text, $t);
my @FileTpl = split(" ", $TTS_FileTpl);
my @FileTplPc;
for(my $i=0; $i<(@FileTpl); $i++) {
#splitte bei jedem Template auf
@FileTplPc = split(/:/, $FileTpl[$i]);
@text = Text2Speech_SplitString(\@text, 100, ":".$FileTplPc[0].":", 1, "as"); # splitte bei bspw: :ring:
}
@text = Text2Speech_SplitString(\@text, 100, $TTS_Delemiter, $TTS_ForceSplit, $TTS_AddDelemiter);
@text = Text2Speech_SplitString(\@text, 100, "(?<=[\\.!?])\\s*", 0, "");
@text = Text2Speech_SplitString(\@text, 100, ",", 0, "al");
@text = Text2Speech_SplitString(\@text, 100, ";", 0, "al");
@text = Text2Speech_SplitString(\@text, 100, "und", 0, "af");
for(my $i=0; $i<(@text); $i++) {
for(my $j=0; $j<(@FileTpl); $j++) {
# entferne führende und abschließende Leerzeichen aus jedem Textbaustein
$text[$i] =~ s/^\s+|\s+$//g;
# ersetze die FileTemplates
@FileTplPc = split(/:/, $FileTpl[$j]);
$text[$i] = $TTS_FileTemplateDir ."/". $FileTplPc[1] if($text[$i] eq ":".$FileTplPc[0].":")
}
}
@{$hash->{helper}{Text2Speech}} = @text;
} else {
@ -370,7 +411,7 @@ sub Text2Speech_PrepareSpeech($$) {
# param3: string: Delemiter
# param4: int : 1 -> es wird am Delemiter gesplittet
# 0 -> es wird nur gesplittet, wenn Stringlänge länger als MaxChar
# param5: string: Add Delemiter to String? [pre|past|<empty>]
# param5: string: Add Delemiter to String? [al|af|as|<empty>] (AddLast/AddFirst/AddSingle)
#
# Splittet die Texte aus $hash->{helper}->{Text2Speech} anhand des
# Delemiters, wenn die Stringlänge MaxChars übersteigt.
@ -395,7 +436,7 @@ sub Text2Speech_SplitString(@$$$$){
for(my $j=0; $j<(@b); $j++) {
$b[$j] = $b[$j] . $Delemiter if($AddDelemiter eq "al"); # Am Satzende wieder hinzufügen.
$b[$j+1] = $Delemiter . $b[$j+1] if(($AddDelemiter eq "af") && ($b[$j+1])); # Am Satzanfang des nächsten Satzes wieder hinzufügen.
push(@newText, $Delemiter) if($AddDelemiter eq "as" && $j>0); # AddSingle: füge Delemiter als EinzelSatz hinzu. Zb. bei FileTemplates
push(@newText, $b[$j]);
}
}
@ -434,6 +475,33 @@ sub Text2Speech_BuildMplayerCmdString($$) {
return $cmd;
}
#####################################
# param1: hash : Hash
# param2: string: Dateiname
# param2: string: Text
#
# Holt den Text aus dem Google Translator als MP3Datei
#####################################
sub Text2Speech_Download($$$) {
my ($hash, $file, $text) = @_;
my $HttpResponse;
my $fh;
Log3 $hash->{NAME}, 4, "Text2Speech: Hole URL: ". "http://" . $ttsHost . $ttsPath . uri_escape($text);
$HttpResponse = GetHttpFile($ttsHost, $ttsPath . uri_escape($text));
$fh = new IO::File ">$file";
if(!defined($fh)) {
Log3 $hash->{NAME}, 2, "Text2Speech: mp3 Datei <$file> konnte nicht angelegt werden.";
return undef;
}
$fh->print($HttpResponse);
Log3 $hash->{NAME}, 4, "Text2Speech: Schreibe mp3 in die Datei $file mit ".length($HttpResponse)." Bytes";
close($fh);
}
#####################################
sub Text2Speech_DoIt($) {
my ($hash) = @_;
@ -445,7 +513,6 @@ sub Text2Speech_DoIt($) {
if($TTS_Ressource eq "Google") {
my $HttpResponse;
my $filename;
my $file;
@ -459,30 +526,35 @@ sub Text2Speech_DoIt($) {
if(AttrVal($hash->{NAME}, "TTS_UseMP3Wrap", 0)) {
# benutze das Tool MP3Wrap um bereits einzelne vorhandene Sprachdateien
# zusammenzuführen. Ziel: sauberer Sprachfluss
my @Mp3WrapArray;
my $Mp3WrapText = "";
my @Mp3WrapFiles;
my @Mp3WrapText;
my $TTS_SentenceAppendix = AttrVal($hash->{NAME}, "TTS_SentenceAppendix", undef); #muss eine mp3-Datei sein, ohne Pfadangabe
undef($TTS_SentenceAppendix) if($TTS_SentenceAppendix && (! -e $TTS_CacheFileDir ."/".$TTS_SentenceAppendix));
my $TTS_FileTemplateDir = AttrVal($hash->{NAME}, "TTS_FileTemplateDir", "templates");
$TTS_SentenceAppendix = $TTS_CacheFileDir ."/". $TTS_FileTemplateDir ."/". $TTS_SentenceAppendix if($TTS_SentenceAppendix);
undef($TTS_SentenceAppendix) if($TTS_SentenceAppendix && (! -e $TTS_SentenceAppendix));
#Abspielliste erstellen
foreach my $t (@{$hash->{helper}{Text2Speech}}) {
$filename = md5_hex($t) . ".mp3";
if(-e $TTS_CacheFileDir."/".$t) { $filename = $t;} else {$filename = md5_hex($t) . ".mp3";} # falls eine bestimmte mp3-Datei gespielt werden soll
$file = $TTS_CacheFileDir."/".$filename;
if(-e $file) {
push(@Mp3WrapArray, $file);
$Mp3WrapText .= $t;
push(@Mp3WrapFiles, $file);
push(@Mp3WrapText, $t);
#Text2Speech_WriteStats($hash, 0, $file, $t);
} else {last;}
}
push(@Mp3WrapArray, $TTS_CacheFileDir ."/".$TTS_SentenceAppendix) if($TTS_SentenceAppendix);
push(@Mp3WrapFiles, $TTS_SentenceAppendix) if($TTS_SentenceAppendix);
if(scalar(@Mp3WrapArray) >= 2) {
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite per MP3Wrap jetzt den Text: ". $Mp3WrapText;
if(scalar(@Mp3WrapFiles) >= 2) {
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite per MP3Wrap jetzt den Text: ". join(" ", @Mp3WrapText);
my $Mp3WrapPrefix = md5_hex(join("|", @Mp3WrapArray));
my $Mp3WrapPrefix = md5_hex(join("|", @Mp3WrapFiles));
my $Mp3WrapFile = $TTS_CacheFileDir ."/". $Mp3WrapPrefix . "_MP3WRAP.mp3";
if(! -e $Mp3WrapFile) {
$cmd = "mp3wrap " .$TTS_CacheFileDir. "/" .$Mp3WrapPrefix. ".mp3 " .join(" ", @Mp3WrapArray);
$cmd = "mp3wrap " .$TTS_CacheFileDir. "/" .$Mp3WrapPrefix. ".mp3 " .join(" ", @Mp3WrapFiles);
$cmd .= " >/dev/null" if($verbose < 5);;
Log3 $hash->{NAME}, 4, "Text2Speech: " .$cmd;
@ -492,36 +564,29 @@ sub Text2Speech_DoIt($) {
$cmd = Text2Speech_BuildMplayerCmdString($hash, $Mp3WrapFile);
Log3 $hash->{NAME}, 4, "Text2Speech:" .$cmd;
system($cmd);
#Text2Speech_WriteStats($hash, 1, $Mp3WrapFile, join(" ", @Mp3WrapText));
} else {
Log3 $hash->{NAME}, 2, "Text2Speech: Mp3Wrap Datei konnte nicht angelegt werden.";
}
return $hash->{NAME} . "|". scalar(@Mp3WrapArray);
return $hash->{NAME} ."|".
($TTS_SentenceAppendix ? scalar(@Mp3WrapFiles)-1: scalar(@Mp3WrapFiles)) ."|".
$Mp3WrapFile;
}
}
if(-e $TTS_CacheFileDir."/".$hash->{helper}{Text2Speech}[0]) {
# falls eine bestimmte mp3-Datei gespielt werden soll
$filename = $hash->{helper}{Text2Speech}[0];
} else {
$filename = md5_hex($hash->{helper}{Text2Speech}[0]) . ".mp3";
}
$file = $TTS_CacheFileDir."/".$filename;
Log3 $hash->{NAME}, 4, "Text2Speech: Bearbeite jetzt den Text: ". $hash->{helper}{Text2Speech}[0];
if(! -e $file) { # Datei existiert noch nicht im Cache
my $fh;
Log3 $hash->{NAME}, 4, "Text2Speech: Hole URL: ". "http://" . $ttsHost . $ttsPath . uri_escape($hash->{helper}{Text2Speech}[0]);
$HttpResponse = GetHttpFile($ttsHost, $ttsPath . uri_escape($hash->{helper}{Text2Speech}[0]));
$fh = new IO::File ">$file";
if(!defined($fh)) {
Log3 $hash->{NAME}, 2, "Text2Speech: mp3 Datei <$file> konnte nicht angelegt werden.";
return undef;
}
$fh->print($HttpResponse);
Log3 $hash->{NAME}, 4, "Text2Speech: Schreibe mp3 in die Datei $file mit ".length($HttpResponse)." Bytes";
close($fh);
} else {
Log3 $hash->{NAME}, 4, "Text2Speech: Datei <$file> bereits vorhanden, erneuter Download nicht notwendig";
Text2Speech_Download($hash, $file, $hash->{helper}{Text2Speech}[0]);
}
if(-e $file) { # Datei existiert jetzt
@ -530,19 +595,26 @@ sub Text2Speech_DoIt($) {
system($cmd);
}
return $hash->{NAME}. "|".
"1" ."|".
$file;
} elsif ($TTS_Ressource eq "ESpeak") {
$cmd = "sudo espeak -vde+f3 -k5 -s150 \"" . $hash->{helper}{Text2Speech}[0] . "\"";
Log3 $hash, 4, "Text2Speech:" .$cmd;
system($cmd);
}
return $hash->{NAME}. "|". "1";
return $hash->{NAME}. "|".
"1" ."|".
"";
}
####################################################
# Rückgabe der Blockingfunktion
# param1: HashName
# param2: Anzahl der abgearbeiteten Textbausteine
# param3: Dateiname der abgespielt wurde
####################################################
sub Text2Speech_Done($) {
my ($string) = @_;
@ -551,7 +623,15 @@ sub Text2Speech_Done($) {
my @a = split("\\|",$string);
my $hash = $defs{shift(@a)};
my $tts_done = shift(@a);
#Log 1, "SleepDone: " . $string;
my $filename = shift(@a);
if($filename) {
my @text;
for(my $i=0; $i<$tts_done; $i++) {
push(@text, $hash->{helper}{Text2Speech}[$i]);
}
Text2Speech_WriteStats($hash, 1, $filename, join(" ", @text));
}
delete($hash->{helper}{RUNNING_PID});
splice(@{$hash->{helper}{Text2Speech}}, 0, $tts_done);
@ -570,6 +650,39 @@ sub Text2Speech_AbortFn($) {
Log3 $hash->{NAME}, 2, "Text2Speech: BlockingCall for ".$hash->{NAME}." was aborted";
}
#####################################
# Hiermit werden Statistken per DbLogModul gesammelt
# Wichitg zur Entscheidung welche Dateien aus dem Cache lange
# nicht benutzt und somit gelöscht werden koennen.
#
# param1: hash
# param2: int: 0=indirekt (über mp3wrap); 1=direkt abgespielt
# param3: string: Datei
# param4: string: Text der als mp3 abgespielt wird
#####################################
sub Text2Speech_WriteStats($$$$){
my($hash, $typ, $file, $text) = @_;
my $DbLogDev;
#suche ein DbLogDevice
return undef unless($modules{"DbLog"} && $modules{"DbLog"}{"LOADED"});
foreach my $key (keys(%defs)) {
if($defs{$key}{TYPE} eq "DbLog") {
$DbLogDev = $key;
last;
}
}
return undef if($defs{$DbLogDev}{STATE} ne "active"); # muss active sein!
# den letzten Value von "Usage" ermitteln um dann die Staistik um 1 zu erhoehen.
my @LastValue = DbLog_Get($defs{$DbLogDev}, "", "current", "array", "-", "-", $hash->{NAME} ."|". $file.":Usage");
my $NewValue = 1;
$NewValue = $LastValue[0]{value} + 1 if($LastValue[0]);
# DbLogHash, DbLogTable, TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT
DbLog_Push($defs{$DbLogDev}, "Current", TimeNow(), $hash->{NAME} ."|". $file, $hash->{TYPE}, $text, "Usage", $NewValue, "");
}
1;
=pod
@ -700,6 +813,20 @@ sub Text2Speech_AbortFn($) {
Example: <code>silence.mp3</code>
</li>
<li>TTS_FileMapping<br>
Definition of mp3files with a custom templatedefinition. Separated by space.
All templatedefinitions can used in audiobricks by i>tts</i>.
The definition must begin and end with e colon.
The mp3files must saved in the given directory by <i>TTS_FIleTemplateDir</i>.<br>
<code>attr myTTS TTS_FileMapping ring:ringtone.mp3 beep:MyBeep.mp3</code><br>
<code>set MyTTS tts Attention: This is my ringtone :ring: Its loud?</code>
</li>
<li>TTS_FileTemplateDir<br>
Directory to save all mp3-files are defined in <i>TTS_FileMapping</i> und <i>TTS_SentenceAppendix</i><br>
Optional, Default: <code>cache/templates</code>
</li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
<li><a href="#disable">disable</a><br>
@ -847,6 +974,21 @@ sub Text2Speech_AbortFn($) {
Beispiel: <code>silence.mp3</code>
</li>
<li>TTS_FileMapping<br>
Angabe von m&ouml;glichen MP3-Dateien mit deren Templatedefinition. Getrennt duch Leerzeichen.
Die Templatedefinitionen können in den per <i>tts</i> &uuml;bergebenen Sprachbausteinen verwendet werden
und m&uuml;ssen mit einem beginnenden und endenden Doppelpunkt angegeben werden.
Die Dateien müssen im Verzeichnis <i>TTS_FIleTemplateDir</i> gespeichert sein.<br>
<code>attr myTTS TTS_FileMapping ring:ringtone.mp3 beep:MyBeep.mp3</code><br>
<code>set MyTTS tts Achtung: hier kommt mein Klingelton :ring: War der laut?</code>
</li>
<li>TTS_FileTemplateDir<br>
Verzeichnis, in dem die per <i>TTS_FileMapping</i> und <i>TTS_SentenceAppendix</i> definierten
MP3-Dateien gespeichert sind.<br>
Optional, Default: <code>cache/templates</code>
</li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li><br>
<li><a href="#disable">disable</a><br>

View File

@ -543,3 +543,5 @@
- Fri Jan 16 2014 (andreas-fey)
- Added new module "pilight"
- Sat Jan 18 2014 (tobiasfaust)
- Added new Module "Text2Speech"