mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-01 13:29:26 +00:00
8327abc312
module does this - but recommend this in commandref. Plus general improvement of documentation. git-svn-id: https://svn.fhem.de/fhem/trunk@17447 2b470e98-0d58-463d-a4d8-8e2adae1ed80
222 lines
7.6 KiB
Perl
222 lines
7.6 KiB
Perl
#
|
|
# Written by Martin Paulat, 2013
|
|
# mainted by Gernot Hillier (yoda_gh), 2018-
|
|
# <gernot@hillier.de>
|
|
#
|
|
# $Id$
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Date::Parse;
|
|
|
|
|
|
|
|
#####################################
|
|
sub Revolt_Initialize($)
|
|
{
|
|
my ($hash) = @_;
|
|
|
|
$hash->{Match} = "^r......................\$";
|
|
$hash->{DefFn} = "Revolt_Define";
|
|
$hash->{UndefFn} = "Revolt_Undef";
|
|
$hash->{ParseFn} = "Revolt_Parse";
|
|
$hash->{AttrList} = "IODev ".
|
|
"EnergyAdjustValue ".
|
|
$readingFnAttributes;
|
|
}
|
|
|
|
#####################################
|
|
sub Revolt_Define($$)
|
|
{
|
|
my ($hash, $def) = @_;
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
|
|
return "wrong syntax: define <name> Revolt <id>" if(int(@a) != 3);
|
|
$a[2] = lc($a[2]);
|
|
return "Define $a[0]: wrong <id> format: specify a 4 digit hex value" if($a[2] !~ m/^[a-f0-9][a-f0-9][a-f0-9][a-f0-9]$/);
|
|
|
|
$hash->{ID} = $a[2];
|
|
#$hash->{STATE} = "Initialized";
|
|
$modules{REVOLT}{defptr}{$a[2]} = $hash;
|
|
AssignIoPort($hash);
|
|
|
|
my $name = $a[0];
|
|
#$attr{$name}{"event-aggregator"} = "power::none:median:120,energy::none:median:120" if(!defined($attr{$name}{"event-aggregator"}));
|
|
$attr{$name}{"stateFormat"} = "P: power E: energy V: voltage C: current Pf: pf" if(!defined($attr{$name}{"stateFormat"}));
|
|
|
|
return undef;
|
|
}
|
|
|
|
#####################################
|
|
sub Revolt_Undef($$)
|
|
{
|
|
my ($hash, $name) = @_;
|
|
delete($modules{REVOLT}{defptr}{$hash->{ID}}) if(defined($hash->{ID}) &&
|
|
defined($modules{REVOLT}{defptr}{$hash->{ID}}));
|
|
return undef;
|
|
}
|
|
|
|
#####################################
|
|
sub Revolt_Parse($$)
|
|
{
|
|
my ($hash, $msg) = @_;
|
|
|
|
$msg = lc($msg);
|
|
my $seq = substr($msg, 1, 2);
|
|
my $dev = substr($msg, 3, 4);
|
|
my $cde = substr($msg, 7, 4);
|
|
my $val = substr($msg, 11, 22);
|
|
my $id = substr($msg, 1, 4);
|
|
my $voltage = hex(substr($msg, 5, 2));
|
|
my $current = hex(substr($msg, 7, 4)) * 0.01;
|
|
my $freq = hex(substr($msg, 11, 2));
|
|
my $power = hex(substr($msg, 13, 4)) * 0.1;
|
|
my $pf = hex(substr($msg, 17, 2)) * 0.01;
|
|
my $energy = hex(substr($msg, 19, 4)) * 0.01;
|
|
my $lastval = 0.0;
|
|
my $type = "";
|
|
my $energyAdj = $energy;
|
|
|
|
if(!defined($modules{REVOLT}{defptr}{$id})) {
|
|
Log3 undef,3, "Unknown Revolt device $id, please define it";
|
|
$type = "Revolt" if(!$type);
|
|
return "UNDEFINED ${type}_$id Revolt $id";
|
|
}
|
|
|
|
my $def = $modules{REVOLT}{defptr}{$id};
|
|
my $name = $def->{NAME};
|
|
return "" if(IsIgnored($name));
|
|
|
|
# check if data is invalid
|
|
if (defined($def->{READINGS}{".lastenergy"})) {
|
|
$lastval = $def->{READINGS}{".lastenergy"}{VAL};
|
|
}
|
|
else {
|
|
readingsSingleUpdate($def,".lastenergy", $energy, 1);
|
|
}
|
|
|
|
# adjust energy value
|
|
$energy -= AttrVal($name, "EnergyAdjustValue", 0);
|
|
|
|
my $isInvalid = 0;
|
|
#my $energydiff = 0;
|
|
#my $maxenergy = 0;
|
|
|
|
#TODO: This plausability check will stop accepting values forever after
|
|
#receiving a very small outlier once. We could use abs(...), but what about
|
|
#changing energyadjustvalue etc.? Do we really need this at all?
|
|
#
|
|
#if (defined($def->{READINGS}{"energy"})) {
|
|
# my $timediff = gettimeofday() - str2time($def->{READINGS}{"energy"}{TIME});
|
|
# $energydiff = $energy - $def->{READINGS}{"energy"}{VAL};
|
|
# $maxenergy = 3.65 * ($timediff / 3600.0);
|
|
#}
|
|
#if ($energydiff > $maxenergy) {
|
|
# $isInvalid = 1;
|
|
#}
|
|
|
|
if (0 == $pf) {
|
|
$pf = 0.0001;
|
|
}
|
|
# plausability check partly taken from http://www.sknorrell.de/blog/energiemesssung-mit-revolt-nc-5462/
|
|
if (($voltage < 80) || ($freq > 65) || ($power > 3650) || ($current > 16) ||
|
|
((($power / $voltage / $pf) > 0.00999) && (0 == $current))) {
|
|
$isInvalid = 1;
|
|
}
|
|
|
|
if (0 == $isInvalid) {
|
|
#my $state = "P: ".sprintf("%5.1f", $power)." E: ".sprintf("%6.2f", $energy)." V: ".sprintf("%3d", $voltage)." C: ".sprintf("%6.2f", $current)." F: $freq Pf: ".sprintf("%4.2f", $pf);
|
|
|
|
readingsBeginUpdate($def);
|
|
|
|
my $timediff = gettimeofday() - str2time($def->{READINGS}{".lastenergy"}{TIME});
|
|
if (($lastval != $energy) && (($energy - $lastval) < (3.65 * ($timediff / 3600.0)))) {
|
|
readingsBulkUpdate($def, ".lastenergy", $energy, 1);
|
|
}
|
|
|
|
readingsBulkUpdate($def, "state", "active", 0);
|
|
readingsBulkUpdate($def, "voltage", $voltage, 1);
|
|
readingsBulkUpdate($def, "current", $current, 1);
|
|
readingsBulkUpdate($def, "frequency", $freq, 1);
|
|
readingsBulkUpdate($def, "power", $power, 1);
|
|
readingsBulkUpdate($def, "pf", $pf, 1);
|
|
readingsBulkUpdate($def, "energy", $energy, 1);
|
|
|
|
readingsEndUpdate($def, 1);
|
|
}
|
|
|
|
return $name;
|
|
}
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item device
|
|
=item summary Receive power, energy, voltage etc. from Revolt NC-5462 433MHz devices
|
|
=item summary_DE Energieverbrauch von Revolt NC-5462 über 433MHz empfangen
|
|
=begin html
|
|
|
|
<a name="Revolt"></a>
|
|
<h3>Revolt NC-5462</h3>
|
|
<ul>
|
|
Provides energy consumption readings for Revolt NC-5462 devices via CUL or
|
|
SIGNALduino (433MHz).
|
|
<br><br>
|
|
These devices send telegrams with measured values every few seconds. Many
|
|
users saw problems with cheap 433MHz receivers - and even with good
|
|
receivers, wrong values are received quite often, leading to outliers
|
|
in plots and sporadic autocreation of devices with wrong IDs.
|
|
<br><br>
|
|
This module now ignores implausible telegrams (e.g. voltage below 80),
|
|
but to further reduce outliers and event frequency, you should use the common
|
|
attributes described below. You also might want to disable autocreation of
|
|
Revolt devices once all of yours are detected.
|
|
<br><br>
|
|
|
|
<a name="RevoltDefine"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> Revolt <id></code>
|
|
<br><br>
|
|
<id> is a 4 digit hex number to identify the NC-5462 device.<br>
|
|
Note: devices are autocreated on reception of the first message.<br>
|
|
</ul>
|
|
<br>
|
|
<a name="RevoltAttributes"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>EnergyAdjustValue: adjust the energy reading (energy = energy - EnergyAdjustValue)</li>
|
|
</ul>
|
|
<br>
|
|
<b>Common attributes</b>
|
|
<ul>
|
|
<li><a href="#event-aggregator">event-aggregator</a>: To reduce the high sending frequency and filter reception errors, you can use FHEM's event-aggregator. Common examples:
|
|
<ul>
|
|
<li><tt>power:60:linear:mean,energy:36000:none:v</tt> reduce sampling frequency to one power event per minute and one energy value per 10 hours, other events can be disabled via <tt>event-on-change-reading</tt> or <tt>event-on-update-reading</tt>.</li>
|
|
<li><tt>power::none:median:120,energy::none:median:120</tt> keep sampling frequency untouched, but filter outliers using statistical median</li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#event-min-interval">event-min-interval</a></li>
|
|
<li><a href="#event-on-change-reading">event-on-change-reading</a>: can be used to disable events for readings you don't need. See documentation for details.</li>
|
|
<li><a href="#event-on-update-reading">event-on-update-reading</a>: can be used to disable events for readings you don't need. See documentatino for details.</li>
|
|
</ul>
|
|
<a name="RevoltReadings"></a>
|
|
<b>Readings</b>
|
|
<ul>
|
|
<li>energy [kWh]: Total energy consumption summed up in the NC-5462
|
|
devices. It seems you can't reset this counter and it will wrap around
|
|
to 0 at 655.35 kWh. The EnergyAdjustValue attribute (see above) allows
|
|
to adapt the reading, e.g. when you connect a new device.</li>
|
|
<li>power [W]</li>
|
|
<li>voltage [V]</li>
|
|
<li>current [A]</li>
|
|
<li>frequency [Hz]</li>
|
|
<li>Pf: Power factor</li>
|
|
</ul>
|
|
|
|
</ul>
|
|
=end html
|
|
=cut
|