[gelöst] Wie kann man Readings schreiben aus einem sub heraus?

Begonnen von mumpitzstuff, 09 Juli 2023, 16:16:46

Vorheriges Thema - Nächstes Thema

mumpitzstuff

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.

CoolTux

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

Damian

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.

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

mumpitzstuff

#3
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"

Damian

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.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

mumpitzstuff

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()

Damian

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};




Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

mumpitzstuff

Uff du bist mein Held. Jetzt geht es. Vielen Dank!