Räume room hinzufügen/entfernen

Begonnen von Tompsg, 22 Februar 2026, 10:53:31

Vorheriges Thema - Nächstes Thema

Tompsg

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;

rudolfkoenig

#1
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

Tompsg

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;

Tompsg

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.

Beta-User

Es gäbe da auch noch den show-Befehl, mit dem man dynamisch Räume erstellen bzw. anzeigen kann.
Server: HP-elitedesk@Debian 13, 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