Perl warning: subroutine ... redefined nach neuem Aufsetzen von FHEM

Begonnen von bmwfan, 23 Juli 2021, 12:08:12

Vorheriges Thema - Nächstes Thema

bmwfan

Hallo,

ich musste aufgrund einer beschädigten SD-Karte und nicht funktionierendem Backup mein Raspi + FHEM neu aufsetzen. Das meiste läuft wieder, aber ich bekomme Fehlermeldungen von einem eigenen Modul, das bisher fehlerfrei lief.

Die Winkeleinstellung meiner Jalousien mache ich mit einem eigenen Modul 99_myJalousie.pm (ursprünglich von gevoo), das ich auch wieder in das FHEM-Verzeichnis kopiert habe. Benutzer ist fhem, Gruppe ist dialout. Beim Start von FHEM erhalte ich diese Fehlermeldung:
2021.07.23 10:56:41.069 1: Including fhem.cfg
2021.07.23 10:56:41.099 1: PERL WARNING: Subroutine Jalousie_Initialize redefined at ./FHEM/99_myJalousie.pm line 45, <$fh> line 14.
2021.07.23 10:56:41.100 1: PERL WARNING: Subroutine Jalousie_Define redefined at ./FHEM/99_myJalousie.pm line 55, <$fh> line 14.
2021.07.23 10:56:41.101 1: PERL WARNING: Subroutine Jalousie_Undef redefined at ./FHEM/99_myJalousie.pm line 104, <$fh> line 14.
2021.07.23 10:56:41.103 1: PERL WARNING: Subroutine Jalousie_Set redefined at ./FHEM/99_myJalousie.pm line 111, <$fh> line 14.
2021.07.23 10:56:41.104 1: PERL WARNING: Subroutine Logger redefined at ./FHEM/99_myJalousie.pm line 202, <$fh> line 14.


Die Zeilen 45, 55, 104... sind die Aufrufe der entsprechenden Routinen in der 99_myJalousie.pm. Zeile 14 in fhem.cfg ist attr global modpath .
Die 99_myJalousie.pm:
package main;

use strict;
use warnings;
use POSIX;

sub Logger($);
sub Jalousie_SetWinkel($$);

my $Jalousie_Version ="V 0.00.09 von gevoo, modifiziert von bmwfan";
my $DrehWinkel = 90; # Wenn Ihr eine Jalousie mit 90 Grad Drehwinkel benutzt, dann 180 auf 90 aendern. = ist geschlossen
my $FahrZeitAb = 64; # Fahrzeit Ab. Daraus wird Fahrzeit Auf mit Fahrzeit Ab + 1 Sekunde ermittelt
my $DrehAb = 2; # Drehzeit Zu
my $DrehAuf = 2; # Drehzeit Auf
# Definition der Jalousie
# define <name> Jalousie <Rolloaktor_03> <Fahrzeit ab> <Drehzeit>
# Daraus folgt: $a[0]: <name>; $a[1]: Modulname hier Jalousie; $a[2]: Device hier Jal_KU_Ost_03; $a[3]: <parameter 1>; $a[4]: <parameter 2>
# Vor Verwendung dieses Modules sind folgende Zeiten zu betimmen:
# - Jalousie steht ganz oben: Abwaertstaste betaetigen und Zeit messen bis Lamellen
# ganz unten sind ==> FahrzeitAb
# - Fahrzeit Auf == Fahrzeit ab + 1 Sekunde
# - Jalousie steht mit völlig geschlossenen Lamellen: Aufwaertstaste betaetigen und Zeit messen bis Lamellen
# komplett offen sind ( 90 Grad- Stellung) ==> Drehzeit
# - Annahme, dass Drehzeit Auf == Drehzeit Zu
# - in der Weboberflaeche des Rolloaktors sind die korrekten Zeiten für den gesamten
# Schliessvorgang ( Lamellen zu + Jalousie runterfahren) und den gesamten
# Oeffnungsvorgang einzutragen
#
# Die Jalousie wird folgendermassen definiert:
# define <name> Jalousie <Rolloaktor_03> <Level> <Winkel>
# - <name> ist frei waehlbar
# - <Rolloaktor_03> ist der Name des Kanal 03 des anzusteuernden Rolloaktors
# - <Level> und <Winkel> sind Werte
# Eingabebefehl: SET jALOUSIE WINKEL %= stellt den Winkel der Lamellen auf 50 Grad ein.
# Eingabebefehl: set Jalousie level 60 faehrt die Jalousie auf 60 %
#

