iobroker.alias-workbench 0.9.11 → 0.9.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -4
- package/admin/css/werkbank.css +42 -6
- package/admin/js/detail.js +10 -4
- package/admin/js/entwurf.js +404 -188
- package/admin/js/enums.js +2 -2
- package/admin/js/ergebnis.js +122 -22
- package/admin/js/erkennung.js +7 -0
- package/admin/js/mqtt.js +52 -3
- package/admin/js/objekte.js +13 -0
- package/admin/js/pruefungen.js +9 -6
- package/admin/js/schreiben.js +54 -25
- package/admin/js/werte.js +1 -1
- package/admin/js/zielleiste.js +8 -2
- package/admin/js/zuordnung.js +40 -12
- package/admin/js/zustandsliste.js +34 -17
- package/admin/sprachen/de.json +13 -10
- package/admin/sprachen/en.json +13 -10
- package/admin/tab.html +44 -44
- package/admin/vorlagen/messpunkt.json +1 -0
- package/admin/vorlagen/tasmota-lampe.json +1 -0
- package/admin/vorlagen/tasmota-mehrfach.json +1 -0
- package/admin/vorlagen/tasmota-steckdose.json +1 -0
- package/io-package.json +25 -16
- package/package.json +1 -1
package/admin/js/entwurf.js
CHANGED
|
@@ -12,7 +12,7 @@ import { kindZustaende, aliasQuellen, holeWerte,
|
|
|
12
12
|
mitVorspann, schreibQuelle, zeileAusAlias
|
|
13
13
|
} from './werte.js';
|
|
14
14
|
import { erkenneEntwurf } from './erkennung.js';
|
|
15
|
-
import { vorschlag , pruefeVorlage, zeigeAbozahl } from './vorlagen.js';
|
|
15
|
+
import { vorschlag , pruefeVorlage, zeigeAbozahl, setzeInstanz } from './vorlagen.js';
|
|
16
16
|
|
|
17
17
|
import { zeichneErgebnis } from './ergebnis.js';
|
|
18
18
|
|
|
@@ -75,6 +75,23 @@ export function baueEntwurf(kanal) {
|
|
|
75
75
|
kindZustaende(kanal).forEach(function (id) {
|
|
76
76
|
var o = S.objects[id], c = o.common || {}, a = c.alias || {}, q = aliasQuellen(o);
|
|
77
77
|
var kurzName = id.slice(kanal.length + 1);
|
|
78
|
+
/* Ein Knopfdruck hat keinen Zustand — sonst hat auch ein
|
|
79
|
+
nur-schreibender Punkt einen.
|
|
80
|
+
|
|
81
|
+
`read: false` allein reicht als Merkmal nicht. Homematic vergibt es
|
|
82
|
+
fuer beides: fuer `OLD_LEVEL` und `RAMP_STOP` (Gerätebeschreibung
|
|
83
|
+
`TYPE: ACTION` — ein Tastendruck) ebenso wie fuer `ON_TIME` und
|
|
84
|
+
`RAMP_TIME` (`TYPE: FLOAT` — eine Vorgabe fuer den naechsten
|
|
85
|
+
Schaltbefehl, die stehen bleibt). Nur beim ersten ist eine
|
|
86
|
+
Lesequelle sinnlos.
|
|
87
|
+
|
|
88
|
+
Nachgemessen am 17.09.2026: einen Alias auf `1.ON_TIME` gelegt, die
|
|
89
|
+
QUELLE direkt auf 30 gesetzt — der Alias zeigte 30. `read: false`
|
|
90
|
+
sperrt das Lesen also nicht, es sagt nur, dass von allein nichts
|
|
91
|
+
kommt. Wer den Wert setzt, will ihn auch sehen. */
|
|
92
|
+
var nat = o.native || {};
|
|
93
|
+
var istTaster = (c.read === false && !!c.write) &&
|
|
94
|
+
(nat.TYPE === 'ACTION' || /^button/.test(String(c.role || '')));
|
|
78
95
|
e.states.push({
|
|
79
96
|
/* Bei einer Quelle wird aus stat.POWER der Zustand stat_POWER —
|
|
80
97
|
ein Punkt im Namen wuerde sonst eine Unterebene im Alias
|
|
@@ -109,7 +126,32 @@ export function baueEntwurf(kanal) {
|
|
|
109
126
|
nichts abzuholen ist (K23). Dieselbe Ablesung wie in
|
|
110
127
|
`zeileAusAlias` — sonst zeigte „Alias bearbeiten" eine Quelle,
|
|
111
128
|
die „Alias anlegen" nie eingetragen hat. */
|
|
112
|
-
|
|
129
|
+
/* An der Quelle ist der Punkt seine eigene Lesequelle — ausser er
|
|
130
|
+
sagt selbst, dass dort nichts ankommt.
|
|
131
|
+
|
|
132
|
+
`read: false` heisst nicht „gesperrt": lesen kann den Punkt
|
|
133
|
+
jeder, er liegt in der Datenbank. Es heisst, dass nie eine
|
|
134
|
+
Aktualisierung eintrifft. Was drinsteht, ist der Wert, den
|
|
135
|
+
zuletzt jemand hineingeschrieben hat — meist der Anfangswert
|
|
136
|
+
beim Adapterstart. Ein Alias, der daraus liest, zeigt fuer immer
|
|
137
|
+
diesen einen Wert und sieht dabei aus wie ein Messwert.
|
|
138
|
+
|
|
139
|
+
Bei Homematic steht es in der Geraetebeschreibung: `OPERATIONS`
|
|
140
|
+
ist eine Bitmaske (1 lesen, 2 schreiben, 4 meldet von selbst),
|
|
141
|
+
und `2.OLD_LEVEL` traegt 2 bei `TYPE: ACTION` — ein Knopfdruck,
|
|
142
|
+
kein Zustand. Am Wohnzimmer_Dimmer sind das 15 von 43 Zeilen,
|
|
143
|
+
jede davon las und schrieb bisher auf denselben Befehlspunkt
|
|
144
|
+
(Ricardo, 17.09.2026).
|
|
145
|
+
|
|
146
|
+
Ist der Punkt beschreibbar, wird daraus also ein Taster: keine
|
|
147
|
+
Lesequelle, nur ein Schreibziel. Genau die Form, die K23/K26 am
|
|
148
|
+
Rollladen-STOP beschreiben — der Alias bekommt `read: false`,
|
|
149
|
+
und vis, Alexa und matter zeichnen einen Knopf statt eines
|
|
150
|
+
Schalters, der ewig auf „aus" steht. Kann der Punkt auch nicht
|
|
151
|
+
schreiben, bleibt er, wie er ist: dann ist die fehlende Meldung
|
|
152
|
+
wirklich ein Mangel, und die Marke sagt es. */
|
|
153
|
+
srcR: istAlias ? ((c.read === false && q.einfach) ? '' : (q.read || ''))
|
|
154
|
+
: (istTaster ? '' : id),
|
|
113
155
|
/* Steht in `common.alias.id` ein einzelner Text, gilt er fuer Lesen
|
|
114
156
|
UND Schreiben - dann ist die Schreibquelle dieselbe wie die
|
|
115
157
|
Lesequelle. Hier stand frueher eine leere Zeichenkette, gedacht
|
|
@@ -565,8 +607,30 @@ export function steuerKanaele(dev) {
|
|
|
565
607
|
if (!S.objects[id] || S.objects[id].type !== 'channel') { return; }
|
|
566
608
|
var e2 = baueEntwurf(id);
|
|
567
609
|
if (!e2.states.length) { return; }
|
|
568
|
-
|
|
569
|
-
|
|
610
|
+
/* Auch Informationskanaele zaehlen mit (Ricardo, 17.09.2026).
|
|
611
|
+
|
|
612
|
+
Vorher fielen sie hier heraus — und damit sagte der Knopf am
|
|
613
|
+
Geschirrspueler „3 Stueck", waehrend im Baum daneben sechs Kanaele
|
|
614
|
+
standen. Wer `general` einzeln anklickt, bekommt laengst einen
|
|
615
|
+
Entwurf („Information ✓ 7/14 belegt") und kann ihn anlegen; nur
|
|
616
|
+
der Sammelweg liess ihn aus. Zwei Wege, zwei Antworten am selben
|
|
617
|
+
Geraet.
|
|
618
|
+
|
|
619
|
+
Der Zweck dieses Wegs ist, die Struktur der Quelle abzubilden —
|
|
620
|
+
dann gehoert jeder Kanal hinein, der fuer sich einen Entwurf
|
|
621
|
+
ergibt, und nicht nur der, den der Detektor fuer ein Geraet haelt.
|
|
622
|
+
Nebenbei faellt damit das Verteilen der „gemeinsamen" Kanaele in
|
|
623
|
+
den meisten Faellen weg: was einen eigenen Ordner bekommt, muss
|
|
624
|
+
nicht mehr in jeden anderen hineinkopiert werden (produktiv
|
|
625
|
+
gemessen: beim Maeher wanderten 206 Rohdatenpunkte in jeden der
|
|
626
|
+
vier Entwuerfe, beim Shelly SHEM-3 galten die drei Emeter-Phasen
|
|
627
|
+
als „gemeinsam" statt als eigene Kanaele). */
|
|
628
|
+
var alle = erkenneEntwurf(e2, null);
|
|
629
|
+
if (!alle.length) { return; }
|
|
630
|
+
/* Ein Kanal, der ein Geraet ergibt, wird danach benannt; nur wenn er
|
|
631
|
+
nichts als Information hergibt, gilt der info-Fund. */
|
|
632
|
+
var f = alle.filter(function (x) { return x.type !== 'info'; });
|
|
633
|
+
if (!f.length) { f = alle; }
|
|
570
634
|
/* Nur zaehlen, was einen Pflichtplatz wirklich besetzt — sonst
|
|
571
635
|
gilt jeder Kanal mit irgendeinem Messwert als Geraet. */
|
|
572
636
|
/* Alles, was der Kanal an Plaetzen belegt — nicht nur die
|
|
@@ -590,92 +654,131 @@ export function steuerKanaele(dev) {
|
|
|
590
654
|
return raus;
|
|
591
655
|
}
|
|
592
656
|
|
|
593
|
-
/*
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
657
|
+
/* Welche Unterordner entstehen, wenn die Struktur der Quelle abgebildet
|
|
658
|
+
wird — und zwar nach den HAKEN, nicht nach einer Vermutung.
|
|
659
|
+
|
|
660
|
+
Bis 17.09.2026 baute dieser Weg je Kanal einen frischen Entwurf und
|
|
661
|
+
hakte an, was das Muster des Kanals hergab. Damit entstand, was
|
|
662
|
+
niemand ausgewaehlt hatte: am `MISCHKANAL` bekam der Wartungskanal
|
|
663
|
+
`LOW_BAT`, `RSSI_DEVICE` und `UNREACH`, obwohl oben nur `UNREACH`
|
|
664
|
+
angehakt war. Umgekehrt fiel weg, was jemand von Hand angehakt hatte —
|
|
665
|
+
der Entwurf wurde ja gar nicht gelesen (Ricardo, 17.09.2026).
|
|
666
|
+
|
|
667
|
+
Jetzt gilt: was angehakt ist, bestimmt beides — welche Ordner es gibt
|
|
668
|
+
und was darin steht. Ein Kanal ohne angehakte Zeile kommt nicht vor.
|
|
669
|
+
Zeilen, deren Quelle direkt am Geraet haengt oder von woanders kommt,
|
|
670
|
+
bleiben im Behaelter selbst (`eigen`). */
|
|
671
|
+
export function kanalGruppen(e) {
|
|
672
|
+
if (!e || !e.kanal || e.kanal.indexOf('alias.') === 0) { return []; }
|
|
673
|
+
var basis = e.kanal + '.';
|
|
674
|
+
var gruppen = [], nach = {}, eigen = [];
|
|
675
|
+
(e.states || []).forEach(function (st) {
|
|
676
|
+
if (!st.on || !st.n) { return; }
|
|
677
|
+
var quelle = st.srcR || st.srcW || '';
|
|
678
|
+
var rest = (quelle.indexOf(basis) === 0) ? quelle.slice(basis.length) : '';
|
|
679
|
+
var p = rest.indexOf('.');
|
|
680
|
+
/* Ohne Punkt liegt der Punkt direkt am Geraet; ohne `rest` liest die
|
|
681
|
+
Zeile von woanders. Beides gehoert in den Behaelter, nicht in einen
|
|
682
|
+
erfundenen Unterordner. */
|
|
683
|
+
if (!rest || p < 0) { eigen.push(st); return; }
|
|
684
|
+
var kid = e.kanal + '.' + rest.slice(0, p);
|
|
685
|
+
if (!S.objects[kid]) { eigen.push(st); return; }
|
|
686
|
+
if (!nach[kid]) {
|
|
687
|
+
var kn = eigenerKanalName(kid);
|
|
688
|
+
var kurz = rest.slice(0, p);
|
|
689
|
+
nach[kid] = { id: kid, kurz: kurz, name: kn || kurz,
|
|
690
|
+
kennung: kennungtauglich(kn || '') || kurz, zeilen: [] };
|
|
691
|
+
gruppen.push(nach[kid]);
|
|
692
|
+
}
|
|
693
|
+
nach[kid].zeilen.push(st);
|
|
612
694
|
});
|
|
613
|
-
|
|
695
|
+
if (eigen.length) {
|
|
696
|
+
gruppen.unshift({ id: e.kanal, kurz: '', name: '', kennung: '',
|
|
697
|
+
eigen: true, zeilen: eigen });
|
|
698
|
+
}
|
|
699
|
+
return gruppen;
|
|
614
700
|
}
|
|
615
701
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
702
|
+
/* Der Entwurf ohne jede Vorlage — alle Punkte des Geraets, alle
|
|
703
|
+
angehakt, dazu das erkannte Muster als Anhaltspunkt.
|
|
704
|
+
|
|
705
|
+
Gebraucht fuer „— keine Vorlage —" in der Vorlagenwahl. Bis zum
|
|
706
|
+
17.09.2026 liess sich eine erkannte Vorlage nicht abwaehlen: der erste
|
|
707
|
+
Eintrag der Liste war eine blosse Ueberschrift, sein Wert leer, und der
|
|
708
|
+
Zweig stieg bei leerem Wert sofort aus. Wechseln ging, weglassen nicht
|
|
709
|
+
(Ricardo).
|
|
710
|
+
|
|
711
|
+
Zuerst hakte dieser Weg an, was im erkannten Muster einen Platz hat.
|
|
712
|
+
Das ging an zwei GLEICHARTIGEN Kanaelen schief: am `hm.ZWEIKANAL`
|
|
713
|
+
nahm der Detektor einen der beiden Ausgaenge — und zwar den zweiten —,
|
|
714
|
+
`Licht_Esstisch` stand angehakt da und `Licht_Bar` leer. Welcher es
|
|
715
|
+
wird, ist Zufall, und danach zu raten ist nicht die Aufgabe eines
|
|
716
|
+
Entwurfs OHNE Vorlage. Wer sie abwaehlt, will die Punkte selbst
|
|
717
|
+
aussuchen; also stehen alle da (Ricardo, 17.09.2026). */
|
|
718
|
+
export function rohEntwurf(id) {
|
|
619
719
|
var e2 = baueEntwurf(id);
|
|
620
720
|
if (!e2.states.length) { return null; }
|
|
621
|
-
|
|
622
|
-
/* Die Wartungsdaten des gemeinsamen Kanals gehoeren in jedes Geraet,
|
|
623
|
-
nicht in eines davon oder in einen Kanal daneben.
|
|
624
|
-
|
|
625
|
-
Ein Alias-Punkt ist ein Verweis, kein Wert — zwei Geraete duerfen
|
|
626
|
-
auf dieselbe Quelle zeigen, und der Batteriestand des Funkmoduls
|
|
627
|
-
gilt fuer beide Lampen gleichermassen. Lagerte man ihn in einen
|
|
628
|
-
eigenen `info`-Kanal aus, haette keine der beiden eine
|
|
629
|
-
Batteriewarnung: der Detektor schaut nur innerhalb eines Kanals.
|
|
630
|
-
Genau so macht es die Tasmota-Mehrfachvorlage mit RSSI — jeder der
|
|
631
|
-
vier Ausgaenge bekommt seinen eigenen, alle lesen aus tele/STATE. */
|
|
632
|
-
(gemeinsam || []).forEach(function (gid) {
|
|
633
|
-
kindZustaende(gid).forEach(function (qid) {
|
|
634
|
-
var o = S.objects[qid]; if (!o) { return; }
|
|
635
|
-
var c = o.common || {};
|
|
636
|
-
var kurz = qid.slice(gid.length + 1).replace(/\./g, '_');
|
|
637
|
-
/* Traegt der Kanal selbst schon einen Punkt dieses Namens, den
|
|
638
|
-
gemeinsamen unterscheidbar machen. */
|
|
639
|
-
if (e2.states.some(function (x) { return x.n === kurz; })) {
|
|
640
|
-
kurz = gid.split('.').pop() + '_' + kurz;
|
|
641
|
-
}
|
|
642
|
-
e2.states.push({
|
|
643
|
-
n: kurz, on: false, role: c.role || '', typ: c.type || '',
|
|
644
|
-
unit: c.unit || '', states: c.states || undefined, wr: false,
|
|
645
|
-
srcR: qid, srcW: '', f: '', fw: '', caption: '', manuell: false,
|
|
646
|
-
gemeinsam: true
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
});
|
|
650
721
|
var f = erkenneEntwurf(e2, null);
|
|
651
722
|
e2.wantAuto = f.length ? f[0].type : null;
|
|
652
723
|
e2.want = e2.wantAuto;
|
|
653
|
-
var funde = e2.want ? erkenneEntwurf(e2, e2.want) : f;
|
|
654
|
-
var haupt = funde.length ? funde[0] : null;
|
|
655
|
-
var platz = {};
|
|
656
|
-
if (haupt) {
|
|
657
|
-
haupt.states.forEach(function (x) {
|
|
658
|
-
if (x.id) { platz[x.id.slice(id.length + 1)] = x.name; }
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
if (Object.keys(platz).length) {
|
|
662
|
-
e2.states.forEach(function (st) { st.on = !!platz[st.n]; });
|
|
663
|
-
}
|
|
664
|
-
/* Zum Schluss die Wartungspunkte, die auf der Geraeteebene einen Platz
|
|
665
|
-
gefunden haben. Warum nicht einfach den Detektor auf dem Kanal
|
|
666
|
-
fragen? Weil er dort nur SET und WORKING zuordnet, obwohl dieselben
|
|
667
|
-
Punkte mit denselben Rollen im Abbild stehen — auf der Geraeteebene
|
|
668
|
-
findet er LOWBAT, UNREACH und RSSI. Die Zuordnung von dort ist die
|
|
669
|
-
belastbare; sie stammt aus demselben Detektor, nur aus dem Lauf, der
|
|
670
|
-
sie sieht. */
|
|
671
|
-
if (gemAn) {
|
|
672
|
-
e2.states.forEach(function (st) {
|
|
673
|
-
if (st.gemeinsam && gemAn[st.srcR]) { st.on = true; }
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
724
|
return merkeHakenVorgabe(e2);
|
|
677
725
|
}
|
|
678
726
|
|
|
727
|
+
/* Wohin die Unterordner kommen — der Behaelter fuer das Geraet.
|
|
728
|
+
|
|
729
|
+
Beim ersten Mal ist das schlicht `zielOrdner` plus Geraetename. Nach
|
|
730
|
+
dem Aufteilen gibt es aber mehrere Aliase zu derselben Quelle, je Kanal
|
|
731
|
+
einen, und `aliasFuer` liefert einen davon — den mit den meisten
|
|
732
|
+
Punkten. Der Behaelter waere dann dieser Unterordner, und der zweite
|
|
733
|
+
Druck haengte alles eine Ebene tiefer: aus
|
|
734
|
+
`alias.0.Geschirrspueler.Befehle` wurde
|
|
735
|
+
`alias.0.Geschirrspueler.Allgemeine_Informationen.Befehle`, beim
|
|
736
|
+
dritten Druck noch eine Ebene tiefer (17.09.2026).
|
|
737
|
+
|
|
738
|
+
Woran man es erkennt: das gefundene Ziel fuehrt in `native.quelle`
|
|
739
|
+
einen KANAL der Quelle, nicht das Geraet. Dann ist es selbst ein
|
|
740
|
+
Unterordner aus einem frueheren Durchgang, und der Behaelter ist sein
|
|
741
|
+
Elternknoten. */
|
|
742
|
+
export function aufteilBehaelter(e) {
|
|
743
|
+
var ordner = (e.zielOrdner || 'alias.0') + '.' + e.zielName;
|
|
744
|
+
var ziel = e.ziel;
|
|
745
|
+
if (!ziel) { return ordner; }
|
|
746
|
+
var q = ((S.objects[ziel] && S.objects[ziel].native) || {}).quelle;
|
|
747
|
+
if (q && e.kanal && q.indexOf(e.kanal + '.') === 0) {
|
|
748
|
+
var p = ziel.lastIndexOf('.');
|
|
749
|
+
if (p > 0) { return ziel.slice(0, p); }
|
|
750
|
+
}
|
|
751
|
+
return ordner;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* Aus einer Gruppe wird ein Entwurf: dieselben Zeilen, nur auf den Kanal
|
|
755
|
+
bezogen benannt. Was jemand an einer Zeile geaendert hat — Rolle, Typ,
|
|
756
|
+
Einheit, Formel, Beschriftung — wandert unveraendert mit; es waere
|
|
757
|
+
sonderbar, eine Handeingabe beim Aufteilen wegzuwerfen. */
|
|
758
|
+
export function teilEntwurf(e, g) {
|
|
759
|
+
var v = { kanal: g.id, states: [], want: null, wantAuto: null,
|
|
760
|
+
alleMuster: false, raum: e.raum, funktion: e.funktion };
|
|
761
|
+
g.zeilen.forEach(function (st) {
|
|
762
|
+
var k = JSON.parse(JSON.stringify(st));
|
|
763
|
+
/* Der Name wird auf den Kanal bezogen: aus `commands_BSH_…` wird im
|
|
764
|
+
Kanal `Befehle` schlicht `BSH_…`. Gekuerzt wird ueber die Quelle —
|
|
765
|
+
und bei einem Taster ist das die SCHREIBquelle, denn `srcR` ist
|
|
766
|
+
dort leer. Ohne diesen Zusatz behielt genau diese Zeile ihren
|
|
767
|
+
langen Namen: `…Befehle.commands_BSH_Common_Command_StopProgram`
|
|
768
|
+
neben `…Allgemeine_Informationen.brand` (17.09.2026). */
|
|
769
|
+
var quelle = st.srcR || st.srcW || '';
|
|
770
|
+
if (!g.eigen && quelle && quelle.indexOf(g.id + '.') === 0) {
|
|
771
|
+
k.n = quelle.slice(g.id.length + 1).replace(/\./g, '_');
|
|
772
|
+
}
|
|
773
|
+
k.on = true;
|
|
774
|
+
v.states.push(k);
|
|
775
|
+
});
|
|
776
|
+
var f = erkenneEntwurf(v, null);
|
|
777
|
+
v.wantAuto = f.length ? f[0].type : null;
|
|
778
|
+
v.want = v.wantAuto;
|
|
779
|
+
return merkeHakenVorgabe(v);
|
|
780
|
+
}
|
|
781
|
+
|
|
679
782
|
/* Alle laufenden Abos abmelden.
|
|
680
783
|
|
|
681
784
|
Stand nur in `waehle` — und damit meldete kein einziger der Wege ab,
|
|
@@ -690,6 +793,108 @@ export function aboLoesen() {
|
|
|
690
793
|
zeigeAbozahl();
|
|
691
794
|
}
|
|
692
795
|
|
|
796
|
+
/* Die Quellen eines Entwurfs - alles, woraus eine Zeile liest oder
|
|
797
|
+
wohin sie schreibt. */
|
|
798
|
+
export function quellenVonEntwurf(e) {
|
|
799
|
+
var raus = [];
|
|
800
|
+
((e && e.states) || []).forEach(function (s) {
|
|
801
|
+
if (s.srcR) { raus.push(s.srcR); }
|
|
802
|
+
if (s.srcW) { raus.push(s.srcW); }
|
|
803
|
+
});
|
|
804
|
+
return raus;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/* Abonniert Quellen dazu, die rechts angezeigt werden.
|
|
808
|
+
|
|
809
|
+
Ergaenzt nur: was ein laufendes Muster schon deckt, kommt nicht noch
|
|
810
|
+
einmal dazu, doppelt rufen schadet also nicht. Die Regeln stammen aus
|
|
811
|
+
`waehle`, wo sie vorher fest verbaut waren und nur am Alias griffen.
|
|
812
|
+
|
|
813
|
+
`quellenVerteilung` fasst zusammen, was die rechte Seite als
|
|
814
|
+
„Quellen" zeigt — dafuer bildet sie den ELTERNknoten jeder Quelle.
|
|
815
|
+
Bei einem flachen MQTT-Geraet ist das der halbe Adapter: gemessen
|
|
816
|
+
09.09.2026 wurde daraus `mqtt-client.0.*` mit 322 Objekten, an einem
|
|
817
|
+
einzigen Alias. Abonniert wird deshalb der Kanal jeder wirklich
|
|
818
|
+
gelesenen Quelle. */
|
|
819
|
+
export function aboErgaenzen(quellen) {
|
|
820
|
+
var muster = (S.abo || []).slice();
|
|
821
|
+
var vorher = muster.length;
|
|
822
|
+
var drinSchon = function (was) {
|
|
823
|
+
return muster.some(function (m0) {
|
|
824
|
+
var p0 = m0.slice(-2) === '.*' ? m0.slice(0, -2) : m0;
|
|
825
|
+
return was === p0 || was.indexOf(p0 + '.') === 0;
|
|
826
|
+
});
|
|
827
|
+
};
|
|
828
|
+
var offen = [];
|
|
829
|
+
(quellen || []).forEach(function (x) {
|
|
830
|
+
if (x && !drinSchon(x) && offen.indexOf(x) === -1) { offen.push(x); }
|
|
831
|
+
});
|
|
832
|
+
if (!offen.length) { zeigeAbozahl(); return; }
|
|
833
|
+
|
|
834
|
+
var kanaele = [];
|
|
835
|
+
offen.forEach(function (x) {
|
|
836
|
+
var t = String(x).split('.');
|
|
837
|
+
t.pop();
|
|
838
|
+
var kn = t.join('.');
|
|
839
|
+
if (kn && kanaele.indexOf(kn) === -1) { kanaele.push(kn); }
|
|
840
|
+
});
|
|
841
|
+
var SCHWELLE = 30;
|
|
842
|
+
var wieBreit = function (knoten) {
|
|
843
|
+
var n = 0;
|
|
844
|
+
S.keysSorted.forEach(function (k0) { if (k0.indexOf(knoten + '.') === 0) { n++; } });
|
|
845
|
+
return n;
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
/* Sparten desselben Geraets zu einem Muster zusammenfassen.
|
|
849
|
+
|
|
850
|
+
Ein Tasmota-Alias liest aus `…Licht.stat`, `…Licht.tele` und
|
|
851
|
+
`…Licht.cmnd` — drei Kanaele, ein Geraet, und in der Kopfleiste
|
|
852
|
+
gehoert dort „ein Abo" zu stehen, nicht drei. Zusammengefasst wird
|
|
853
|
+
aber nur, wo wirklich MEHRERE Kanaele unter demselben Knoten
|
|
854
|
+
haengen: Sonst waere aus `…Garten.Weihnachten_aussen` schlicht
|
|
855
|
+
`…Garten` geworden — breiter als noetig, ohne dass etwas
|
|
856
|
+
zusammenfaellt. */
|
|
857
|
+
for (var runde = 0; runde < 4; runde++) {
|
|
858
|
+
var unter = {};
|
|
859
|
+
kanaele.forEach(function (kn) {
|
|
860
|
+
var t = kn.split('.');
|
|
861
|
+
if (t.length <= 3) { return; }
|
|
862
|
+
var ob = t.slice(0, -1).join('.');
|
|
863
|
+
(unter[ob] = unter[ob] || []).push(kn);
|
|
864
|
+
});
|
|
865
|
+
var geaendert = false;
|
|
866
|
+
Object.keys(unter).forEach(function (ob) {
|
|
867
|
+
if (unter[ob].length < 2 || wieBreit(ob) > SCHWELLE) { return; }
|
|
868
|
+
kanaele = kanaele.filter(function (kn) { return unter[ob].indexOf(kn) === -1; });
|
|
869
|
+
if (kanaele.indexOf(ob) === -1) { kanaele.push(ob); }
|
|
870
|
+
geaendert = true;
|
|
871
|
+
});
|
|
872
|
+
if (!geaendert) { break; }
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/* Ein schmaler Kanal wird als Muster abonniert, ein breiter nicht.
|
|
876
|
+
|
|
877
|
+
Bei einem flachen Geraet IST der Kanal der breite Knoten: Die
|
|
878
|
+
Quelle `mqtt-client.0.SmartHome.Lavalampe_POWER` liegt direkt
|
|
879
|
+
unter `SmartHome`, und `SmartHome.*` sind 320 Objekte (gemessen
|
|
880
|
+
09.09.2026). Ab dieser Schwelle werden die Quellen einzeln
|
|
881
|
+
abonniert — ein paar Abos mehr, dafuer genau die, deren Werte auch
|
|
882
|
+
angezeigt werden. */
|
|
883
|
+
kanaele.forEach(function (kn) {
|
|
884
|
+
if (drinSchon(kn)) { return; }
|
|
885
|
+
if (wieBreit(kn) > SCHWELLE) { return; }
|
|
886
|
+
muster.push(kn + '.*');
|
|
887
|
+
});
|
|
888
|
+
offen.forEach(function (x) {
|
|
889
|
+
if (!drinSchon(x) && muster.indexOf(x) === -1) { muster.push(x); }
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
var neu = muster.slice(vorher);
|
|
893
|
+
S.abo = muster;
|
|
894
|
+
neu.forEach(function (m) { socket.emit('subscribe', m); });
|
|
895
|
+
zeigeAbozahl();
|
|
896
|
+
}
|
|
897
|
+
|
|
693
898
|
export function waehle(id, fertig) {
|
|
694
899
|
/* Wer links etwas anderes anklickt, will es rechts sehen - auch wenn
|
|
695
900
|
der Fokus noch in einem Feld der rechten Seite steht. `tipptGerade`
|
|
@@ -743,109 +948,28 @@ export function waehle(id, fertig) {
|
|
|
743
948
|
`alias.0.Solar.Balkon.Energie`, wo sich im Sekundentakt etwas
|
|
744
949
|
aendert, fiel es auf (Ricardo, 08.09.2026).
|
|
745
950
|
|
|
746
|
-
Deshalb am Alias zusaetzlich seine Quellen -
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
951
|
+
Deshalb am Alias zusaetzlich seine Quellen, und - seit dem
|
|
952
|
+
18.09.2026 - an der Quelle ebenso: dort ergaenzt `uebernehmeBestand`
|
|
953
|
+
die Zeilen des vorhandenen Alias, und die lesen oft woanders
|
|
954
|
+
(`Stromzaehler` zeigt drei Zeilen „aus Solar.Netz"). Die standen
|
|
955
|
+
nach dem ersten Abholen still, gemessen 428 W gegen 22 W am System
|
|
956
|
+
(J9). `aboErgaenzen` wird darum von jeder Stelle gerufen, an der
|
|
957
|
+
Zeilen mit neuen Quellen dazukommen. Eine Liste, damit beim
|
|
958
|
+
naechsten Wechsel `aboLoesen` alles abmeldet. */
|
|
752
959
|
aboLoesen();
|
|
753
|
-
|
|
960
|
+
S.abo = [id + '.*'];
|
|
961
|
+
socket.emit('subscribe', id + '.*');
|
|
754
962
|
if (id.indexOf('alias.') === 0) {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
`quellenVerteilung` fasst zusammen, was die rechte Seite als
|
|
758
|
-
„Quellen" zeigt — dafuer bildet sie den ELTERNknoten jeder
|
|
759
|
-
Quelle. Bei einem flachen MQTT-Geraet ist das der halbe Adapter:
|
|
760
|
-
gemessen 09.09.2026 wurde daraus `mqtt-client.0.*` mit 322
|
|
761
|
-
Objekten, an einem einzigen Alias. Und `S.werte` wird nie
|
|
762
|
-
geleert, das sammelt sich also.
|
|
763
|
-
|
|
764
|
-
Abonniert wird deshalb der Kanal jeder wirklich gelesenen Quelle.
|
|
765
|
-
Wo die Quellen ohnehin gebuendelt liegen, bleibt es bei einem
|
|
766
|
-
Muster; wo nicht, sind es ein paar mehr — aber jedes davon eng. */
|
|
767
|
-
var kanaele = [];
|
|
963
|
+
var ausAlias = [];
|
|
768
964
|
kindZustaende(id).forEach(function (kid) {
|
|
769
965
|
var q = aliasQuellen(S.objects[kid]);
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
var t = String(x).split('.');
|
|
773
|
-
t.pop();
|
|
774
|
-
var kn = t.join('.');
|
|
775
|
-
if (kn && kanaele.indexOf(kn) === -1) { kanaele.push(kn); }
|
|
776
|
-
});
|
|
777
|
-
});
|
|
778
|
-
/* Ein schmaler Kanal wird als Muster abonniert, ein breiter nicht.
|
|
779
|
-
|
|
780
|
-
Bei einem flachen Geraet IST der Kanal der breite Knoten: Die
|
|
781
|
-
Quelle `mqtt-client.0.SmartHome.Lavalampe_POWER` liegt direkt
|
|
782
|
-
unter `SmartHome`, und `SmartHome.*` sind 320 Objekte. Ab dieser
|
|
783
|
-
Schwelle werden die Quellen einzeln abonniert — ein paar Abos
|
|
784
|
-
mehr, dafuer genau die, deren Werte auch angezeigt werden. */
|
|
785
|
-
var SCHWELLE = 30;
|
|
786
|
-
var wieBreit = function (knoten) {
|
|
787
|
-
var n = 0;
|
|
788
|
-
S.keysSorted.forEach(function (k0) { if (k0.indexOf(knoten + '.') === 0) { n++; } });
|
|
789
|
-
return n;
|
|
790
|
-
};
|
|
791
|
-
var drinSchon = function (was) {
|
|
792
|
-
return muster.some(function (m0) {
|
|
793
|
-
var p0 = m0.slice(-2) === '.*' ? m0.slice(0, -2) : m0;
|
|
794
|
-
return was === p0 || was.indexOf(p0 + '.') === 0;
|
|
795
|
-
});
|
|
796
|
-
};
|
|
797
|
-
|
|
798
|
-
/* Sparten desselben Geraets zu einem Muster zusammenfassen.
|
|
799
|
-
|
|
800
|
-
Ein Tasmota-Alias liest aus `…Licht.stat`, `…Licht.tele` und
|
|
801
|
-
`…Licht.cmnd` — drei Kanaele, ein Geraet, und in der Kopfleiste
|
|
802
|
-
gehoert dort „ein Abo" zu stehen, nicht drei. Zusammengefasst wird
|
|
803
|
-
aber nur, wo wirklich MEHRERE Kanaele unter demselben Knoten
|
|
804
|
-
haengen: Sonst waere aus `…Garten.Weihnachten_aussen` schlicht
|
|
805
|
-
`…Garten` geworden — breiter als noetig, ohne dass etwas
|
|
806
|
-
zusammenfaellt. */
|
|
807
|
-
for (var runde = 0; runde < 4; runde++) {
|
|
808
|
-
var unter = {};
|
|
809
|
-
kanaele.forEach(function (kn) {
|
|
810
|
-
var t = kn.split('.');
|
|
811
|
-
if (t.length <= 3) { return; }
|
|
812
|
-
var ob = t.slice(0, -1).join('.');
|
|
813
|
-
(unter[ob] = unter[ob] || []).push(kn);
|
|
814
|
-
});
|
|
815
|
-
var geaendert = false;
|
|
816
|
-
Object.keys(unter).forEach(function (ob) {
|
|
817
|
-
if (unter[ob].length < 2 || wieBreit(ob) > SCHWELLE) { return; }
|
|
818
|
-
kanaele = kanaele.filter(function (kn) { return unter[ob].indexOf(kn) === -1; });
|
|
819
|
-
if (kanaele.indexOf(ob) === -1) { kanaele.push(ob); }
|
|
820
|
-
geaendert = true;
|
|
821
|
-
});
|
|
822
|
-
if (!geaendert) { break; }
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
/* Ein schmaler Kanal wird als Muster abonniert, ein breiter nicht.
|
|
826
|
-
|
|
827
|
-
Bei einem flachen Geraet IST der Kanal der breite Knoten: Die
|
|
828
|
-
Quelle `mqtt-client.0.SmartHome.Lavalampe_POWER` liegt direkt
|
|
829
|
-
unter `SmartHome`, und `SmartHome.*` sind 320 Objekte (gemessen
|
|
830
|
-
09.09.2026; vorher wurde daraus sogar `mqtt-client.0.*` mit 322).
|
|
831
|
-
Ab dieser Schwelle werden die Quellen einzeln abonniert — ein paar
|
|
832
|
-
Abos mehr, dafuer genau die, deren Werte auch angezeigt werden. */
|
|
833
|
-
kanaele.forEach(function (kn) {
|
|
834
|
-
if (drinSchon(kn)) { return; }
|
|
835
|
-
if (wieBreit(kn) > SCHWELLE) { return; }
|
|
836
|
-
muster.push(kn + '.*');
|
|
837
|
-
});
|
|
838
|
-
/* Was jetzt noch von keinem Muster gedeckt ist, kommt einzeln. */
|
|
839
|
-
kindZustaende(id).forEach(function (kid) {
|
|
840
|
-
var q = aliasQuellen(S.objects[kid]);
|
|
841
|
-
[q.read, q.write].forEach(function (x) {
|
|
842
|
-
if (x && !drinSchon(x) && muster.indexOf(x) === -1) { muster.push(x); }
|
|
843
|
-
});
|
|
966
|
+
if (q.read) { ausAlias.push(q.read); }
|
|
967
|
+
if (q.write) { ausAlias.push(q.write); }
|
|
844
968
|
});
|
|
969
|
+
aboErgaenzen(ausAlias);
|
|
970
|
+
} else {
|
|
971
|
+
zeigeAbozahl();
|
|
845
972
|
}
|
|
846
|
-
S.abo = muster;
|
|
847
|
-
muster.forEach(function (m) { socket.emit('subscribe', m); });
|
|
848
|
-
zeigeAbozahl();
|
|
849
973
|
|
|
850
974
|
/* Erst die Werte, dann der Vorschlag. Die Erkennung schaut in den
|
|
851
975
|
Rohwert von tele.SENSOR hinein — ohne Werte haelt sie ein Geraet
|
|
@@ -922,10 +1046,14 @@ export function waehle(id, fertig) {
|
|
|
922
1046
|
if (fest) { v.vonHandGewaehlt = false; v.ausBestand = true; }
|
|
923
1047
|
/* Gibt es den Alias schon, gilt sein Stand - in beiden Ansichten
|
|
924
1048
|
dasselbe Bild (Ricardo, 25.08.2026). */
|
|
925
|
-
|
|
1049
|
+
/* An einem Mehrfachgeraet zaehlt der Alias DIESES Ausgangs,
|
|
1050
|
+
nicht der mit den meisten Punkten (C13). */
|
|
1051
|
+
var vorhA = aliasFuer(id, ausgangsQuellen(v)) || (v.instanz === null || v.instanz === undefined ? vorh : null);
|
|
1052
|
+
if (vorhA && S.objects[vorhA]) { bestandVorrang(v, vorhA); }
|
|
926
1053
|
S.entwurf = v;
|
|
927
1054
|
}
|
|
928
1055
|
}
|
|
1056
|
+
aboErgaenzen(quellenVonEntwurf(S.entwurf));
|
|
929
1057
|
var nach = [];
|
|
930
1058
|
S.entwurf.states.forEach(function (s) {
|
|
931
1059
|
if (s.srcR && !S.werte[s.srcR]) { nach.push(s.srcR); }
|
|
@@ -1123,7 +1251,75 @@ function alsQuelleKarten() {
|
|
|
1123
1251
|
return alsQuelleKarte;
|
|
1124
1252
|
}
|
|
1125
1253
|
|
|
1126
|
-
|
|
1254
|
+
/* Welche Quellen gehoeren zu genau diesem Ausgang?
|
|
1255
|
+
|
|
1256
|
+
An einem Mehrfachgeraet ist "der Alias dieses Geraets" keine
|
|
1257
|
+
beantwortbare Frage - es gibt je Ausgang einen, dazu oft einen fuer
|
|
1258
|
+
die gemeinsame Messung. Beantwortbar ist nur: welcher gehoert zu dem
|
|
1259
|
+
Ausgang, der gerade gewaehlt ist.
|
|
1260
|
+
|
|
1261
|
+
Geraten wird dabei nichts an Namen herum. Gefragt wird die Vorlage:
|
|
1262
|
+
welche ihrer Pfade tragen den Platzhalter? Genau die unterscheiden die
|
|
1263
|
+
Ausgaenge (bei `tasmota-mehrfach` `stat.POWER%N%` und `cmnd.POWER%N%`),
|
|
1264
|
+
alles andere (`tele.SENSOR`, `tele.LWT`) ist allen gemeinsam. Damit
|
|
1265
|
+
faellt auch die Falle aus I31 weg: `tele.INFO2` traegt zwar eine Zwei,
|
|
1266
|
+
aber keinen Platzhalter - es gehoert zu keinem Ausgang.
|
|
1267
|
+
|
|
1268
|
+
Fuer Ausgang 1 kommt das blanke `cmnd.POWER` dazu. Bei Tasmota ist
|
|
1269
|
+
POWER ohne Nummer ein Zweitname fuer POWER1 - am 16.09.2026 an der
|
|
1270
|
+
Steckdosenleiste nachgemessen: eine Abfrage an `cmnd/POWER` wird mit
|
|
1271
|
+
`{"POWER1":"ON"}` beantwortet, und `stat/POWER` gibt es nicht. Ein
|
|
1272
|
+
Alias, der so gebaut wurde, schaltet wirklich Ausgang 1 und gehoert
|
|
1273
|
+
dorthin. */
|
|
1274
|
+
export function ausgangsQuellen(e) {
|
|
1275
|
+
if (!e || e.instanz === null || e.instanz === undefined || !e.kanal) { return null; }
|
|
1276
|
+
var v = null;
|
|
1277
|
+
S.VORLAGEN.forEach(function (x) { if (x.id === e.vorlage) { v = x; } });
|
|
1278
|
+
if (!v || !v.mehrfach) { return null; }
|
|
1279
|
+
var platz = (v.mehrfach && v.mehrfach.platzhalter) || '%N%';
|
|
1280
|
+
var raus = [];
|
|
1281
|
+
var dazu = function (p) {
|
|
1282
|
+
if (!p) { return; }
|
|
1283
|
+
var voll = e.kanal + '.' + p;
|
|
1284
|
+
if (raus.indexOf(voll) === -1) { raus.push(voll); }
|
|
1285
|
+
};
|
|
1286
|
+
(v.zustaende || []).forEach(function (z) {
|
|
1287
|
+
[z.lesen, z.schreiben].forEach(function (p) {
|
|
1288
|
+
if (!p || String(p).indexOf(platz) === -1) { return; }
|
|
1289
|
+
dazu(setzeInstanz(p, v, e.instanz));
|
|
1290
|
+
if (String(e.instanz) === '1') { dazu(String(p).split(platz).join('')); }
|
|
1291
|
+
});
|
|
1292
|
+
});
|
|
1293
|
+
return raus.length ? raus : null;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/* Mit `ausgang` - der Liste aus `ausgangsQuellen` - fragt sie enger: nur
|
|
1297
|
+
ein Alias, der wirklich aus einer dieser Quellen liest oder in eine
|
|
1298
|
+
schreibt, gehoert zu diesem Ausgang. Ohne das Argument, und das sind
|
|
1299
|
+
alle anderen sieben Aufrufer, bleibt sie Zeile fuer Zeile wie sie war.
|
|
1300
|
+
|
|
1301
|
+
Die Mehrheitsregel unten ist an einem Geraet mit einem Ausgang richtig
|
|
1302
|
+
und an einem Mehrfachgeraet die falsche Frage: An Ricardos
|
|
1303
|
+
Steckdosenleiste gewann `Verbrauch` mit sechs Punkten aus
|
|
1304
|
+
`tele.SENSOR` gegen `RF1000` mit zwei Punkten aus `stat.POWER1`, und
|
|
1305
|
+
der Entwurf fuer Ausgang 1 uebernahm dessen Haken. Im Musterfeld stand
|
|
1306
|
+
danach "✕ SET fehlt" an einem Geraet mit funktionierendem SET
|
|
1307
|
+
(C13, produktiv gemessen 16.09.2026).
|
|
1308
|
+
|
|
1309
|
+
Auch die Abkuerzung ueber `native.quelle` faellt in diesem Fall weg:
|
|
1310
|
+
die zeigt auf das GERAET, nicht auf den Ausgang. */
|
|
1311
|
+
export function aliasFuer(quelle, ausgang) {
|
|
1312
|
+
if (ausgang && ausgang.length) {
|
|
1313
|
+
var karteA = alsQuelleKarten();
|
|
1314
|
+
var zaehlA = {}, bestA = null, vielA = 0;
|
|
1315
|
+
ausgang.forEach(function (q0) {
|
|
1316
|
+
(karteA.zweig[q0] || []).forEach(function (kanal) {
|
|
1317
|
+
zaehlA[kanal] = (zaehlA[kanal] || 0) + 1;
|
|
1318
|
+
if (zaehlA[kanal] > vielA) { vielA = zaehlA[kanal]; bestA = kanal; }
|
|
1319
|
+
});
|
|
1320
|
+
});
|
|
1321
|
+
return bestA;
|
|
1322
|
+
}
|
|
1127
1323
|
var karte = alsQuelleKarten();
|
|
1128
1324
|
var treffer = karte.fest[quelle] || null;
|
|
1129
1325
|
if (treffer) { return treffer; }
|
|
@@ -1170,6 +1366,22 @@ export function aliasFuer(quelle) {
|
|
|
1170
1366
|
export function bestandVorrang(e, aliasId) {
|
|
1171
1367
|
if (!e || !e.states || !aliasId) { return e; }
|
|
1172
1368
|
var kanal = aliasId;
|
|
1369
|
+
/* `vorlagenWert` heisst, was es heisst: was die VORLAGE sagen wuerde.
|
|
1370
|
+
Ist keine in Kraft — abgewaehlt oder nie gefunden —, gibt es nichts,
|
|
1371
|
+
wovon etwas abweichen koennte, und die Kopie darf nicht entstehen.
|
|
1372
|
+
|
|
1373
|
+
Bis zum 17.09.2026 wurde sie unbesehen gesetzt, und dann log die
|
|
1374
|
+
Zeile: an `hm-rpc.2.NEQ1660737` nach „keine Vorlage" stand an SET
|
|
1375
|
+
„weicht von der Vorlage ab" und darunter „Die Vorlage will hier:
|
|
1376
|
+
switch" — waehrend im Alias `switch.light` steht, was auf das Muster
|
|
1377
|
+
`light` sogar passt. Verglichen wurde in Wahrheit gegen den
|
|
1378
|
+
Rohentwurf, also gegen die blanke Rolle des Quellpunkts, und als
|
|
1379
|
+
abweichend markiert ausgerechnet der bessere Wert. Dasselbe an einem
|
|
1380
|
+
Geraet, zu dem NIE eine Vorlage gefunden wurde (nachgestellt an
|
|
1381
|
+
`echt.Warmwasser`): auch dort erschien die Marke. Ricardo: „es gibt
|
|
1382
|
+
ja gar keine Vorlage mehr, man kann hoechstens vom Muster
|
|
1383
|
+
abweichen." */
|
|
1384
|
+
var mitVorlage = !!(e.vorschlag && e.vorlage);
|
|
1173
1385
|
e.states.forEach(function (s) {
|
|
1174
1386
|
if (!s.n) { return; }
|
|
1175
1387
|
var o = S.objects[kanal + '.' + s.n];
|
|
@@ -1179,22 +1391,26 @@ export function bestandVorrang(e, aliasId) {
|
|
|
1179
1391
|
anlegen (Ricardo, 25.08.2026: UNREACH und RSSI standen angehakt,
|
|
1180
1392
|
obwohl sie im Alias fehlen). Anhaken kann man sie weiterhin, und
|
|
1181
1393
|
der Chip „Vorlage" holt die Vorgabe der Vorlage zurueck. */
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1394
|
+
if (mitVorlage) {
|
|
1395
|
+
s.vorlagenWert = { on: s.on, role: s.role, typ: s.typ, unit: s.unit,
|
|
1396
|
+
caption: s.caption, f: s.f, fw: s.fw,
|
|
1397
|
+
srcR: s.srcR, srcW: s.srcW, states: s.states };
|
|
1398
|
+
}
|
|
1185
1399
|
s.on = false;
|
|
1186
1400
|
return;
|
|
1187
1401
|
}
|
|
1188
1402
|
var c = o.common;
|
|
1189
1403
|
var q = aliasQuellen(o);
|
|
1190
1404
|
/* Was die Vorlage wollte - fuer den Vergleich und den Knopf. */
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1405
|
+
if (mitVorlage) {
|
|
1406
|
+
s.vorlagenWert = {
|
|
1407
|
+
role: s.role, typ: s.typ, unit: s.unit, caption: s.caption,
|
|
1408
|
+
f: s.f, fw: s.fw, srcR: s.srcR, srcW: s.srcW, states: s.states,
|
|
1409
|
+
/* Auch der Haken der Vorlage - der Chip „Vorlage" stellt ihn wieder
|
|
1410
|
+
her, nachdem der Bestand ihn ueberschrieben hat. */
|
|
1411
|
+
on: s.on
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1198
1414
|
var ist = zeileAusAlias(o, s.n);
|
|
1199
1415
|
/* Rolle und Typ NUR, wenn sie im Alias ueberhaupt stehen.
|
|
1200
1416
|
|