99_myUtils_calendar - Perl Code

Begonnen von hydrotec, 10 Oktober 2020, 09:41:23

Vorheriges Thema - Nächstes Thema

hydrotec

Hallo zusammen,

bin mir fast sicher das ich hier nicht im richtigen Bereich bin.
Ursprünglich wollte ich das Thema in dem Bereich "Perl-Ecke" anlegen,
doch dazu fehlt mir richtigerweise die Berechtigung.
Andererseits bin ich ja in dem Thema Perl Anfänger,
dann passt es wieder.  ;)


Es dreht sich um folgendes.
Bei meinen Kalendern habe ich mir ein paar userreadings angelegt.
Damit ich nicht immer den ganzen Code bei jedem Kalender eintippen muss,
habe ich eine 99_myUtils_calendar.pm angelegt, und dort die Definitionen der userreadings vereinheitlicht.
Prinzipiell funktioniert das auch wie gewünscht.
Worum es mir geht, ob der von mir erstellte Code überhaupt den, ich sag mal, Perl-Normen entspricht.
Was das angeht, bin ich blutiger Anfänger. Seither viel mit copy->modify->paste gearbeitet.
Wenn etwas unklar war, Internetsuche ist mein Freund.
Doch wie es so ist, viele Programmierer = unterschiedliche Herangehensweise.
Mehr als eine Plausibilitätsprüfung ist daher bei mir nicht vorhanden.

Daher meine Bitte.
Könnte sich bitte ein Profi meiner annehmen, und sich den Code einmal ansehen.
Mir eventuell Tipps geben wie ich etwas besser lösen, bzw. vereinfachen könnte.
Hauptsächlich geht es mir um den Code selbst, damit ich zukünftig eine Art Vorlage hätte.

Vorab schon einmal Dankeschön für eure Mühen.


!Die hier geposteten Codes nicht verwenden!
siehe hier

Aufruf userreadings (am Beispiel eines Test-Kalenders)
defmod Cal_WoW Calendar ical url https://{USERNAME}:{PASSWORD}@192.168.78.33:31443/remote.php/dav/calendars/{USERNAME}/wow?export 43200
attr Cal_WoW DbLogExclude .*
attr Cal_WoW hideLaterThan 030d
attr Cal_WoW hideOlderThan 00:15
attr Cal_WoW room Kalender
attr Cal_WoW stateFormat Status: state T: lastUpdate<br/>\
Event in: Event_at Tag(en) Morgen: Event_tomorrow, Heute: Event_today<br/>\
Hallo in: Search_Hallo_at Tag(en) Morgen: Search_Hallo_tomorrow, Heute: Search_Hallo_today<br/>\
Ciao in: Search_Ciao_at Tag(en) Morgen: Search_Ciao_tomorrow, Heute: Search_Ciao_today
attr Cal_WoW synchronousUpdate 0
attr Cal_WoW userReadings Event_name {Cal_na($NAME)},\
Event_at {Cal_at($NAME)},\
Event_tomorrow {Cal_tm($NAME)},\
Event_today {Cal_td($NAME)},\
Search_Hallo_name {Cal_na($NAME, "Hallo")},\
Search_Hallo_at {Cal_at($NAME, "Hallo")},\
Search_Hallo_tomorrow {Cal_tm($NAME, "Hallo")},\
Search_Hallo_today {Cal_td($NAME, "Hallo")},\
Search_Ciao_name {Cal_na($NAME, "Ciao")},\
Search_Ciao_at {Cal_at($NAME, "Ciao")},\
Search_Ciao_tomorrow {Cal_tm($NAME, "Ciao")},\
Search_Ciao_today {Cal_td($NAME, "Ciao")}




99_myUtils_calendar.pm (2020-10-10 / ursprüngliche Version)
##############################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z 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.

#************************************************************************
# 99_myUtils_calendar.pm kst
#************************************************************************
# 2020-10-03 - Datei erstellt
# 2020-10-03 - Abfrage Tage bis zu Event hinzu
# 2020-10-03 - Nicht Ganztagestermine Zeit bis Mitternacht verechnen
# 2020-10-04 - Event Morgen/Heute hinzu
# 2020-10-05 - Event Name hinzu
#
#------------------------------------------------------------------------

package main;

use strict;
use warnings;
use POSIX;

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

# Enter you functions below _this_ line.

##************************************************************************
## Zeit in Sekunden von Mitternacht bis aktuelle Zeit in Sekunden
##************************************************************************
## Kopie aus 57_Calendar.pm
#sub Calendar_GetSecondsFromMidnight()
#{
# my @time = localtime();
# return (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
#}


#************************************************************************
# Tage bis zum anstehenden Termin
#************************************************************************
sub
Cal_at ($;$)
{
my ($cname, $sword) = @_; # Übernahmeparameter (calendername, searchword)
my $format = '"$t1"'; # $t1 Startzeit in Sekunden
my $zeit = '0'; # Parameter setzen, damit keine Warnmeldung erscheint
my $timewordoff = fhem("get $cname events format:custom=$format limit:from=0,count=1"); # Zeit in Sekunden ohne Suchwort
my $timewordon = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1"); # Zeit in Sekunden mit Suchwort
if (defined $sword && length($sword) > 0) # Abfrage ob Zeit mit oder ohne Suchwort verwendet wird
  {
  $zeit = $timewordon;
  }
  else
  {
  $zeit = $timewordoff;
  }
my $todaymidnight = Calendar_GetSecondsFromMidnight();# Zeit von Mitternacht bis aktueller Zeit in Sekunden
my $day = int(($zeit / 86400) - ((time - $todaymidnight) / 86400)); # Berechnung der Tage bis zum anstehenden Termin
if (defined $day && $day < 0) {999} else {$day}; # Übergabe der Tage bis zum anstehenden Termin (999=kein Termin)
}


