FHEM Forum

FHEM => Sonstiges => Thema gestartet von: LuBeDa am 12 August 2017, 16:09:59

Titel: [gelöst][Entwicklerfrage] events-on-change.. in eigenen Modul
Beitrag von: LuBeDa am 12 August 2017, 16:09:59
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
Titel: Antw:[Entwicklerfrage] events-on-change.. in eigenen Modul
Beitrag von: CoolTux am 12 August 2017, 16:18:06
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.
Titel: Antw:[Entwicklerfrage] events-on-change.. in eigenen Modul
Beitrag von: rudolfkoenig am 12 August 2017, 16:20:48
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.
Titel: [Entwicklerfrage] events-on-change.. in eigenen Modul
Beitrag von: LuBeDa am 13 August 2017, 13:57:49
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
Titel: Antw:[Entwicklerfrage] events-on-change.. in eigenen Modul
Beitrag von: CoolTux am 13 August 2017, 14:08:50

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


Letzte Zeile ist das was Du suchst
Titel: Antw:[Entwicklerfrage] events-on-change.. in eigenen Modul
Beitrag von: LuBeDa am 13 August 2017, 18:44:28
O.K.

Danke