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.
- package/LICENSE +21 -0
- package/README.md +516 -0
- package/admin/alias-workbench.png +0 -0
- package/admin/css/werkbank.css +916 -0
- package/admin/detector.js +1 -0
- package/admin/geraetewissen/tasmota-befehle.json +116 -0
- package/admin/i18n/de.json +552 -0
- package/admin/i18n/en.json +552 -0
- package/admin/js/aufzaehlungen.js +332 -0
- package/admin/js/basis.js +36 -0
- package/admin/js/baum.js +453 -0
- package/admin/js/detail.js +335 -0
- package/admin/js/einstellungen.js +40 -0
- package/admin/js/entwurf.js +908 -0
- package/admin/js/enums.js +23 -0
- package/admin/js/ergebnis.js +934 -0
- package/admin/js/erkennung.js +126 -0
- package/admin/js/katalog.js +313 -0
- package/admin/js/mqtt.js +885 -0
- package/admin/js/musternamen.js +94 -0
- package/admin/js/musterwahl.js +334 -0
- package/admin/js/objekte.js +243 -0
- package/admin/js/pruefungen.js +130 -0
- package/admin/js/quellentausch.js +570 -0
- package/admin/js/rollenwahl.js +199 -0
- package/admin/js/schreiben.js +1537 -0
- package/admin/js/sprache.js +137 -0
- package/admin/js/start.js +39 -0
- package/admin/js/verbindung.js +10 -0
- package/admin/js/vorlagen.js +572 -0
- package/admin/js/vorlagenblatt.js +1907 -0
- package/admin/js/vorschlagen.js +391 -0
- package/admin/js/werte.js +193 -0
- package/admin/js/zielleiste.js +339 -0
- package/admin/js/zuordnung.js +695 -0
- package/admin/js/zustand.js +47 -0
- package/admin/js/zustandsliste.js +515 -0
- package/admin/jsonConfig.json +249 -0
- package/admin/tab.html +148 -0
- package/admin/vorlagen/hm-dimmer.json +204 -0
- package/admin/vorlagen/hm-fensterkontakt-hm.json +176 -0
- package/admin/vorlagen/hm-fensterkontakt-hmip.json +191 -0
- package/admin/vorlagen/hm-heizgruppe.json +214 -0
- package/admin/vorlagen/hm-heizkoerper.json +236 -0
- package/admin/vorlagen/hm-rollladen.json +190 -0
- package/admin/vorlagen/hm-schaltaktor-lampe.json +197 -0
- package/admin/vorlagen/hm-schaltaktor-mehrfach.json +203 -0
- package/admin/vorlagen/hm-schaltaktor-steckdose.json +197 -0
- package/admin/vorlagen/hm-temperatur-feuchte.json +166 -0
- package/admin/vorlagen/hm-wandthermostat.json +228 -0
- package/admin/vorlagen/index.json +21 -0
- package/admin/vorlagen/messpunkt.json +225 -0
- package/admin/vorlagen/tasmota-lampe.json +263 -0
- package/admin/vorlagen/tasmota-mehrfach.json +203 -0
- package/admin/vorlagen/tasmota-rgb.json +239 -0
- package/admin/vorlagen/tasmota-steckdose.json +265 -0
- package/io-package.json +122 -0
- 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
|