#************************************************************************
# Termin Morgen
#************************************************************************
sub
Cal_tm ($;$)
{
my ($cname, $sword) = @_; # Übernahmeparameter (calendername, searchword)
my $format = '"$S"'; # $S Ereignis
my $tmwordoff = fhem("get $cname events format:custom=$format limit:when=tomorrow"); # Ereignis ohne Suchwort
my $tmwordon = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:when=tomorrow"); # Ereignis mit Suchwort
if (defined $sword && length($sword) > 0) # Abfrage ob Ereignis mit oder ohne Suchwort verwendet wird
  {
   if (defined $tmwordon && $tmwordon =~ m/$sword/i)
   {1} else {0}; # Übergabe Status Termin mit Suchwort (0=nein/1=ja)
  }
else
  {
   if (defined $tmwordoff && length($tmwordoff) > 0)
   {1} else {0}; # Übergabe Status Termin ohne Suchwort (0=nein/1=ja)
  }
}


#************************************************************************
# Termin Heute
#************************************************************************
sub
Cal_td ($;$)
{
my ($cname, $sword) = @_; # Übernahmeparameter (calendername, searchword)
my $format = '"$S"'; # $S Ereignis
my $tdwordoff = fhem("get $cname events format:custom=$format limit:when=today"); # Ereignis ohne Suchwort
my $tdwordon = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:when=today"); # Ereignis mit Suchwort
if (defined $sword && length($sword) > 0) # Abfrage ob Ereignis mit oder ohne Suchwort verwendet wird
  {
   if (defined $tdwordon && $tdwordon =~ m/$sword/i)
   {1} else {0}; # Übergabe Status Termin mit Suchwort (0=nein/1=ja)
  }
else
  {
   if (defined $tdwordoff && length($tdwordoff) > 0)
   {1} else {0}; # Übergabe Status Termin ohne Suchwort (0=nein/1=ja)
  }
}


#************************************************************************
# Name zum Termin
#************************************************************************
sub
Cal_na ($;$)
{
my ($cname, $sword) = @_; # Übernahmeparameter (calendername, searchword)
my $format = '"$S"'; # $S Ereignis
my $nawordoff = fhem("get $cname events format:custom=$format limit:from=0,count=1"); # Name ohne Suchwort
my $nawordon = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1"); # Name mit Suchwort
if (defined $sword && length($sword) > 0) # Abfrage ob Name mit oder ohne Suchwort verwendet wird
  {
   if (defined $nawordon && length($nawordon) > 0)
   {$nawordon} else {"Kein Treffer"}; # Übergabe Name mit Suchwort
  }
else
  {
   if (defined $nawordoff && length($nawordoff) > 0)
   {$nawordoff} else {"Kein Termin"}; # Übergabe Name ohne Suchwort
  }
}


#************************************************************************
# Temporaer
#************************************************************************
#Feiertag_name {fhem('get Cal_Feiertage events format:custom="$S" limit:from=0,count=1',1)},
#
#Formel1_name {my $name = fhem('get Cal_Formel1 events format:custom="$S" limit:from=0,count=1',1)},
#Formel1_name_short { my @c = split ' / ',ReadingsVal($name,'Formel1_name',0);$c[1] },
#
#NFL_name {fhem('get Cal_NFL events format:custom="$S" limit:from=0,count=1',1)},
#NFL_Vikings_name {fhem('get Cal_NFL events format:custom="$S" filter:field(summary)=~"Vikings" limit:from=0,count=1',1)},



##************************************************************************
## Vorlage
##************************************************************************
#sub
#Cal_tmtd ($$;$)
#{
#}


1;



99_myUtils_calendar.pm (2020-10-11 / angepasste Version / !Zwischenstand!)
##############################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z 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.

#************************************************************************
# 99_myUtils_calendar.pm kst
#************************************************************************
# 2020-10-03 - Datei erstellt
# 2020-10-03 - Abfrage Tage bis zu Event hinzu
# 2020-10-03 - Nicht Ganztagestermine Zeit bis Mitternacht verechnen
# 2020-10-04 - Event Morgen/Heute hinzu
# 2020-10-05 - Event Name hinzu
# 2020-10-10 - Cal_at umformatiert nach Vorlage CoolTux (Forum)
# 2020-10-11 - Code leserlich formatiert
#            - Event Morgen/Heute angepasst
#            - Event Name angepasst
#
#------------------------------------------------------------------------

package main;

use strict;
use warnings;
use POSIX;

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

# Enter you functions below _this_ line.

##************************************************************************
## Zeit in Sekunden von Mitternacht bis aktuelle Zeit in Sekunden
##************************************************************************
## Kopie aus 57_Calendar.pm
#sub Calendar_GetSecondsFromMidnight()
#{
# my @time = localtime();
# return (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
#}


