FHEM Forum

FHEM => Automatisierung => DOIF => Thema gestartet von: eddy242 am 13 Oktober 2022, 10:33:40

Titel: uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: eddy242 am 13 Oktober 2022, 10:33:40
Hallo zusammen,

folgender Code funktioniert prima (uiState). Die $_recommendList und $_onoffList enthalten jeweils ca. 8 bzw. 14 Elemente. Ich würde gerne erreichen, dass nach 5 Elementen eine neue Zeile begonnen wird. Ich kann mir im Package eine Counterfunktion definieren, aber ich müsste innerhalb der FOR-Schleife eine Möglichkeit haben, abhängig vom Rückgabewert der Counterfkt ein "|" einzufügen oder eben auch nicht. Also ganz konkret, wird das "|" am Ende des Statements ICON($SELF_pickicon([$SELF:$_$2]))| eingefügt oder nicht. Ginge sowas?

{
  package ui_Table;           ## Package für uiTable-Funktionen

    sub $SELF_pickicon {
        my ($pos)=@_;
        my $icon="general_aus\@grey";

        if ($pos eq "keepOn" || $pos eq "switchOn" || $pos eq "on" ) {
            $icon="general_an\@green";
        } elsif ($pos eq "switchOff") {
            $icon="general_aus\@red";
        }
        return $icon;
    }

  $TABLE = "border-collapse:separate;border-spacing: 10px 1px;border-left-width:10px;border-right-width:10px";
}

style("Recommendation","Darkorange")|""
FOR (@{$_recommendList},"$_$1"|ICON($SELF_pickicon([$SELF:$_$2]))|)
style(" ","Darkorange")

style("Status Device","Darkorange")|""
FOR (@{$_onoffList},"$_$1"|ICON($SELF_pickicon([$SELF:$_$2]))|)
style(" ","Darkorange")
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: Damian am 13 Oktober 2022, 11:30:57
Du musst mir hier die ganze Definition posten, also mit den beiden Array-Listen: $_recommendList und $_onoffList
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: eddy242 am 13 Oktober 2022, 13:08:44
Gerne, auch wenn sich mir nicht ganz erschließt wie das hilft, denn der Zeilenumbruch hat ja nichts mit dem Array als solches zu tun. Das gesamte DOIF hat ca. 600 Zeilen und wird bei Dir sicher nicht 1:1 laufen wegen der gerätespezifischen Anpassungen. Ich paste mal hier den Teil, wie die beiden Arrays befüllt werden. Aber nochmal: es geht ja nicht darum, dass der Code nicht funktioniert. Da ist alles prima. Auch der uiState funktioniert prima. Es geht nur um die Frage, ob ich einen Zeilenumbruch mit Hilfe einer Prozedur auslösen kann.


