iobroker.alias-workbench 0.9.9 → 0.9.11

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.
@@ -14,7 +14,8 @@ import {
14
14
  } from './aufzaehlungen.js';
15
15
  import { enumVorlagen, katalogFehlt, ikonCache, ikonErlaubt, ikonNachtrag,
16
16
  ikonTaugt, vorlageZu, holeIkon } from './katalog.js';
17
- import { kindZustaende, aliasQuellen, holeEinzelne, schreibQuelle } from './werte.js';
17
+ import { kindZustaende, aliasQuellen, holeEinzelne,
18
+ zeileAusAlias } from './werte.js';
18
19
  import { aliasFuer, zielId, knotenDa } from './entwurf.js';
19
20
  import { zeichneErgebnis, entwurfAngefasst, angebotFrisch } from './ergebnis.js';
20
21
 
@@ -580,7 +581,8 @@ export function uebernehmeBestand(e) {
580
581
  hiesse, dem Vorlagenknopf den Wert zu nehmen, den er zurueckholen
581
582
  soll. */
582
583
  function vomAliasUebernehmen(z, o) {
583
- var c = o.common || {}, a = c.alias || {}, q2 = aliasQuellen(o);
584
+ var c = o.common || {}, q2 = aliasQuellen(o);
585
+ var ist = zeileAusAlias(o, z.n);
584
586
  if (!z.vorlagenWert) {
585
587
  z.vorlagenWert = {
586
588
  on: z.on, role: z.role, typ: z.typ, unit: z.unit, caption: z.caption,
@@ -593,10 +595,10 @@ export function uebernehmeBestand(e) {
593
595
  stellen, kann der Stand nicht wieder auseinanderlaufen. */
594
596
  if (c.role !== undefined) { z.role = c.role; }
595
597
  if (c.type !== undefined) { z.typ = c.type; }
596
- z.unit = c.unit || '';
597
- z.states = c.states || undefined;
598
- z.f = (typeof a.read === 'string') ? a.read : '';
599
- z.fw = (typeof a.write === 'string') ? a.write : '';
598
+ z.unit = ist.unit;
599
+ z.states = ist.states;
600
+ z.f = ist.f;
601
+ z.fw = ist.fw;
600
602
  /* Die Beschriftung steht im Alias und gehoert dem Nutzer.
601
603
 
602
604
  Sie fehlte hier als einzige - `bestandVorrang` holt sie laengst
@@ -607,9 +609,10 @@ export function uebernehmeBestand(e) {
607
609
  „Bezug" geworden (Ricardo, 07.09.2026, an alias.0.Solar.Netz).
608
610
  Gleicht die Beschriftung dem Zeilennamen, bleibt sie leer - so
609
611
  haelt es der Zweig darunter, der neue Zeilen anlegt, auch. */
610
- var nm2 = txt(c.name);
611
- z.caption = (nm2 && nm2 !== z.n) ? nm2 : '';
612
- if (q2.read) { z.srcR = q2.read; }
612
+ z.caption = ist.caption;
613
+ /* Wie im Bestandsvorrang: `ist.srcR` kennt den Taster, `q2.read`
614
+ nicht. */
615
+ if (q2.read) { z.srcR = ist.srcR; }
613
616
  /* Und dieselbe Schreibregel wie im Bestandsvorrang.
614
617
 
615
618
  Hier stand die Schreibquelle nur fuer das getrennte Paar; sonst
@@ -622,7 +625,7 @@ export function uebernehmeBestand(e) {
622
625
  Belegt ist das Schreiben durch `common.write` oder durch eine
623
626
  hinterlegte Schreibformel; bei getrennten Quellen zaehlt, was in
624
627
  `alias.id.write` steht. */
625
- z.srcW = schreibQuelle(o);
628
+ z.srcW = ist.srcW;
626
629
  if (q2.write && !q2.einfach && q2.write !== q2.read) {
627
630
  /* Die Gegenzeile eines Paars ist keine eigene mehr - ihre Quelle
628
631
  steckt jetzt als Schreibquelle in dieser Zeile. */
@@ -663,7 +666,7 @@ export function uebernehmeBestand(e) {
663
666
  kindZustaende(e.ziel).forEach(function (id) {
664
667
  var n = id.slice(e.ziel.length + 1);
665
668
  if (n.indexOf('.') !== -1 || kennt[n]) { return; }
666
- var o = S.objects[id], c = o.common || {}, a = c.alias || {}, q = aliasQuellen(o);
669
+ var o = S.objects[id], q = aliasQuellen(o);
667
670
 
668
671
  /* Derselbe Punkt unter anderem Namen? Dann ist es kein zweiter,
669
672
  sondern derselbe — und der Name, der schon im Alias steht, gilt.
@@ -699,31 +702,24 @@ export function uebernehmeBestand(e) {
699
702
  kennt[n] = vorhanden;
700
703
  return;
701
704
  }
702
- var nm = txt(c.name);
703
- e.states.push({
704
- n: n, on: true, ausBestand: true, nurImAlias: true,
705
- role: c.role || '', typ: c.type || '', unit: c.unit || '',
706
- states: c.states || undefined,
707
- wr: !!c.write,
708
- srcR: q.read || '',
709
- /* Dieselbe Schreibregel wie oben und im Bestandsvorrang.
710
-
711
- Hier stand `q.einfach ? '' : (q.write || '')` - bei schlichtem
712
- `alias.id` also immer leer, ohne `common.write` ueberhaupt
713
- anzusehen. Es trifft jeden Alias, bei dem MEHRERE Punkte auf
714
- denselben Quellpunkt zeigen: die eine Vorschlagszeile bekommt
715
- der erste von ihnen, alle weiteren landen hier. Am
716
- `alias.0.Badezimmer.Rollladen` zeigen OPEN, CLOSE, SET und pct
717
- alle auf `…Bad.level`; CLOSE lief oben durch und behielt seine
718
- Schreibquelle, OPEN, SET und pct verloren sie - ein
719
- Aktualisieren haette den Rollladen ueber den Alias unfahrbar
720
- gemacht (Ricardo, 08.09.2026). */
721
- srcW: schreibQuelle(o),
722
- f: (typeof a.read === 'string') ? a.read : '',
723
- fw: (typeof a.write === 'string') ? a.write : '',
724
- caption: (nm && nm !== n) ? nm : '',
725
- manuell: false
726
- });
705
+ /* Rolle, Typ, Einheit, Zustaende, Formeln, Quellen und Beschriftung
706
+ kommen geschlossen aus `zeileAusAlias` - dieselbe Ablesung wie in
707
+ `bestandVorrang`, `bestandsAbweichung` und `vomAliasUebernehmen`.
708
+
709
+ Dazu gehoert die Schreibregel: Hier stand `q.einfach ? '' :
710
+ (q.write || '')` - bei schlichtem `alias.id` also immer leer, ohne
711
+ `common.write` ueberhaupt anzusehen. Es trifft jeden Alias, bei dem
712
+ MEHRERE Punkte auf denselben Quellpunkt zeigen: die eine
713
+ Vorschlagszeile bekommt der erste von ihnen, alle weiteren landen
714
+ hier. Am `alias.0.Badezimmer.Rollladen` zeigen OPEN, CLOSE, SET und
715
+ pct alle auf `…Bad.level`; CLOSE lief oben durch und behielt seine
716
+ Schreibquelle, OPEN, SET und pct verloren sie - ein Aktualisieren
717
+ haette den Rollladen ueber den Alias unfahrbar gemacht (Ricardo,
718
+ 08.09.2026). Seit dem Zusammenlegen der vier Stellen (Y5) gilt die
719
+ Regel fuer alle zugleich. */
720
+ e.states.push(Object.assign(zeileAusAlias(o, n), {
721
+ n: n, on: true, ausBestand: true, nurImAlias: true, manuell: false
722
+ }));
727
723
  });
728
724
 
729
725
  /* Einmal nachzeichnen.
@@ -14,6 +14,9 @@ export var S = {
14
14
  objects: {},
15
15
  keysSorted: [],
16
16
  kleinIndex: {},
17
+ /* Alias-Kanal -> Zahl der Punkte, deren Quelle es nicht (mehr) gibt.
18
+ Einmal beim Laden gerechnet; der Baum schlaegt nur nach. */
19
+ aliasKaputt: {},
17
20
  werte: {},
18
21
  current: null,
19
22
  openRow: null,
@@ -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 } from './erkennung.js';
12
+ import { erkenneEntwurf, musterVon, rolleVonPlatz, typKonflikte } 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';
@@ -17,6 +17,7 @@ import { detailZeile } from './detail.js';
17
17
  import { rateAnzahl, rateZurueck, rateZurueckEine, rateBehalten } from './vorschlagen.js';
18
18
  import { mqttEinzeln } from './mqtt.js';
19
19
  import { zeichneErgebnis, entwurfAngefasst } from './ergebnis.js';
20
+ import { taster } from './schreiben.js';
20
21
 
21
22
  export function berechnePlaetze(e, haupt) {
22
23
  /* --- welcher Punkt sitzt auf welchem Platz --- */
@@ -367,10 +368,30 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
367
368
  var legendenPlatz = el('div');
368
369
  card.appendChild(legendenPlatz);
369
370
 
371
+ /* Kippt das ganze Muster an einem einzelnen Typkonflikt? Einmal
372
+ gerechnet: die Zeilenschleife braucht es, die Legende darunter
373
+ ebenso, und beide sollen dieselbe Antwort geben. */
374
+ var kipptAnTyp = typKonflikte(e.states, e.want).filter(function (x) { return x.pflicht; })[0] || null;
375
+
370
376
  /* --- Zustandsliste --- */
371
377
  e.states.forEach(function (s, i) {
372
378
  var pl = platzVon[s.n];
373
- var unfertig = (!s.n || !s.srcR);
379
+ /* „Quelle eingetragen" und „Quelle vorhanden" sind zweierlei. Bis
380
+ zum 14.09.2026 fragte die Zeile nur das erste - ein Alias, dessen
381
+ Geraet aus dem System verschwunden ist (Ricardo: der Fensterkontakt
382
+ zeigte noch auf den laengst abgeloesten zigbee-Adapter), stand
383
+ deshalb ohne jedes Zeichen da. Gesagt wurde es nur im aufgeklappten
384
+ Detail und im Pruefungen-Kasten. */
385
+ var quelleWeg = !!(s.srcR && !S.objects[s.srcR]);
386
+ /* Ein Taster hat keine Lesequelle, und das ist kein Mangel: das Ziel
387
+ sagt selbst, dass dort nichts abzuholen ist (`read: false`). Ohne
388
+ diese Ausnahme stand an der STOP-Zeile weiter das rote `!` mit
389
+ „Quelle fehlt", obwohl der Alias sich laengst schreiben liess —
390
+ zwei Ansichten, zwei Urteile (Ricardo, 15.09.2026, K23). */
391
+ var istTaster = taster(s);
392
+ var unfertig = (!s.n || (!s.srcR && !istTaster) || quelleWeg);
393
+ var wasFehlt = !s.n ? tr('list.nameMissing')
394
+ : (quelleWeg ? tr('list.sourceGone') : tr('list.sourceMissing'));
374
395
  /* Angehakt, vollstaendig, aber ohne Platz im Muster. Frueher stand
375
396
  dazu in JEDER betroffenen Zeile derselbe Satz — bei einem
376
397
  Thermostat mit 42 Punkten zwanzigmal dasselbe, und die Spalte
@@ -378,12 +399,27 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
378
399
  06.09.2026). Jetzt traegt die Zeile eine Marke, der Satz steht
379
400
  einmal als Legende ueber der Liste, und der lange Text haengt als
380
401
  Hinweis an der Zeile. */
381
- var ohnePlatz = (s.on && !unfertig && !pl);
402
+ /* Kippt das Muster an einem Typkonflikt, wird nur der Verursacher
403
+ getoent - nicht die ganze Liste.
404
+
405
+ Dass danach keine Zeile einen Platz hat, stimmt zwar, taugt aber
406
+ nicht als Auskunft: Die Toenung liest sich als „mit dieser Zeile
407
+ stimmt etwas nicht", und das trifft auf sieben von acht nicht zu.
408
+ Sie zeigte die Folge und nicht die Ursache (Ricardo, 12.09.2026).
409
+ Die Legende darueber nennt den Grund; markiert wird die Zeile, an
410
+ der er haengt. */
411
+ var ohnePlatz = (s.on && !unfertig && !pl &&
412
+ (!kipptAnTyp || kipptAnTyp.n === s.n));
382
413
  if (ohnePlatz) { ohnePlatzZahl++; ohnePlatzNamen.push(s.n); }
383
414
  var row = el('div', 'erow' + (s.on ? '' : ' skip') + (S.openRow === i ? ' open' : '') +
384
415
  (ohnePlatz ? ' ohneplatz' : ''));
385
416
  row.tabIndex = 0;
386
- if (ohnePlatz) { row.title = tr('pattern.noPlaceLong', musterName(e.want) || e.want || '?'); }
417
+ if (ohnePlatz) {
418
+ row.title = kipptAnTyp
419
+ ? tr('pattern.noPlaceBecauseType', musterName(e.want) || e.want || '?',
420
+ kipptAnTyp.platz, kipptAnTyp.erwartet.join(tr('pattern.typeOr')), kipptAnTyp.typ)
421
+ : tr('pattern.noPlaceLong', musterName(e.want) || e.want || '?');
422
+ }
387
423
 
388
424
  var cbw = el('span');
389
425
  var cb = document.createElement('input');
@@ -405,7 +441,7 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
405
441
  Ueberfliegen wirklich sucht: wo klemmt es. */
406
442
  var mk = el('span', 'mk2 bad');
407
443
  mk.textContent = (s.on && unfertig) ? '!' : '';
408
- if (mk.textContent) { mk.title = !s.n ? tr('list.nameMissing') : tr('list.sourceMissing'); }
444
+ if (mk.textContent) { mk.title = wasFehlt; }
409
445
  row.appendChild(mk);
410
446
 
411
447
  var n3 = el('span', 'nm3', s.n || tr('list.newPoint'));
@@ -547,7 +583,10 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
547
583
  n3.appendChild(fb2);
548
584
  }
549
585
  if (s.on) {
550
- if (unfertig) { n3.appendChild(el('em', null, !s.n ? tr('list.nameMissing') : tr('list.sourceMissing'))); }
586
+ if (unfertig) { n3.appendChild(el('em', null, wasFehlt)); }
587
+ /* Beim Taster gehoert hin, WARUM keine Lesequelle dasteht — sonst
588
+ sieht die leere Spalte aus wie ein vergessener Eintrag. */
589
+ else if (istTaster) { n3.appendChild(el('em', null, tr('list.buttonOnly'))); }
551
590
  else if (pl && pl !== s.n && platzAnzahl[pl] === 1) {
552
591
  var pe = el('em', null, pl);
553
592
  pe.title = tr('pattern.slotName', pl, musterName(e.want) || e.want || '?');
@@ -670,7 +709,20 @@ export function baueListe(host, e, pl, rateKnopf, musterBlock) {
670
709
  if (ohnePlatzZahl) {
671
710
  var mn = musterName(e.want) || e.want || '?';
672
711
  var lg = el('div', 'legendenzeile');
673
- lg.appendChild(document.createTextNode(tr('pattern.noPlaceLegend', mn)));
712
+ /* Steht die ganze Liste ohne Platz da, weil EINE Zeile im falschen
713
+ Datentyp ist, sagt die Legende das - statt acht Zeilen pauschal zu
714
+ beschuldigen.
715
+
716
+ Der Ablauf: der Punkt faellt wegen des Typs aus dem Muster, damit
717
+ ist ein Pflichtplatz leer, damit greift das Muster nicht mehr, und
718
+ damit hat KEINE Zeile mehr einen Platz. Am Bastelzimmer_Licht
719
+ reichte ein Wechsel an SET von `boolean` auf `mixed`: acht von acht
720
+ Zeilen getoent, Musterfeld „✕ SET fehlt", und die Ursache stand
721
+ nur in der aufgeklappten SET-Zeile (Ricardo, 12.09.2026). */
722
+ lg.appendChild(document.createTextNode(kipptAnTyp
723
+ ? tr('pattern.noPlaceBecauseType', mn, kipptAnTyp.platz,
724
+ kipptAnTyp.erwartet.join(tr('pattern.typeOr')), kipptAnTyp.typ)
725
+ : tr('pattern.noPlaceLegend', mn)));
674
726
 
675
727
  var ib = el('button', 'infoknopf', 'i');
676
728
  ib.type = 'button';
@@ -37,6 +37,11 @@
37
37
  "check.sendUnknown": "Ob {0} senden darf, steht nicht im Objekt — das Thema liegt nur in `native`. Bei ioBroker.mqtt und sonoff ist das normal.",
38
38
  "check.sourceExists": "Quelle existiert",
39
39
  "check.sourceHasValue": "Quelle hat einen Wert",
40
+ "check.targetCan": "Ziel kann, was verlangt wird",
41
+ "check.targetCanFine": "alle in Ordnung",
42
+ "check.targetNoRead": "{0}: die Lesequelle meldet nichts",
43
+ "check.targetNoWrite": "{0}: das Ziel ist nicht beschreibbar",
44
+ "check.targetVoidFormula": "{0}: Schreibformel läuft ins Leere, das Ziel ist {1}",
40
45
  "check.title": "Prüfungen — laufen immer mit, fassen nichts an",
41
46
  "del.allOutputs": "Alle {0} Ausgänge dieses Geräts entfernen",
42
47
  "del.allOutputsHint": "Sonst bleibt der Rest verwaist stehen: {0}",
@@ -49,6 +54,9 @@
49
54
  "del.hint": "Der Alias samt allen Datenpunkten darunter wird gelöscht. Die Quellen bleiben unberührt — es verschwindet nur die Hülle, nicht das Gerät. Rückgängig geht das nicht.",
50
55
  "del.now": "Endgültig entfernen",
51
56
  "del.objects": "Was verschwindet",
57
+ "del.scriptsHead": "{0} Skripte nennen diese Kennung:",
58
+ "del.scriptsHead1": "Ein Skript nennt diese Kennung:",
59
+ "del.scriptsHint": "Durchsucht wurden nur die Skripte des javascript-Adapters, im Klartext. vis-Ansichten, Szenen und die Einstellungen fremder Adapter bleiben außen vor.",
52
60
  "del.title": "Alias entfernen",
53
61
  "detail.aliasEmpty": "Im Alias ist dieses Feld leer.",
54
62
  "detail.aliasHas": "Im Alias steht: ",
@@ -75,6 +83,7 @@
75
83
  "detail.noSource": "— keine Quelle bekannt —",
76
84
  "detail.noValue": "kein Wert",
77
85
  "detail.noWrite": "— nicht schreiben —",
86
+ "detail.notWritable": "nicht beschreibbar",
78
87
  "detail.objectId": "Objekt-ID",
79
88
  "detail.otherObject": "… anderes Objekt eintragen",
80
89
  "detail.ownFormula": "eigene Formel",
@@ -83,6 +92,7 @@
83
92
  "detail.rawValue": "Rohwert",
84
93
  "detail.readsFrom": "liest aus",
85
94
  "detail.removePoint": "Diesen Punkt entfernen",
95
+ "detail.reportsNothing": "meldet nichts",
86
96
  "detail.role": "Rolle",
87
97
  "detail.sameAsRead": "— dieselbe wie lesen —",
88
98
  "detail.separateHint": "getrennt — der Schalter zeigt den Zustand, nicht den Befehl",
@@ -90,6 +100,10 @@
90
100
  "detail.stateSays": "Zustand sagt {0}",
91
101
  "detail.takeFromAlias": "Diesen einen Wert aus dem gespeicherten Alias zurückholen",
92
102
  "detail.takeOne": "Diesen einen Wert aus der Vorlage übernehmen",
103
+ "detail.targetNoRead": "Die Lesequelle trägt read: false — sie meldet nie einen Wert. Bei einem Tastendruck ist das richtig so: er hat keinen Zustand. Dann gehört hier gar keine Lesequelle hin.",
104
+ "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
+ "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
+ "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.",
93
107
  "detail.tplWants": "Die Vorlage will hier: ",
94
108
  "detail.tplWantsEmpty": "Die Vorlage lässt dieses Feld leer.",
95
109
  "detail.type": "Typ",
@@ -130,6 +144,7 @@
130
144
  "enums.members": "{0} drin",
131
145
  "enums.newSuffix": "neu",
132
146
  "enums.noMatch": "nichts gefunden zu „{0}“",
147
+ "enums.nowEmpty": "ist danach leer und wird entfernt",
133
148
  "enums.placeholder": "leer = keine Zuordnung",
134
149
  "enums.removeFrom": "wird herausgenommen",
135
150
  "enums.room": "Raum",
@@ -151,7 +166,12 @@
151
166
  "folder.nothingHere": "Hier liegt nichts, woraus ein Gerät werden könnte.",
152
167
  "folder.withAlias": "{0} mit Alias",
153
168
  "folder.withoutTemplate": "{0} ohne Vorlage",
169
+ "guess.alsoRow": "mit Vorschlag: passt",
154
170
  "guess.bar": "{0} Plätze vermutet — bitte prüfen",
171
+ "guess.better": "{0} würde evtl. besser passen",
172
+ "guess.betterGoHint": "Wechselt auf {0} und drückt gleich „{1}\". Jede Zuordnung steht danach als „vermutet\" da und ist einzeln zu prüfen; verwerfen geht jederzeit. Am Gerät ändert sich dabei nichts — gesetzt werden nur Rollen im Entwurf.",
173
+ "guess.betterHint": "{0} käme auf {1} belegte Plätze, {2} auf {3} — beide Zahlen nach dem Vorschlag. Wechseln und dann „Freie Plätze vorschlagen\" drücken; jede Zuordnung ist einzeln zu prüfen.",
174
+ "guess.betterHintNone": "{0} käme nach dem Vorschlag auf {1} belegte Plätze; {2} passt auch dann nicht. Wechseln und dann „Freie Plätze vorschlagen\" drücken; jede Zuordnung ist einzeln zu prüfen.",
155
175
  "guess.button": "Freie Plätze vorschlagen",
156
176
  "guess.drop": "verwerfen",
157
177
  "guess.hint": "Belegt die freien Plätze des Musters aus den übrigen Datenpunkten — ein Versuch, kein Wissen. Vermutet wird nach Namen, Werteliste, Einheit und Typ; jede Zuordnung ist als „vermutet\" markiert und einzeln zu verwerfen.",
@@ -159,10 +179,14 @@
159
179
  "guess.keepAll": "alle behalten",
160
180
  "guess.locked": "{0}× vermutet, noch unentschieden — erst behalten (✓) oder verwerfen (✕), dann lässt sich anlegen und speichern.",
161
181
  "guess.mark": "vermutet",
162
- "guess.none": "Nichts vorzuschlagen: entweder sind alle Plätze besetzt, oder kein übriger Datenpunkt passt zu einem freien Platz.",
163
- "guess.tplAsk": "Dieses Gerät ist als „{0}“ identifiziert; die Zuordnung steht damit schon. Der Vorschlag rät 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.",
182
+ "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
+ "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.",
185
+ "guess.noneUsed": "Frei bleibt {0}. Jeder übrige Datenpunkt steckt schon als Lese- oder Schreibquelle in einer belegten Zeile.",
186
+ "guess.slotsMore": "{0} und {1} weitere",
187
+ "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.",
164
188
  "guess.tplGo": "Trotzdem vorschlagen",
165
- "guess.tplHint": "Die Vorlage deckt das Gerät schon ab — Raten ist hier nur für Sonderfälle.",
189
+ "guess.tplHint": "Die Vorlage deckt das Gerät schon ab — ein Vorschlag ist hier nur für Sonderfälle.",
166
190
  "guess.tplTitle": "Freie Plätze trotz Vorlage?",
167
191
  "guess.undo": "Vorschläge verwerfen",
168
192
  "help.aliases": "Links einen vorhandenen Alias wählen. Punkte entfernen, Rollen, Quellen und Formeln ändern — oder ihn verlegen, umbenennen und löschen.",
@@ -179,6 +203,7 @@
179
203
  "list.addByHand": "Datenpunkt von Hand hinzufügen",
180
204
  "list.aliasDiffers": "weicht vom gespeicherten Alias ab",
181
205
  "list.all": "alle",
206
+ "list.buttonOnly": "nur schreiben",
182
207
  "list.byHand": "von Hand",
183
208
  "list.changed": "geändert",
184
209
  "list.colOn": "an",
@@ -198,6 +223,7 @@
198
223
  "list.reset": "zurücksetzen",
199
224
  "list.resetHint": "Verwirft alle Änderungen dieser Sitzung — Haken, Rollen, Formeln, Quellen — und zeigt wieder den Stand, wie er im System steht.",
200
225
  "list.sendPointMissing": "Sendepunkt fehlt noch",
226
+ "list.sourceGone": "Quelle gibt es nicht",
201
227
  "list.sourceHint": "Dieser Punkt liest aus {0}.",
202
228
  "list.sourceMissing": "Quelle fehlt",
203
229
  "list.tpl": "Vorlage",
@@ -288,6 +314,7 @@
288
314
  "pattern.manualInstead": "von Hand statt {0}",
289
315
  "pattern.missing": "{0} fehlt",
290
316
  "pattern.noMatch": "kein Muster passt zu „{0}“",
317
+ "pattern.noPlaceBecauseType": "Das {0}-Muster greift gerade nicht: {1} verlangt {2}, eingestellt ist {3}. Deshalb hat keine Zeile einen Platz.",
291
318
  "pattern.noPlaceLegend": "So hinterlegte Zeilen haben keinen Platz im {0}-Muster",
292
319
  "pattern.noPlaceLong": "kein Platz im {0}-Muster — der Punkt wird trotzdem angelegt und ist voll benutzbar, nur Alexa & Co. zählen ihn separat",
293
320
  "pattern.notDetected": "nicht erkannt",
@@ -311,6 +338,8 @@
311
338
  "result.sourceCount": "{0} Quellen",
312
339
  "result.sourceCountHint": "Die Punkte dieses Alias lesen aus mehr als einem Knoten. „zur Quelle\" führt zu dem, aus dem die meisten stammen; ein Klick zeigt alle zur Auswahl.",
313
340
  "result.sourceGone": "Die Quelle {0} gibt es nicht mehr.",
341
+ "result.sourceGone1": "1 Punkt zeigt ins Leere",
342
+ "result.sourceGoneN": "{0} Punkte zeigen ins Leere",
314
343
  "result.states": "{0} Zustände",
315
344
  "result.statesDirect": "{0} Zustände ({1} direkt)",
316
345
  "result.toAlias": "zum Alias",
@@ -326,14 +355,19 @@
326
355
  "roles.slot": "Platz {0} im {1}-Muster",
327
356
  "roles.slotFree": "frei",
328
357
  "roles.slotTaken": "belegt von {0}",
358
+ "swap.blocked": "Erst entscheiden — diese Punkte können nicht mitziehen: {0}. Entweder beim Tauschen entfernen oder den Tausch lassen; ein Punkt, der schreiben soll, braucht ein Schreibziel.",
329
359
  "swap.button": "Quelle tauschen …",
330
360
  "swap.diffRange": "Wertebereich {0} → {1}",
331
361
  "swap.diffType": "Typ {0} → {1}",
332
362
  "swap.diffUnit": "Einheit {0} → {1}",
333
363
  "swap.done": "Getauscht. Der Alias liest jetzt aus {0}.",
334
364
  "swap.from": "Liest heute aus:",
365
+ "swap.goHigher": "eine Ebene höher nehmen",
335
366
  "swap.gone": "Dieses Gerät gibt es nicht mehr — genau dafür ist dieser Weg gedacht.",
336
367
  "swap.guessHint": "Die mit „vermutet“ gekennzeichneten Zeilen sind über Namen oder Rolle geraten — die bitte einzeln prüfen.",
368
+ "swap.guessedByName": "Über den Punktnamen geraten: unter der neuen Quelle heißt ebenfalls etwas „{0}\". Das kann weit danebenliegen — bitte prüfen.",
369
+ "swap.guessedByRole": "Über die Rolle geraten: unter der neuen Quelle trägt ein Punkt dieselbe Rolle „{0}\". Bitte prüfen.",
370
+ "swap.higherLevel": "Eine Ebene höher ({0}) finden {1} von {2} Punkten ein Ziel, hier nur {3}.",
337
371
  "swap.keeps": "Der Alias behält seine Kennung, seine Namen, Rollen und Formeln, die Aufzeichnung in der Datenbank sowie Raum und Funktion. Geändert wird nur, woher jeder Punkt liest und wohin er schreibt.",
338
372
  "swap.mapping": "Zuordnung",
339
373
  "swap.mind": "Darauf achten:",
@@ -393,6 +427,7 @@
393
427
  "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.",
394
428
  "tpl.showProposal": "Vorschlag zeigen",
395
429
  "tpl.showProposalHelp": "Zurück zu dem, was die Vorlage für dieses Gerät vorschlägt.",
430
+ "tpl.skippedEmpty": "„{0}“ hätte die höhere Punktzahl, baut an diesem Gerät aber keine einzige Zeile — übergangen",
396
431
  "tpl.skippedHead": "Weggelassen, weil die Quelle fehlt: {0}",
397
432
  "tpl.skippedNowhere": "{0}: weder in {1}",
398
433
  "tpl.skippedSource": "{0}: {1} fehlt",
@@ -406,6 +441,7 @@
406
441
  "tpls.absoluteTitle": "Ein Punkt zeigt auf ein festes Objekt. ",
407
442
  "tpls.andMore": "… und {0} weitere, hier nicht aufgeführt",
408
443
  "tpls.beats": "schlägt {0}",
444
+ "tpls.buildsNone": "passt nicht — keine Zeile findet ihre Quelle",
409
445
  "tpls.button": "Als Vorlage speichern …",
410
446
  "tpls.channelName": "Kanal je Ausgang",
411
447
  "tpls.colDefault": "Vorgabe",
@@ -424,6 +460,7 @@
424
460
  "tpls.droppedCount": "{0} Punkte weggelassen.",
425
461
  "tpls.evidence": "{0} Belege",
426
462
  "tpls.failed": "Speichern fehlgeschlagen:",
463
+ "tpls.fitsNot": "{0}× passt nicht",
427
464
  "tpls.function": "Funktion",
428
465
  "tpls.head": "Kopfdaten",
429
466
  "tpls.hits": "{0} Geräte getroffen, {1} davon gewonnen",
@@ -432,6 +469,12 @@
432
469
  "tpls.json": "Das wird gespeichert",
433
470
  "tpls.loadFailed": "eigene Vorlagen nicht geladen",
434
471
  "tpls.loadFailedHint": "Die Instanzkonfiguration hat nicht geantwortet oder einen Fehler gemeldet. Deine eigenen Vorlagen sind nicht verschwunden — sie fehlen nur in dieser Ansicht. Solange dieser Hinweis steht, kann ein Speichern eine vorhandene Vorlage überschreiben: erst neu laden.",
472
+ "tpls.lockBadHint": "Der Namenshinweis ist kein brauchbarer Ausdruck",
473
+ "tpls.lockIdTaken": "Die Kennung gehört schon „{0}“",
474
+ "tpls.lockNoId": "Die Kennung fehlt",
475
+ "tpls.lockNoRequired": "Kein Punkt ist als Pflicht angehakt — so passt die Vorlage auf gar nichts",
476
+ "tpls.lockNoRows": "Es ist keine Zeile übrig",
477
+ "tpls.lockedWhy": "Speichern ist gesperrt:",
435
478
  "tpls.losesTo": "verliert gegen {0}",
436
479
  "tpls.multiple": "Dieses Gerät hat mehrere Ausgänge",
437
480
  "tpls.multipleHelp": "Die {0} in den Pfaden wird durch %N% ersetzt — nur am Ende eines Abschnitts, damit ENERGY.Power heil bleibt.",
@@ -442,6 +485,8 @@
442
485
  "tpls.nameHint": "Namenshinweis",
443
486
  "tpls.nameHintBad": "Kein brauchbarer Ausdruck — er zählt als „trifft nicht“.",
444
487
  "tpls.nameHintHelp": "Entscheidet nur zwischen Vorlagen, die gleich gut passen — etwa Lampe gegen Steckdose. Mehrere Wörter mit | trennen. Dieses Gerät heißt \"{0}\".",
488
+ "tpls.needsRow": "passt nicht — {0} findet nichts",
489
+ "tpls.needsRowHint": "Eine Pflichtzeile der Vorlage findet an diesem Gerät ihre Quelle nicht — meist ein Feld, das es in der JSON-Nachricht dort nicht gibt. Die Vorlage tritt hier gar nicht erst an; den Platz bekommt die nächstbeste.",
445
490
  "tpls.noFunction": "— keine —",
446
491
  "tpls.noHits": "Trifft im Moment kein Gerät. Prüfe die Pflichtpunkte.",
447
492
  "tpls.noInstance": "Instanz {0} nicht gefunden.",
@@ -452,6 +497,8 @@
452
497
  "tpls.otherOutputsText": "Eine Vorlage für mehrere Ausgänge beschreibt immer nur einen — die übrigen entstehen daraus. Nimm die fremden Punkte im Gerät heraus, sonst passt die Vorlage nur auf genau dieses eine Gerät.",
453
498
  "tpls.pickDeviceFirst": "erst ein Gerät wählen",
454
499
  "tpls.rank": "Rang",
500
+ "tpls.rowBuilt": "1 Zeile",
501
+ "tpls.rowsBuilt": "{0} Zeilen",
455
502
  "tpls.saveAsNew": "Als neue Vorlage speichern",
456
503
  "tpls.saveAsNewHint": "die bisherige bleibt, wie sie ist",
457
504
  "tpls.saveNew": "Vorlage speichern",
@@ -482,6 +529,7 @@
482
529
  "tree.looksLikeDevice": "sieht wie ein einzelnes Gerät aus",
483
530
  "tree.noObjectHint": "kein Objekt — nur aus der ID abgeleitet",
484
531
  "tree.nothingFound": "nichts gefunden",
532
+ "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.",
485
533
  "tree.sources": "Alias anlegen",
486
534
  "tree.templates": "Vorlagen",
487
535
  "tv.addFallback": "Ersatzquelle hinzufügen",
@@ -538,6 +586,22 @@
538
586
  "tv.save": "Speichern",
539
587
  "tv.show": "zeigen",
540
588
  "tv.unsaved": "nicht gespeichert",
589
+ "use.again": "neu einlesen",
590
+ "use.aliasHead": "Der Alias",
591
+ "use.custom": "Aufzeichnung, Smart-Namen",
592
+ "use.enums": "Aufzählungen",
593
+ "use.files": "Dateien",
594
+ "use.head": "Wird genannt in",
595
+ "use.limits": "Gesucht wird im Klartext. Dateien nur in Instanzordnern (vis.0, vis-2.0, web.0 …) — die Oberflächen der Adapter bleiben draußen, sonst fände die Werkbank deren Beispiele und ihre eigenen Quelldateien. Nicht durchsucht werden Zustandswerte, und zusammengebaute Kennungen findet keine Textsuche.",
596
+ "use.look": "nachsehen",
597
+ "use.lookHint": "Sucht die Kennung des Alias und die seiner Quelle — in den Skripten, den Aufzählungen, den Einträgen am Punkt selbst, in allen geladenen Objekten und in den Dateien der Instanzordner. Wird erst auf Klick gemacht, weil dafür alles einmal gelesen wird.",
598
+ "use.none": "—",
599
+ "use.objects": "Objekte",
600
+ "use.otherAliases": "weitere Aliase darauf",
601
+ "use.scripts": "Skripte",
602
+ "use.searching": "wird gesucht …",
603
+ "use.sourceHead": "Die Quelle",
604
+ "use.sourceHint": "Dass die Quelle noch genannt wird, ist kein Fehler: ein Skript, das sie beschreibt, gehört genau dorthin. Ob eine Stelle auf den Alias umgestellt gehört, sagt nur der Blick hinein.",
541
605
  "write.aliasNowAt": "Der Alias steht jetzt unter {0}.",
542
606
  "write.cannotWrite": "So kann nicht geschrieben werden:",
543
607
  "write.changes": "ändert sich",