#************************************************************************
# Tage bis zum anstehenden Termin
#************************************************************************
sub
Cal_at {
my $cname       = shift;             # Uebernahmeparameter (calendername)
my $sword       = shift // undef;    # Uebernahmeparameter (searchword)

my $format      = '"$t1"';           # $t1 Startzeit in Sekunden
my $zeit        = 0;                 # Parameter setzen, damit keine Warnmeldung erscheint

                                      # Zeit in Sekunden ohne Suchwort
my $timewordoff = fhem("get $cname events format:custom=$format limit:from=0,count=1");
                                      # Zeit in Sekunden mit Suchwort
my $timewordon  = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1");


if ( defined $sword
    && length($sword) > 0)            # Abfrage ob Zeit mit oder ohne Suchwort verwendet wird
     {
$zeit = $timewordon;
     }
     else {
     $zeit = $timewordoff;
     }

                                      # Zeit von Mitternacht bis aktueller Zeit in Sekunden
my $todaymidnight = Calendar_GetSecondsFromMidnight();
                                      # Berechnung der Tage bis zum anstehenden Termin
my $day           = int(($zeit / 86400) - ((time - $todaymidnight) / 86400));

                                      # Uebergabe der Tage bis zum anstehenden Termin (999=kein Termin)
return ( (defined $day && $day < 0) ? 999 : $day );
}


#************************************************************************
# Termin Morgen
#************************************************************************
sub
Cal_tm {
my $cname       = shift;             # Uebernahmeparameter (calendername)
my $sword       = shift // undef;    # Uebernahmeparameter (searchword)

my $format      = '"$S"';            # $S Ereignis

                                      # Ereignis ohne Suchwort
my $tmwordoff   = fhem("get $cname events format:custom=$format limit:when=tomorrow");
                                      # Ereignis mit Suchwort
my $tmwordon    = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:when=tomorrow");

if (defined $sword
    && length($sword) > 0)            # Abfrage ob Ereignis mit oder ohne Suchwort verwendet wird
  {
                                      # Uebergabe Status Termin mit Suchwort (0=nein/1=ja)
   return ( (defined $tmwordon && $tmwordon =~ m/$sword/i) ? 1 : 0 );
  }
else{
                                      # Uebergabe Status Termin ohne Suchwort (0=nein/1=ja)
   return ( (defined $tmwordoff && length($tmwordoff) > 0) ? 1 : 0);
  }
}


#************************************************************************
# Termin Heute
#************************************************************************
sub
Cal_td {
my $cname       = shift;             # Uebernahmeparameter (calendername)
my $sword       = shift // undef;    # Uebernahmeparameter (searchword)

my $format      = '"$S"';            # $S Ereignis

                                      # Ereignis ohne Suchwort
my $tdwordoff   = fhem("get $cname events format:custom=$format limit:when=today");
                                      # Ereignis mit Suchwort
my $tdwordon    = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:when=today");

if (defined $sword
    && length($sword) > 0)            # Abfrage ob Ereignis mit oder ohne Suchwort verwendet wird
  {
                                      # Uebergabe Status Termin mit Suchwort (0=nein/1=ja)
   return ( (defined $tdwordon && $tdwordon =~ m/$sword/i) ? 1 : 0 );
  }
else{
                                      # Uebergabe Status Termin ohne Suchwort (0=nein/1=ja)
   return ( (defined $tdwordoff && length($tdwordoff) > 0) ? 1 : 0);
  }
}


#************************************************************************
# Name zum Termin
#************************************************************************
sub
Cal_na {
my $cname       = shift;             # Uebernahmeparameter (calendername)
my $sword       = shift // undef;    # Uebernahmeparameter (searchword)

my $format      = '"$S"';            # $S Ereignis

                                      # Name ohne Suchwort
my $nawordoff   = fhem("get $cname events format:custom=$format limit:from=0,count=1");
                                      # Name mit Suchwort
my $nawordon    = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1");

if (defined $sword
    && length($sword) > 0)            # Abfrage ob Name mit oder ohne Suchwort verwendet wird
  {
                                      # Uebergabe Name mit Suchwort
   return ( (defined $nawordon && length($nawordon) > 0) ? $nawordon : "Kein Treffer" );
  }
else{
                                      # Uebergabe Name ohne Suchwort
   return ( (defined $nawordoff && length($nawordoff) > 0) ? $nawordoff : "Kein Termin" );
  }
}


#************************************************************************
# Temporaer
#************************************************************************
#[erledigt]Formel1_name {my $name = fhem('get Cal_Formel1 events format:custom="$S" limit:from=0,count=1',1)},
#Formel1_name_short { my @c = split ' / ',ReadingsVal($name,'Formel1_name',0);$c[1] },
#


1;


edit: 99_myUtils_calendar.pm
           - Ursprüngliche Version (Thread-Start) wieder eingefügt
           - Angepasste Version (!Zwischenstand!) darunter eingefügt

Mit freundlichem Gruß
Karsten

CoolTux

Wie immer ist das wichtigste die Formatierung. Da müsstest Du noch mal nachbessern.
Desweiteren gehe ich davon aus das Du ja einen Rückgabewert hast. Da fehlt also ein return ganz am Ende jder Funktion gefolgt von dem was Du zurück geben willst. Solltest Du nichts zurück geben wollen schreibt man nur return.

Ich habe mir nur kurz die erste Funktion angeschaut. Willst Du da $day zurück geben?


Grüße
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

CoolTux

#2