subs  {
    ###########################################################################################
    ### Lokale Helper Variablen ###############################################################
    ###########################################################################################
    my @params;
    my @rawData;
    my $temp;
    my @tempArray;
    my $now = time();

    ###########################################################################################
    ### Globale Variablen #####################################################################
    ###########################################################################################
   
    ## Code Deleted
    ## Code Deleted
    ## Code Deleted

    ## Consumer Name, Peak, Normal - Zahlen in Watt
    @params = qw/Known Peak Normal CalcRecommend ReadingActual                          ReadingRecommend      WaitTimeNormal WaitTimeNow PriorityVsCar/;
    @rawData = qw/
        Sauna               0 7000    500     0 consumption.assumed.sauna               0                                         0     0 0
        Ofen                0 5000    800     0 consumption.assumed.ofen                0                                         0     0 0
        Kueche              0 3000    500     0 consumption.assumed.kueche              0                                         0     0 0
        Unknown             0 100     100     0 consumption.assumed.unknown             0                                         0     0 0
        Lampen              1 100     8       0 consumption.assumed.lampen              0                                         0     0 0
        Kleinkram           1 0       0       0 consumption.measured.kleinkram          0                                         0     0 0
        Heizung             1 300     300     0 consumption.assumed.heizung             0                                         0     0 0
        Grundwasserpumpe    1 1000    1000    1 consumption.assumed.grundwasserpumpe    consumption.recommend.grundwasserpumpe   990  990 1
        Bewaesserung        1 1000    1000    1 consumption.assumed.bewaesserungspumpe  consumption.recommend.bewaesserungspumpe 930  930 1
        Klima               1 4000    800     1 consumption.assumed.klima               consumption.recommend.klima              900  900 2
        LuftTrocknerWkst    1 250     250     1 consumption.measured.lufttrocknerwkst   consumption.recommend.lufttrocknerwkst   780  780 3
        LuftTrocknerHobby   1 250     250     1 consumption.measured.lufttrocknerhobby  consumption.recommend.lufttrocknerhobby  730  730 3
    /;

    for (my $i=0; $i < @rawData; $i+=(@params+1)) {
        for (my $j=0; $j < @params; $j++) {
            $_consumers{$rawData[$i]}{$params[$j]} = $rawData[$i+$j+1];
        }
    }

    ## Code Deleted
    ## Code Deleted
    ## Code Deleted

    ## nun gehen wir alle Unique-Values (aka Consumer) durch und erzeugen das Array für die UITable
    foreach (sort keys %{ $_consumers }) {
        push (@{$_onoffList},["$_",$_consumers{$_}{ReadingActual}.".mode"]);
        push (@{$_recommendList},["$_",$_consumers{$_}{ReadingRecommend}]) if ($_consumers{$_}{ReadingRecommend} ne "0");
        Log3("$SELF", 5, "$SELF: _onoffList: $_ $_consumers{$_}{ReadingActual}.mode");
        Log3("$SELF", 5, "$SELF: _recommendList: $_ $_consumers{$_}{ReadingRecommend}");
    }

    ## Code Deleted
    ## Code Deleted
    ## Code Deleted

}
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: Damian am 13 Oktober 2022, 13:39:29
Also die Tabelle ist zwar dynamisch aufbaubar, aber nach der Definition statisch. Dh. der Tabellenaufbau kann nicht geändert werden, ohne eine Neudefinition (defmod). Ich befürchte, dass eine "dynamische Definition" so, wie du es willst, nicht möglich ist, da hier ein eigener Parser den Aufbau bei der Definition auswertet.

Ich arbeite immer so, dass ich das Array zeilenweise aufbaue, ein Element eines zweidimensionalen Arrays ist also eine Zeile der Tabelle und das entspricht im Abstrakten einer Szene mit beliebig vielen Attributen pro Szene (Spalten), siehe hier die Beispiele:

https://wiki.fhem.de/wiki/DOIF/Automatisierung#Beschattungssteuerung_abh.C3.A4ngig_von_der_Zimmertemperatur_und_Sonneneinstrahlung_f.C3.BCr_mehrere_Szenarien_mit_Visualisierung

oder

https://wiki.fhem.de/wiki/DOIF/Automatisierung#Steuerung_von_Raumthermostaten_f.C3.BCr_mehrere_R.C3.A4ume_mit_GUI

vielleicht kannst du es auch so aufbauen.

Edit: Im zweiten Beispiel habe ich sogar zwei FOR-Schleifen ineinander geschachtelt, das Zeilenende erreiche ich durch ein "" hinter dem |

ZitatFOR (@{$_sc},\
  ("$1$1"|\
    card([$1$2:measured-temp:col1d],undef,\
         [$1$3:state] eq "off" ? "sani_floor_heating_neutral\@silver" : "sani_floor_heating\@red" ,15,25,\
         undef,undef,"°C",\&temp_hue,"1,,fill:silver","130,1,1,1,1,,200",\
         undef,undef,[$1$3:state:col1d:$_ eq "on" ? 1:0],0,5,0,0,"I-O",\&onoff_hue,"0,,fill:silver")|\
    "Modus:".widget([$SELF:$1$1_mode],"select,auto,off"),,"aktuell:".widget([$1$2:desired-temp],"selectnumbers,18,0.5,22,1,lin","set")|\
    FOR(@{$_Timer},\
      ("AT: ".widget([$SELF:$1$1_temp_at_$2],"selectnumbers,18,0.5,22,1,lin"),,"WE: ".widget([$SELF:$1$1_temp_we_$2],"selectnumbers,18,0.5,22,1,lin")|))\
    ""\
  )\
)
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: eddy242 am 14 Oktober 2022, 18:25:19
Ich habs gepackt. So geht es!


