FHEM Forum

FHEM => Codeschnipsel => Thema gestartet von: supernova1963 am 09 Juni 2021, 17:00:10

Titel: FHEM als fing(Box) api client
Beitrag von: supernova1963 am 09 Juni 2021, 17:00:10
Hallo zusammen,

ich habe vor ewigen Zeiten eine fingBox (V1) erworben und im Einsatz. Die wiederholte Nachfrage nach einer api hat vor einiger Zeit zumindest einen ersten Ansatz für eine api gebracht, - wobei ich ich das "p" eher streichen würde. Sei es, wie es ist, man kann die eine Liste (json) mittlerweile abfragen, wenn man bereit ist 49,00 EUR p.a. für einen Premium Plan zu zahlen (Klar beinhaltet der Premium Plan nicht nur diese "minimal api" ...).

Da ich es habe, wollte ich auch diese api Funktion der fingBox nutzen und frage mit ein paar Zeilen Code und einer readingsGroup Definition mir die Liste der vorhandenen Netzwerkgeräte ab und lasse mir ihren Status anzeigen.

Für alle, die es interessiert, hier meine "stümperhafte" Umsetzung (Über Empfehlungen und Verbesserungsvorschläge würde ich mich sehr freuen):

1. Das FHEM device, dass die Daten abholt:

defmod fingAPI MQTT2_DEVICE
attr fingAPI userattr model2icon state2icon type2icon
attr fingAPI group fingBox
attr fingAPI model2icon Shelly 1PM:eigene/shelly@red,Shelly 1:eigene/shelly@blue,Shelly 2.5:eigene/shelly@black,Shelly RGBW 2:eigene/shelly@yellow,Shelly Plug S:eigene/shellyplug@CornflowerBlue
attr fingAPI periodicCmd read:1
attr fingAPI room 99_SYSTEM->fing
attr fingAPI setList read:noArg {fing_HttpRequest($NAME,"http://10.100.1.14:49090/1/devices?auth=rKHYN9LNQ4yFQFnkyXmIGjzt")}
attr fingAPI sortby 1


2. Das readingsGroup Device:

defmod fingAPI_clients readingsGroup <>,<SORT>,<IP>,<NAME>,<MAC>,<STATE>,<TYPE>,<MAKER>,<MODEL> \
fingAPI:@1,(.*)_ip_1_sort,#1_ip_1,#1_name,#1_mac,#1_state,#1_type,#1_make,#1_model
attr fingAPI_clients alias FingBox - Clients
attr fingAPI_clients group fingBox
attr fingAPI_clients room 99_SYSTEM->fing
attr fingAPI_clients sortColumn > 1
attr fingAPI_clients valueIcon {\
return "eigene/philips.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Philips/i);;\
return "eigene/fing.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Fing/i);;\
return "eigene/sonos.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Sonos/i);;\
return "eigene/netatmo.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Netatmo/i);;\
return "eigene/panasonic.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Panasonic/i);;\
return "eigene/ubiquiti.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Ubiquiti/i);;\
return "eigene/eq3.svg" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /EQ-3/i);;\
return "eigene/apple.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Apple/i);;\
return "eigene/devolo.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /devolo/i);;\
return "eigene/eq3" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /EQ-3/i);;\
return "eigene/itead.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Sonoff/i);;\
return "eigene/allterco.png" if (substr($READING,length($READING)-4,4) eq "make" && $VALUE =~ /Shelly/i);; \
return "eigene/shelly\@red" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Shelly 1PM/i);; \
return "eigene/shelly\@blue" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Shelly 1/i);;\
return "eigene/shelly\@yellow" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Shelly RGBW 2/i);; \
return "eigene/shelly\@black" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Shelly 2.5/i);; \
return "eigene/shellyplug\@CornflowerBlue" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Shelly Plug/i);; \
return "eigene/shellyht\@grey" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Shelly H\&T/i);;\
return "eigene/tasmota\@CornflowerBlue" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Sonoff/i);;\
return "eigene/tasmota\@CornflowerBlue" if (substr($READING,length($READING)-5,5) eq "make" && $VALUE =~ /Sonoff/i);;\
return "eigene/iphone.png" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /iPhone/i);;\
return "eigene/netatmo-weather-station.png" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /Weather Station/i);;\
return "eigene/ipad.png" if (substr($READING,length($READING)-5,5) eq "model" && $VALUE =~ /iPad/i);;\
return "eigene/lwt_status\@lime" if (substr($READING,length($READING)-5,5) eq "state" && $VALUE eq "UP");;\
return "eigene/lwt_status\@red" if (substr($READING,length($READING)-5,5) eq "state" && $VALUE eq "DOWN");;\
}


