iobroker.alias-workbench 0.9.12 → 0.10.0
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 +54 -0
- package/admin/css/werkbank.css +8 -0
- package/admin/js/aufzaehlungen.js +24 -8
- package/admin/js/baum.js +13 -2
- package/admin/js/detail.js +302 -87
- package/admin/js/entwurf.js +44 -14
- package/admin/js/enums.js +7 -0
- package/admin/js/ergebnis.js +26 -6
- package/admin/js/erkennung.js +45 -0
- package/admin/js/mqtt.js +128 -67
- package/admin/js/musterwahl.js +103 -26
- package/admin/js/objekte.js +3 -0
- package/admin/js/pruefungen.js +1 -2
- package/admin/js/quellentausch.js +59 -12
- package/admin/js/schreiben.js +22 -18
- package/admin/js/vorlagen.js +28 -5
- package/admin/js/vorlagenblatt.js +49 -7
- package/admin/js/vorschlagen.js +60 -7
- package/admin/js/werte.js +98 -20
- package/admin/js/zuordnung.js +39 -16
- package/admin/js/zustand.js +5 -1
- package/admin/js/zustandsliste.js +185 -25
- package/admin/sprachen/de.json +35 -11
- package/admin/sprachen/en.json +35 -11
- package/admin/vorlagen/hm-rollladen.json +3 -2
- package/admin/vorlagen/messpunkt.json +6 -2
- package/admin/vorlagen/tasmota-lampe.json +6 -2
- package/admin/vorlagen/tasmota-mehrfach.json +6 -2
- package/admin/vorlagen/tasmota-rgb.json +6 -2
- package/admin/vorlagen/tasmota-steckdose.json +6 -2
- package/io-package.json +14 -14
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { S } from './zustand.js';
|
|
10
10
|
import { el, $ } from './basis.js';
|
|
11
11
|
import { tr } from './sprache.js';
|
|
12
|
-
import { erkenneEntwurf, musterVon, rolleVonPlatz, typKonflikte } from './erkennung.js';
|
|
12
|
+
import { erkenneEntwurf, musterVon, rolleVonPlatz, typKonflikte, plaetzeFuerRolle, typPasstZuPlatz, fehlendePflicht } from './erkennung.js';
|
|
13
13
|
import { kindZustaende, wertVon, fmt } from './werte.js';
|
|
14
14
|
import { steuerKanaele, vorlagenAbweichung, bestandsAbweichung, waehle, quelleHier, quellenVerteilung } from './entwurf.js';
|
|
15
15
|
import { musterName } from './musternamen.js';
|
|
@@ -18,6 +18,7 @@ import { rateAnzahl, rateZurueck, rateZurueckEine, rateBehalten } from './vorsch
|
|
|
18
18
|
import { mqttEinzeln } from './mqtt.js';
|
|
19
19
|
import { zeichneErgebnis, entwurfAngefasst } from './ergebnis.js';
|
|
20
20
|
import { taster } from './schreiben.js';
|
|
21
|
+
import { rateUndMelde } from './musterwahl.js';
|
|
21
22
|
|
|
22
23
|
export function berechnePlaetze(e, haupt) {
|
|
23
24
|
/* --- welcher Punkt sitzt auf welchem Platz --- */
|
|
@@ -105,8 +106,16 @@ export function berechnePlaetze(e, haupt) {
|
|
|
105
106
|
stillschweigend weg. Ein Alias, dem heimlich ein Licht fehlt, ist
|
|
106
107
|
schlimmer als einer mit einem Punkt zu viel. Also kommen die
|
|
107
108
|
Pflichtpunkte der anderen Kanaele mit dazu; dass sie keinen Platz
|
|
108
|
-
finden, steht als Hinweis darueber.
|
|
109
|
+
finden, steht als Hinweis darueber.
|
|
110
|
+
|
|
111
|
+
Nur Kanaele mit einer Funktion. Ein Kanal, den der Detektor bloss
|
|
112
|
+
als `info` erkennt — der Wartungskanal 0 bei Homematic —, hat
|
|
113
|
+
keinen Ausgang, der verloren gehen koennte; bei `info` ist aber
|
|
114
|
+
JEDER Punkt Pflicht, und so kamen AES_KEY, DEVICE_IN_BOOTLOADER,
|
|
115
|
+
DUTYCYCLE und RSSI_DEVICE angehakt in jeden HM-Aktor ohne Vorlage
|
|
116
|
+
(Ricardo, 19.09.2026, an hm-rpc.2.LEQ0605614). */
|
|
109
117
|
(e.kanalGeraete || []).forEach(function (k) {
|
|
118
|
+
if (k.typ === 'info') { return; }
|
|
110
119
|
(k.pflicht || []).forEach(function (pid) {
|
|
111
120
|
var kurz = pid.slice(S.current.length + 1).replace(/\./g, '_');
|
|
112
121
|
e.states.forEach(function (st) { if (st.n === kurz) { st.on = true; } });
|
|
@@ -117,6 +126,30 @@ export function berechnePlaetze(e, haupt) {
|
|
|
117
126
|
return { platzVon: platzVon, platzAnzahl: platzAnzahl, imInfo: imInfo };
|
|
118
127
|
}
|
|
119
128
|
|
|
129
|
+
/* Angehakt wird genau, wer im Muster `e.want` einen Platz bekommt. Alle
|
|
130
|
+
Zeilen treten dazu an, unabhaengig vom Haken — sonst haette die
|
|
131
|
+
Auswahl ein Gedaechtnis: nach „alle" lieferte sie mehr als direkt nach
|
|
132
|
+
dem Oeffnen (Ricardo, 25.08.2026).
|
|
133
|
+
|
|
134
|
+
`geaenderteBehalten`: Zeilen, an denen jemand etwas eingestellt hat
|
|
135
|
+
(Rolle, Typ, Einheit, Formel, Beschriftung), bleiben angehakt. Das
|
|
136
|
+
braucht der Musterwechsel (C54) — wer eine Zeile von Hand hergerichtet
|
|
137
|
+
hat, will sie nicht verlieren, nur weil das neue Muster keinen Platz
|
|
138
|
+
fuer sie hat. Der Knopf „nur was ins Muster passt" behaelt sie nicht:
|
|
139
|
+
er sagt woertlich, was er tut. */
|
|
140
|
+
export function nurWasInsMusterPasst(e, geaenderteBehalten) {
|
|
141
|
+
var kopie = JSON.parse(JSON.stringify({ kanal: e.kanal, states: e.states }));
|
|
142
|
+
kopie.states.forEach(function (s) { s.on = true; });
|
|
143
|
+
var f = erkenneEntwurf(kopie, e.want);
|
|
144
|
+
var drin = {};
|
|
145
|
+
if (f.length) {
|
|
146
|
+
f[0].states.forEach(function (x) {
|
|
147
|
+
if (x.id) { drin[x.id.slice(e.kanal.length + 1)] = true; }
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
e.states.forEach(function (s) { s.on = !!drin[s.n] || !!(geaenderteBehalten && s.geaendert); });
|
|
151
|
+
}
|
|
152
|
+
|
|
120
153
|
export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
121
154
|
/* Bezugspunkt der Marken: die Quelle, an der ich gerade STEHE.
|
|
122
155
|
|
|
@@ -173,6 +206,7 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
173
206
|
keinen Platz hat? Genau die, die eben dazugekommen sind. */
|
|
174
207
|
var ohnePlatz = 0;
|
|
175
208
|
e.kanalGeraete.forEach(function (k) {
|
|
209
|
+
if (k.typ === 'info') { return; } /* wie die Vorbelegung oben */
|
|
176
210
|
(k.pflicht || []).forEach(function (pid) {
|
|
177
211
|
var kurz = pid.slice(S.current.length + 1).replace(/\./g, '_');
|
|
178
212
|
e.states.forEach(function (st) {
|
|
@@ -234,7 +268,10 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
234
268
|
bar.appendChild(document.createTextNode(tr('list.ofDatapoints')));
|
|
235
269
|
bar.appendChild(el('span', 'sp2'));
|
|
236
270
|
/* Mittig zwischen der Zahl und den drei Filtern - zwischen zwei
|
|
237
|
-
Dehnfugen steht er von selbst in der Mitte.
|
|
271
|
+
Dehnfugen steht er von selbst in der Mitte. An einer Quelle ist das
|
|
272
|
+
seit 19.09.2026 „Alle Datenpunkte des Geraets laden" (aus dem
|
|
273
|
+
Vorlagenkasten hierher getauscht), im Aliasmodus weiter „Freie
|
|
274
|
+
Plaetze vorschlagen" - dort gibt es keinen Kasten. */
|
|
238
275
|
if (rateKnopf) { bar.appendChild(rateKnopf); rateKnopf = null; }
|
|
239
276
|
bar.appendChild(el('span', 'sp2'));
|
|
240
277
|
/* Die vier Auswahlknoepfe nur an einer Quelle. Am fertigen Alias sind
|
|
@@ -273,16 +310,7 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
273
310
|
direkt nach dem Oeffnen (Ricardo, 25.08.2026). Jetzt treten
|
|
274
311
|
alle Zeilen zur Platzvergabe an, unabhaengig vom Haken, und
|
|
275
312
|
angehakt wird genau, wer einen Platz bekommt. */
|
|
276
|
-
|
|
277
|
-
kopie.states.forEach(function (s) { s.on = true; });
|
|
278
|
-
var f = erkenneEntwurf(kopie, e.want);
|
|
279
|
-
var drin = {};
|
|
280
|
-
if (f.length) {
|
|
281
|
-
f[0].states.forEach(function (x) {
|
|
282
|
-
if (x.id) { drin[x.id.slice(e.kanal.length + 1)] = true; }
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
e.states.forEach(function (s) { s.on = !!drin[s.n]; });
|
|
313
|
+
nurWasInsMusterPasst(e, false);
|
|
286
314
|
}, tr('list.onlyPatternHint')]])
|
|
287
315
|
.filter(function (pr) { return mitVorlage || pr[0] !== tr('list.tpl'); })
|
|
288
316
|
.forEach(function (pr) {
|
|
@@ -337,7 +365,13 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
337
365
|
rl.appendChild(bWeg);
|
|
338
366
|
card.appendChild(rl);
|
|
339
367
|
}
|
|
340
|
-
|
|
368
|
+
/* Greift das Muster gar nicht, erklaert die orange Legende ueber der
|
|
369
|
+
Liste, was fehlt und welche Zeile hilft. Die Meldung des Vorschlagens
|
|
370
|
+
(„Kein uebriger Datenpunkt passt dazu …") stand dann direkt darueber
|
|
371
|
+
und widersprach ihr — sie laesst Zeilen, an denen jemand etwas
|
|
372
|
+
eingestellt hat, absichtlich in Ruhe (Ricardo, 19.09.2026). */
|
|
373
|
+
var musterGreift = !e.want || Object.keys(pl.platzVon || {}).length > 0;
|
|
374
|
+
if (e.rateMeldung && musterGreift) {
|
|
341
375
|
var rm = el('div', 'aside');
|
|
342
376
|
rm.style.margin = '8px 15px';
|
|
343
377
|
rm.textContent = e.rateMeldung;
|
|
@@ -636,24 +670,62 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
636
670
|
var belegteSlots = {};
|
|
637
671
|
Object.keys(platzVon).forEach(function (n) { belegteSlots[platzVon[n]] = 1; });
|
|
638
672
|
var muster = e.want && musterVon(e.want);
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
673
|
+
/* Ein Platzname, ein Eintrag (E6, 19.09.2026).
|
|
674
|
+
|
|
675
|
+
Manche Muster fuehren denselben Platz mehrfach - als Alternativen,
|
|
676
|
+
von denen der Detektor genau eine nimmt („one of the following“ im
|
|
677
|
+
type-detector). Mediaplayer: COVER als `media.cover` und als
|
|
678
|
+
Auffangnetz `media.cover.…` ohne Standardrolle; Warnung: START als
|
|
679
|
+
`date.start` und `date`; Klimaanlage, Luftreiniger, Ventilator:
|
|
680
|
+
SWING als `level.mode.swing` oder `switch.mode.swing`; Saugroboter:
|
|
681
|
+
BATTERY zweimal gleich. Einzeln gezeigt stand COVER zweimal da, die
|
|
682
|
+
zweite Zeile mit dem rohen Ausdruck statt einer Rolle, und jeder
|
|
683
|
+
Klick darauf legte einen Punkt ohne Rolle an. Jetzt steht der Platz
|
|
684
|
+
einmal da, mit der ersten Alternative, die eine Rolle hat; die
|
|
685
|
+
anderen Rollen stehen daneben. */
|
|
686
|
+
var platzGruppen = [], gruppeVon = {};
|
|
687
|
+
(muster ? muster.states : []).forEach(function (st) {
|
|
688
|
+
if (!st.name || st.multiple) { return; }
|
|
689
|
+
var g = gruppeVon[st.name];
|
|
690
|
+
if (!g) { g = gruppeVon[st.name] = { st: st, rollen: [] }; platzGruppen.push(g); }
|
|
691
|
+
else if (!rolleVonPlatz(g.st) && rolleVonPlatz(st)) { g.st = st; }
|
|
692
|
+
if (st.required) { g.pflicht = true; }
|
|
693
|
+
var r0 = rolleVonPlatz(st);
|
|
694
|
+
if (r0 && g.rollen.indexOf(r0) === -1) { g.rollen.push(r0); }
|
|
695
|
+
});
|
|
696
|
+
/* Belegt ist ein Platz auch, wenn es seine Zeile schon gibt - unter
|
|
697
|
+
seinem Namen oder aus ihm angelegt -, selbst wenn der Detektor sie
|
|
698
|
+
(noch) nicht einordnet. Greift das Muster gar nicht, ordnet er keine
|
|
699
|
+
ein, und die Liste bot jeden Platz weiter an: ein zweiter Klick legte
|
|
700
|
+
eine zweite Zeile gleichen Namens an, die der Alias nicht haben kann
|
|
701
|
+
(gemessen am Mediaplayer ohne STATE, 19.09.2026). */
|
|
702
|
+
var zeileDa = {};
|
|
703
|
+
e.states.forEach(function (s0) {
|
|
704
|
+
if (s0.n) { zeileDa[s0.n] = 1; }
|
|
705
|
+
if (s0.ausPlatz) { zeileDa[s0.ausPlatz] = 1; }
|
|
706
|
+
});
|
|
707
|
+
var freie = platzGruppen.filter(function (g) {
|
|
708
|
+
return !belegteSlots[g.st.name] && !zeileDa[g.st.name];
|
|
709
|
+
});
|
|
642
710
|
|
|
643
711
|
if (freie.length) {
|
|
644
712
|
var fk = el('div', 'freikopf');
|
|
645
713
|
fk.appendChild(el('span', null, tr('pattern.freeSlots', musterName(e.want) || e.want)));
|
|
646
|
-
fk.appendChild(el('span', 'cnt2', tr('list.countOf', freie.length,
|
|
714
|
+
fk.appendChild(el('span', 'cnt2', tr('list.countOf', freie.length, platzGruppen.length)));
|
|
647
715
|
card.appendChild(fk);
|
|
648
716
|
|
|
649
|
-
freie.forEach(function (
|
|
650
|
-
var
|
|
717
|
+
freie.forEach(function (g) {
|
|
718
|
+
var st = g.st;
|
|
719
|
+
var rolle = rolleVonPlatz(st);
|
|
720
|
+
var andere = g.rollen.filter(function (r0) { return r0 !== rolle; });
|
|
721
|
+
var fr = el('div', 'freirow' + (g.pflicht ? ' pflicht' : ''));
|
|
651
722
|
fr.tabIndex = 0;
|
|
652
723
|
fr.setAttribute('role', 'button');
|
|
653
|
-
fr.appendChild(el('span', 'mk3',
|
|
724
|
+
fr.appendChild(el('span', 'mk3', g.pflicht ? '✕' : '+'));
|
|
654
725
|
fr.appendChild(el('span', 'sn2', st.name));
|
|
655
|
-
fr.appendChild(el('span', 'rl2',
|
|
656
|
-
fr.appendChild(el('span', 'rx2',
|
|
726
|
+
fr.appendChild(el('span', 'rl2', rolle || String(st.role || '')));
|
|
727
|
+
fr.appendChild(el('span', 'rx2', g.pflicht ? tr('pattern.required')
|
|
728
|
+
: (andere.length ? tr('pattern.orRole', andere.join(', ')) : String(st.role || ''))));
|
|
657
729
|
|
|
658
730
|
var nimm = function () {
|
|
659
731
|
e.states.push({
|
|
@@ -723,7 +795,60 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
723
795
|
hoch und legte sich ueber die Liste, die man gerade lesen wollte
|
|
724
796
|
(Ricardo, 08.09.2026). Ein Klick auf das „i" oeffnet sie stattdessen
|
|
725
797
|
als Dialog — dort darf sie so lang sein, wie sie ist. */
|
|
726
|
-
|
|
798
|
+
/* Greift das Muster gar nicht, weil ein Pflichtplatz fehlt, sagt die
|
|
799
|
+
Legende welcher — und ob eine NICHT angehakte Zeile ihn bekaeme.
|
|
800
|
+
|
|
801
|
+
Vorher stand das nur als „✕ SET fehlt" im Musterfeld, und ob
|
|
802
|
+
`cmnd_POWER` mit seiner Rolle `switch` passen wuerde, sah man nicht:
|
|
803
|
+
nicht angehakte Zeilen bekommt der Detektor gar nicht zu sehen. Ein
|
|
804
|
+
Hinweis in der Detailzeile („… wird vergeben, sobald das Muster
|
|
805
|
+
greift") stand an der falschen Stelle — die Zeile, die ihn trug, war
|
|
806
|
+
in Ordnung (Ricardo, 19.09.2026). Deshalb steht es hier, auch wenn
|
|
807
|
+
gar nichts angehakt ist. */
|
|
808
|
+
var fehlt = [];
|
|
809
|
+
var muL = e.want && musterVon(e.want);
|
|
810
|
+
if (muL && !kipptAnTyp && !Object.keys(platzVon).length) {
|
|
811
|
+
var passtAuf = function (st, s, auchTyp) {
|
|
812
|
+
return plaetzeFuerRolle(e.want, s.role).some(function (p) {
|
|
813
|
+
return p.name === st.name && (!auchTyp || !s.typ || typPasstZuPlatz(p, s.typ));
|
|
814
|
+
});
|
|
815
|
+
};
|
|
816
|
+
var gesehenL = {};
|
|
817
|
+
muL.states.forEach(function (st) {
|
|
818
|
+
if (!st.required || gesehenL[st.name]) { return; }
|
|
819
|
+
gesehenL[st.name] = 1;
|
|
820
|
+
if (e.states.some(function (s) { return s.on && passtAuf(st, s, true); })) { return; }
|
|
821
|
+
/* Kandidat ist jede nicht angehakte Zeile, deren ROLLE passt — auch
|
|
822
|
+
wenn der Typ nicht passt. Am 3D-Drucker bringt `cmnd.POWER` die
|
|
823
|
+
Rolle `switch` selbst mit, aber den Typ `mixed`; nur nach
|
|
824
|
+
passendem Typ gefragt, fiel er stillschweigend heraus, und die
|
|
825
|
+
Legende nannte niemanden (Ricardo, 19.09.2026). Den Typ stellt
|
|
826
|
+
der Knopf gleich mit. Passende Typen zuerst. */
|
|
827
|
+
var aus = e.states.filter(function (s) { return !s.on && s.n && passtAuf(st, s, false); });
|
|
828
|
+
aus.sort(function (a, b) { return (passtAuf(st, b, true) ? 1 : 0) - (passtAuf(st, a, true) ? 1 : 0); });
|
|
829
|
+
var soll = Array.isArray(st.type) ? st.type[0] : st.type;
|
|
830
|
+
fehlt.push({ platz: st.name, aus: aus, soll: soll,
|
|
831
|
+
typFalsch: aus.length ? !passtAuf(st, aus[0], true) : false });
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/* Was wirklich fehlt, samt der Gruppen (`requiredOneOf`): an der
|
|
836
|
+
Klimaanlage ist das der Sollwert, nicht MODE (U13). Die Kandidaten
|
|
837
|
+
oben kennen nur `required`; der Text nimmt die genauere Liste. */
|
|
838
|
+
var fehltNamen = (muL && !kipptAnTyp && !Object.keys(platzVon).length)
|
|
839
|
+
? fehlendePflicht(e.states, e.want) : [];
|
|
840
|
+
if (!fehltNamen.length) { fehltNamen = fehlt.map(function (f) { return f.platz; }); }
|
|
841
|
+
|
|
842
|
+
/* Greift das Muster erst nach dem Vorschlag, sagt die Legende das und
|
|
843
|
+
bietet den Knopf gleich hier an. Sonst liest man „greift gerade
|
|
844
|
+
nicht" und haelt das Muster fuer falsch gewaehlt, obwohl ein Klick
|
|
845
|
+
fehlt (Ricardo, 19.09.2026). Die Aussicht hat die Musterwahl schon
|
|
846
|
+
berechnet. */
|
|
847
|
+
var ausR = e.rateAussicht;
|
|
848
|
+
var greiftNachRaten = !!(fehltNamen.length && ausR && ausR.want === e.want &&
|
|
849
|
+
ausR.selbst && ausR.selbst.passt && !rateAnzahl(e));
|
|
850
|
+
|
|
851
|
+
if (ohnePlatzZahl || fehltNamen.length) {
|
|
727
852
|
var mn = musterName(e.want) || e.want || '?';
|
|
728
853
|
var lg = el('div', 'legendenzeile');
|
|
729
854
|
/* Steht die ganze Liste ohne Platz da, weil EINE Zeile im falschen
|
|
@@ -739,8 +864,43 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
|
|
|
739
864
|
lg.appendChild(document.createTextNode(kipptAnTyp
|
|
740
865
|
? tr('pattern.noPlaceBecauseType', mn, kipptAnTyp.platz,
|
|
741
866
|
kipptAnTyp.erwartet.join(tr('pattern.typeOr')), kipptAnTyp.typ)
|
|
742
|
-
:
|
|
867
|
+
: (fehltNamen.length
|
|
868
|
+
? tr('pattern.offMissing', mn, fehltNamen.join(', '))
|
|
869
|
+
: tr('pattern.noPlaceLegend', mn))));
|
|
870
|
+
if (greiftNachRaten && !kipptAnTyp) {
|
|
871
|
+
lg.appendChild(document.createTextNode(' ' + tr('pattern.offGuess', tr('guess.button'))));
|
|
872
|
+
var bR = el('button', 'btn schmal', tr('guess.button'));
|
|
873
|
+
bR.type = 'button';
|
|
874
|
+
bR.title = tr('guess.hint');
|
|
875
|
+
bR.style.marginLeft = '6px';
|
|
876
|
+
bR.addEventListener('click', function (ev) {
|
|
877
|
+
ev.stopPropagation();
|
|
878
|
+
rateUndMelde(e);
|
|
879
|
+
entwurfAngefasst(); S.openRow = null; zeichneErgebnis();
|
|
880
|
+
});
|
|
881
|
+
lg.appendChild(bR);
|
|
882
|
+
}
|
|
883
|
+
var mitKandidat = fehlt.filter(function (f) { return f.aus.length; })[0];
|
|
884
|
+
if (mitKandidat) {
|
|
885
|
+
var kand = mitKandidat.aus[0];
|
|
886
|
+
var mitTyp = mitKandidat.typFalsch && mitKandidat.soll;
|
|
887
|
+
lg.appendChild(document.createTextNode(' ' + (mitTyp
|
|
888
|
+
? tr('pattern.offCandidateType', kand.n, mitKandidat.platz, kand.typ, mitKandidat.soll)
|
|
889
|
+
: tr('pattern.offCandidate', kand.n, mitKandidat.platz))));
|
|
890
|
+
var bk = el('button', 'btn schmal', mitTyp
|
|
891
|
+
? tr('pattern.tickItType', mitKandidat.soll) : tr('pattern.tickIt'));
|
|
892
|
+
bk.type = 'button';
|
|
893
|
+
bk.style.marginLeft = '6px';
|
|
894
|
+
bk.addEventListener('click', function (ev) {
|
|
895
|
+
ev.stopPropagation();
|
|
896
|
+
kand.on = true;
|
|
897
|
+
if (mitTyp) { kand.typ = mitKandidat.soll; kand.geaendert = true; }
|
|
898
|
+
entwurfAngefasst(); zeichneErgebnis();
|
|
899
|
+
});
|
|
900
|
+
lg.appendChild(bk);
|
|
901
|
+
}
|
|
743
902
|
|
|
903
|
+
if (!ohnePlatzZahl) { legendenPlatz.appendChild(lg); host.appendChild(card); return; }
|
|
744
904
|
var ib = el('button', 'infoknopf', 'i');
|
|
745
905
|
ib.type = 'button';
|
|
746
906
|
ib.title = tr('info.more');
|
package/admin/sprachen/de.json
CHANGED
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"check.sourceHasValue": "Quelle hat einen Wert",
|
|
40
40
|
"check.targetCan": "Ziel kann, was verlangt wird",
|
|
41
41
|
"check.targetCanFine": "alle in Ordnung",
|
|
42
|
-
"check.targetNoRead": "{0}: die Lesequelle ändert sich nie",
|
|
43
42
|
"check.targetNoWrite": "{0}: das Ziel ist nicht beschreibbar",
|
|
44
43
|
"check.targetVoidFormula": "{0}: Schreibformel läuft ins Leere, das Ziel ist {1}",
|
|
45
44
|
"check.title": "Prüfungen — laufen immer mit, fassen nichts an",
|
|
@@ -70,7 +69,7 @@
|
|
|
70
69
|
"detail.display": "Anzeige",
|
|
71
70
|
"detail.elsewhere": "(anderswo)",
|
|
72
71
|
"detail.expects": "erwartet {0}",
|
|
73
|
-
"detail.formula": "
|
|
72
|
+
"detail.formula": "Leseformel",
|
|
74
73
|
"detail.formulaBroken": "Formel fehlerhaft",
|
|
75
74
|
"detail.formulaHint": "\"ON\"/\"OFF\" → boolean macht der Alias von selbst, dafür braucht es keine Formel.",
|
|
76
75
|
"detail.formulaPlaceholder": "leer = Wert unverändert übernehmen",
|
|
@@ -78,6 +77,7 @@
|
|
|
78
77
|
"detail.formulaTooSlow": "Diese Formel hat {0} ms gebraucht und wird nicht mehr ausgeführt. Nach dem Neuladen des Reiters wird sie einmal neu versucht.",
|
|
79
78
|
"detail.jsonField": "Feld im JSON",
|
|
80
79
|
"detail.matchesState": "✓ deckt sich mit dem Zustand",
|
|
80
|
+
"detail.nameTaken": "Den Namen {0} trägt schon eine andere Zeile.",
|
|
81
81
|
"detail.name": "Name",
|
|
82
82
|
"detail.namePlaceholder": "z. B. UNREACH",
|
|
83
83
|
"detail.noSource": "— keine Quelle bekannt —",
|
|
@@ -90,17 +90,24 @@
|
|
|
90
90
|
"detail.pickOne": "— bitte wählen —",
|
|
91
91
|
"detail.rawNothing": "— Quelle liefert nichts —",
|
|
92
92
|
"detail.rawValue": "Rohwert",
|
|
93
|
+
"detail.readOnlySlotWrites": "{0} ist im Muster nur zum Lesen da — „schreibt auf“ sollte „— nicht schreiben —“ sein, sonst geht ein geschriebener Wert ans Gerät.",
|
|
93
94
|
"detail.readsFrom": "liest aus",
|
|
94
95
|
"detail.removePoint": "Diesen Punkt entfernen",
|
|
95
|
-
"detail.
|
|
96
|
+
"detail.readIsButton": "Taster",
|
|
97
|
+
"detail.slot": "Platz im Muster",
|
|
98
|
+
"detail.slotNone": "— kein Platz —",
|
|
99
|
+
"detail.slotNotGiven": "{0} ist gewählt, aber nicht vergeben — unter „Rolle“ steht, was nicht passt (meist der Typ).",
|
|
100
|
+
"detail.slotRequired": "Pflicht",
|
|
101
|
+
"detail.slotHint": "Setzt Rolle, Typ, Einheit und Werteliste so, wie das Muster sie für diesen Platz vorgibt. Datenpunkt und Name bleiben.",
|
|
96
102
|
"detail.role": "Rolle",
|
|
97
103
|
"detail.sameAsRead": "— dieselbe wie lesen —",
|
|
98
|
-
"detail.separateHint": "
|
|
104
|
+
"detail.separateHint": "Liest woanders, als es schreibt: angezeigt wird, was das Gerät zurückmeldet — nicht der zuletzt gesendete Befehl.",
|
|
99
105
|
"detail.sourceGone": "Quelle existiert nicht",
|
|
100
106
|
"detail.stateSays": "Zustand sagt {0}",
|
|
101
107
|
"detail.takeFromAlias": "Diesen einen Wert aus dem gespeicherten Alias zurückholen",
|
|
102
108
|
"detail.takeOne": "Diesen einen Wert aus der Vorlage übernehmen",
|
|
103
|
-
"detail.
|
|
109
|
+
"detail.readIsButtonHint": "Rolle button mit Schreibziel: der Alias-Datenpunkt bekommt read: false, und vis, Alexa und matter zeichnen ihn als Knopf. Die Lesequelle stört dabei nicht — mit ihr bekommt der Alias jeden Druck mit, auch einen an der echten Taste. Nach dem Druck bleibt der letzte Wert stehen, wie an der Quelle auch.",
|
|
110
|
+
"detail.buttonNoRead": "Knopf ohne Lesequelle — liest nicht mit",
|
|
104
111
|
"detail.targetNoWrite": "Der Zielpunkt trägt write: false — sein Adapter reicht nichts ans Gerät weiter. ioBroker legt den Wert trotzdem ab, passieren wird aber nichts.",
|
|
105
112
|
"detail.targetTypeHint": "Der Typ des Zielpunktes ist {0}. Er entscheidet, was von der Schreibformel ankommt: mixed und string nehmen Text, boolean und number rechnen ihn zurück.",
|
|
106
113
|
"detail.targetTypeVoid": "Das Ziel ist {0} und nimmt keinen Text. Die Schreibformel liefert aber Text — der js-controller rechnet ihn beim Schreiben wieder auf {0} zurück, die Formel bleibt also wirkungslos. Geschaltet wird trotzdem.",
|
|
@@ -108,7 +115,6 @@
|
|
|
108
115
|
"detail.tplWantsEmpty": "Die Vorlage lässt dieses Feld leer.",
|
|
109
116
|
"detail.type": "Typ",
|
|
110
117
|
"detail.unit": "Einheit",
|
|
111
|
-
"detail.willBecome": "entsteht als",
|
|
112
118
|
"detail.writeFormula": "Schreibformel",
|
|
113
119
|
"detail.writeFormulaHint": "rechnet in die andere Richtung: was das Gerät beim Schalten empfangen soll.",
|
|
114
120
|
"detail.writeFormulaPlaceholder": "z. B. val ? \"ON\" : \"OFF\"",
|
|
@@ -150,6 +156,7 @@
|
|
|
150
156
|
"enums.room": "Raum",
|
|
151
157
|
"enums.roomHint": "Ordnet den Alias einem Raum zu. Das steht nicht am Objekt, sondern in der Aufzählung „enum.rooms\" — Alexa, Google und die Oberflächen gruppieren danach.",
|
|
152
158
|
"enums.suggested": "vorgeschlagen",
|
|
159
|
+
"enums.notLoadedField": "Räume und Funktionen konnten nicht geladen werden — Raum und Funktion werden deshalb nicht geschrieben; der Alias selbst entsteht trotzdem. Die Werkbank versucht es von selbst noch dreimal, sonst den Reiter neu laden.",
|
|
153
160
|
"enums.unknown": "Aufzählungen nicht geladen — Raum und Funktion bleiben unangetastet.",
|
|
154
161
|
"enums.unused": "leer",
|
|
155
162
|
"enums.willCreate": "neu anlegen",
|
|
@@ -181,7 +188,8 @@
|
|
|
181
188
|
"guess.mark": "vermutet",
|
|
182
189
|
"guess.noneFit": "Frei bleibt {0}. Kein übriger Datenpunkt passt dazu — vermutet wird nach Namen, Werteliste, Einheit und Typ, und nichts kam über die Schwelle.",
|
|
183
190
|
"guess.noneFull": "Alle Plätze des Musters sind besetzt — es bleibt nichts vorzuschlagen.",
|
|
184
|
-
"guess.noneHand": "{0} Zeilen sind von Hand entschieden und bleiben unangetastet.",
|
|
191
|
+
"guess.noneHand": "{0} Zeilen sind von Hand entschieden und bleiben unangetastet: {1}.",
|
|
192
|
+
"guess.noneHandOne": "{0} ist von Hand entschieden und bleibt unangetastet.",
|
|
185
193
|
"guess.noneUsed": "Frei bleibt {0}. Jeder übrige Datenpunkt steckt schon als Lese- oder Schreibquelle in einer belegten Zeile.",
|
|
186
194
|
"guess.slotsMore": "{0} und {1} weitere",
|
|
187
195
|
"guess.tplAsk": "Dieses Gerät ist als „{0}“ identifiziert; die Zuordnung steht damit schon. Der Vorschlag belegt zusätzliche Plätze aus den übrigen Datenpunkten — ein Versuch, kein Wissen, jede Zuordnung wäre einzeln zu prüfen. Gedacht für Sonderfälle, etwa wenn das Gerät mehr kann, als die Vorlage abdeckt.",
|
|
@@ -302,6 +310,8 @@
|
|
|
302
310
|
"mq.stFine": "angelegt, sendet",
|
|
303
311
|
"mq.stMissing": "Punkt fehlt",
|
|
304
312
|
"mq.stMute": "kann nicht senden",
|
|
313
|
+
"mq.stOff": "angelegt, aber abgeschaltet",
|
|
314
|
+
"mq.stUnknown": "angelegt, Senden unbekannt",
|
|
305
315
|
"mq.title": "MQTT-Gerät",
|
|
306
316
|
"mq.unknownCommand": "unbekannter Befehl",
|
|
307
317
|
"mq.write": "Anlegen ({0})",
|
|
@@ -315,13 +325,22 @@
|
|
|
315
325
|
"pattern.manualInstead": "von Hand statt {0}",
|
|
316
326
|
"pattern.missing": "{0} fehlt",
|
|
317
327
|
"pattern.noMatch": "kein Muster passt zu „{0}“",
|
|
328
|
+
"pattern.offGuess": "Mit „{0}“ würde es greifen.",
|
|
329
|
+
"pattern.offMissing": "Das {0}-Muster greift gerade nicht: {1} fehlt. Deshalb hat keine Zeile einen Platz.",
|
|
330
|
+
"pattern.offCandidate": "{0} passt auf {1}, ist aber nicht angehakt.",
|
|
331
|
+
"pattern.slotHeldBy": "{0} hat schon {1} — diese Zeile bekommt so keinen Platz. Oben unter „Platz im Muster“ einen freien Platz wählen.",
|
|
332
|
+
"pattern.tickIt": "anhaken",
|
|
333
|
+
"pattern.offCandidateType": "{0} passt mit seiner Rolle auf {1}, ist aber nicht angehakt und hat den Typ {2} statt {3}.",
|
|
334
|
+
"pattern.tickItType": "anhaken, {0}",
|
|
318
335
|
"pattern.noPlaceBecauseType": "Das {0}-Muster greift gerade nicht: {1} verlangt {2}, eingestellt ist {3}. Deshalb hat keine Zeile einen Platz.",
|
|
319
336
|
"pattern.noPlaceLegend": "So hinterlegte Zeilen haben keinen Platz im {0}-Muster",
|
|
320
337
|
"pattern.noPlaceLong": "kein Platz im {0}-Muster — der Punkt wird trotzdem angelegt und ist voll benutzbar, nur Alexa & Co. zählen ihn separat",
|
|
321
338
|
"pattern.notDetected": "nicht erkannt",
|
|
339
|
+
"pattern.orRole": "oder {0}",
|
|
322
340
|
"pattern.required": "PFLICHT — fehlt",
|
|
323
341
|
"pattern.search": "tippen zum Suchen …",
|
|
324
342
|
"pattern.slotName": "Der Punkt sitzt auf dem Platz „{0}\" des {1}-Musters. Diese Platznamen kommen aus dem type-detector und sind überall gleich — sie werden nicht übersetzt, weil der Datenpunkt im Alias genau so heißt.",
|
|
343
|
+
"pattern.pointsTaken": "✓ {0} Punkte",
|
|
325
344
|
"pattern.slotsTaken": "✓ {0}/{1} belegt",
|
|
326
345
|
"pattern.toSlot": " → Platz {0} im {1}-Muster",
|
|
327
346
|
"pattern.typeMismatch": "Der Platz {0} verlangt {1}, eingestellt ist {2} — so fällt der Punkt aus dem Muster, auch wenn die Rolle stimmt.",
|
|
@@ -379,6 +398,7 @@
|
|
|
379
398
|
"swap.now": "Jetzt tauschen",
|
|
380
399
|
"swap.removeIt": "diesen Punkt beim Tauschen entfernen",
|
|
381
400
|
"swap.same": "Das ist dieselbe Quelle wie bisher.",
|
|
401
|
+
"swap.pickFirst": "Erst eine neue Quelle wählen.",
|
|
382
402
|
"swap.search": "Suchen (Kennung oder Name) …",
|
|
383
403
|
"swap.title": "Quelle tauschen",
|
|
384
404
|
"swap.to": "Neue Quelle",
|
|
@@ -424,15 +444,19 @@
|
|
|
424
444
|
"tpl.presentIn": "{0} vorhanden",
|
|
425
445
|
"tpl.remembered": "gemerkt",
|
|
426
446
|
"tpl.rememberedHint": "Dieser Alias ist aus dieser Vorlage entstanden — sie bleibt, bis du sie ausdrücklich umstellst.",
|
|
427
|
-
"tpl.showAllPoints": "Alle Datenpunkte des Geräts",
|
|
447
|
+
"tpl.showAllPoints": "Alle Datenpunkte des Geräts laden",
|
|
428
448
|
"tpl.showAllPointsHelp": "Verlässt den Vorschlag der Vorlage und zeigt jeden Datenpunkt, den das Gerät hat — auch die, die keine Vorlage aufführt. Von hier lässt sich ein einzelner davon in den Alias holen.",
|
|
429
|
-
"tpl.showProposal": "Vorschlag
|
|
449
|
+
"tpl.showProposal": "Vorschlag der Vorlage laden",
|
|
430
450
|
"tpl.showProposalHelp": "Zurück zu dem, was die Vorlage für dieses Gerät vorschlägt.",
|
|
431
451
|
"tpl.skippedEmpty": "„{0}“ hätte die höhere Punktzahl, baut an diesem Gerät aber keine einzige Zeile — übergangen",
|
|
432
452
|
"tpl.skippedHead": "{0} weggelassen, weil die Quelle fehlt",
|
|
433
453
|
"tpl.skippedChip": "{0} ohne Quelle",
|
|
434
454
|
"tpl.skippedNowhere": "{0}: weder in {1}",
|
|
435
455
|
"tpl.skippedSource": "{0}: {1} fehlt",
|
|
456
|
+
"tpl.skippedWhy": "{0}: {1}",
|
|
457
|
+
"tpl.whyNoPoint": "{0} gibt es nicht",
|
|
458
|
+
"tpl.whyNoJson": "{0} liefert kein JSON",
|
|
459
|
+
"tpl.whyNoField": "{0} hat kein Feld {1}",
|
|
436
460
|
"tpl.whyNone": "Warum keine Vorlage greift",
|
|
437
461
|
"tpl.whyThis": "Warum diese Vorlage",
|
|
438
462
|
"tpl.withoutField": "{0} ohne {1}",
|
|
@@ -528,7 +552,7 @@
|
|
|
528
552
|
"tree.filterAria": "Objekte filtern",
|
|
529
553
|
"tree.loading": "lade Objekte …",
|
|
530
554
|
"tree.looksLikeDevice": "sieht wie ein einzelnes Gerät aus",
|
|
531
|
-
"tree.noObjectHint": "kein
|
|
555
|
+
"tree.noObjectHint": "kein echter Ordner",
|
|
532
556
|
"tree.nothingFound": "nichts gefunden",
|
|
533
557
|
"tree.sourceGone": "{0} Punkt(e) dieses Alias zeigen auf eine Quelle, die es nicht gibt. Der js-controller merkt sich das dauerhaft — hilft nur löschen und neu anlegen.",
|
|
534
558
|
"tree.sources": "Alias anlegen",
|
|
@@ -543,7 +567,7 @@
|
|
|
543
567
|
"tv.badNoStates": "Es fehlen die Datenpunkte (zustaende).",
|
|
544
568
|
"tv.badNotObject": "Erwartet wird eine einzelne Vorlage als JSON-Objekt.",
|
|
545
569
|
"tv.badRecog": "„erkennung“ muss ein Objekt sein.",
|
|
546
|
-
"tv.badState": "{0} Datenpunkte ohne Namen oder ohne
|
|
570
|
+
"tv.badState": "{0} Datenpunkte ohne Namen oder ohne Lese- und Schreibpfad.",
|
|
547
571
|
"tv.badType": "Den Gerätetyp „{0}“ kennt dieser Detector nicht.",
|
|
548
572
|
"tv.clickRow": "Zeile anklicken, um den Punkt zu bearbeiten",
|
|
549
573
|
"tv.delete": "Löschen",
|
package/admin/sprachen/en.json
CHANGED
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"check.sourceHasValue": "source has a value",
|
|
40
40
|
"check.targetCan": "target can do what is asked",
|
|
41
41
|
"check.targetCanFine": "all fine",
|
|
42
|
-
"check.targetNoRead": "{0}: the read source never changes",
|
|
43
42
|
"check.targetNoWrite": "{0}: the target is not writable",
|
|
44
43
|
"check.targetVoidFormula": "{0}: write formula runs into nothing, the target is {1}",
|
|
45
44
|
"check.title": "Checks — always running, never touching anything",
|
|
@@ -70,7 +69,7 @@
|
|
|
70
69
|
"detail.display": "Display",
|
|
71
70
|
"detail.elsewhere": "(elsewhere)",
|
|
72
71
|
"detail.expects": "expects {0}",
|
|
73
|
-
"detail.formula": "
|
|
72
|
+
"detail.formula": "Read formula",
|
|
74
73
|
"detail.formulaBroken": "formula is faulty",
|
|
75
74
|
"detail.formulaHint": "\"ON\"/\"OFF\" → boolean is done by the alias itself, no formula needed.",
|
|
76
75
|
"detail.formulaPlaceholder": "empty = take the value unchanged",
|
|
@@ -78,6 +77,7 @@
|
|
|
78
77
|
"detail.formulaTooSlow": "This formula took {0} ms and is no longer executed. Reloading the tab gives it one more try.",
|
|
79
78
|
"detail.jsonField": "Field in the JSON",
|
|
80
79
|
"detail.matchesState": "✓ matches the state",
|
|
80
|
+
"detail.nameTaken": "Another row already has the name {0}.",
|
|
81
81
|
"detail.name": "Name",
|
|
82
82
|
"detail.namePlaceholder": "e.g. UNREACH",
|
|
83
83
|
"detail.noSource": "— no source known —",
|
|
@@ -90,17 +90,24 @@
|
|
|
90
90
|
"detail.pickOne": "— please choose —",
|
|
91
91
|
"detail.rawNothing": "— the source delivers nothing —",
|
|
92
92
|
"detail.rawValue": "Raw value",
|
|
93
|
+
"detail.readOnlySlotWrites": "{0} is read-only in the pattern — “writes to” should be “— do not write —”, otherwise a written value goes to the device.",
|
|
93
94
|
"detail.readsFrom": "reads from",
|
|
94
95
|
"detail.removePoint": "Remove this point",
|
|
95
|
-
"detail.
|
|
96
|
+
"detail.readIsButton": "button",
|
|
97
|
+
"detail.slot": "Place in pattern",
|
|
98
|
+
"detail.slotNone": "— no place —",
|
|
99
|
+
"detail.slotNotGiven": "{0} is chosen but not assigned — see “Role” for what does not fit (usually the type).",
|
|
100
|
+
"detail.slotRequired": "required",
|
|
101
|
+
"detail.slotHint": "Sets role, type, unit and value list as the pattern prescribes for this place. Datapoint and name stay.",
|
|
96
102
|
"detail.role": "Role",
|
|
97
103
|
"detail.sameAsRead": "— same as read —",
|
|
98
|
-
"detail.separateHint": "
|
|
104
|
+
"detail.separateHint": "Reads from somewhere else than it writes to: what is shown is what the device reports back — not the command sent last.",
|
|
99
105
|
"detail.sourceGone": "source does not exist",
|
|
100
106
|
"detail.stateSays": "state says {0}",
|
|
101
107
|
"detail.takeFromAlias": "Take this one value back from the stored alias",
|
|
102
108
|
"detail.takeOne": "Take this one value from the template",
|
|
103
|
-
"detail.
|
|
109
|
+
"detail.readIsButtonHint": "Role button with a write target: the alias datapoint gets read: false, and vis, Alexa and matter draw it as a button. The read source does no harm — with it the alias sees every press, including one on the physical button. After a press the last value stays, as it does on the source.",
|
|
110
|
+
"detail.buttonNoRead": "Button without read source — does not read along",
|
|
104
111
|
"detail.targetNoWrite": "The target point carries write: false — its adapter passes nothing on to the device. ioBroker stores the value anyway, but nothing will happen.",
|
|
105
112
|
"detail.targetTypeHint": "The target point is of type {0}. It decides what survives of the write formula: mixed and string take text, boolean and number convert it back.",
|
|
106
113
|
"detail.targetTypeVoid": "The target is {0} and takes no text. The write formula does produce text — the js-controller converts it back to {0} on write, so the formula has no effect. Switching still works.",
|
|
@@ -108,7 +115,6 @@
|
|
|
108
115
|
"detail.tplWantsEmpty": "The template leaves this field empty.",
|
|
109
116
|
"detail.type": "Type",
|
|
110
117
|
"detail.unit": "Unit",
|
|
111
|
-
"detail.willBecome": "will become",
|
|
112
118
|
"detail.writeFormula": "Write formula",
|
|
113
119
|
"detail.writeFormulaHint": "converts the other way: what the device should receive when switched.",
|
|
114
120
|
"detail.writeFormulaPlaceholder": "e.g. val ? \"ON\" : \"OFF\"",
|
|
@@ -150,6 +156,7 @@
|
|
|
150
156
|
"enums.room": "Room",
|
|
151
157
|
"enums.roomHint": "Assigns the alias to a room. This is not stored on the object but in the \"enum.rooms\" enumeration — Alexa, Google and the dashboards group by it.",
|
|
152
158
|
"enums.suggested": "suggested",
|
|
159
|
+
"enums.notLoadedField": "Rooms and functions could not be loaded — so room and function will not be written; the alias itself is still created. The workbench retries three times by itself, otherwise reload the tab.",
|
|
153
160
|
"enums.unknown": "Enumerations not loaded — room and function stay untouched.",
|
|
154
161
|
"enums.unused": "empty",
|
|
155
162
|
"enums.willCreate": "create new",
|
|
@@ -181,7 +188,8 @@
|
|
|
181
188
|
"guess.mark": "guessed",
|
|
182
189
|
"guess.noneFit": "{0} stays free. No remaining datapoint fits — guessing goes by name, value list, unit and type, and nothing cleared the threshold.",
|
|
183
190
|
"guess.noneFull": "Every slot of the pattern is taken — there is nothing left to suggest.",
|
|
184
|
-
"guess.noneHand": "{0} rows were decided by hand and are left untouched.",
|
|
191
|
+
"guess.noneHand": "{0} rows were decided by hand and are left untouched: {1}.",
|
|
192
|
+
"guess.noneHandOne": "{0} was decided by hand and is left untouched.",
|
|
185
193
|
"guess.noneUsed": "{0} stays free. Every remaining datapoint already serves as a read or write source in a filled row.",
|
|
186
194
|
"guess.slotsMore": "{0} and {1} more",
|
|
187
195
|
"guess.tplAsk": "This device is identified as “{0}”, so the assignment is already settled. The suggestion fills additional slots from the remaining data points — an attempt, not knowledge, and every match would need checking. Meant for special cases, e.g. when the device can do more than the template covers.",
|
|
@@ -302,6 +310,8 @@
|
|
|
302
310
|
"mq.stFine": "present, sends",
|
|
303
311
|
"mq.stMissing": "point missing",
|
|
304
312
|
"mq.stMute": "cannot send",
|
|
313
|
+
"mq.stOff": "present, but switched off",
|
|
314
|
+
"mq.stUnknown": "present, sending unknown",
|
|
305
315
|
"mq.title": "MQTT device",
|
|
306
316
|
"mq.unknownCommand": "unknown command",
|
|
307
317
|
"mq.write": "Create ({0})",
|
|
@@ -315,13 +325,22 @@
|
|
|
315
325
|
"pattern.manualInstead": "by hand instead of {0}",
|
|
316
326
|
"pattern.missing": "{0} missing",
|
|
317
327
|
"pattern.noMatch": "no pattern matches \"{0}\"",
|
|
328
|
+
"pattern.offGuess": "With “{0}” it would apply.",
|
|
329
|
+
"pattern.offMissing": "The {0} pattern does not apply right now: {1} is missing. That is why no row has a slot.",
|
|
330
|
+
"pattern.offCandidate": "{0} fits {1} but is not ticked.",
|
|
331
|
+
"pattern.slotHeldBy": "{1} already holds {0} — this row gets no place that way. Pick a free place under “Place in pattern” above.",
|
|
332
|
+
"pattern.tickIt": "tick it",
|
|
333
|
+
"pattern.offCandidateType": "{0} fits {1} by its role, but is not ticked and has type {2} instead of {3}.",
|
|
334
|
+
"pattern.tickItType": "tick it, {0}",
|
|
318
335
|
"pattern.noPlaceBecauseType": "The {0} pattern does not apply right now: {1} requires {2}, but {3} is set. That is why no row has a slot.",
|
|
319
336
|
"pattern.noPlaceLegend": "Rows shaded like this have no slot in the {0} pattern",
|
|
320
337
|
"pattern.noPlaceLong": "no slot in the {0} pattern — the point is still created and fully usable, only Alexa and friends count it separately",
|
|
321
338
|
"pattern.notDetected": "not detected",
|
|
339
|
+
"pattern.orRole": "or {0}",
|
|
322
340
|
"pattern.required": "REQUIRED — missing",
|
|
323
341
|
"pattern.search": "type to search …",
|
|
324
342
|
"pattern.slotName": "This point sits in slot \"{0}\" of the {1} pattern. Slot names come from the type-detector and are the same everywhere — they are not translated, because the alias datapoint is named exactly that.",
|
|
343
|
+
"pattern.pointsTaken": "✓ {0} points",
|
|
325
344
|
"pattern.slotsTaken": "✓ {0}/{1} filled",
|
|
326
345
|
"pattern.toSlot": " → slot {0} in the {1} pattern",
|
|
327
346
|
"pattern.typeMismatch": "Slot {0} requires {1}, but {2} is set — the state drops out of the pattern even though the role is right.",
|
|
@@ -379,6 +398,7 @@
|
|
|
379
398
|
"swap.now": "Swap now",
|
|
380
399
|
"swap.removeIt": "remove this point while swapping",
|
|
381
400
|
"swap.same": "That is the same source as before.",
|
|
401
|
+
"swap.pickFirst": "Pick a new source first.",
|
|
382
402
|
"swap.search": "Search (id or name) …",
|
|
383
403
|
"swap.title": "Swap source",
|
|
384
404
|
"swap.to": "New source",
|
|
@@ -424,15 +444,19 @@
|
|
|
424
444
|
"tpl.presentIn": "{0} present",
|
|
425
445
|
"tpl.remembered": "remembered",
|
|
426
446
|
"tpl.rememberedHint": "This alias was built from this template — it stays until you change it deliberately.",
|
|
427
|
-
"tpl.showAllPoints": "
|
|
447
|
+
"tpl.showAllPoints": "Load all datapoints of the device",
|
|
428
448
|
"tpl.showAllPointsHelp": "Leaves the template proposal and lists every datapoint the device has, including those no template mentions. From here you can pull a single one into the alias.",
|
|
429
|
-
"tpl.showProposal": "
|
|
449
|
+
"tpl.showProposal": "Load the template proposal",
|
|
430
450
|
"tpl.showProposalHelp": "Back to what the template proposes for this device.",
|
|
431
451
|
"tpl.skippedEmpty": "\"{0}\" would score higher but builds not a single row on this device — skipped",
|
|
432
452
|
"tpl.skippedHead": "{0} left out because the source is missing",
|
|
433
453
|
"tpl.skippedChip": "{0} without source",
|
|
434
454
|
"tpl.skippedNowhere": "{0}: neither in {1}",
|
|
435
455
|
"tpl.skippedSource": "{0}: {1} missing",
|
|
456
|
+
"tpl.skippedWhy": "{0}: {1}",
|
|
457
|
+
"tpl.whyNoPoint": "{0} does not exist",
|
|
458
|
+
"tpl.whyNoJson": "{0} delivers no JSON",
|
|
459
|
+
"tpl.whyNoField": "{0} has no field {1}",
|
|
436
460
|
"tpl.whyNone": "Why no template applies",
|
|
437
461
|
"tpl.whyThis": "Why this template",
|
|
438
462
|
"tpl.withoutField": "{0} without {1}",
|
|
@@ -528,7 +552,7 @@
|
|
|
528
552
|
"tree.filterAria": "Filter objects",
|
|
529
553
|
"tree.loading": "loading objects …",
|
|
530
554
|
"tree.looksLikeDevice": "looks like a single device",
|
|
531
|
-
"tree.noObjectHint": "
|
|
555
|
+
"tree.noObjectHint": "not a real folder",
|
|
532
556
|
"tree.nothingFound": "nothing found",
|
|
533
557
|
"tree.sourceGone": "{0} point(s) of this alias refer to a source that does not exist. The js-controller remembers this permanently — only deleting and recreating helps.",
|
|
534
558
|
"tree.sources": "Create alias",
|
|
@@ -543,7 +567,7 @@
|
|
|
543
567
|
"tv.badNoStates": "The datapoints (zustaende) are missing.",
|
|
544
568
|
"tv.badNotObject": "A single template as a JSON object is expected.",
|
|
545
569
|
"tv.badRecog": "“erkennung” must be an object.",
|
|
546
|
-
"tv.badState": "{0} datapoints without a name or without
|
|
570
|
+
"tv.badState": "{0} datapoints without a name or without any read or write path.",
|
|
547
571
|
"tv.badType": "This detector does not know the device type “{0}”.",
|
|
548
572
|
"tv.clickRow": "Click a row to edit the datapoint",
|
|
549
573
|
"tv.delete": "Delete",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "hm-rollladen",
|
|
3
|
-
"version":
|
|
3
|
+
"version": 4,
|
|
4
4
|
"rang": 40,
|
|
5
5
|
"name": {
|
|
6
6
|
"de": "Homematic Rollladenaktor",
|
|
@@ -42,9 +42,10 @@
|
|
|
42
42
|
"name": "STOP",
|
|
43
43
|
"rolle": "button.stop",
|
|
44
44
|
"typ": "boolean",
|
|
45
|
+
"lesen": "1.STOP",
|
|
45
46
|
"schreiben": "1.STOP",
|
|
46
47
|
"optional": true,
|
|
47
|
-
"hinweis": "
|
|
48
|
+
"hinweis": "Liest und schreibt 1.STOP. Der Alias-Punkt bekommt trotzdem read: false - das kommt aus der Rolle button.stop -, und vis, Alexa und matter zeichnen einen Knopf. Mit der Lesequelle sieht der Alias auch einen Druck von aussen."
|
|
48
49
|
},
|
|
49
50
|
{
|
|
50
51
|
"name": "DIRECTION",
|