sub Cal_at {
    my $cname   = shift;
    my $sword   = shift; # Übernahmeparameter (calendername, searchword)

    my $format      = '"$t1"'; # $t1 Startzeit in Sekunden
    my $zeit        = 0; # Parameter setzen, damit keine Warnmeldung erscheint
    my $timewordoff = fhem("get $cname events format:custom=$format limit:from=0,count=1"); # Zeit in Sekunden ohne Suchwort
    my $timewordon  = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1"); # Zeit in Sekunden mit Suchwort


    if ( defined $sword
      && length($sword) > 0 )  # Abfrage ob Zeit mit oder ohne Suchwort verwendet wird
    {
        $zeit = $timewordon;
    }
    else {
        $zeit = $timewordoff;
    }
   
    my $todaymidnight   = Calendar_GetSecondsFromMidnight();# Zeit von Mitternacht bis aktueller Zeit in Sekunden
    my $day             = int(($zeit / 86400) - ((time - $todaymidnight) / 86400)); # Berechnung der Tage bis zum anstehenden Termin

    #if (defined $day && $day < 0) {999} else {$day}; # Übergabe der Tage bis zum anstehenden Termin (999=kein Termin)
   
    return ( (defined $day && $day < 0) ? 999 : $day);
}


Ein Beispiel wäre so.
Aber wie Du schon sagtest, viele Programmierer viele Möglichkeiten. Daher gibt es das Buch PBP (Perl Best Practices)


Grüße
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

hydrotec

Hallo CoolTux,

Dankeschön für die Hinweise.

PBP (Perl Best Practices) hab ich auch schon einmal überflogen.
Jedoch nicht wirklich alles verstanden.
Deswegen hab ich einfach mal losgelegt, und dann um eure Mithilfe gebeten.
Jetzt habe ich, dank dir, schon einmal Ansätze wonach ich mich genauer informieren kann.

z.B. warum anstatt my ($cname, $sword) = @_; my $cname   = shift; my $sword   = shift;
(funktioniert dann die optionale Übergabe von "$sword" noch)
oder warum ich return explizid angeben muss, dachte "{Rückgabewert}" würde ausreichen.

Werde nachher den Code in meiner 99_myUtils_calendar.pm anpassen.
Kann etwas dauern  ;)

Gruß Karsten

CoolTux

Zitat von: hydrotec am 10 Oktober 2020, 11:09:57
z.B. warum anstatt my ($cname, $sword) = @_; my $cname   = shift; my $sword   = shift;
(funktioniert dann die optionale Übergabe von "$sword" noch)
@_ verwendet man laut PBP so ab 4 Übergabewerte. Es ist ein spezial Variable.
Was die Sache mit der optionalen Übergabe an geht so kannst Du das gerne auch abfangen

my $sword = shift // undef;


Zitat von: hydrotec am 10 Oktober 2020, 11:09:57
oder warum ich return explizid angeben muss, dachte "{Rückgabewert}" würde ausreichen.

Jede Funktion muss mit einen return sauber beendet werden.

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

hydrotec

Hallo CoolTux,

mal eben schnell deine Vorschläge umgesetzt, passt einwandfrei.  :)
Jetzt muss ich mir nur noch PBP zur Brust nehmen, damit ich das Umgesetzte auch wirklich verstehe.

Vielen Dank noch einmal.
Gruß Karsten

hydrotec

Guten Morgen Miteinander,

habe mich ein wenig über PBP (Perl Best Practices) informiert.
Das es sich um ein Buch handelt, war mir nicht wirklich bewußt.
Kann es sein, das es keine digitale Version dieses Taschenbuches zu erwerben gibt?

Über folgende Website https://perl.programmingpedia.net/en/tutorial/5919/best-practices bin ich auf perlcritic.com gestoßen.
Ist sehr hilfreich um seinen Code analysieren zu lassen, doch ohne Buch fehlt einem der Hintergrund.

Angenehmen Sonntag noch  :)
Gruß Karsten

hydrotec

Hallo CoolTux,

Zitat von: CoolTux am 10 Oktober 2020, 09:58:02
Wie immer ist das wichtigste die Formatierung. Da müsstest Du noch mal nachbessern.
Wo du recht hast, hast du recht.
Gelobe zukünftig Besserung.  ;)

Danke nochmal für deine hilfreiche Unterstützung  :)

Gruß Karsten

Beta-User

Zitat von: CoolTux am 10 Oktober 2020, 11:22:54
Was die Sache mit der optionalen Übergabe an geht so kannst Du das gerne auch abfangen

my $sword = shift // undef;

Dazu eine Frage: Bisher hatte ich den "defined-or"-Operator immer so interpretiert, dass man den verwendet, um das "undef" in einen anderen Wert zu überführen. Da mir das aber jüngst auch in jemand anderen's Code über den Weg gelaufen ist, würde mich  interessieren, ob ich mal wieder was wesentliches übersehe.

Mein bisheriges Verständnis war eher, dass man damit u.A. auch iVm. shift eindeutigere Fehlermeldungen generieren kann (wenn man das möchte, macht shift auch bei mehr Parametern Sinn...) oder eben "echte" Defaultwerte zuweist (Auchtung: das Beispiel hier ist in dieser Form sinnlos, weil man eigentlich einfacher einen undefinierten Zustand lassen und dann direkt mit "if" arbeiten könnte):