3. Die zugehörige 99_myFingUtils.pm:

##############################################
# $Id: myUtilsTemplate.pm 21509 2020-03-25 11:20:51Z rudolfkoenig $
#
# Save this file as 99_myUtils.pm, and create your own functions in the new
# file. They are then available in every Perl expression.

package main;

use strict;
use warnings;
use DateTime::Format::Strptime;

sub
myFingUtils_Initialize($$)
{
  my ($hash) = @_;
}

# Enter you functions below _this_ line.

################################################################################





################################################################################
#
# Aufruf: fing_HttpRequest(<devicename>,<apiurl>)
# => Für fhem device (z.B. MQTT2_DEVICE) einen Common HTTP API Befehl ausführen
# shelly_HttpRequest, shelly_HttpResponse
#
################################################################################

sub fing_HttpRequest
{
    my ($name, $apiurl) = @_;
    my $hash = $defs{$name};
my $httpCMND = $apiurl;
    if ($httpCMND eq "" || !defined($httpCMND))
    {     
  Log3 $name, 3, "Parameter API-URL ist nicht definiert!";
  return "Keine API-URL angegeben: ";
    }
$hash->{helper}{httpCMND} = $httpCMND;
my $param = {
                    url        => $httpCMND,
                    timeout    => 5,
                    hash       => $hash,
                    method     => "GET",
                    header     => "User-Agent: TeleHeater/2.2.3\r\nAccept: application/json",
                    callback   => \&fing_HttpResponse
                };

    HttpUtils_NonblockingGet($param);
}

################################################################################

sub fing_HttpResponse($)
{
my ($param, $err, $data) = @_;
my $hash = $param->{hash};
my $name = $hash->{NAME};
my $rc = "";
my $counter = 0;
my $counter_up = 0;
my $counter_down = 0;
my $regex = "";
my $httpCMND = $hash->{helper}{httpCMND};

  if($err ne "")
  {
  Log3 $name, 3, "Fehler bei dem URL-Aufruf: ".$param->{url}." - $err";
#$hash->{helper}{fullResponse} = "ERROR: ".$err;
return $err;
  }
  elsif($data ne "")
  {
    Log3 $name, 5, $param->{url}." returned: $data";
    my $json = new JSON;
    my $perl_scalar = $json->decode($data);
if($@)
{
        Log3 $hash, 3, $name.": json error: $@ in:\n".$data."\n";
        return "json error; $@!";
    }
my $rc_json2nameValue = json2nameValue($data);
my $ip = "";
my @model2icon = split(/,/,AttrVal($name,"model2icon",""));
readingsBeginUpdate($hash);
while (my ($key, $value) = each %{$rc_json2nameValue})
{
### Counter
if (index($key,"state") != -1) {
if ($value eq "UP") {
$counter_up = $counter_up + 1;
$counter = $counter + 1;
}
else {
$counter_down = $counter_down + 1;
$counter = $counter + 1;
}
}

### Sorter
if (index($key,"ip") != -1) {
$ip = $value;
my @subnet = split(/\./,$value);
readingsBulkUpdateIfChanged($hash, $key."_sort", sprintf("%03d", $subnet[3]), 1);
}

### model2icon
if (index($key,"model") != -1) {

foreach my $mapping (@model2icon){
my ($model,$icon) = split(/:/,$mapping);
if ($model eq $value) {
readingsBulkUpdateIfChanged($hash, $key."_icon", "<html>".FW_makeImage($icon, $model)."</html>", 1);
}
}
}
#Standardumsetzung json
$rc = readingsBulkUpdateIfChanged($hash, $key, $value, 1);

}
readingsBulkUpdateIfChanged($hash, "state", $counter." clients with ".$counter_up." clients up and ".$counter_down." clients down", 1);
readingsEndUpdate($hash, 1);
}
# Damit ist die Abfrage zuende.
# Evtl. einen InternalTimer neu schedulen
return $data;
}

################################################################################

1;


3. Die zugehörigen Icons im ../fhem/www/images/default/eigene Ordner (hänge ich als Dateianhang an)

4. Einen Screenshot hänge ich ebenfalls an

Wer bis hierhin gelesen hat, scheint wirklich interessiert und kann in der fing Community (http://'https://community.fing.com/discussion/comment/4616#Comment_4616') ggf. mit dazu beitragen, dass auch so interessante Informationen wie Ereignisse und An-/Abwesenheitsinformationen, Störungen usw. nicht nur sehr eingeschränkt über ifttt zur Verfügung gestellt werden.

Danke,

Gernot