# # Written by Martin Paulat, 2013 # mainted by Gernot Hillier (yoda_gh), 2018- # # # $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 Revolt " if(int(@a) != 3); $a[2] = lc($a[2]); return "Define $a[0]: wrong 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

Revolt NC-5462

    Provides energy consumption readings for Revolt NC-5462 devices via CUL or SIGNALduino (433MHz).

    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.

    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.

    Define
      define <name> Revolt <id>

      <id> is a 4 digit hex number to identify the NC-5462 device.
      Note: devices are autocreated on reception of the first message.

    Attributes
    • EnergyAdjustValue: adjust the energy reading (energy = energy - EnergyAdjustValue)

    Common attributes
    • event-aggregator: To reduce the high sending frequency and filter reception errors, you can use FHEM's event-aggregator. Common examples:
      • power:60:linear:mean,energy:36000:none:v reduce sampling frequency to one power event per minute and one energy value per 10 hours, other events can be disabled via event-on-change-reading or event-on-update-reading.
      • power::none:median:120,energy::none:median:120 keep sampling frequency untouched, but filter outliers using statistical median
    • event-min-interval
    • event-on-change-reading: can be used to disable events for readings you don't need. See documentation for details.
    • event-on-update-reading: can be used to disable events for readings you don't need. See documentatino for details.
    Readings
    • 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.
    • power [W]
    • voltage [V]
    • current [A]
    • frequency [Hz]
    • Pf: Power factor
=end html =cut