sub Cal_at {
    my $cname   = shift // return "Error: we need at least one parameter!"; # ggf. carp (?) nutzen, um das als explizite Fehlerrückmeldung zu kennzeichnen zu füllen
    my $sword   = shift // "unknown"; # optionaler Parameter, wenn ohne aufgerufen, wird "unknown" zugewiesen)

    my $format      = '"$t1"'; # $t1 Startzeit in Sekunden
    my $zeit        = 0; # Parameter setzen, damit keine Warnmeldung erscheint
    my $timewordoff = fhem("get $cname events format:custom=$format limit:from=0,count=1"); # Zeit in Sekunden ohne Suchwort
    my $timewordon  = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1"); # Zeit in Sekunden mit Suchwort


    if ( $sword ne "unknown" )  # Abfrage ob Zeit mit oder ohne Suchwort verwendet wird
[...]





Ergänzende Hinweise:
- "use POSIX;" sollte raus.
- aus hygienischen Gründen sollte man userReadings immer mit trigger definieren (hier ist es vermutlich egal, da HTTPMOD bulkUpdate verwenden dürfte und daher sowieso alles in derselben trigger-Stufe mit abgearbeitet wird).
- Für ganztägige Sachen (an anderer Stelle ging es mal um "Müll") ist der Umweg über Calendar m.E. nicht optimal, das kann man einfacher in einem holiday-Device haben...
- Im Developer-Bereich bzw. der Perl-Ecke  kann afaik auch posten, wer als Tester angemeldet ist. Da sind auch noch mehr Infos zu den Fragen rund um perlcritic/perltidy zu finden (vielleicht schaust du mal den RandomTimer-Thread durch).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

hydrotec

Hallo Beta-User,

auch dir erst einmal ein Dankeschön für deine Unterstützung.  :)

Der erste Schritt um meinen Code zu optimieren ist ja schon geschehen.
Da die von mir erwünschten Funktionen erst einmal machen was sie sollen,
kann ich mir nun etwas Zeit nehmen und die einzelnen Themen explizit näher anschauen.


Zu dem Thema
my $sword = shift // undef;
Nachdem ich mich im Internet etwas schlauer gemacht habe,
muss ich dir zustimmem. Man könnte das // undef auch weg lassen und später über
if (defined $sword && length($sword) > 0)
abfangen.
Das mit dem
my $cname   = shift // return "Error: we need at least one parameter!"; # ggf. carp (?) nutzen, um das als explizite Fehlerrückmeldung zu kennzeichnen zu füllen
ist eine gute Idee, muss ich mir später einmal genauer anschauen.


Zu den ergänzenden Hinweisen.

- "use POSIX;" sollte raus.
Im Wiki zu "99 myUtils anlegen", und im "myUtilsTemplate.pm" ist "use POSIX;" vorhanden.
(vermutlich nur aus Kompatibilitätsgründen, falls jemand mit POSIX Funktionen arbeitet)
Da ich diese Funktionen nicht nutze, kann ich sie auch abschalten, oder.
(aktuell "use POSIX;" gelöscht, funktioniert)

- aus hygienischen Gründen...
Da siehst du mal, so tief bin ich noch gar nicht in der Materie.
Bin, einfach so, davon ausgegangen das die userreadings mit "calendar set reload/update" getriggert werden.
Also, noch ein Punkt den ich mir bei Gelegenheit mal ansehen sollte.

- Für ganztägige Sachen...
Das ist bei mir historisch so gewachsen.
Ich verwende mobile einige Kalender in Nextcloud, und verwalte sie auch dort.
Die hatte ich dann auf FHEM verfügbar gemacht,
um sie für kleinere Schaltungen, oder zur Information zu verwenden.
Zur Information nutze ich hauptsächlich die Tage bis zum anstehenden Termin.
Bei ganztägigen Terminen werden die Tage bis zum Termin korrekt ausgegeben,
anders bei Terminen die nur einen gewissen Zeitraum am Tag einnehmen.
Da werden die Tage im 24h Format zum Termin berechnet.
Für mich sind die Tage von-bis Mitternacht relevant.

- Im Developer-Bereich...
Sollten es noch mehr Fragen in diesem Bereich geben,
werde ich mich als Tester anmelden, und gleich dort posten.
Danke für den Hinweis.
RandomTimer-Thread werde ich mir einmal anschauen.


Erst einmal noch einen angenehmen Abend  8)
Gruß Karsten

CoolTux

In der Tat ist ein undef eher doppelt gemoppelt nach einem //
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

Beta-User

@CoolTux:
Danke für die Rückmeldung.

Zitat von: hydrotec am 11 Oktober 2020, 19:10:03
Im Wiki zu "99 myUtils anlegen", und im "myUtilsTemplate.pm" ist "use POSIX;" vorhanden.
...dann ist dein FHEM nicht ganz aktuell: https://svn.fhem.de/trac/changeset/21509/
Im Wiki habe ich es eben auch rausgenommen, Danke für den Hinweis.

Was die "ganztägigen Kalender" angeht: Müll und Ferien kommen bei mir auch aus einem (Familien-) ical und werden dann als holiday (mit Ferien als holiday2we-Eintrag in global) eingebunden, irgendwo im Forum hatte ich dazu auch mal ein (grottiges) Code-Schnippsel veröffentlicht (muß ich mal überarbeiten und dann neu posten, aber es funktioniert ja grundsätzlich...).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

hydrotec

