iobroker.alias-workbench 0.8.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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +516 -0
  3. package/admin/alias-workbench.png +0 -0
  4. package/admin/css/werkbank.css +916 -0
  5. package/admin/detector.js +1 -0
  6. package/admin/geraetewissen/tasmota-befehle.json +116 -0
  7. package/admin/i18n/de.json +552 -0
  8. package/admin/i18n/en.json +552 -0
  9. package/admin/js/aufzaehlungen.js +332 -0
  10. package/admin/js/basis.js +36 -0
  11. package/admin/js/baum.js +453 -0
  12. package/admin/js/detail.js +335 -0
  13. package/admin/js/einstellungen.js +40 -0
  14. package/admin/js/entwurf.js +908 -0
  15. package/admin/js/enums.js +23 -0
  16. package/admin/js/ergebnis.js +934 -0
  17. package/admin/js/erkennung.js +126 -0
  18. package/admin/js/katalog.js +313 -0
  19. package/admin/js/mqtt.js +885 -0
  20. package/admin/js/musternamen.js +94 -0
  21. package/admin/js/musterwahl.js +334 -0
  22. package/admin/js/objekte.js +243 -0
  23. package/admin/js/pruefungen.js +130 -0
  24. package/admin/js/quellentausch.js +570 -0
  25. package/admin/js/rollenwahl.js +199 -0
  26. package/admin/js/schreiben.js +1537 -0
  27. package/admin/js/sprache.js +137 -0
  28. package/admin/js/start.js +39 -0
  29. package/admin/js/verbindung.js +10 -0
  30. package/admin/js/vorlagen.js +572 -0
  31. package/admin/js/vorlagenblatt.js +1907 -0
  32. package/admin/js/vorschlagen.js +391 -0
  33. package/admin/js/werte.js +193 -0
  34. package/admin/js/zielleiste.js +339 -0
  35. package/admin/js/zuordnung.js +695 -0
  36. package/admin/js/zustand.js +47 -0
  37. package/admin/js/zustandsliste.js +515 -0
  38. package/admin/jsonConfig.json +249 -0
  39. package/admin/tab.html +148 -0
  40. package/admin/vorlagen/hm-dimmer.json +204 -0
  41. package/admin/vorlagen/hm-fensterkontakt-hm.json +176 -0
  42. package/admin/vorlagen/hm-fensterkontakt-hmip.json +191 -0
  43. package/admin/vorlagen/hm-heizgruppe.json +214 -0
  44. package/admin/vorlagen/hm-heizkoerper.json +236 -0
  45. package/admin/vorlagen/hm-rollladen.json +190 -0
  46. package/admin/vorlagen/hm-schaltaktor-lampe.json +197 -0
  47. package/admin/vorlagen/hm-schaltaktor-mehrfach.json +203 -0
  48. package/admin/vorlagen/hm-schaltaktor-steckdose.json +197 -0
  49. package/admin/vorlagen/hm-temperatur-feuchte.json +166 -0
  50. package/admin/vorlagen/hm-wandthermostat.json +228 -0
  51. package/admin/vorlagen/index.json +21 -0
  52. package/admin/vorlagen/messpunkt.json +225 -0
  53. package/admin/vorlagen/tasmota-lampe.json +263 -0
  54. package/admin/vorlagen/tasmota-mehrfach.json +203 -0
  55. package/admin/vorlagen/tasmota-rgb.json +239 -0
  56. package/admin/vorlagen/tasmota-steckdose.json +265 -0
  57. package/io-package.json +122 -0
  58. package/package.json +48 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ricardo Hipp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,516 @@