# my $Zeit = strftime( "%Y-%m-%d\x5f%H-%M-%S", localtime);
my $Zeit = strftime( "%Y-%m-%d", localtime); # logdateien nur täglich
my $LogOffen = undef;

sub Jalousie_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn}    = "Jalousie_Define";
$hash->{UndefFn}  = "Jalousie_Undef";
$hash->{SetFn}    = "Jalousie_Set";

Log3( "Jalousie", 3, "Modul 99_myJalousie.pm: Init Done with Version $Jalousie_Version"); # Ausgabe Meldung im fhem.log
}

########################################
sub Jalousie_Define($$$) {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
my $name = $a[0];
my $reFloat ='^([\\+,\\-]?\\d+\\.?\d*$)'; # gleitpunkt 
Log3( $name, 3, "Name = $a[0], Parameter = $a[1] $a[2] $a[3] $a[4]");
# Logger( 'Jalousie_Define_alle Werte: ' . $a[0] . ', ' . $a[1] . ', ' . $a[2] . ',' . $a[3] . ',' . $a[4]);

if ( @a != 5) {
return "wrong syntax: define <name> Jalousie <Rolloaktor_03> <DrehzeitAb> <DrehzeitAuf>";
}
###################
# Aktor Werte ermitteln
my $aktor = $a[2];
my $drehAb = $a[3];
my $drehAuf = $a[4];
my $drehWinkel = $DrehWinkel; # Hier: 90 Grad Drehwinkel
my $fahrzeitab = $FahrZeitAb;
my $fahrzeitauf = $FahrZeitAb + 1;
   
# wenn aktor nicht definiert?
if ( !$defs{ $aktor} ) {
my $msg = "Jalousie_Define: $name: Unbekannter Aktor $aktor als Device festgelegt";
Log3 ( "Jalousie", 1, $msg);
return $msg;
}

# pruefen ob die angegebenen Zeiten mit der Config des Aktors uebereinstimmen
my $dabAnteil = 0;
my $daufAnteil = 0;

$hash->{Jalousie}{aktor} = $aktor;
$hash->{Jalousie}{drehZeitAb} = $drehAb;
$hash->{Jalousie}{ab} = ReadingsVal( $aktor, "R-reference_running_time_top_bottom", 50);
# $hash->{Jalousie}{ab} = $fahrzeitab; # wenn auslesen nicht geht: Fahrzeiten fest vorgeben
$hash->{Jalousie}{drehZeitAuf} = $drehAuf;
$hash->{Jalousie}{auf} = ReadingsVal( $aktor, "R-reference_running_time_bottom_top", 50);
# $hash->{Jalousie}{auf} = $fahrzeitauf; # wenn auslesen nicht geht: Fahrzeiten fest vorgeben
$hash->{Jalousie}{winkel} = 0;
$hash->{Jalousie}{lastMove} = 'ab'; # merkt sich die letzte Bewegungsrichtung

$modules{Jalousie}{defptr}{$name} = $hash;
Log3 ( "Jalousie", 1, "Jalousie mit Rolloaktor $aktor verbunden");

return undef;
}

########################################
sub Jalousie_Undef($$)
{
   my ( $hash, $arg ) = @_;
   RemoveInternalTimer($hash->{NAME});
   return undef;
}

