FHEM Forum

FHEM => Codeschnipsel => Thema gestartet von: Tompsg am 22 Februar 2026, 10:53:31

Titel: Räume room hinzufügen/entfernen
Beitrag von: Tompsg am 22 Februar 2026, 10:53:31
Hallo Zusammen,

ich hatte die Herausforderung einen Raum (room) automatisch mit Geräten zu füllen und dabei die bestehenden Räume nicht zu verändern. Dazu müssen die vorhandenen room Attribute ergänzt werden. In meinem Fall möchte ich alle Geräte mit dem Attribut alexaName in einem Raum zusammenfassen, ohne die bestehenden Räume zu überschreiben. Dabei ist das angefügte myUtils entstanden, welches ich in einem at nutze. Die alte attr Syntax bleibt ansonsten erhalten.

attr <devspec> room {+|-}<roomname>

##############################################
# $Id: 99_myUtils.pm 0001 2026-02-22 09:45:00Z Gemini $
package main;

use strict;
use warnings;
use POSIX;

# Variable für die Sicherung der Originalfunktion
use vars qw($oldCommandAttr);

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

{
  no warnings 'redefine';
 
  # Sicherung der originalen Funktion (einmalig beim Laden)
  if (!defined($oldCommandAttr)) {
      $oldCommandAttr = \&main::CommandAttr;
  }

  # Überlagerung der Funktion CommandAttr
  *main::CommandAttr = sub {
    my ($cl, $param) = @_;
   
    # Zerlegen des Befehls (Device, Attribut, Neuer Wert)
    my ($dev, $attrName, $newVal) = split("[ \t]+", $param, 3);

    # Wir springen sofort raus, wenn:
    # - kein Attributname vorhanden ist
    # - es nicht um 'room' geht
    # - eine Option wie -a oder -silent verwendet wird (erkannt am führenden - in $dev)
    if (!$attrName || $attrName ne "room" || ($dev && $dev =~ /^-/)) {
        return $oldCommandAttr->($cl, $param);
    }
   
    # Prüfung: Wenn das erste Zeichen + oder - ist
    if ($newVal && $newVal =~ /^[\+\-]/) {
     
        # Prüfung: Abbruch, wenn kein Einzel-Device ist (DevSpec Schutz)
        if ($dev && !defined($defs{$dev})) {
            return "Fehler: Die Nutzung von +/- ist bei DevSpecs (Filtern) nicht erlaubt!";
        }
       
        my $modifier = substr($newVal, 0, 1);

        # Prüfung: Abbruch bei Komma (mehrere Räume nicht erlaubt)
        if (substr($newVal, 1) =~ /,/) {
            return "Fehler: Mehrere Räume (Komma) sind bei +/- nicht erlaubt!";
        }

        # Prüfung: Abbruch wenn nach +/- nichts kommt
        if (length(substr($newVal, 1)) == 0) {
            return "Fehler: Kein Raumname nach $modifier angegeben!";
        }

        # Aktuelle Räume des Devices laden
        my $currentRooms = $attr{$dev}{room} // "";
        my @roomList = split(',', $currentRooms);
       
        # Zielraum isolieren und Leerzeichen säubern
        my $targetRoom = substr($newVal, 1);
        $targetRoom =~ s/^\s+|\s+$//g;
       
        if ($modifier eq "+") {
            # Hinzufügen, falls noch nicht vorhanden
            push(@roomList, $targetRoom) unless grep { $_ eq $targetRoom } @roomList;
        }
        elsif ($modifier eq "-") {
            # Entfernen des spezifischen Raums
            @roomList = grep { $_ ne $targetRoom } @roomList;
        }

        # Bereinigung: Leere Einträge entfernen
        @roomList = grep { length($_) > 0 } @roomList;

        # Sortierung: Alphabetisch (Standard / Case-Sensitive)
        @roomList = sort { $a cmp $b } @roomList;
       
        # Wenn kein Raum mehr übrig ist: Attribut komplett löschen
        if (scalar @roomList == 0) {
            Log 3, "CustomAttr: Letzter Raum entfernt, lösche Attribut room für $dev";
            return main::CommandDeleteAttr($cl, "$dev room");
        }
       
        # Parameter für die Original-Funktion mit der neuen Liste neu aufbauen
        my $finalRooms = join(',', @roomList);
        $param = "$dev room $finalRooms";
    }

    # Aufruf der Originallogik
    return $oldCommandAttr->($cl, $param);
  };
}

1;
Titel: Aw: Räume room hinzufügen/entfernen
Beitrag von: rudolfkoenig am 22 Februar 2026, 11:45:45
Alternativ koennte man auch attr -a verwenden: https://fhem.de/commandref_modular.html#attr


Fuer die Ueberlagerung von Befehlen gibt es auch eine Alternative: cmdalias: https://fhem.de/commandref_modular.html#cmdalias
Titel: Aw: Räume room hinzufügen/entfernen
Beitrag von: Tompsg am 22 Februar 2026, 12:59:51
Update mit devspec-Unterstützung:

##############################################
# $Id: 99_myAttrRoom.pm 0001 2026-02-22 12:30:00Z Gemini $
# FORK: Unterstützung für room +/- mit DevSpecs
##############################################
package main;

use strict;
use warnings;
use POSIX;

# Variable für die Sicherung der Originalfunktion
use vars qw($oldCommandAttr);

sub myAttrRoom_Initialize($$) {
    my ($hash) = @_;
    Log3(undef, 1, "myAttrRoom: custom CommandAttr hook loaded - support for room +/- enabled");
}

{
  no warnings 'redefine';
 
  # Sicherung der originalen Funktion (einmalig beim Laden)
  if (!defined($oldCommandAttr)) {
      $oldCommandAttr = \&main::CommandAttr;
  }

  # Überlagerung der Funktion CommandAttr
  *main::CommandAttr = sub {
    my ($cl, $param) = @_;
   
    # Zerlegen des Befehls (Device, Attribut, Neuer Wert)
    my ($dev, $attrName, $newVal) = split("[ \t]+", $param, 3);

    # Wir springen sofort raus, wenn:
    # - kein Attributname vorhanden ist
    # - es nicht um 'room' geht
    # - eine Option wie -a oder -silent verwendet wird (erkannt am führenden - in $dev)
    if (!$attrName || $attrName ne "room" || ($dev && $dev =~ /^-/)) {
        return $oldCommandAttr->($cl, $param);
    }
   
    # Prüfung: Wenn das erste Zeichen + oder - ist
    if ($newVal && $newVal =~ /^[\+\-]/) {

        # Prüfung: Abbruch bei Komma (mehrere Räume nicht erlaubt)
        if (substr($newVal, 1) =~ /,/) {
            return "Fehler: Mehrere Räume (Komma) sind bei +/- nicht erlaubt!";
        }

        # Fehler: Kein Name
        my $modifier = substr($newVal, 0, 1);

        # Zielraum isolieren und Leerzeichen säubern
        my $targetRoom = substr($newVal, 1);
        $targetRoom =~ s/^\s+|\s+$//g;
       
        if (length($targetRoom) == 0) {
            return "Fehler: Kein Raumname nach $modifier angegeben!";
        }
 
        # Fehler: Ziel nicht auffindbar
        my @devices = devspec2array($dev);
        if (scalar @devices == 0) {
             return "Fehler: Device/DevSpec $dev nicht gefunden!";
        }

        # --- VERARBEITUNG ---
        foreach my $singleDev (@devices) {
            # Aktuelle Räume des Devices laden
            my $currentRooms = $attr{$singleDev}{room} // "";
            my @roomList = split(',', $currentRooms);
           
            if ($modifier eq "+") {
                push(@roomList, $targetRoom) unless grep { $_ eq $targetRoom } @roomList;
            }
            elsif ($modifier eq "-") {
                @roomList = grep { $_ ne $targetRoom } @roomList;
            }

            # Bereinigung: Leere Einträge entfernen
            @roomList = grep { length($_) > 0 } @roomList;
            # Sortierung: Alphabetisch (Standard / Case-Sensitive)
            @roomList = sort { $a cmp $b } @roomList;
           
            # Wenn kein Raum mehr übrig ist: Attribut komplett löschen
            if (scalar @roomList == 0) {
                Log 3, "myAttrRoom: Letzter Raum entfernt, lösche Attribut room für $singleDev";
                main::CommandDeleteAttr($cl, "$singleDev room");
            } else {
                my $finalRooms = join(',', @roomList);
                Log 4, "myAttrRoom: $singleDev -> neue Räume: $finalRooms"; # Detail-Log
                $oldCommandAttr->($cl, "$singleDev room $finalRooms");
            }
        }
        return undef; # Erfolg
    }
 
    # Aufruf der Originallogik
    return $oldCommandAttr->($cl, $param);
  };
}

1;
Titel: Aw: Räume room hinzufügen/entfernen
Beitrag von: Tompsg am 22 Februar 2026, 13:01:19
Zitat von: rudolfkoenig am 22 Februar 2026, 11:45:45Alternativ koennte man auch attr -a verwenden: https://fhem.de/commandref_modular.html#attr


Fuer die Ueberlagerung von Befehlen gibt es auch eine Alternative: cmdalias: https://fhem.de/commandref_modular.html#cmdalias

Danke für den Hinweis. Mit attr -a konnte ich das nicht so "schön" umsetzen. Überlagerung muss ich mir mal ansehen.
Titel: Aw: Räume room hinzufügen/entfernen
Beitrag von: Beta-User am 22 Februar 2026, 13:19:16
Es gäbe da auch noch den show-Befehl, mit dem man dynamisch Räume erstellen bzw. anzeigen kann.