1
+ <img src="admin/alias-workbench.png" width="80" align="right" alt="logo">
2
+
3
+ # ioBroker.alias-workbench
4
+
5
+ Creates aliases the comfortable way — devices that vis, Alexa and the device
6
+ adapter understand. Templates do the work: shipped ones for HomeMatic and
7
+ Tasmota, your own for everything else.
8
+
9
+ *(Eine Kurzfassung auf Deutsch steht in [README_de.md](README_de.md).)*
10
+
11
+ ---
12
+
13
+ ## Why
14
+
15
+ An alias is quickly created and always looks fine afterwards. Whether it is any
16
+ good is decided by things you **cannot see**:
17
+
18
+ - whether the **roles** are chosen so that the type-detector recognises a device
19
+ - whether the **source** exists at all and carries a value
20
+ - whether the **read function** returns a number or `undefined`
21
+ - whether the **write path** works
22
+
23
+ A tool that only links datapoints helps with none of that. This adapter shows
24
+ all four while you are building, not hours later in the log.
25
+
26
+ ## What it does
27
+
28
+ **Live detector report.** The real `@iobroker/type-detector` runs against a
29
+ draft of your alias while you edit it. Change a role and the report changes with
30
+ it — you see immediately whether you built a device or a pile of loose values,
31
+ which pattern slots are filled and which are still free.
32
+
33
+ **Live value preview.** Every datapoint shows what its read function returns
34
+ *right now*, next to the raw value of the source. A formula that yields
35
+ `undefined` or throws is visible before anything is written.
36
+
37
+ **Templates.** A template describes how a device source becomes a finished alias
38
+ device. Templates are plain JSON files, one per template — see
39
+ [Template format](#template-format). Sixteen ship with the adapter: four for
40
+ Tasmota, one plain measuring point, and eleven for Homematic — see
41
+ [What the shipped templates cover](#what-the-shipped-templates-cover).
42
+
43
+ **Your own templates.** Build a device — by hand or by adapting a shipped
44
+ template — and save it as a template of your own. What can be derived is
45
+ derived; what cannot be derived is asked. Before anything is stored, a try-out
46
+ runs the new template against every device in the system and shows which ones it
47
+ matches, which template wins there, and which devices would change hands. See
48
+ [Saving your own templates](#saving-your-own-templates).
49
+
50
+ **Devices with several outputs.** A power strip or valve manifold has
51
+ `POWER1`, `POWER2`, … Since a `socket` pattern has exactly one `SET`, each
52
+ output becomes its own channel, grouped under one folder. The output numbers are
53
+ read from what actually exists — gaps are allowed.
54
+
55
+ **Move, rename, swap the source.** An id cannot be changed in the object store,
56
+ so moving is always: create new, move the enum memberships, delete old — in that
57
+ order, so a failure leaves you with two aliases rather than none. Swapping the
58
+ source keeps the alias untouched and only re-points it, which is what you want
59
+ when a device dies. See [Swapping a source](#swapping-a-source).
60
+
61
+ **Filling free slots.** A device that matches no pattern is often not an unknown
62
+ device — a role is simply missing. **Suggest free slots** sets roles in the
63
+ draft and lets the detector decide again. It only ever runs on that button, never
64
+ during normal detection, every guessed row is marked, and while any guess is
65
+ undecided the write buttons stay locked. Not deciding is no longer a silent yes.
66
+
67
+ **Nothing is written without a dry run.** The dry run lists every object that
68
+ would be created, changed or removed, as full JSON. For anything that changes it
69
+ puts **before and after side by side**, line against line, so you can see *what*
70
+ changes instead of only *that* it changes. Field order and trailing commas are
71
+ normalised first — otherwise half the lines light up for no reason. Only from
72
+ there can you write. If a source does not exist, writing is blocked: the js-controller
73
+ remembers a missing source permanently, and only deleting and recreating the
74
+ object fixes it.
75
+
76
+ ## Status
77
+
78
+ Early. Usable, but not finished.
79
+
80
+ - Works as an admin tab; the adapter itself runs no process (`mode: none`).
81
+ The instance exists only to carry the settings.
82
+ - German and English, 550 keys each
83
+ - Not published on npm yet — install from GitHub
84
+ - 16 bundled templates: eleven Homematic, four Tasmota, one plain measuring point
85
+ - **Missing:** "who uses this alias" — vis views, Alexa and Google names cannot
86
+ be searched from here, so a rename warns you instead of pretending to be
87
+ complete. Exporting a template to a file and reading it back works but is
88
+ the least tested path.
89
+
90
+ ## Why the tree shows devices that do not exist
91
+
92
+ With MQTT, ioBroker only creates objects for the datapoints themselves. A topic
93
+ like `SmartHome/Bastelzimmer/Gartenpumpe/stat/POWER` produces one object for
94
+ `stat.POWER` — the level `Gartenpumpe` is only part of a name, not an object.
95
+
96
+ The type-detector, however, looks for a `channel` or `device` to group
97
+ datapoints under. It finds none, so it recognises no device, and Alexa, Matter
98
+ and Material have nothing to attach to.
99
+
100
+ That gap is what the alias fills: `alias.0.…Gartenpumpe` is a real channel with
101
+ proper roles beneath it. The workbench therefore lets you pick such a
102
+ non-existent node in the tree and build a device out of it.
103
+
104
+ ## How it works
105
+
106
+ ```
107
+ source (e.g. mqtt-client.0.…)
108
+ ↓ a template is matched and applied
109
+ draft in memory → object image → type-detector → report
110
+ ↓ dry run
111
+ alias.0.<folder>.<device> channel + states with common.alias
112
+ ```
113
+
114
+ The draft never touches the object database. The detector runs against an image
115
+ of the draft, which is why the report reacts instantly and why nothing can break
116
+ while you experiment.
117
+
118
+ The type-detector is a real npm dependency, bundled for the browser with
119
+ esbuild. It is never copied into the source tree — a frozen copy that drifts
120
+ from the library was the main weakness of the existing alias manager.
121
+
122
+ ### How the tab itself is built
123
+
124
+ The tab is **29 ES modules** under `admin/js/`, loaded by the browser as
125
+ modules. There is no build step for them: what stands in the file is what runs.
126
+ Styling lives in one file, `admin/css/werkbank.css`.
127
+
128
+ That has a price. A module boundary can be crossed wrongly in ways the browser
129
+ only notices while running, so three checks run before any clicking — they need
130
+ no browser and take two minutes:
131
+
132
+ ```bash
133
+ #1. does it still bundle? finds missing or misspelled exports
134
+ npx esbuild --bundle admin/js/start.js --outfile=/dev/null --format=esm
135
+
136
+ #2. free names — identifiers that are neither declared nor imported
137
+ npm install --no-save acorn@8
138
+ node ../werkzeug/freie-namen.js admin/js node_modules/acorn/dist/acorn.js
139
+
140
+ #3. translations: both files carry the same keys, every tr() has one
141
+ ```
142
+
143
+ The second one earns its keep. `socket` was used in `detail.js` without being
144
+ imported — valid JavaScript, and it would only have thrown when someone picked
145
+ a source whose value was not loaded yet.
146
+
147
+ ## Template format
148
+
149
+ One JSON file per template under `admin/vorlagen/`. Example:
150
+
151
+ ```jsonc
152
+ {
153
+ "id": "tasmota-steckdose",
154
+ "version": 1,
155
+ "rang": 20,
156
+ "name": { "en": "Tasmota socket", "de": "Tasmota-Steckdose" },
157
+ "geraetetyp": "socket",
158
+
159
+ "erkennung": {
160
+ "erforderlich": ["stat.POWER", "cmnd.POWER"],
161
+ "inhalt": { "tele.SENSOR": "ENERGY" },
162
+ "namenshinweis": "steckdose|dose|plug|socket"
163
+ },
164
+
165
+ "zustaende": [
166
+ { "name": "SET", "rolle": "switch", "typ": "boolean",
167
+ "lesen": "stat.POWER", "schreiben": "cmnd.POWER",
168
+ "schreibformel": "val ? \"ON\" : \"OFF\"" },
169
+
170
+ { "name": "ELECTRIC_POWER", "rolle": "value.power", "einheit": "W",
171
+ "lesen": "tele.SENSOR", "feld": "ENERGY.Power", "optional": true },
172
+
173
+ { "name": "TODAY", "rolle": "value", "einheit": "kWh",
174
+ "lesen": "tele.SENSOR", "feld": "ENERGY.Today",
175
+ "optional": true, "vorgabeAus": true }
176
+ ]
177
+ }
178
+ ```
179
+
180
+ | Key | Meaning |
181
+ |---|---|
182
+ | `erkennung.erforderlich` | these datapoints must exist, otherwise the template does not match |
183
+ | `erkennung.inhalt` | the named datapoint must contain this field in its JSON |
184
+ | `erkennung.verboten` | these datapoints must **not** exist, otherwise the template does not match |
185
+ | `erkennung.namenshinweis` | only breaks ties between templates that fit equally well |
186
+ | `rang` | last tie-breaker, so the same device is always detected the same way |
187
+ | `optional` | the state is skipped when its source or JSON field is missing |
188
+ | `vorgabeAus` | proposed but unchecked — see **What a template ticks by default** below |
189
+ | `feld` | builds the read function `JSON.parse(val).<field>` |
190
+ | `mehrfach` + `%N%` | one device per output; the numbers are read from what exists |
191
+ | `werteliste` | value list for the datapoint — slots like EFFECT are not detected without one |
192
+ | `absolut` | `lesen` is a full object id, not relative to the device — the same object for every device |
193
+ | `beschriftung` | the datapoint's display name, if it should differ from its slot name |
194
+ | `nachkommastellen` | decimals for the value display |
195
+
196
+ `verboten` is what genuinely separates a single socket from a multi-output one:
197
+ the single one has no `stat.POWER2`. An absent datapoint deliberately does **not**
198
+ count as evidence — otherwise a list of invented exclusions could inflate a
199
+ template's score.
200
+
201
+ Datapoint names are matched case-insensitively as a fallback, because MQTT keeps
202
+ whatever casing was published — the same device family sends `cmnd.POWER` on one
203
+ unit and `cmnd.power` on the next.
204
+
205
+ ## What a template ticks by default
206
+
207
+ Whether a datapoint has a slot in the type-detector pattern is **not** the
208
+ criterion. That only decides *where* the point ends up — inside the device or
209
+ in a separate info device. It says nothing about whether anyone needs it. The
210
+ `thermostat` pattern has 24 slots, `socket` has 14; everything that could ever
211
+ sit in such a device is listed there, down to frequency and apparent power.
212
+
213
+ The criterion is purpose: **tick what you need to operate the device and to
214
+ notice when something is wrong.** Setpoint, actual value, and the signals that
215
+ announce a failure — `LOWBAT`, `UNREACH`.
216
+
217
+ Left unticked: diagnostics. Signal strength, uptime, ramp times, inhibit
218
+ flags. You tick those when you are chasing a problem.
219
+
220
+ Battery **voltage** looks like it belongs in the first group — it falls
221
+ visibly over weeks while `LOW_BAT` only flips once the change is already due.
222
+ It stays unticked anyway, because the detector has nowhere to put it. Patterns
223
+ are assembled from two shared groups:
224
+
225
+ ```
226
+ maintenance WORKING UNREACH LOWBAT MAINTAIN ERROR DIRECTION
227
+ CONNECTED RSSI ON_TIME BATTERY value.battery unit %
228
+ metering ELECTRIC_POWER CURRENT VOLTAGE CONSUMPTION
229
+ FREQUENCY SPEED POWER value.voltage unit V
230
+ ```
231
+
232
+ `VOLTAGE` sits between current and consumption: it is the **mains voltage of a
233
+ metering device**, not a sensor's cell voltage. A window contact has no
234
+ metering group at all, which is why it has no voltage slot — and `BATTERY`,
235
+ the slot it does have, means a percentage. Writing volts into either is
236
+ wrong, so the point is offered and left off.
237
+
238
+ Two things override that:
239
+
240
+ - A point that reads the **same source** as an already-ticked one is never
241
+ ticked. Otherwise the same value sits in the alias twice and the seventh
242
+ check reports it, rightly. Homematic switch actuators have no separate
243
+ feedback value — `1.STATE` is both — so their `ON_ACTUAL` stays off.
244
+ - Where the purpose says tick but the pattern has **no slot**, weigh it: the
245
+ point lands in an info device next to the real one. For a single value that
246
+ is rarely worth it, and the template's `hinweis` has to say so. And check
247
+ what a slot **means** before using it — a matching name is not a matching
248
+ purpose, as the voltage case above shows.
249
+
250
+ ## Saving your own templates
251
+
252
+ The **Save as template …** button turns the device you are looking at back into
253
+ a template. Paths become relative to the device, `JSON.parse(val).ENERGY.Power`
254
+ becomes `feld: "ENERGY.Power"` again, and roles, units and formulas are kept.
255
+
256
+ What a template cannot know by itself is **which datapoints make a device this
257
+ kind of device**. That is a statement about all future devices, so the dialog
258
+ asks:
259
+
260
+ - **required datapoints** — proposed (anything with a write path is required by
261
+ default), decided by you with a tick per row. Every extra required point makes
262
+ the template more precise and more brittle at the same time.
263
+ - **content checks** — proposed wherever a JSON field is read. This is what
264
+ separates "socket" from "socket with metering", so it is offered but not
265
+ ticked.
266
+ - **name hint** — never derived. It only breaks ties between templates that fit
267
+ equally well; MQTT cannot tell a lamp from a PC.
268
+ - **several outputs** — a tick plus the number that identifies this output.
269
+ `stat.POWER1` then becomes `stat.POWER%N%`, replaced only at the end of a path
270
+ segment so `ENERGY.Power` stays intact. If the draft still refers to the other
271
+ outputs, the dialog says so: such a template would only ever fit this one
272
+ device.
273
+ - **must not exist** — datapoints whose presence rules the template out.
274
+
275
+ Then the try-out shows what the detection actually catches, before anything is
276
+ saved.
277
+
278
+ ### Managing them
279
+
280
+ The third view next to **Sources** and **Aliases** is **Templates**: every
281
+ template with its detection, its datapoints, a permanent try-out and the raw
282
+ JSON. Everything about a template of yours can be changed there: name, rank,
283
+ name hint, the required and forbidden datapoints, and every datapoint itself —
284
+ click a row to open its role, type, unit, paths, formulas and flags. Datapoints
285
+ can be added and removed. The try-out below reacts to every change, so you see
286
+ what an edit does to the detection before you save.
287
+
288
+ Shipped templates cannot be edited — that way they always stay the state they
289
+ were delivered in. *Make an editable copy* gives you a copy under the same id
290
+ that shadows the original; delete that copy and the shipped one reappears.
291
+ *Duplicate* on a template of your own gives it a new id, for a variant that
292
+ stands next to the original rather than replacing it.
293
+
294
+ Import accepts one template per file, in exactly the format under
295
+ `admin/vorlagen/`. Nothing is stored on import: the file appears as a preview
296
+ first, with a line saying what saving would do — create, replace your own
297
+ version, or shadow a shipped one.
298
+
299
+ Your templates live in `native.vorlagen` of the instance object, so they survive
300
+ `iobroker upload` and adapter updates and are part of a Backitup backup. A
301
+ template of yours with the same `id` as a shipped one shadows it. Storage and
302
+ exchange format are the same JSON, so a template that turned out well can move
303
+ into the package unchanged.
304
+
305
+ ### How a template is picked
306
+
307
+ When several templates fit, the winner is decided in this order:
308
+
309
+ 1. **how many datapoints the template actually verified** — required points, per
310
+ output for multi-output devices, plus content checks that came out true
311
+ 2. **the name hint**, if it matches
312
+ 3. **your own template** over a shipped one
313
+ 4. **`rang`**, so the same device is always detected the same way
314
+
315
+ Order matters. Counting evidence first is what keeps a template you built on
316
+ purpose from losing to a shipped one whose word happens to appear in the device
317
+ name.
318
+
319
+ Note what step 3 means for updates: a template of yours **cannot be outranked by
320
+ a shipped one on `rang`** — that step sits above `rang` in the order, so no
321
+ future version of this adapter can quietly take a device away from a template
322
+ you built. `rang` only ever breaks ties between templates of the same origin,
323
+ which is also why a new template of yours is numbered from your own templates
324
+ and ignores the shipped numbers entirely.
325
+
326
+ A shipped template can still win on step 1 by verifying strictly more
327
+ datapoints. That is deliberate — more evidence should win — and it only affects
328
+ devices you have not built yet: a finished alias records the template it came
329
+ from and keeps it.
330
+
331
+ ## What the shipped templates cover
332
+
333
+ Sixteen templates come with the adapter. Four Tasmota, one plain measuring
334
+ point — and eleven for Homematic, where the interesting part is not that a
335
+ template matches but that the **right** one does. The devices look alike in the
336
+ data; what separates them is one datapoint each:
337
+
338
+ | Told apart by | Which is which |
339
+ |---|---|
340
+ | `1.WORKING` | switch actuator, not a window contact — both have `1.STATE` |
341
+ | `2.STATE` | multi-channel actuator; the single-channel template refuses when it is present |
342
+ | `1.LEVEL_REAL` vs `1.STOP` | dimmer vs shutter — both have `1.LEVEL` |
343
+ | `1.ERROR` | classic window contact vs HmIP, which computes a boolean from a number |
344
+ | `0.SABOTAGE` | required for the HmIP contact. Without it, `1.STATE` + `0.LOW_BAT` matched twelve devices, eight of them actuators |
345
+ | `1.LEVEL` / `1.HUMIDITY` / `4.SECTION` | radiator valve vs wall thermostat vs heating group |
346
+ | `1.TEMPERATURE` vs `1.ACTUAL_TEMPERATURE` | a plain sensor vs something that also sets a value |
347
+
348
+ The CCU's own receivers — `HM-RCV-50`, `HmIP-RCV-50`, `RPI-RF-MOD` — match
349
+ nothing on purpose. Fifty bare `LEVEL` channels are not a device.
350
+
351
+ When a template is rejected, the picker says why: *"1.LEVEL missing"*, not
352
+ *"does not fit"*. A reason you cannot act on is not a reason.
353
+
354
+ ### Role knowledge beside the rows
355
+
356
+ A template can carry `weiterePunkte`: roles for datapoints that get no row of
357
+ their own. Without it, "all datapoints of the device" showed *no role* on most
358
+ lines, because hm-rpc simply leaves the field empty. A `*.NAME` wildcard applies
359
+ per channel, so `2.LEVEL` and `3.RAMP_TIME` are covered without listing every
360
+ channel. It changes nothing about which template wins — only raw rows are
361
+ enriched.
362
+
363
+ ## What an existing alias contributes
364
+
365
+ Pick a source that already has an alias, and the alias wins. Role, type, unit,
366
+ value list, caption, formulas, both sources and the ticks come from what is
367
+ stored — in **both** views, "create alias" and "edit alias".
368
+
369
+ Before that, the same row carried a different role depending on which tab you
370
+ were in, and refreshing did something different in each. Now refreshing changes
371
+ nothing by itself.
372
+
373
+ Where the template wants something else, the row says so — *"Template:
374
+ sensor.window"* — and a button above the list offers to apply it. That is a
375
+ click, never a side effect. The caption is exempt: the display name belongs to
376
+ whoever typed it.
377
+
378
+ ## Swapping a source
379
+
380
+ A device breaks and gets replaced. The alias should stay exactly as it is —
381
+ same id, same recording, same room and function — and only point somewhere
382
+ else. **Swap source…** does that, and it changes only `common.alias.id` per
383
+ datapoint plus `native.quelle` on the channel.
384
+
385
+ Each datapoint is matched in three steps, and the dialog says which one was
386
+ used:
387
+
388
+ 1. **same relative path** below the new device — `…ABC.1.STATE` → `…XYZ.1.STATE`
389
+ 2. **through the template row** — finds `LOWBAT` on a device that spells it
390
+ `LOWBAT` where the old one said `LOW_BAT`
391
+ 3. **guessed** from name or role — deliberately weak, and marked **guessed** so
392
+ you check it
393
+
394
+ Rows with no match at all turn red and offer a checkbox: *remove this point
395
+ when swapping*. Leave it unticked and the point stays, still pointing at the
396
+ old source — allowed, but visible.
397
+
398
+ Two things the dialog is careful about. It names the old source even when the
399
+ device is **gone** — that is the normal case for "device broken". And it warns
400
+ where the new source measures differently: *"Watch out: ACTUAL: value range
401
+ 0..100 → 0..255"*. The alias keeps its formulas; if the new device counts
402
+ differently, the numbers are wrong afterwards and nothing else would tell you.
403
+
404
+ ## Room and function
405
+
406
+ Both live in `enum.rooms.*` / `enum.functions.*`, not on the object — so this
407
+ is the one place where the workbench writes outside `alias.`. Nothing else
408
+ outside that namespace is ever touched.
409
+
410
+ The proposal comes from, in order: the room already on the source or one of its
411
+ channels, the device name (`FK_Max_Spielzimmer` → `Max_Spielzimmer`), the
412
+ target folder. The function comes from the template's `funktion` field, or from
413
+ the detected type when the template has none.
414
+
415
+ The admin ships 62 function and 58 room templates, each with a picture. The
416
+ workbench does not copy them; it reads them out of the admin's own bundle at
417
+ runtime, so there are never two lists ageing apart. If that fails, the field
418
+ quietly shows only what exists — and says so in the last row, rather than
419
+ looking empty for no reason.
420
+
421
+ **The picture is shown before it is written.** Next to each of the two fields
422
+ stands the picture of the chosen enum: solid when one is already stored, faded
423
+ with a small **new** corner when the workbench would add one on writing, and
424
+ nothing at all when the catalogue does not know the name or the switch is off.
425
+ So the settings page is visible in the row itself, instead of having to be
426
+ guessed from a dry run.
427
+
428
+ ## Settings
429
+
430
+ The instance has no process; its settings only decide how the workbench writes.
431
+ Four switches, all on by default — and if `native` is missing entirely, the same
432
+ defaults apply rather than everything counting as off:
433
+
434
+ | Switch | What it does |
435
+ |---|---|
436
+ | `ikonRaeume` | add a missing picture to a **room** |
437
+ | `ikonFunktionen` | the same for a **function** |
438
+ | `ikonErsetzen` | also replace an entry that is not a picture. ioBroker's default rooms carry `icon: "Bedroom"` — a bare word that renders as a broken box |
439
+ | `vorlagenVomAdmin` | offer the admin's room and function templates at all |
440
+
441
+ The tab reads them **once on load**. After saving, reload the tab.
442
+
443
+ ## Installation
444
+
445
+ Open the ioBroker admin, go to **Adapters**, look for **Alias Workbench** and
446
+ create an instance. Then reload the admin and pick **Alias Workbench** in the
447
+ left menu.
448
+
449
+ The adapter has not been accepted into the ioBroker repository yet, so it does
450
+ not show up there for the moment. Until it does, [README_de.md](README_de.md)
451
+ describes the interim route.
452
+
453
+ ## Development
454
+
455
+ ```bash
456
+ npm install
457
+ npm run build # bundles @iobroker/type-detector into admin/detector.js
458
+ ```
459
+
460
+ `npm run build` touches **only** the detector bundle. The tab's own modules are
461
+ served as they are; editing one and reloading the tab is the whole cycle. On a
462
+ running installation the admin caches adapter files, so `iobroker upload
463
+ alias-workbench` after copying is what makes the browser see the change.
464
+
465
+ Translations live in `admin/i18n/`. A new language is a new file there and an
466
+ entry in `SPRACHEN` in `admin/js/sprache.js` — nothing else. Watch for strings
467
+ written straight into `admin/tab.html`: they are replaced at runtime, and one
468
+ that nobody wired up stays German forever without anyone noticing.
469
+
470
+ ## Background
471
+
472
+ - [@iobroker/type-detector](https://github.com/ioBroker/ioBroker.type-detector) —
473
+ decides what counts as a device, by roles rather than names
474
+ - [Tasmota](https://tasmota.github.io/docs/) — the device family the shipped
475
+ templates cover
476
+ - [ioBroker aliases](https://github.com/ioBroker/ioBroker.docs) — aliases are a
477
+ core feature of the js-controller, not of any adapter
478
+
479
+ ## Changelog
480
+
481
+ ### 0.8.0
482
+ * Settings page in eleven languages
483
+ * ESLint and a CI workshop; checks run before every commit
484
+ * The buttons at the bottom follow the mode
485
+ * New description
486
+
487
+ ### 0.7.12
488
+ * Tab rebuilt as ES modules
489
+ * Eleven Homematic templates
490
+ * Settings page
491
+ * Swap the source of an alias
492
+ * Picture preview beside room and function
493
+
494
+ ## License
495
+
496
+ MIT License
497
+
498
+ Copyright (c) 2026 Ricardo Hipp <ricardo.hipp@googlemail.com>
499
+
500
+ Permission is hereby granted, free of charge, to any person obtaining a copy
501
+ of this software and associated documentation files (the "Software"), to deal
502
+ in the Software without restriction, including without limitation the rights
503
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
504
+ copies of the Software, and to permit persons to whom the Software is
505
+ furnished to do so, subject to the following conditions:
506
+
507
+ The above copyright notice and this permission notice shall be included in all
508
+ copies or substantial portions of the Software.
509
+
510
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
511
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
512
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
513
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
514
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
515
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
516
+ SOFTWARE.
Binary file