[gelöst][Entwicklerfrage] events-on-change.. in eigenen Modul

Begonnen von LuBeDa, 12 August 2017, 16:09:59

Vorheriges Thema - Nächstes Thema

LuBeDa

Hallo zusammen,

ich arbeite zur Zeit an einem Modul das den Buienradar Service benutzt um eine Art Regenradar Vorhersage zu haben.

Das Modul macht schon etwas, hat aber noch eine Menge Optimierungspotential. Als erstes möchte ich das Attribut "events-on-change-reading" umsetzen. Dazu habe ich aber keine Doku gefunden.

Kann mir jemand eine Tipp geben?

Ludger

Mein bisheriger Quelltext:

package main;

use strict;
use warnings;
use HttpUtils;

#####################################
sub Buienradar_Initialize($) {

  my ($hash) = @_;

  $hash->{DefFn}   = "Buienradar_Define";
  $hash->{UndefFn} = "Buienradar_Undef";
  $hash->{GetFn}  = "Buienradar_Get"
}

#####################################
sub Buienradar_Undef($$) {

  my ($hash, $arg) = @_;

  RemoveInternalTimer($hash);
  return undef;
}

###################################
sub Buienradar_Get($@) {

  my ($hash, @a) = @_;

  return "argument is missing" if(int(@a) != 2);

  $hash->{LOCAL} = 1;
  Buienradar_GetUpdate($hash);
  delete $hash->{LOCAL};

  my $reading= $a[1];
  my $value;

  if(defined($hash->{READINGS}{$reading})) {
        $value= $hash->{READINGS}{$reading}{VAL};
  } else {
        return "no such reading: $reading";
  }

  return "$a[0] $reading => $value";
}

#####################################
sub Buienradar_Define($$) {

  my ($hash, $def) = @_;

  my @a = split("[ \t][ \t]*", $def);

  return "syntax: define <name> Buienradar <latitude> <longitude>"
  if(int(@a) == 3); # interval option not acitve

  $hash->{STATE} = "Initialized";
  $hash->{fhem}{interfaces}= "temperature;humidity;wind";

  my $name      = $a[0];
  my $latitude  = $a[2];
  my $longitude = $a[3];

  $hash->{STATE} = "Initialized";

  my $interval  = 60*5;
 
  $hash->{INTERVAL}     = $interval;
  $hash->{LATITUDE}     = $latitude;
  $hash->{LONGITUDE}     = $longitude;
  $hash->{URL}     = "http://gps.buienradar.nl/getrr.php?lat=".  $hash->{LATITUDE} ."&lon=".$hash->{LONGITUDE};;
  $hash->{READINGS}{rainBegin}{TIME}= TimeNow();
  $hash->{READINGS}{rainBegin}{VAL}= "none";
  $hash->{READINGS}{rainEnd}{TIME}= TimeNow();
  $hash->{READINGS}{rainEnd}{VAL}= "none";
  $hash->{READINGS}{rainAmount}{TIME}= TimeNow();
  $hash->{READINGS}{rainAmount}{VAL}= "none";
  $hash->{READINGS}{rainRespone}{TIME}= TimeNow();
  $hash->{READINGS}{rainRespone}{VAL}= "none";
 
  InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Buienradar_GetUpdate", $hash, 0);

  return undef;
}

sub Buienradar_GetUpdate($)
{
  my ($hash) = @_;

  if(!$hash->{LOCAL}) {
    InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Buienradar_GetUpdate", $hash, 1);
  }
 
my $param = {
                    url        => $hash->{URL},
                    timeout    => 5,
                    hash       => $hash,                                                           
                    method     => "GET",                                                           
                    callback   =>  \&Buienradar_ParseHttpResponse                                 
                };

 
  HttpUtils_NonblockingGet($param);     
  $hash->{STATE} = "Request update";
  return 1;
}

sub Buienradar_ParseHttpResponse($)
{
    my ($param, $err, $data) = @_;
    my $hash = $param->{hash};
    my $name = $hash->{NAME};

   $hash->{STATE} = "Updated";
   if($err ne "")                                                                                     
    {
        Log3 $name, 3, "error while requesting ".$param->{url}." - $err";
        $hash->{STATE} = "Error";
        readingsSingleUpdate($hash, "rainResponse", "ERROR",1);         
    }
    elsif($data ne "") {
       Log3 $name, 3, "url ".$param->{url}." returned: $data";           
        $hash->{STATE} = "Updated";
       
    my $rainamount = 0;
    my $rainbegin = $hash->{READINGS}{rainBegin}{VAL};
    my $rainend = $hash->{READINGS}{rainEnd}{VAL};
   
    foreach (split(/\n/,$data)) {
        my ($amount, $time) = (split(/\|/,$_))[0,1];
        Log3 $hash,3, $amount .  " " . $time . " ";           
        $rainamount +=  10**(($amount - 109) / 32);
        if ($amount > 0) {
            if ($rainbegin eq $hash->{READINGS}{rainBegin}{VAL})
           {
                $rainbegin = $time;
                $rainend = $time;
            }
            if ($rainend ne $hash->{READINGS}{rainEnd}{VAL}) {
                $rainend = $time
            }
        }
    }
   
    readingsSingleUpdate($hash, "rainResponse", $data,1);                                                       
    readingsSingleUpdate($hash, "rainAmount", sprintf("%.0f",$rainamount),1);                                   
    readingsSingleUpdate($hash, "rainBegin", $rainend,1);                                                       
    readingsSingleUpdate($hash, "rainEnd", $rainend,1);                                                         
  }

}

1;

=pod
=begin html

<a name="Buienradar"></a>
<h3>Buienradar</h3>
<ul>
  <br>

  <a name="Buienradardefine"></a>
  <b>Define</b>
</ul>

=end html
=cut

CoolTux

Attribute gehören dem User. Was Du machen kannst ist readingsBulkUpdateIfChanged oder so ähnlich nehmen. Lese einfach das Developer Guide im Wiki zu readingsBeginUpdate und so.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

rudolfkoenig

ZitatAls erstes möchte ich das Attribut "events-on-change-reading" umsetzen

Falls man die Events "normal" mit readings*Update() generiert, kriegt man das vom Framework geschenkt.

Was mir beim Code drueberfliegen aufgefallen ist:
- Konstrukte wie "if(defined($hash->{READINGS}{$reading})" sind keine Gute Idee: das laegt naemlich ein leeres $hash->{READINGS} an, wenn keins existiert. Readings fragt man mit ReadingsVal ab, die macht das richtig.
- falls man mehrere readings aendern will, dann sollte man das mit readingsBeginUpdate, readingsBulkUpdate, readingsEndupdate setzen. jedes readingsSingleUpdate benachrichtigt jeweils alle notifies/FileLogs/DOIF/etc.

LuBeDa

OK,
das mit dem BulkUpdate habe ich umgesetzt aber im FHEM Web werden die Attribute "event-on-..." nicht angeboten.. Muss ich die erst manuell zu den Device Attributen hinzufügen? Vielleicht mit addToDevAttrList($name, $attrib)?

Außerdem möchte ich noch Einheiten z.B. mm/m²  hinzufügen, dazu habe ich auch noch nichts gefunden.

Was muss man machen um im Developer Forum zu posten?

Ludger

CoolTux


$hash->{AttrList}   = "fhemControlMode:trigger,setControl,thirdPartControl ".
                          "debugJSON:0,1 ".
                          "enableSubCalls:0,1 ".
                          "disable:1 ".
                          "allowFrom ".
                          $readingFnAttributes;


Letzte Zeile ist das was Du suchst
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net