########################################
sub Jalousie_Set($@) {
my ($hash, @params) = @_;

my $name  = $params[0];
my $cmd   = $params[1];
my $value = $params[2]; # gewünschter Level oder Winkel der Jalousie
my $istwinkel = 0; # Winkel vorbelegen. 0: Stellung bei Fahrt down

my $msg = undef;
if (@params < 3) {
$msg =  '\"set ' . $name . '\" benoetigt 3 Parameter'; # pruefen, ob alle Parameetr angegeben wurden
} else {
if ( $cmd eq 'level') {
my $hash = $defs{$name};
my $level = ReadingsVal( $hash->{Jalousie}{aktor}, "level", 110);
if ( $level < 110) {
if ( $value > $level) { # hochfahren
Logger( 'Jalousie_Set_value>level: ' . $name . ' hoch fahren auf ' . $value);
$istwinkel = 90;
$hash->{Jalousie}{winkel} = $istwinkel;
Logger( 'Jalousie_Set_value:Winkel: ' . $name . ' Winkel setzen auf ' . $istwinkel . ' grad');
}
if ( $value < $level) { # runterfahren
Logger( 'Jalousie_Set_value<level: ' . $name . ' runter fahren auf ' . $value);
$istwinkel = 0;
$hash->{Jalousie}{winkel} = $istwinkel;
Logger( 'Jalousie_Set_value:Winkel: ' . $name . ' Winkel setzen auf ' . $istwinkel . ' grad');
}
fhem( "set $hash->{Jalousie}{aktor} level $value");
fhem( "setreading $hash->{Jalousie}{aktor} level $value");
fhem( "setreading $name level $value");
fhem( "setreading $hash->{Jalousie}{aktor} winkel $istwinkel");
fhem( "setreading $name winkel $istwinkel");
}
} elsif ( $cmd eq "winkel") {
# Ungültige Winkelangaben korrigieren: > 90 Grad und < 0 Grad
if ( $value > $DrehWinkel) {
$value = $DrehWinkel;
}
if ( $value < 0) {
$value = 0;
}
my $deltaW = $value - $hash->{Jalousie}{winkel}; # negative Werte = Lamellen zu fahren
Logger( 'Jalousie_Set_Winkel: ' . $name . ' Sollwinkel = ' . $value);
Logger( 'Jalousie_Set_Winkel: ' . $name . ' deltaW = ' . $deltaW);
my $deltaZeit = 0;
my $deltaLevel= 0;
Logger( 'Jalousie_SetWinkel: ' . $name . ' Fahrzeit auf = ' . $hash->{Jalousie}{auf} . ' Fahrzeit zu = ' . $hash->{Jalousie}{ab});
Logger( 'Jalousie_SetWinkel: ' . $name . ' Drehzeit auf = ' . $hash->{Jalousie}{drehZeitAuf} . ' Drehzeit zu = ' . $hash->{Jalousie}{drehZeitAb});
if ( $deltaW > 0.00001) {
$deltaZeit = $hash->{Jalousie}{drehZeitAuf} / $DrehWinkel * $deltaW;
$deltaLevel = 100 / $hash->{Jalousie}{auf} * $deltaZeit;
} elsif ( $deltaW < -0.00001) {
$deltaZeit = $hash->{Jalousie}{drehZeitAb} / $DrehWinkel * $deltaW;
$deltaLevel = 100 / $hash->{Jalousie}{ab} * $deltaZeit;
} else {
# $deltaW = 0
return
}
# Logger( 'Jalousie_SetWinkel: ' . $name . ' deltaZeit = ' . $deltaZeit . ' deltaLevel = ' . $deltaLevel);
my $level = ReadingsVal( $hash->{Jalousie}{aktor}, "level", 110);
# Logger( 'Jalousie_SetWinkel: ' . $name . ' Istlevel = ' . $level);
if ( $level < 110) {
# bei zu kleinen Winkelaenderungen reagiert der Aktor nicht
# if ( abs( $deltaLevel) < 0.1) {
# $deltaLevel = $deltaLevel/ abs( $deltaLevel) * 0.1;
# if ( $deltaLevel > 0) { # aufdrehen
# $deltaZeit = $deltaLevel * 100 / $hash->{Jalousie}{auf};
# $deltaW = $deltaZeit * $DrehWinkel / $hash->{Jalousie}{drehZeitAuf};
# } else {
# $deltaZeit = $deltaLevel * 100 / $hash->{Jalousie}{ab};
# $deltaW = $deltaZeit * $DrehWinkel / $hash->{Jalousie}{drehZeitAb};
# }
# $value = $deltaW + $hash->{Jalousie}{winkel};
#}
$level = $level + $deltaLevel;
Logger( 'Jalousie_SetWinkel: ' . $name . ' Solllevel = ' . $level);
fhem( "set $hash->{Jalousie}{aktor} level $level");
$hash->{Jalousie}{winkel} = $value;
fhem( "setreading $hash->{Jalousie}{aktor} winkel $value");
fhem( "setreading $name winkel $value");
Logger( 'Jalousie_SetWinkel: ' . $name . ' Winkel auf ' . $value . ' grad');
}
$msg = 'Winkelangabe ist mit ' . $value . ' Grad vorgegeben';
} else {
$msg = 'Unknown argument ' . $cmd . ', choose level';
}
}
return $msg;
}