#12
Zitat von: Beta-User am 12 Oktober 2020, 11:43:14
...dann ist dein FHEM nicht ganz aktuell: https://svn.fhem.de/trac/changeset/21509/
Sorry, mein Fehler.
Auch bei mir ist "use POSIX;" in "myUtilsTemplate.pm" nicht vorhanden.
Da hatte ich wohl Augentinnitus.  :-[
Kleine Rückfrage, sollte POSIX generell in den 99_myUtils... entfernt werden?
(Hab da noch ein paar ältere Versionen)

FHEM ist (fast) aktuell
Zitatfhem.pl 22894 2020-10-01 19:49:32Z rudolfkoenig


Zitat von: Beta-User am 12 Oktober 2020, 11:43:14
Was die "ganztägigen Kalender" angeht: Müll und Ferien kommen bei mir auch aus einem (Familien-) ical und werden dann als holiday (mit Ferien als holiday2we-Eintrag in global) eingebunden, irgendwo im Forum hatte ich dazu auch mal ein (grottiges) Code-Schnippsel veröffentlicht (muß ich mal überarbeiten und dann neu posten, aber es funktioniert ja grundsätzlich...).
Solltest du diesen Code noch finden, werde ich mir das gerne ansehen.
Man lernt ja nie aus.  ;)


!Die hier geposteten Codes nicht verwenden!
siehe hier

Was den aktuellen Code meiner 99_myUtils_calendar.pm angeht, bin ich bis jetzt ganz glücklich damit.

calendar device (Test-Kalender)
defmod Cal_WoW Calendar ical url https://{USERNAME}:{PASSWORD}@192.168.78.33:31443/remote.php/dav/calendars/{USERNAME}/wow?export 43200
attr Cal_WoW DbLogExclude .*
attr Cal_WoW event-on-change-reading Event_.*,Search_.*
attr Cal_WoW event-on-update-reading state
attr Cal_WoW hideLaterThan 030d
attr Cal_WoW hideOlderThan 00:15
attr Cal_WoW room Kalender
attr Cal_WoW stateFormat Status: state T: lastUpdate<br/>\
Event in: Event_at Tag(en) Morgen: Event_tomorrow, Heute: Event_today<br/>\
Hallo in: Search_Hallo_at Tag(en) Morgen: Search_Hallo_tomorrow, Heute: Search_Hallo_today<br/>\
Ciao in: Search_Ciao_at Tag(en) Morgen: Search_Ciao_tomorrow, Heute: Search_Ciao_today
attr Cal_WoW synchronousUpdate 0
attr Cal_WoW userReadings Event_name {Cal_na($NAME)},\
Event_at {Cal_at($NAME)},\
Event_tomorrow {Cal_tm($NAME)},\
Event_today {Cal_td($NAME)},\
Search_Hallo_name {Cal_na($NAME, "Hallo")},\
Search_Hallo_at {Cal_at($NAME, "Hallo")},\
Search_Hallo_tomorrow {Cal_tm($NAME, "Hallo")},\
Search_Hallo_today {Cal_td($NAME, "Hallo")},\
Search_Ciao_name {Cal_na($NAME, "Ciao")},\
Search_Ciao_at {Cal_at($NAME, "Ciao")},\
Search_Ciao_tomorrow {Cal_tm($NAME, "Ciao")},\
Search_Ciao_today {Cal_td($NAME, "Ciao")}


99_myUtils_calendar.pm
##############################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z 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.

#************************************************************************
# 99_myUtils_calendar.pm kst
#************************************************************************
# 2020-10-03 - Datei erstellt
# 2020-10-03 - Abfrage Tage bis zu Event hinzu
# 2020-10-03 - Nicht Ganztagestermine Zeit bis Mitternacht verrechnen
# 2020-10-04 - Event Morgen/Heute hinzu
# 2020-10-05 - Event Name hinzu
# 2020-10-10 - Thread erstellt (99_myUtils_calendar - Perl Code)
#            - https://forum.fhem.de/index.php/topic,114901.0.html
#            - Cal_at umformatiert nach Vorlage CoolTux (Forum)
# 2020-10-11 - Code leserlich formatiert
#            - Event Morgen/Heute angepasst
#            - Event Name angepasst
#            - use POSIX; entfernt nach Hinweis von Beta-User (Forum)
# 2020-10-12 - Bei Optionalem Parameter ($sword) " // undef" entfernt
#            - (wird ueber "if (defined $sword && length($sword) > 0)" abgfragt)
#            - Abfrage ob Pflichtparameter ($cname) angegeben ist
#            - Rueckmeldung ueber Text im Reading verwendet, da in diesem Fall ausreichend
#            - carp (?) ist eher was fuer Modulentwickler (bessere Fehlerauswertung)
#            -
#            -
#            -
#
#------------------------------------------------------------------------

package main;

use strict;
use warnings;
#use Carp;
#use POSIX;

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

# Enter you functions below _this_ line.

##************************************************************************
## Zeit in Sekunden von Mitternacht bis aktuelle Zeit in Sekunden
##************************************************************************
## Kopie aus 57_Calendar.pm
#sub Calendar_GetSecondsFromMidnight()
#{
# my @time = localtime();
# return (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
#}


