FHEM Forum

FHEM => Automatisierung => DOIF => Thema gestartet von: mumpitzstuff am 09 Juli 2023, 16:16:46

Titel: [gelöst] Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: mumpitzstuff am 09 Juli 2023, 16:16:46
Ich habe mal wieder ein kleines Projekt und scheitere jetzt daran Readings schreiben zu wollen. So sieht es aktuell aus:

defmod doif_Shares DOIF subs\
{\
  use utf8;;\
  use Blocking;;\
  use LWP::UserAgent;;\
  use HTTP::Request::Common;;\
  use JSON qw( decode_json );;\
  ##use Encode qw(encode_utf8 decode_utf8);;\
\
  ### CONFIG AREA ###\
\
\
\
  sub startUpdate($)\
  {\
    my $name = shift;;\
\
    if (defined($_blockingcalls{PID_UPDATE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (update).';;\
\
      ::BlockingKill($_blockingcalls{PID_UPDATE});;\
    }\
\
    $_blockingcalls{PID_UPDATE} = ::BlockingCall('DOIF::doUpdate', $name, 'DOIF::endUpdate', 300, 'DOIF::abortUpdate', $name);;\
  }\
\
  sub DOIF::doUpdate($)\
  {\
    my $name = shift;;\
    my $output = '';;\
    my $ua = LWP::UserAgent->new;;\
    my $reply = $ua->request(GET 'https://query2.finance.yahoo.com/v11/finance/quoteSummary/MI9T.SG?modules=price,summaryDetail,defaultKeyStatistics');;\
    \
    if (200 == $reply->code)\
    {\
        my $json_data = JSON::decode_json $reply->content;;\
        my $json_data_count = scalar @{ $json_data->{'quoteSummary'}{'result'} };;\
\
        if ($json_data_count >= 1)\
        {\
            my $json_resources_price                = $json_data->{'quoteSummary'}{'result'}[0]{'price'};;\
            my $json_symbol                         = $json_resources_price->{'symbol'};;\
            my $json_volume                         = $json_resources_price->{'regularMarketVolume'}{'raw'};;\
            my $json_timestamp                      = $json_resources_price->{'regularMarketTime'};;\
            my $json_name                           = $json_resources_price->{'shortName'};;\
            my $json_type                           = $json_resources_price->{'quoteType'};;\
            my $json_price                          = $json_resources_price->{'regularMarketPrice'}{'raw'};;\
            my $json_exchangeName                   = $json_resources_price->{'exchangeName'};;\
            my $json_currency                       = $json_resources_price->{'currency'};;\
            my $json_open                           = $json_resources_price->{'regularMarketOpen'}{'raw'};;\
            my $json_high                           = $json_resources_price->{'regularMarketDayHigh'}{'raw'};;\
            my $json_low                            = $json_resources_price->{'regularMarketDayLow'}{'raw'};;\
            my $json_close                          = $json_resources_price->{'regularMarketPreviousClose'}{'raw'};;\
            \
            if (($json_currency eq "GBp") ||\
                ($json_currency eq "GBX"))\
            {\
                $json_price = $json_price / 100;;\
                $json_currency = "GBP";;\
            }\
            elsif ($json_currency eq "ZAc")\
            {\
                $json_price = $json_price / 100;;\
                $json_currency = "ZAR";;\
            }\
            \
            $output .= $json_symbol.'|'.$json_volume.'|'.$json_timestamp.'|'.$json_name.'|'.$json_type.'|'.$json_price.'|'.$json_exchangeName.'|'.$json_currency.'|'.$json_open.'|'.$json_high.'|'.$json_low.'|'.$json_close;;\
        }\
    }\
\
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endUpdate($)\
  {\
    my ($name, @output) = split("\\|", shift);;\
\
    ::Log3 $name, 5, $name.': '.scalar(@output);;\
    ::Log3 $name, 4, $name.': Blocking call finished to update shares.';;\
    \
    for (my $i = 0;; $i < scalar(@output);; $i += 12)\
    {\
        set_Reading_Begin();;\
        set_Reading_Update("test", 0);;\
        set_Reading_End(1);;\
        ##set_Reading_Begin;;\
        ##set_Reading_Update("symbol", $output[$i]);;\
        ##set_Reading_Update("volume", $output[$i + 1]);;\
        ##set_Reading_Update("timestamp", $output[$i + 2]);;\
        ##set_Reading_Update("name", $output[$i + 3]);;\
        ##set_Reading_Update("type", $output[$i + 4]);;\
        ##set_Reading_Update("price", $output[$i + 5]);;\
        ##set_Reading_Update("exchangeName", $output[$i + 6]);;\
        ##set_Reading_Update("currency", $output[$i + 7]);;\
        ##set_Reading_Update("open", $output[$i + 8]);;\
        ##set_Reading_Update("high", $output[$i + 9]);;\
        ##set_Reading_Update("low", $output[$i + 10]);;\
        ##set_Reading_Update("close", $output[$i + 11]);;        \
        ##set_Reading_End(1);;\
    }\
\
    delete($_blockingcalls{PID_UPDATE});;\
  }\
\
  sub DOIF::abortUpdate($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_UPDATE});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (update).';;\
  }\
}\
init\
{\
  startUpdate("$SELF");;\
}\
## start in a raster of 5min\
{[+:05];;startUpdate("$SELF")}
attr doif_Shares room FINANCE
attr doif_Shares verbose 5

Das Problem sind die Zeilen:

set_Reading_Begin();;\
set_Reading_Update("test", 0);;\
set_Reading_End(1);;\

Versucht habe ich schon :: vor die Funktionen zu schreiben und auch $name als ersten Parameter zu übergeben. Irgendwie gehts nicht. Im Log kommt meistens:

2023.07.09 16:08:47.402 1: ERROR: empty name in readingsBeginUpdate
oder
Undefined subroutine &main::set_Reading_Begin called at (eval 220834) line 81.

Ist wahrscheinlich nur irgend eine dumme Kleinigkeit, aber ich finde sie nicht.
Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: CoolTux am 09 Juli 2023, 16:30:29
https://wiki.fhem.de/wiki/DevelopmentModuleAPI#Readings_/_Events
Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: Damian am 09 Juli 2023, 16:34:09
set_Reading_Begin und die anderen sind ebenfalls im DOIF-Package. Du kannst es mit DOIF::set_Reading_Begin probieren, allerdings, weiß ich nicht, ob der intern übergebener Hash dann noch existiert. Sonst müsste man den $hash geschickt übergeben.

Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: mumpitzstuff am 09 Juli 2023, 17:20:39
Sry ich stell mich wahrscheinlich grad etwas blöd an, aber wie komme ich noch mal an den hash vom DOIF device aus dem sub heraus ran?

PS: DOIF::set_Reading_Begin funktioniert nicht, ich erhalte auch hier immer: "ERROR: empty name in readingsBeginUpdate"
Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: Damian am 09 Juli 2023, 17:42:38
Du könntest in der Argumentenliste von Blockingcalls ($name) die globale DOIF-Variable $hs übergeben und in der doUpdate-Routine statt mit set_Reading_... mit den originalen BulkUpdate-Funktionen
 (https://wiki.fhem.de/wiki/DevelopmentModuleAPI#Readings_/_Events) arbeiten, dort dann eben bei $hash das übergebene $hs angeben.

Ebenfalls kann man aus dem DOIF-Devicenamen, welchen man dann übergeben müsste, mit $defs{<DOIF_name>} den Wert von $hash ermitteln und dann bei den BulkUpdate-Funktionen angeben.
Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: Damian am 09 Juli 2023, 18:03:45
siehe dazu auch https://forum.fhem.de/index.php?topic=84969.msg832760#msg832760 und folgende.

Da ging es auch um $hash.

Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: mumpitzstuff am 09 Juli 2023, 18:53:08
Ich würde gern was anderes berichten, aber es geht einfach nicht:

my $hash = $defs{$SELF}; führt zu
doif_Shares DOIF: error in defs block: Global symbol "%defs" requires explicit package name (did you forget to declare "my %defs"?) at (eval 2335) line 96.

my $hash = DOIF::$defs{$SELF}; führt zu
doif_Shares DOIF: error in defs block: Bad name after DOIF:: at (eval 2382) line 96.

my $hash = $_defs{$SELF};
gibt irgendwas leeres zurück...

Ist das ein Problem weil das inneralb von diesem Konstrukt gemacht wird:

subs {

sub abc {
   hier mache ich das
}

}

Ach und $hs wird gar nicht erkannt. Irgendwie bin ich in dem Blockingcall DOIF::startUpdate und DOIF::endUpdate komplett isoliert. Normalerweise sollte das ja nur innerhalb des Blockingcalls so sein, also in DOIF::doUpdate()
Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: Damian am 09 Juli 2023, 19:26:41
Naja, ich habe mir die Perlsyntax nicht ausgedacht  ;D

Standard Package ist main, daher die korrekte Angabe in einem fremden Package:

$main::defs{$SELF};
main kann man in Perl auch weglassen:

$::defs{$SELF};




Titel: Aw: Wie kann man Readings schreiben aus einem sub heraus?
Beitrag von: mumpitzstuff am 09 Juli 2023, 19:38:23
Uff du bist mein Held. Jetzt geht es. Vielen Dank!