sub Logger($){
my ( $LogText) = @_;
my $ZeitStr = strftime( "%Y-%m-%d\x5f%H:%M:%S", localtime);
my $LogName = "$main::attr{global}{modpath}/log/99myJalousie" . $Zeit . ".log";
if ( $LogOffen) {
print Datei "$ZeitStr $LogText\n";
} else {
open( Datei, ">$LogName") || die "Datei nicht gefunden\n";    # Datei zum Schreiben oeffnen
Datei->autoflush(1);
$LogOffen = "offen";
print Datei "aktuelle Version ist jetzt $Jalousie_Version\n";
print Datei "$ZeitStr $LogText\n";
}
}

1;


Wo kann der Fehler liegen?

Beim define des entsprechenden Devices define Jal_KU_Ost myJalousie Jal_KU_Ost_03 64 2 erhalte ich dann die Meldung Cannot load module myJalousie

Die ganze Logik hat vor dem Neuaufsetzen des Raspi und FHEM funktioniert.

Hat jemand eine Idee zur Lösung des Problemes?

Grüße Jürgen
Synology DS720+ mit Docker-Container und Haupt-FHEM, HM-LAN, Jalousienaktoren HmWired, Shelly-Devices; Raspi 3B+ mit piVCCU ohne FHEM-Instanz, CUL, JeeLink; Raspi 3B+ mit FHEM und HMUARTUSB,  Raspi 3B+ mit HMUARTGPIO, 1-wire, ebusd

betateilchen

Hinweis 1:
Nimm nicht 99_ am Anfang der Moduldatei, besser ist z.B. 98_
99_ am Anfang führt dazu, dass die Datei schon beim FHEM Start geladen wird, unabhängig davon, ob sie überhaupt gebraucht wird oder nicht.

Hinweis 2:
Wenn beim define eine Fehlermeldung auftritt, kann es daran liegen, dass der Modulname falsch angegeben wurde.
Bist Du sicher, dass im define "myJalousie" als Modultyp stehen muss und nicht "Jalousie"?

Das steht übrigens auch ausdrücklich in Deinem Code:
# define <name> Jalousie <Rolloaktor_03> <Fahrzeit ab> <Drehzeit>
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Beta-User

Dateiname und Initialize müssen auch zusammenpassen, und "use POSIX;" solltest du rauswerfen bzw. durch eine Angabe ersetzen, welche Funktion(en) du daraus haben willst:use POSIX qw(strftime);


(Generelle Frage, _falls_ es um das Timing von "zwei Relays geht": wäre das nicht eine sinnvolle Erweiterung für ROLLO?)
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

