mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 06:39:11 +00:00
7f4ed0896f
git-svn-id: https://svn.fhem.de/fhem/trunk@15098 2b470e98-0d58-463d-a4d8-8e2adae1ed80
314 lines
8.7 KiB
Perl
314 lines
8.7 KiB
Perl
|
|
# $Id$
|
|
#
|
|
# TODO:
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use SetExtensions;
|
|
|
|
no if $] >= 5.017011, warnings => 'experimental::smartmatch';
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_Initialize($) {
|
|
my ($hash) = @_;
|
|
|
|
$hash->{DefFn} = "CustomReadings_Define";
|
|
$hash->{UndefFn} = "CustomReadings_Undef";
|
|
$hash->{SetFn} = "CustomReadings_Set";
|
|
$hash->{AttrList} = "readingDefinitions "
|
|
. "interval "
|
|
. "$readingFnAttributes";
|
|
}
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_Define($$) {
|
|
my ($hash, $def) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
CustomReadings_OnTimer($hash);
|
|
|
|
return undef;
|
|
}
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_OnTimer($) {
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
RemoveInternalTimer($hash);
|
|
InternalTimer(gettimeofday()+ AttrVal( $name, "interval", 5), "CustomReadings_OnTimer", $hash, 0);
|
|
|
|
CustomReadings_Read($hash);
|
|
}
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_Read($) {
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
# Get the readingDefinitions and remove all newlines from the attribute
|
|
my $readingDefinitions = AttrVal( $name, "readingDefinitions", "");
|
|
$readingDefinitions =~ s/\n//g;
|
|
|
|
my @used = ("state");
|
|
my $isCombined = 0;
|
|
my @combinedOutput = ();
|
|
my $hasErrors = 0;
|
|
|
|
readingsBeginUpdate($hash);
|
|
|
|
my @definitionList = split(",", $readingDefinitions);
|
|
while (@definitionList) {
|
|
my $param = shift(@definitionList);
|
|
|
|
while ($param && $param =~ /{/ && $param !~ /}/ ) {
|
|
my $next = shift(@definitionList);
|
|
last if( !defined($next) );
|
|
$param .= ",". $next;
|
|
}
|
|
|
|
my @definition = split(':', $param, 2);
|
|
if ($definition[0] eq "COMBINED") {
|
|
$isCombined = 1;
|
|
my $cmdStr = $definition[1];
|
|
my $cmdTemp = eval("$cmdStr");
|
|
if (ref $cmdTemp eq 'ARRAY') {
|
|
@combinedOutput = @{ $cmdTemp };
|
|
} else {
|
|
@combinedOutput = split(/^/, $cmdTemp);
|
|
}
|
|
Log 5, "Using combined mode for customReadings: $cmdStr";
|
|
next;
|
|
}
|
|
else {
|
|
push(@used, $definition[0]);
|
|
}
|
|
|
|
if($definition[1] ne "") {
|
|
$isCombined = 0;
|
|
}
|
|
|
|
my $value;
|
|
if ($isCombined) {
|
|
$value = shift @combinedOutput;
|
|
|
|
if (!($value)) {
|
|
$value = 0;
|
|
$hasErrors = 1;
|
|
Log 3, "customReadings: Warning for $name: combined command for " . $definition[0] . " returned nothing or not enough lines.";
|
|
}
|
|
}
|
|
else {
|
|
$value = eval($definition[1]);
|
|
}
|
|
|
|
if(defined $value) {
|
|
$value =~ s/^\s+|\s+$//g;
|
|
}
|
|
else {
|
|
$value = "ERROR";
|
|
$hasErrors = 1;
|
|
}
|
|
|
|
readingsBulkUpdate($hash, $definition[0], $value);
|
|
}
|
|
|
|
readingsBulkUpdate($hash, "state", $hasErrors ? "Errors" : "OK");
|
|
|
|
readingsEndUpdate($hash, 1);
|
|
|
|
foreach my $r (keys %{$hash->{READINGS}}) {
|
|
if (not $r ~~ @used) {
|
|
delete $hash->{READINGS}{$r};
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_Undef($$) {
|
|
my ($hash, $arg) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
return undef;
|
|
}
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_GetHTML ($) {
|
|
my ($name) = @_;
|
|
my $hash = $main::defs{$name};
|
|
my $result = "";
|
|
|
|
$result .= "<table>";
|
|
my @sortedReadings = sort keys %{$hash->{READINGS}};
|
|
foreach my $reading (@sortedReadings) {
|
|
$result .= "<tr>";
|
|
$result .= "<td>$reading: </td><td>" . ReadingsVal($name, $reading, "???") . "</td>";
|
|
$result .= "</tr>";
|
|
}
|
|
$result .= "</table>";
|
|
|
|
return $result;
|
|
}
|
|
|
|
#=======================================================================================
|
|
sub CustomReadings_Set($@) {
|
|
my ($hash, @a) = @_;
|
|
my $name = shift @a;
|
|
my $cmd = shift @a;
|
|
my $arg = join(" ", @a);
|
|
|
|
my $list = "update";
|
|
return $list if( $cmd eq '?' || $cmd eq '');
|
|
|
|
if ($cmd eq "update") {
|
|
CustomReadings_Read($hash);
|
|
}
|
|
else {
|
|
return "Unknown argument $cmd, choose one of ".$list;
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item summary Allows to define own readings.
|
|
=item summary_DE Ermöglicht eingen readings.
|
|
=begin html
|
|
|
|
<a name="CustomReadings"></a>
|
|
<h3>CustomReadings</h3>
|
|
|
|
<ul>
|
|
FHEM module to define own readings.
|
|
<br><br>
|
|
This module allows to define own readings. The readings can be defined in an attribute so that they can get changed without changing the code of the module.<br>
|
|
To use this module you should have some perl and linux knowledge<br>
|
|
The examples presuppose that you run FHEM on a linux machine like a Raspberry Pi or a Cubietruck.<br>
|
|
Note: the "bullshit" definition is an example to show what happens if you define bullshit :-)<br><br>
|
|
<u>Example (definition in fhem.cfg)</u>
|
|
<br><code>
|
|
define myReadings CustomReadings<br>
|
|
attr myReadings room 0-Test<br>
|
|
attr myReadings group Readings<br>
|
|
attr myReadings interval 2<br>
|
|
attr myReadings readingDefinitions hdd_temperature:qx(hddtemp /dev/sda 2>&1),<br>
|
|
ac_powersupply_voltage:qx(cat /sys/class/power_supply/ac/voltage_now 2>&1) / 1000000,<br>
|
|
ac_powersupply_current:qx(cat /sys/class/power_supply/ac/current_now 2>&1) / 1000000,<br>
|
|
perl_version:$],<br>
|
|
timezone:qx(cat /etc/timezone 2>&1),<br>
|
|
kernel:qx(uname -r 2>&1),<br>
|
|
device_name:$hash->{NAME},<br>
|
|
bullshit: $hash->{bullshit},<br>
|
|
fhem_backup_folder_size:qx(du -ch /opt/fhem/backup | grep total | cut -d 't' -f1 2>&1)<br>
|
|
|
|
<br><br>
|
|
<b>Optionally, to display the readings:</b><br>
|
|
define myReadingsDisplay weblink htmlCode {CustomReadings_GetHTML('myReadings')}<br>
|
|
attr myReadingsDisplay group Readings<br>
|
|
attr myReadingsDisplay room 0-Test<br>
|
|
</code>
|
|
|
|
<br>
|
|
<u>Resulting readings:</u><br>
|
|
<table>
|
|
<colgroup width="250" span="3"></colgroup>
|
|
<tr>
|
|
<td>ac_powersupply_current</td>
|
|
<td>0.236</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>ac_powersupply_voltage</td>
|
|
<td>5.028</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>bullshit</td>
|
|
<td>ERROR</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>device_name</td>
|
|
<td>myReadings</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>fhem_backup_folder_size</td>
|
|
<td>20M</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>hdd_temperature</td>
|
|
<td>/dev/sda: TS128GSSD320: 47°C</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>kernel</td>
|
|
<td>3.4.103-sun7i+</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>perl_version</td>
|
|
<td>5.014002</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
<tr>
|
|
<td>timezone</td>
|
|
<td>Europe/Berlin</td>
|
|
<td>2014-08-09 15:40:21</td>
|
|
</tr>
|
|
</table>
|
|
|
|
|
|
<br>
|
|
<a name="CustomReadings_Define"></a>
|
|
<b>Define</b><br>
|
|
define <name> CustomReadings<br>
|
|
<br>
|
|
|
|
<a name="CustomReadings_Readings"></a>
|
|
<b>Readings</b><br>
|
|
As defined
|
|
<br><br>
|
|
|
|
<a name="CustomReadings_Attr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>interval<br>
|
|
Refresh interval in seconds</li><br>
|
|
<li>readingDefinitions<br>
|
|
The definitions are separated by a comma. A definition consists of two parts, separated by a colon.<br>
|
|
The first part is the name of the reading and the second part the function.<br>
|
|
The function gets evaluated and must return a result.<br><br>
|
|
Example: <code>kernel:qx(uname -r 2>&1)</code><br>
|
|
Defines a reading with the name "kernel" and evaluates the linux function uname -r<br>
|
|
|
|
Multiline output from commands, systemcall, scripts etc. can be use for more than one reading with <br>
|
|
the keyword <code>COMBINED</code> as reading (which wont appear itself) while its command output<br>
|
|
will be put line by line in the following readings defined (so they don't need a function defined<br>
|
|
after the colon (it would be ignored)).But the lines given must match the number and order of the<br>
|
|
following readings.<br><br>
|
|
|
|
COMBINED can be used together or lets say after or even in between normal expressions if the<br>
|
|
number of lines of the output matches exactly.
|
|
Example: <code>COMBINED:qx(cat /proc/sys/vm/dirty_background*),dirty_bytes:,dirty_ration:</code><br>
|
|
Defines two readings (dirty_bytes and dirty_ratio) which will get set by the lines of those <br>
|
|
two files the cat command will find in the kernel proc directory.<br>
|
|
In some cases this can give an noticeable performance boost as the readings are filled up all at once.
|
|
</li>
|
|
</ul><br>
|
|
</ul>
|
|
|
|
|
|
=end html
|
|
=cut
|