#************************************************************************
# Tage bis zum anstehenden Termin
#************************************************************************
sub
Cal_at {
                                      # Pflicht-Uebernahmeparameter (calendername), mit Ueberpruefung
my $cname       = shift // return '"Error: minimum call {Cal_at($NAME)}!"';
my $sword       = shift;             # Optionaler Uebernahmeparameter (searchword)

my $format      = '"$t1"';           # $t1 Startzeit in Sekunden
my $zeit        = 0;                 # Parameter setzen, damit keine Warnmeldung erscheint

                                      # Zeit in Sekunden ohne Suchwort
my $timewordoff = fhem("get $cname events format:custom=$format limit:from=0,count=1");
                                      # Zeit in Sekunden mit Suchwort
my $timewordon  = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1");


if ( defined $sword
    && length($sword) > 0)            # Abfrage ob Zeit mit oder ohne Suchwort verwendet wird
     {
$zeit = $timewordon;
     }
     else {
     $zeit = $timewordoff;
     }

                                      # Zeit von Mitternacht bis aktueller Zeit in Sekunden
my $todaymidnight = Calendar_GetSecondsFromMidnight();
                                      # Berechnung der Tage bis zum anstehenden Termin
my $day           = int(($zeit / 86400) - ((time - $todaymidnight) / 86400));

                                      # Uebergabe der Tage bis zum anstehenden Termin (999=kein Termin)
return ( (defined $day && $day < 0) ? 999 : $day );
}


#************************************************************************
# Termin Morgen
#************************************************************************
sub
Cal_tm {
                                      # Pflicht-Uebernahmeparameter (calendername), mit Ueberpruefung
my $cname       = shift // return '"Error: minimum call {Cal_tm($NAME)}!"';
my $sword       = shift;             # Optionaler Uebernahmeparameter (searchword)

my $format      = '"$S"';            # $S Ereignis

                                      # Ereignis ohne Suchwort
my $tmwordoff   = fhem("get $cname events format:custom=$format limit:when=tomorrow");
                                      # Ereignis mit Suchwort
my $tmwordon    = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:when=tomorrow");

if (defined $sword
    && length($sword) > 0)            # Abfrage ob Ereignis mit oder ohne Suchwort verwendet wird
  {
                                      # Uebergabe Status Termin mit Suchwort (0=nein/1=ja)
   return ( (defined $tmwordon && $tmwordon =~ m/$sword/i) ? 1 : 0 );
  }
else{
                                      # Uebergabe Status Termin ohne Suchwort (0=nein/1=ja)
   return ( (defined $tmwordoff && length($tmwordoff) > 0) ? 1 : 0);
  }
}


#************************************************************************
# Termin Heute
#************************************************************************
sub
Cal_td {
                                      # Pflicht-Uebernahmeparameter (calendername), mit Ueberpruefung
my $cname       = shift // return '"Error: minimum call {Cal_td($NAME)}!"';
my $sword       = shift;             # Optionaler Uebernahmeparameter (searchword)

my $format      = '"$S"';            # $S Ereignis

                                      # Ereignis ohne Suchwort
my $tdwordoff   = fhem("get $cname events format:custom=$format limit:when=today");
                                      # Ereignis mit Suchwort
my $tdwordon    = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:when=today");

if (defined $sword
    && length($sword) > 0)            # Abfrage ob Ereignis mit oder ohne Suchwort verwendet wird
  {
                                      # Uebergabe Status Termin mit Suchwort (0=nein/1=ja)
   return ( (defined $tdwordon && $tdwordon =~ m/$sword/i) ? 1 : 0 );
  }
else{
                                      # Uebergabe Status Termin ohne Suchwort (0=nein/1=ja)
   return ( (defined $tdwordoff && length($tdwordoff) > 0) ? 1 : 0);
  }
}


#************************************************************************
# Name zum Termin
#************************************************************************
sub
Cal_na {
                                      # Pflicht-Uebernahmeparameter (calendername), mit Ueberpruefung
my $cname       = shift // return '"Error: minimum call {Cal_na($NAME)}!"';
my $sword       = shift;             # Optionaler Uebernahmeparameter (searchword)

my $format      = '"$S"';            # $S Ereignis

                                      # Name ohne Suchwort
my $nawordoff   = fhem("get $cname events format:custom=$format limit:from=0,count=1");
                                      # Name mit Suchwort
my $nawordon    = fhem("get $cname events format:custom=$format filter:field(summary)=~'$sword' limit:from=0,count=1");

if (defined $sword
    && length($sword) > 0)            # Abfrage ob Name mit oder ohne Suchwort verwendet wird
  {
                                      # Uebergabe Name mit Suchwort
   return ( (defined $nawordon && length($nawordon) > 0) ? $nawordon : "Kein Treffer" );
  }
else{
                                      # Uebergabe Name ohne Suchwort
   return ( (defined $nawordoff && length($nawordoff) > 0) ? $nawordoff : "Kein Termin" );
  }
}


#************************************************************************
# Temporaer
#************************************************************************
#[erledigt]Formel1_name {my $name = fhem('get Cal_Formel1 events format:custom="$S" limit:from=0,count=1',1)},
#Formel1_name_short { my @c = split ' / ',ReadingsVal($name,'Formel1_name',0);$c[1] },
#


1;


Sollten doch noch Kritikpunkte (positiv wie negativ) vorhanden sein,
gerne her damit.  ;)

Mit freundlichen Grüßen, Karsten  :)

Beta-User

Ja, POSIX sollte aus allem raus, was mit im Namespace von main rumspukt... Betrifft nicht nur myUtils-Code, sondern auch eine ganze Zahl von FHEM-Modulen (Die Diskussion dazu findest du über den svn-diff-Link).