defmod di_tester DOIF init {\
    my $constItemsPerColumn = 5;;\
    my $elementCount        = int(rand(25))+11;;\
    $_uiStateArrays      = int($elementCount/$constItemsPerColumn)+1;;\
    my $processed           = 0;;\
    my $readingName;;\
    my @tempArray;;\
\
    fhem("deletereading $SELF .*");;\
    Log3("$SELF", 5, "$SELF: Anzahl Elemente: $elementCount, Anzahl Arrays: $_uiStateArrays");;\
    \
    for (my $i=0;; $i<$_uiStateArrays;; $i++) {\
      @tempArray = ();;\
      for (my $j=0;; $j<$constItemsPerColumn;; $j++) {\
        $processed    = $i*$constItemsPerColumn+$j;;\
        $readingName  = "zustand_".sprintf("%02d", $processed);;\
\
        last if($processed==$elementCount);;\
\
        push(@tempArray, $readingName);;\
        push(@{$_zustaende},$readingName);; \
        \
        Log3("$SELF", 5, "$SELF: i: $i, j: $j, processed: $processed, readingName: $readingName");;\
      }\
      @{$_uiStateList{$i}} = @tempArray;; \
    }\
\
    for (my $i=0;; $i<$_uiStateArrays-1;; $i++) {\
      Log3("$SELF", 5, "$SELF: readingName: $_") foreach(@{$_uiStateList{$i}});;\
    }  \
}\
\
setter {\
[+15];;\
set_Reading("$_",("on","off")[int(rand(2))],1) foreach (@{$_zustaende}) ;;\
}\
\

attr di_tester disable 0
attr di_tester room Labor
attr di_tester uiState {\
    package ui_Table;;\
    $TABLE = "border-collapse: separate;;border-spacing: 10px 1px";; \
}\
\
##$TC{0,2,4,6} = "style='font-size: normal;;text-align:right;;color: DarkOrange'";;\
\
FOR (0..$_uiStateArrays-1,\
FOR(@{$_uiStateList{$1}},\
"$2"|[$SELF:$2,"off"]| icon([$SELF:$2,"off"]) |\
)|""\
)\

attr di_tester verbose 5

Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: Damian am 14 Oktober 2022, 21:40:17
Das Problem ist, dass ich beim FOR-Befehl keine Indizierung vorgesehen habe.

Man kann also nicht mit Zahlen hantieren, sondern nur mit Platzhaltern.

Daher kann man z. B. nicht einzelne Elemente eines Arrays durchzählen, sondern muss sie einzeln angeben mit $_$1, $_$2, ... (entspricht $1$1, $1$2, ...)

In deinem Beispiel ist die Anzahl der Spalten festgelegt (5), daher sollte man mit :

FOR (@{$_uiStateList},"$_$1"|"$_$2"|"$_$3"|"$_$4"|"$_$5")

die Tabelle darstellen können.

Flexibler wäre man mit einem echten Perl-for-Befehl, aber dieser ist an dieser Stelle im uiTable/uiState-Attribut nicht vorgesehen. Meine Idee war seinerzeit für den Nichtprogrammierer es einfacher zu machen, daher die Platzhalter und keine Laufvariablen mit Indizierungen.

Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: eddy242 am 14 Oktober 2022, 21:43:25
Ich hab gerade meinen vorigen Beitrag editiert. GEHT!!!
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: Damian am 14 Oktober 2022, 21:48:33
Zitat von: eddy242 am 14 Oktober 2022, 21:43:25
Ich hab gerade meinen vorigen Beitrag editiert. GEHT!!!
gut, aber nur deswegen, weil du die Indizierung über einen Hash realisiert hast :)

Edit: Dann hast du schon mehr erreicht, als ich vorgesehen hatte
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: eddy242 am 14 Oktober 2022, 21:51:30
reicht mir :-) danke für den Support und das grossartige Modul
Titel: Antw:uiState/uiTable programmatisch neue Zeile erzwingen?
Beitrag von: Damian am 14 Oktober 2022, 21:57:21
Zitat von: eddy242 am 14 Oktober 2022, 21:51:30
reicht mir :-) danke für den Support und das grossartige Modul

Es ist immer wieder spannend zu sehen, was die Leute so alles aus dem Modul rausholen :)