FHEM Forum

FHEM - Hausautomations-Systeme => Homematic => Thema gestartet von: noansi am 03 Oktober 2026, 14:26:20

Titel: 10_CUL_HM.pm erzeugt ghost devices mit Anwendung von fhem delete
Beitrag von: noansi am 03 Oktober 2026, 14:26:20
Hallo Martin,

hier https://forum.fhem.de/index.php?topic=145558.0 (https://forum.fhem.de/index.php?topic=145558.0) habe ich auch auf das Problem aufmerksam gemacht.

Ab 10_CUL_HM.pm Zeile 1638
    elsif ($evnt =~ m/^(DELETED|RENAMED) (.*?) ?/){
      my ($cmd,$ent,$new) =split(" ",$evnt." ");
      # $ent no longer exist
      # $new is the renamed (if rename)
      if (($evnt eq "DELETED" && $defs{$ent}{TYPE} eq "CUL_HM")
wurde nicht beachtet, dass der gelöschtet device hash gelöscht ist und schon der Versuch
'$defs{$ent}{TYPE} eq "CUL_HM"'
erzeugt einen ghost hash auf den DELETED Trigger hin.
Und das nicht nur für HM devices, sondern generell bei Nutzung von 'delete' und geladenem CUL_HM!

Die HM-device spezifische Funktionalität kann in die UndefFn verlagert werden, denn diese wird von CommandDelete vorher mit noch existierendem device hash aufgerufen.

Insbesondere findet in der jetzigen Form auch kein 'remove' vom IO statt, wie es gedacht ist, als weiterer nicht funktionaler Effekt.

Und das primaryDevice wird nicht aktualisiert, weil die Abfrage scheitert. Umziehen darf das aber nicht, weil der device hash wirklich weg sein muss.

Vorschlag CUL_HM_Notify
sub CUL_HM_Notify(@) {###############################
  my ($ntfy, $dev) = @_;
  #$ntfy - whom to notify
  #$dev  - who changed
  return if(  $dev->{NAME} ne 'global'
            ||$dev->{NAME} eq $ntfy->{NAME}
            );# no notification about myself
  my $events = deviceEvents($dev, 0);
  return if (!defined($events)); # Some previous notify deleted the array.
#  my $cws = join(';#',@{$dev->{CHANGED}});
  my ($cmd,$ent,$new,$count);
  for my $evnt (@{$events}){
    ($cmd,$ent,$new) = split(" ",$evnt,3);
    if    ($cmd eq 'ATTR'){#ATTR
      if(   $new =~ /^ignore 1/ #ATTR ignore - was it the primary notification device?
         && $ent eq $modules{CUL_HM}{helper}{primary}){
        $modules{CUL_HM}{helper}{primary} = ''; # force rescan
        CUL_HM_primaryDev();
      }
    }
    elsif ($cmd eq 'DELETEATTR'){
    }
    elsif ($cmd eq 'RENAMED'){
      # $ent no longer exist
      # $new is the renamed
      if ($defs{$new}{TYPE} eq 'CUL_HM'){
        CUL_HM_Rename($new,$ent);
        CUL_HM_primaryDev() if ($ent eq $modules{CUL_HM}{helper}{primary});
        $count++;
      }
      else{##------- update dependancies to IO devices used
        my @culHmDevs = grep{$defs{$_}{DEF} =~ /^......$/} grep{$defs{$_}{TYPE} eq 'CUL_HM'} keys %defs;
        ## ------ correct IOList and IOGrp
        {
          my ($ea, $eaOld, $ios);
          for my $vccu (grep{AttrVal($_,'IOList','') =~ /,?$ent/} @culHmDevs){# for each vccu
            $ea = $eaOld = AttrVal($vccu,'IOList','');
            $ea = join(',',grep{defined $defs{$_}}
                           map{my $foo = $_ ne $ent?$_:$new;$foo}
                           split(/,/,$ea));
            for my $HMdef(grep{AttrVal($_,'IOgrp','') =~ /$vccu:.*$ent/} @culHmDevs){
              if($ea){#vccu still operational
                (undef,$ios) = split(/:/,AttrVal($HMdef,'IOgrp',''));
                $ios = join(',',
                       grep{defined $defs{$_}}
                       map{my $foo = $_ ne $ent?$_:$new;$foo}
                       split(/,/,$ios)
                       );
                $attr{$HMdef}{IOgrp} = "$vccu".($ios ? ":$ios" : '');
                $count++;
              }
              else {# the vccu has no IO anymore - delete clients
                CommandDeleteAttr(undef,"$HMdef IOgrp") ;
                $count++;
              }
            }
            if ($ea ne $eaOld) {
              CommandAttr(undef,"$vccu IOList $ea");
              $count++;
            }
          }
        }
        for my $HMdef (grep{AttrVal($_,'IODev',ReadingsVal($_,'IODev','')) eq $ent} @culHmDevs){# for each IODev
          next if CUL_HM_notActivebyName($HMdef);
          CommandAttr(undef,"$HMdef IODev $new");
          $count++;
        }
      }
      return ($count ? "CUL_HM: $count device(s) renamed or attributes changed due to $cmd event"
                     : undef);
    }
    elsif ($cmd eq 'DELETED'){
      # $ent no longer exist
      CUL_HM_primaryDev() if ($ent eq $modules{CUL_HM}{helper}{primary});
      $count++;
      my @culHmDevs = grep{$defs{$_}{DEF} =~ /^......$/} grep{$defs{$_}{TYPE} eq 'CUL_HM'} keys %defs;
      ## ------ correct IOList and IOGrp
      {
        my ($ea, $eaOld, $ios);
        for my $vccu (grep{AttrVal($_,'IOList','') =~ /,?$ent/} @culHmDevs){# for each vccu
          $ea = $eaOld = AttrVal($vccu,'IOList','');
          $ea = join(',',grep{defined $defs{$_}}
                         map{my $foo = $_ ne $ent?$_:'';$foo}
                         split(/,/,$ea));
          for my $HMdef (grep{AttrVal($_,'IOgrp','') =~ /$vccu:.*$ent/} @culHmDevs){
            if($ea){#vccu still operational
              (undef,$ios) = split(/:/,AttrVal($HMdef,'IOgrp',''));
              $ios = join(',',
                     grep{defined $defs{$_}}
                     map{my $foo = $_ ne $ent?$_:'';$foo}
                     split(/,/,$ios)
                     );
              $attr{$HMdef}{IOgrp} = "$vccu".($ios ? ":$ios" : '');
              $count++;
            }
            else {# the vccu has no IO anymore - delete clients
              CommandDeleteAttr(undef,"$HMdef IOgrp") ;
              $count++;
            }
          }
          if ($ea ne $eaOld) {
            CommandAttr(undef,"$vccu IOList $ea");
            $count++;
          }
        }
      }
      for my $HMdef (grep{AttrVal($_,'IODev',ReadingsVal($_,'IODev','')) eq $ent} @culHmDevs){# for each IODev
        next if CUL_HM_notActivebyName($HMdef);
        CUL_HM_assignIO($defs{$HMdef});
        $count++;
      }
      return ($count ? "CUL_HM: $count device(s) attributes changed due to $cmd event"
                     : undef);
    }
    elsif ($cmd eq 'REREADCFG'){
      Log3($ntfy,0,'[FAILURE] CUL_HM does not reliably support rereadcfg any longer! Restart FHEM instead.');
      delete $modules{CUL_HM}{helper}{initDone};
      CUL_HM_updateConfig('startUp');
      InternalTimer(1,\&CUL_HM_setupHMLAN, 'initHMLAN', 0);
    }
    elsif ($cmd eq 'INITIALIZED'){
      if (!$modules{CUL_HM}{helper}{initDone}){# grep the first initialize
        CUL_HM_updateConfig('startUp');
        InternalTimer(1,\&CUL_HM_setupHMLAN, 'initHMLAN', 0);#start asap once FHEM is operational
      }
    }
#    elsif ($cmd eq 'DEFINED' ){ Log 1,"Info --- $dev->{NAME} -->$ntfy->{NAME} :  $evnt";}
#    elsif ($cmd eq 'SHUTDOWN'){ Log 1,"Info --- $dev->{NAME} -->$ntfy->{NAME} :  $evnt";}#SHUTDOWN|DELAYEDSHUTDOWN
#    elsif ($cmd eq 'SAVE'    ){ Log 1,"Info --- $dev->{NAME} -->$ntfy->{NAME} :  $evnt";}
#    elsif ($cmd eq 'MODIFIED'){ Log 1,"Info --- $dev->{NAME} -->$ntfy->{NAME} :  $evnt";}
#    else                      { Log 1,"Info --- $dev->{NAME} -->$ntfy->{NAME} :  $evnt";}

  }

  return;
}

Vorschlag CUL_HM_Undef
sub CUL_HM_Undef($$) {###############################
  my ($hash, $name) = @_;
  my $HMid = $hash->{DEF};
  CUL_HM_unQEntity($name,'qReqConf');
  CUL_HM_unQEntity($name,'qReqStat');
  CUL_HM_complConfigTestRm($name);
  my $devName = $hash->{device};
  my $chn = substr($HMid,6,2);
  if ($chn){# delete a channel
    if (   $devName
        && defined(my $devHash = $defs{$devName})) {
      delete $devHash->{"channel_$chn"};
      $devHash->{helper}{role}{chn} = 1 if($chn eq '01');# return chan 01 role
      CUL_HM_hmInitMsg($devHash);
    }
    delete $hash->{helper}{mId};
  }
  else{# delete a device
    CommandDelete(undef,$hash->{$_}) for (grep(/^channel_/,keys %{$hash}));
    if (   defined($hash->{IODev}) #noansi: not possible in DELETED notify
        && (   $hash->{IODev}{helper}{VTS_AES}
            || (   defined($hash->{IODev}{TYPE})
                && $hash->{IODev}{TYPE} =~ /^HM(?:LAN|UARTLGW)$/s) )
        ) {
      IOWrite($hash, '', 'remove:'.CUL_HM_hash2Id($hash));
    }
  }
  delete($modules{CUL_HM}{defptr}{$HMid});
  delete $modules{CUL_HM}{helper}{primary} if (devspec2array('TYPE=CUL_HM') == 1);
  return;
}