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.
https://wiki.fhem.de/wiki/DevelopmentModuleAPI#Readings_/_Events
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.
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"
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.
siehe dazu auch https://forum.fhem.de/index.php?topic=84969.msg832760#msg832760 und folgende.
Da ging es auch um $hash.
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()
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};
Uff du bist mein Held. Jetzt geht es. Vielen Dank!