Das ist der Link zu dem nämlichen Code; wie gesagt, der ist nicht in allen Punkten "auf dem aktuellen Stand der Erkenntnis".

Zu deinem Code kann ich jetzt grade wenig sagen, tendenziell würde ich mal die Lektüre von irgendwas empfehlen, was "Quotes in Perl" erläutert (und q() bzw. qq()), z.B. das hier: https://www.perlmonks.org/?node_id=401006. Da scheinen noch ein paar Workarounds zu dem Thema drin zu sein.

Wenn es in Richtung Modulentwicklung ginge, würde ich auch die fhem-Aufrufe noch ersetzen wollen, für myutils ist es m.E. aber ok.

Aber Achtung: Ich lerne auch immer noch was dazu...

Grüße, Beta-User
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

hydrotec

Hallo Beta-User,

OK, das mit POSIX glaube ich grob (ganz grob) verstanden zu haben.
Perl bringt ja im "package main" schon einige Funktionen mit.
Sollte eine Funktion nicht vorhanden sein, kann man auf das Modul POSIX zurückgreifen.
Generell wird aber nicht empfohlen das Modul komplett zu laden (use POSIX;),
sondern es soll explizit nur die benötigte Funktion aus dem Modul geladen werden (z.B.: use POSIX qw(strftime);).
Ich denke mal das ich in diesem Bereich der Programmierung noch nicht gelandet bin.
Aber gut zu wissen, das wenn einmal eine Funktion nicht wie gewünscht funktioniert,
man über diesen Punkt nachdenken sollte.


Die fhem-Aufrufe in sub(s) zu legen hatte ich mir auch schon überlegt.
Eventuell mache ich das auch noch, einfach nur zur Übung.
Doch vorher muss ich mich erst einmal mit der Materie "Anführungszeichen und Klammersetzung" auseinandersetzen.
Ist derzeit noch mehr learning by doing, als wirklich wissen wann was benötigt wird.
Habe so ein Gefühl das sich FHEM und Perl nicht immer einig sind ;)


Zu "57_Calendar2holiday.pm"
So wie ich das verstehe, ist dein Ansatz, deine (benötigten) Kalender aus dem Netz mittels 57_Calendar.pm in FHEM zur Verfügung zu stellen.
Anschließend wird einmal die Woche der betreffende Kalender in eine .holiday geschrieben.
Diese wiederum verwendest du dann um diverse "Schaltungen" zu steuern.
(z.B.: Rolladen hoch um 06:00 Uhr wenn kein Eintrag im .holiday vorhanden sein sollte, ansonsten erst um 09:00 Uhr)
Zitat von: Beta-User am 11 Januar 2019, 21:29:27
Die Vorgehenweise eignet sich eher für längerfristig planende Themen, die potentiell alle Bewohner treffen, nicht für tages- oder stundenaktuelles Reagieren...
Und dafür ist es m.E. gut geeignet.

Bei mir war der Ausgangspunkt etwas anders.
Ich wollte eine "Schaltung" die mir schon einen Tag vorher berechnet wie mein Szenario am Folgetag auszusehen hat.
Muss wohl etwas weiter ausholen (sorry für OT, aber gehört ja irgendwie doch auch zur Hintergrundinformation)
Es gibt ja im Forum und Wiki schon einige gute Lösungsansätze wie man einen dummy über einen Kalender schalten kann,
oder die verbleibenden Tage bis zur Müllverwertung berechnet werden können.
Weder das eine noch das andere war das was ich mir vorgestellt hatte.
Nur so z.B., die Lampe sollte am Vortag schon wissen wie lange sie am Abend an sein darf, weil morgen Urlaub oder kein Urlaub ist.
OK, also einen Kalender angelegt und über userreadings die Abfrage morgen/heute eingebaut.
(userreading deshalb, weil für mich die Ausgabe in dem jeweiligen Kalender mehr Sinn macht als sie woanders noch einmal extra zu definieren)
Hat wunderbar funktioniert, und ich hatte Werte mit dene ich weiter arbeiten konnte (bei mir größtenteils doif).
Weil das so reibungslos funktioniert hatte, gleich noch den Abfallkalender mit angelegt,
und dort die Abfrage der anstehenden Tage in ein userreading gepackt.
Und so kam dann ein Kalender nach dem Anderen hinzu.
Jetzt hatte jeder Kalender die für mich benötigten Berechnungen in den userreadings enthalten.
Da kam mir die Idee, die Berechnungen zu vereinheitlichen und in eine myUtils zu legen.
Prinzipiell waren es ja nur die Auswertungen
- Event morgen/heute mit/ohne Suchwort
- Name des Events (mit Einkürzen des Textes ist in Planung)
- Anzahl der Tage bis zum Event mit/ohne Suchwort
   (inkl. der Verrechnung, bei Terminen die Tageszeitabhängig sind, bis 00:00:00 am selbigen Tag)

In Planung (wenn ich mal wieder Lust zum Programmieren habe)
- Einkürzen des Event-Namens parametrisieren
- Anzahl der Tage auch mit mehrtägigen Terminen

Deswegen bin ich diesen Weg, hier stark vereinfacht, gegangen.
Wie sagt man so schön, viele Wege führen nach Rom,
man muss nur das mobile bedienen können.


Grüße, Karsten