bmwfan

Danke für die Antworten

Hinweis 1:
Habe ich geändert. War mir nicht bekannt.

Hinweis 2:
Als define "myJalousie" war so vor dem Neuaufsetzen. Erstens deswegen war ich der Meinung, dass es so stimmt und zweitens dachte ich, dass dies der Aufruf des Moduls ist und das Modul heisst ja 99_myJalousie. Der Kommentar in 99_myJalousie.pm stammt noch aus dem ursprünglichen Modul, von dem ich meines entwickelt habe.

Use POSIX: War so im Modul und ich habe es übernommen ohne zu wissen, wofür das ist. Habe es jetzt wie vorgeschlagen geändert.

Generelle Frage: Da verstehe ich nicht, was Du meinst. Mit dem Modul gebe ich einen kurzen "Öffnen"-Befehl auf die Jalousiemotoren, damit eine Winkelstellung der Lamellen erreicht wird.

Bei einem define Jal_KU_Ost myJalousie Jal_KU_Ost_03 64 2 kommt als Meldung: Cannot load module myJalousie
Bei einem define Jal_KU_Ost Jalousie Jal_KU_Ost_03 64 2 kommt als Meldung: Unknown module Jalousie

Kann es sein, dass die Meldung Cannot load module myJalousie darauf hindeutet, dass eine Bibliothek von der Raspi-Installation fehlt?

Nach ändern der 99_myJalousie in 98_myJalousie steht folgendes im Log:
2021.07.23 15:51:31.368 1: PERL WARNING: Subroutine Jalousie_Initialize redefined at ./FHEM/98_myJalousie.pm line 45.
2021.07.23 15:51:31.373 1: PERL WARNING: Subroutine Jalousie_Define redefined at ./FHEM/98_myJalousie.pm line 55.
2021.07.23 15:51:31.374 1: PERL WARNING: Subroutine Jalousie_Undef redefined at ./FHEM/98_myJalousie.pm line 104.
2021.07.23 15:51:31.376 1: PERL WARNING: Subroutine Jalousie_Set redefined at ./FHEM/98_myJalousie.pm line 111.
2021.07.23 15:51:31.377 1: PERL WARNING: Subroutine Logger redefined at ./FHEM/98_myJalousie.pm line 202.
2021.07.23 15:51:31.393 0: Undefined subroutine &main::myJalousie_Initialize called at fhem.pl line 2724.

Synology DS720+ mit Docker-Container und Haupt-FHEM, HM-LAN, Jalousienaktoren HmWired, Shelly-Devices; Raspi 3B+ mit piVCCU ohne FHEM-Instanz, CUL, JeeLink; Raspi 3B+ mit FHEM und HMUARTUSB,  Raspi 3B+ mit HMUARTGPIO, 1-wire, ebusd

betateilchen

#4
Zitat von: bmwfan am 23 Juli 2021, 15:54:12
2021.07.23 15:51:31.393 0: Undefined subroutine &main::myJalousie_Initialize called at fhem.pl line 2724.

Du versuchst, ein define mit "myJalousie", obwohl die xxx_Initialize in Deiner Datei Jalousie_Initialize heißt und nicht myJalousie_Initialize.

Zitat von: bmwfan am 23 Juli 2021, 15:54:12
war ich der Meinung, dass es so stimmt und zweitens dachte ich, dass dies der Aufruf des Moduls ist und das Modul heisst ja 99_myJalousie.

Weder Deine Meinung noch Deine Gedanken sind für das Funktionieren von FHEM wichtig, sondern nur die korrekte Syntax bei der Anwendung von FHEM Funktionen.

Tipp: Vielleicht solltest Du erstmal die Development_Guidelines lesen und versuchen, diese zu verstehen, bevor Du versuchst, irgendwelche "Module" selbst zu stricken, ohne den Hintergrund verstanden zu haben.

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!