iobroker.alias-workbench 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -98
- package/admin/css/werkbank.css +88 -0
- package/admin/i18n/de.json +766 -1
- package/admin/i18n/en.json +766 -1
- package/admin/i18n/es.json +766 -1
- package/admin/i18n/fr.json +766 -1
- package/admin/i18n/it.json +766 -1
- package/admin/i18n/nl.json +766 -1
- package/admin/i18n/pl.json +766 -1
- package/admin/i18n/pt.json +766 -1
- package/admin/i18n/ru.json +766 -1
- package/admin/i18n/uk.json +766 -1
- package/admin/i18n/zh-cn.json +766 -1
- package/admin/js/ablage.js +118 -0
- package/admin/js/attrappe.js +749 -0
- package/admin/js/baum.js +52 -5
- package/admin/js/detail.js +64 -3
- package/admin/js/entwurf.js +246 -31
- package/admin/js/ergebnis.js +77 -2
- package/admin/js/katalog.js +235 -40
- package/admin/js/mqtt.js +297 -27
- package/admin/js/musternamen.js +70 -26
- package/admin/js/objekte.js +2 -0
- package/admin/js/quellentausch.js +823 -16
- package/admin/js/schreiben.js +3 -2
- package/admin/js/sprache.js +11 -8
- package/admin/js/vorlagen.js +8 -3
- package/admin/js/vorlagenblatt.js +228 -64
- package/admin/js/werte.js +294 -5
- package/admin/js/zielleiste.js +19 -10
- package/admin/js/zuordnung.js +8 -7
- package/admin/js/zustand.js +32 -0
- package/admin/js/zustandsliste.js +9 -2
- package/admin/tab.html +24 -0
- package/admin/vorlagen/hm-dimmer.json +32 -8
- package/admin/vorlagen/hm-fensterkontakt-hm.json +20 -5
- package/admin/vorlagen/hm-fensterkontakt-hmip.json +28 -7
- package/admin/vorlagen/hm-heizgruppe.json +38 -11
- package/admin/vorlagen/hm-heizkoerper.json +42 -12
- package/admin/vorlagen/hm-rollladen.json +28 -7
- package/admin/vorlagen/hm-schaltaktor-lampe.json +24 -6
- package/admin/vorlagen/hm-schaltaktor-mehrfach.json +32 -8
- package/admin/vorlagen/hm-schaltaktor-steckdose.json +24 -6
- package/admin/vorlagen/hm-temperatur-feuchte.json +8 -2
- package/admin/vorlagen/hm-wandthermostat.json +36 -9
- package/admin/vorlagen/messpunkt.json +40 -10
- package/admin/vorlagen/tasmota-lampe.json +48 -12
- package/admin/vorlagen/tasmota-mehrfach.json +40 -10
- package/admin/vorlagen/tasmota-rgb.json +36 -9
- package/admin/vorlagen/tasmota-steckdose.json +56 -14
- package/io-package.json +41 -28
- package/package.json +3 -3
- package/admin/sprachen/de.json +0 -685
- package/admin/sprachen/en.json +0 -685
package/README.md
CHANGED
|
@@ -187,8 +187,9 @@ Early. Usable, but not finished.
|
|
|
187
187
|
|
|
188
188
|
- Works as an admin tab; the adapter itself runs no process (`mode: none`).
|
|
189
189
|
The instance exists only to carry the settings.
|
|
190
|
-
- Interface in
|
|
191
|
-
|
|
190
|
+
- Interface in all eleven admin languages, 712 keys each — one dictionary at
|
|
191
|
+
`admin/i18n/`, shared by the tab and the settings page. An unknown language
|
|
192
|
+
falls back to English
|
|
192
193
|
- 16 bundled templates: eleven Homematic, four Tasmota, one plain measuring point
|
|
193
194
|
- **Missing:** "who uses this alias" — vis views, Alexa and Google names cannot
|
|
194
195
|
be searched from here, so a rename warns you instead of pretending to be
|
|
@@ -565,12 +566,10 @@ served as they are; editing one and reloading the tab is the whole cycle. On a
|
|
|
565
566
|
running installation the admin caches adapter files, so `iobroker upload
|
|
566
567
|
alias-workbench` after copying is what makes the browser see the change.
|
|
567
568
|
|
|
568
|
-
There
|
|
569
|
-
(jsonConfig with `"i18n": true
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
language is a new file in `admin/sprachen/` and an entry in `SPRACHEN` in
|
|
573
|
-
`admin/js/sprache.js` — nothing else. Watch for strings
|
|
569
|
+
There is one dictionary, `admin/i18n/`, all eleven languages. The admin loads
|
|
570
|
+
it for the settings page (`jsonConfig` with `"i18n": true`). The tab loads the
|
|
571
|
+
same files from `admin/js/sprache.js`. A language that is not in the list falls
|
|
572
|
+
back to English. Watch for strings
|
|
574
573
|
written straight into `admin/tab.html`: they are replaced at runtime, and one
|
|
575
574
|
that nobody wired up stays English in every language without anyone noticing.
|
|
576
575
|
|
|
@@ -579,7 +578,7 @@ modules — there is no build step for them, and styling lives in one file,
|
|
|
579
578
|
`admin/css/werkbank.css`. Because a module boundary can be crossed wrongly in
|
|
580
579
|
ways the browser only notices while running, `npm test` checks before every
|
|
581
580
|
commit that everything still bundles, that every identifier is declared or
|
|
582
|
-
imported, and that
|
|
581
|
+
imported, and that all eleven language files carry the same keys.
|
|
583
582
|
|
|
584
583
|
## Background
|
|
585
584
|
|
|
@@ -592,6 +591,55 @@ imported, and that both language files carry the same keys.
|
|
|
592
591
|
|
|
593
592
|
## Changelog
|
|
594
593
|
|
|
594
|
+
### 0.12.0 (2026-10-14)
|
|
595
|
+
**Swapping the source**
|
|
596
|
+
* **Swapping now asks the same recognition as the tree.** The existing stages all started from the **old** source — path, remembered template, names, roles. Yet swapping asks the same question the workbench answers anyway when you click a device: which point **there** is the `ELECTRIC_POWER`? Now, before guessing, the draft of the **new** source is computed and mapped through its pattern slots — template first, otherwise the detector. That carries in **both** directions, which was the point: to a device that labels its points (Matter: `role: value.power`, `unit: W`) the detector answers; to one that labels nothing, the template does. Measured at `mqtt-client.0.SmartHome.PC_Jonas`: all ten points without `common.role`, type `mixed`, the type detector makes `info` of it — but the Tasmota template knows that `stat.POWER` is the status point and the power sits in `tele.SENSOR` under `ENERGY.Power`. Swapping from Matter back to MQTT previously found **0 of 7** points; now 6 of 7, with separate read and write sources.
|
|
597
|
+
* **And the formulas come along.** They belong to the source, not to the alias: `JSON.parse(val)?.ENERGY?.Power ?? null` describes how to get a power reading out of a Tasmota telemetry message. Left in place when swapping to Matter, the point sat silently at `null` — four readings empty with no error at all, and `SET` would have written the string from `val ? "ON" : "OFF"` onto a boolean. Each direction now brings its own: none towards Matter, the JSON formula again back to Tasmota.
|
|
598
|
+
* **A point no stage can find can be named by hand.** Until now the only choices were "remove" or leave it. The row now offers a list of every point on the new device, with role and unit beside it. What you pick there carries the mark "by hand" and the note that **formula, unit and value range stay as they are on the alias** — the workbench knows nothing about that point, so it changes nothing about it.
|
|
599
|
+
* **When the unit changes, the numbers sit beside it — nothing is decided for you.** Tasmota delivers `ENERGY.Total` in kWh, Matter `CONSUMPTION` in Wh: the same meter, factor 1000, invisible. Nothing is converted automatically, because the labelling itself is unreliable — Matter writes the unit `mA` on `CURRENT` and delivers amperes (0.926 at 245 W and 228 V). An automation that believed the label would have made 926 A of it. Instead the row states the finding ("on the alias A · new source: none"), shows what the alias displays today, and offers **two free fields**: unit and factor, both at the current state. The result recomputes as you type. Where the workbench knows something, a shortcut sits beside the field (`Wh`, `/ 1000`) — a suggestion from the labelling, checkable against the numbers above. Free fields, because fixed buttons fail where the target carries **no** unit at all: a JSON collector point has none, the unit sits in the field. This is only shown when the **new source** delivers something other than the old one — swapping between devices of the same kind shows nothing.
|
|
600
|
+
* **When swapping, the remembered template is checked against the new source.** An alias remembers which template it came from, and the workbench keeps applying it until you explicitly change it — exactly right for a like-for-like replacement. For a differently built device it was not, and the bad part was the silence: after swapping a Tasmota socket for a Matter one, the channel still read "Tasmota socket, forced, ✕ cmnd.POWER" — and the **formulas** from that same template stayed on the points. `JSON.parse(val)?.ENERGY?.Power ?? null` is meant for a telemetry JSON; Matter delivers a plain number, and the point sat at `null`. Four readings were empty with no error anywhere, and `SET` would have written the string from `val ? "ON" : "OFF"` onto a boolean. The dialog now checks the remembered template against the **new** device: if it still fits, nothing changes; if it does not, it says why, how many points carry formulas, and — if a different template fits the new source — which one. Plus a pre-ticked box that drops the remembering and the formulas along with it. **Nothing is decided automatically**: the formula belongs to the source, not to the alias, and on the way back to MQTT it is needed again — deleting it silently would be the same mistake as silently keeping it. `native.geraetetyp` and the whole of `common` are left untouched; the swap changes the source, not what the device is.
|
|
601
|
+
* **Source swapping now also asks the alias point itself.** Until now all three mapping stages started from the **old source** — its path, its template row, the name or role of the old state. That works while both devices are built alike and fails completely once they are not: moving an alias from a Tasmota socket to a Matter socket produced **0 out of 8** mappings, for two devices that do the same thing. Both reasons were on the source side, never on the target — `mqtt-client` keeps no roles, and five of the eight points read from **one** telemetry JSON. Yet the answer is already in the alias: `ELECTRIC_POWER` carries `role: value.power`, and the new device holds exactly one point of that name with that role. So before guessing, the **alias point** is asked. If **name and role** match and the point exists exactly once, that counts like a path hit and the row carries the grey mark "from alias"; if only the **role** matches, and it too exactly once, it is a suggestion marked "guessed". Two points of the same role cancel each other out instead of one being picked. In the measured case that is six out of eight, spread over **both** Matter endpoints; `TODAY` and `YESTERDAY` stay empty because the new device has no such thing.
|
|
602
|
+
* **If one point at the new device both reads and writes, it may do so.** The rule "the write target is never the read source" guards against a guessed status point (`stat.POWER` instead of `cmnd.POWER`). Where a single point can do both — `OnOffPlugInUnit-1.SET` on Matter, `1.STATE` on Homematic — it was too strict and reported "no write target found" at exactly the point meant for it. The exception applies only to the evidenced hit via the alias point, and only when both sides are writable; a status point such as `ACTUAL` still gets none.
|
|
603
|
+
|
|
604
|
+
**Tree**
|
|
605
|
+
* **Several branches can be selected as one device.** Some adapters spread one device across sibling branches: Matter stores a socket as a folder without data points of its own, holding two `device` nodes — the switch in one, the readings in the other. The folder was not selectable, and each endpoint on its own produced half a device: at the switch the detector recognised a socket and offered the five readings as "to be created", while the neighbouring branch already had them. **Ctrl-click** now adds a branch to the selection or takes it out; the selection moves to the common parent, and every branch involved is marked in the tree. The same sits in the **context menu**, for anyone without a keyboard, and in the header of the right-hand side as a button **"Add neighbouring branches (N)"** — where the adapter provides evidence, the tooltip says so (Matter writes the same node id to every endpoint). Point names are shortened where they are unambiguous: `OnOffPlugInUnit-1.SET` becomes `SET`. Not for Tasmota — there the branch carries meaning, and the templates address `stat.POWER` and `tele.SENSOR`. **Nothing is merged automatically**: many devices can sit side by side under one node, and only a person knows what counts as one device.
|
|
606
|
+
* **Right-click a node → "Export as mock device".** Everything below that node goes into a file: the objects and the values they carry right now. The point is not backup but rebuilding — from that file a device can be recreated elsewhere, so a template can be built for a device you do not own. What goes in is a positive list, not a filter: `native` is dropped entirely, and from `common` only `name`, `role`, `type`, `unit`, `read`, `write`, `min`, `max`, `def` and `states` are kept. `states` has to come along, otherwise the type detector does not recognise the slots with `statesDefined`. Paths are relative to the exported node, which is why the mock device matches the same templates somewhere else. Levels without an object of their own are recorded as such.
|
|
607
|
+
* **Before writing the file, the workbench shows what goes into it.** One row per entry with value, path, type, role and name — and a checkbox per value: untick what should not travel, and the object still stays. Values that look like an IP, a MAC or an identifier are highlighted. Above that stands what travels even without `native`: identifiers often sit **in the path and in the names too**, and leaving out `native` does not remove those. Measured on a HomeMatic central: twelve such places, although the file carries no `native` at all.
|
|
608
|
+
* **And read back in.** Right-click → "Import mock device …" takes such a file and builds a device from it again — **always under `0_userdata.0.wb-attrappe.<name>`, never at the original path.** That is not a rule but a way of building: a foreign export cannot overwrite a real device. The templates still match, because they check relative names (`stat.POWER`, `1.LEVEL`) and not the root. Beforehand a dialog shows every object that would appear, with a name to change; a file that does not fit is rejected with a reason. Measured: an HmIP wall thermostat, exported and imported as a mock device, is recognised there by the same template — same device type, the same eleven filled slots.
|
|
609
|
+
|
|
610
|
+
### 0.11.0 (2026-10-11)
|
|
611
|
+
**Templates**
|
|
612
|
+
* **Template notes are German and English.** The description, the recognition note and each row note are `{ "de", "en" }`. The tab shows the admin language, otherwise English, otherwise German. The name hint stays one search pattern (`licht|lampe|light|…`): it matches the device name, which does not follow the admin language.
|
|
613
|
+
* **One dictionary for the settings page and the tab.** Both live in `admin/i18n/`, all eleven languages, the same keys. The tab loads that same file. An unknown language falls back to English. The tab used to keep its own dictionary at `admin/sprachen/`, German and English only.
|
|
614
|
+
|
|
615
|
+
**Identifiers**
|
|
616
|
+
* **Object ids no longer contain umlauts.** An id may only contain unaccented letters, digits, `-` and `_`. `Küche` in the name field becomes `Kueche` (`ä`/`Ä` to `ae`/`Ae`, `ö`/`Ö` to `oe`/`Oe`, `ü`/`Ü` to `ue`/`Ue`, `ß` to `ss`). The same applies to "Place under", the move dialog and the name of a new point. Dots in the folder field stay, they separate the levels. An alias whose id already contains an umlaut is left as it is, until the name field is left again.
|
|
617
|
+
* **Rooms and functions keep the umlaut.** The room is still called `Wohnküche`. When the folder is taken from it, the folder is `Wohnkueche` and the path is `alias.0.Wohnkueche.…`.
|
|
618
|
+
* **Typing a folder by hand does not rename the room suggestion.** `Küche` in "Place under" becomes the folder `Kueche`. The question below still names the room `Küche`. Confirming it creates `enum.rooms.Küche`, not `enum.rooms.Kueche`.
|
|
619
|
+
|
|
620
|
+
**Value list and thermostats**
|
|
621
|
+
* **Shipped templates can now be opened row by row**, read-only. Until now the row view was reserved for your own templates: to see which fallback sources, formulas or notes a shipped one carries, you had to make an own copy first — and were left with a copy you never wanted. Every field in the block is disabled, so no working copy is created by looking.
|
|
622
|
+
* The **‚must be present‘ mark** now shows whether the row itself is mandatory, not whether its read path appears in the recognition list — two different questions that had been shown under one word. At the HmIP heating group one row was marked where four are mandatory; the Tasmota templates marked none at all. The same applied to the checkbox in the expanded row, so there was nowhere in the interface showing the truth. Counted across all 16 templates, 15 now show a different number — each matching what the template file says.
|
|
623
|
+
* That checkbox also **silently edited the recognition list**. Ticking SET on the Tasmota light template would have bound it to `stat.POWER`, a point the MQTT adapter only creates once the device has been switched at least once. It now sets only what it says; the recognition list is edited in its own field above.
|
|
624
|
+
* The row overview marks rows that have **fallback read paths** („+3 fallback“). Previously only the first path was shown and the others were invisible until the row was expanded.
|
|
625
|
+
* The **device type** field in the template sheet is now a search field with its own list instead of a 52-entry dropdown. Typing searches both names — `socket` and `Steckdose` both find it — just as the pattern chooser has always done. A dropdown cannot be searched, and since the label starts with the translated name, the browser’s type-ahead never found the raw one.
|
|
626
|
+
* The detail row now has a **value list** field (`common.states`). Until now it could only be inherited from a template — not seen, not created, not changed, although the workbench wrote it all along. Where the source carries one and the draft does not, a button offers to take it over, and "yields" shows the text for the value instead of the bare number. Both deviation comparisons include it; against the existing object in both directions, so a list can no longer disappear silently.
|
|
627
|
+
* **Fixed**: the HmIP radiator and heating-group templates read the valve opening from `1.VALVE_STATE`. On HmIP that is a state code 0-8 (ADAPTION_DONE, TOO_TIGHT, ERROR_POSITION, …), not a percentage — a thermostat reporting code 4 showed "4 %". They now read `1.LEVEL`, which the radiator template already required for detection anyway.
|
|
628
|
+
|
|
629
|
+
**MQTT**
|
|
630
|
+
* The card now says whether the device is reporting: a red "offline" chip when the broker published the last will, a yellow "not reporting" chip when the device claims to be online but no telemetry has arrived within three telemetry periods, and nothing at all when there is no information. Only an explicit offline counts as offline — other firmwares use other words, and an unknown one means "do not know", not "gone". A retained "Online" can be years old: a device that runs for a year never repeats it.
|
|
631
|
+
* "Ask the device" now also fetches the device IP and the telemetry period, and the button appears whenever one of the three is missing — not only when the command list is incomplete. Neither is reported by the device on its own: the IP only in `tele/INFO2` (sent once at boot) or `stat/STATUS5` (on request), the period only on request. Previously a device with a complete command list offered no button at all, so there was no way to get either.
|
|
632
|
+
* The telemetry period was read from `tele/STATE`, where Tasmota does not put it — measured across 36 devices, not one carried the field. It is now asked for and remembered, so the SetOption59 hint names the real number instead of leaving it out.
|
|
633
|
+
* `Status 5` is now requested twice, like `Status 11`: on first contact the MQTT adapter only creates the answer object and discards the value. Captured on the broker — the answer was published, the value never arrived.
|
|
634
|
+
* A Tasmota using the factory FullTopic `%prefix%/%topic%/` is now treated as one device. The MQTT adapters map the topic straight onto the object path, so such a device is spread over `tele.<name>`, `stat.<name>` and `cmnd.<name>` with no node holding it together — the MQTT card did not appear, and a send point created one level up would have been shared with the next device on the same prefix. Both layouts now yield the same relative names, so the shipped templates apply unchanged, and the card says how many branches were joined.
|
|
635
|
+
* Only the factory prefixes `cmnd`/`stat`/`tele` count as a prefix. A structural fallback for renamed ones turned out to merge unrelated nodes — measured against a live installation it joined the L1 phases of eight different AC sources into one device — and Victron data and a renamed Tasmota are indistinguishable in the object tree.
|
|
636
|
+
**Admin enumerations**
|
|
637
|
+
* **The room and function catalogue works again under Admin 8.0.x.** Admin ships 58 room and 62 function templates, translated and with icons; the workbench reads them from its bundles instead of keeping a copy of its own. Since Admin 8.0.x they sit elsewhere and in a different notation — no longer as JSON text in a dedicated "Enums" chunk, but as plain JavaScript inside a shared module of nearly eight megabytes. Two things were in the way: a three-megabyte size limit skipped exactly the right file, and the search pattern required `JSON.parse`. Both notations are now read. Anyone who saw only the existing entries instead of 120 templates under Admin 8 gets them back; under Admin 7 nothing changes.
|
|
638
|
+
* The result is then kept **in the adapter's file area** and is only fetched again when Admin rewrites its bundles — recognised by the bundle names rather than the version number, so an interim build is noticed too. While it is being fetched, a note in the bottom right explains why it takes a few seconds that one time. For storage the workbench creates an `alias-workbench.0` object of type `meta` on first use; the file area does not exist otherwise, because the workbench has no backend.
|
|
639
|
+
* **The pattern names now come from the store as well.** `socket` → “Socket” is also taken from Admin, because the type detector only knows raw type names — and since Admin 8 that map sits in the same shared module as the room catalogue. Both now share one store, so it is fetched once instead of twice. Measured on the second opening of the tab: **404 instead of 2,255 KB under Admin 8.0.14**, 419 instead of 864 KB under Admin 7.8.23, with no request above 100 KB in either case. Both interface languages are taken along, so switching language does not trigger the fetch again.
|
|
640
|
+
* **Fixed: the “n sources” chip counted one device twice** when an alias reads from two nodes, one of which sits below the other. Until now only siblings were merged — so `…Solar_Balkon.stat` and `…Solar_Balkon.tele` were, but `…inverter.HM600.ch0` and `…inverter.HM600` were not. `Solar.Balkon.Einspeisung` therefore showed “4 sources” although the HM600 is a single inverter. A source that sits below another source now counts towards it — under the same condition as before: only if the deeper node has no object of its own (that is how MQTT creates its key levels) or the ancestor is a `device` (that is where Homematic keeps its channels). Two `channel` objects stay separate even when one sits below the other — those are two devices.
|
|
641
|
+
* **Fixed: a German leftover in the English tab.** In the change card a hand-added row without a name showed „(ohne Namen)“ — hardcoded instead of translated, in an otherwise entirely English interface. The text now comes from the language files (`diff.noName`).
|
|
642
|
+
|
|
595
643
|
### 0.10.0 (2026-09-20)
|
|
596
644
|
**Detection and patterns**
|
|
597
645
|
* Picking another pattern re-ticks the rows and leaves them alone while the new pattern does not apply yet.
|
|
@@ -703,95 +751,7 @@ All changes in detail, with cause and measurement: [docs/aenderungen-ausfuehrlic
|
|
|
703
751
|
* The data type now follows the role. A pattern slot prescribes not only the role but also the type, and both sit in the same type-detector record — so picking a role sets the matching type as well. Where a slot allows several types nothing is set, and where it prescribes none any choice stays right. If the type does not fit the slot after all, the workbench says so instead of staying quiet: in the row ("expects number"), as a warning underneath, and in the pattern field, which now gives the reason — "✕ CONSUMPTION: type mixed instead of number" — rather than a bare "does not fit". Before, a state with the right role and the wrong type dropped out of the pattern silently, and the whole device was recognised as something lesser Where a role matches several slots that differ in type — the blind's travel direction sits on DIRECTION as a boolean and on DIRECTION_ENUM as a number — the workbench picks the slot whose type fits, and both forms count as right.
|
|
704
752
|
* Saving a template no longer loses the write targets. Every actuator that keeps its own state writes to the same point it reads - a blind, a dimmer and a thermostat all use 1.LEVEL for both. Saving dropped the write path in exactly that case, and the resulting alias showed the position but could no longer be moved. Rows that only write, like the blind's STOP, disappeared altogether. With Tasmota it never showed, because there tele.STATE is read and cmnd.POWER is written. The device type in the template sheet was affected by a second slip: three patterns are named differently from their type (blinds/blind, mediaPlayer/media, levelSlider/slider), so a blind always claimed to have no type at all
|
|
705
753
|
|
|
706
|
-
|
|
707
|
-
* The changelog only lists versions that actually exist on npm. The entries 0.9.1 to 0.9.6 were local intermediate steps and were never published; their content is now summarised under 0.9.7. Found by the repochecker (E2004, E1032)
|
|
708
|
-
* The README no longer describes how to add the adapter by hand — in the official repository it is picked from the adapter list (E6013)
|
|
709
|
-
* `dependabot.yml` gets a seven-day cooldown for npm packages: what appears today is proposed a week later. If a compromised release is pulled within that time, it never arrives here (E8915). And `@types/node` stays on its major version — the types must match the Node release the adapter runs on (E8917)
|
|
710
|
-
|
|
711
|
-
### 0.9.7
|
|
712
|
-
*Versions 0.9.1 to 0.9.6 were local intermediate steps and were never
|
|
713
|
-
published — their changes are part of 0.9.7.*
|
|
714
|
-
|
|
715
|
-
Seven packages from a code review — 45 fixes between 0.9.0 and this release. The intermediate steps 0.9.1 to 0.9.6 stayed local and were never published; they are summarised here.
|
|
716
|
-
|
|
717
|
-
**Data loss and failure paths**
|
|
718
|
-
* An enumeration error now stops a move. Previously the old alias was deleted anyway — and afterwards it was gone while the new one sat in no enumeration at all
|
|
719
|
-
* A partial failure while deleting no longer turns the retry button into a prop: only what really went is dropped
|
|
720
|
-
* Orphaned points are deleted on the second attempt too
|
|
721
|
-
* A load error on the enumerations leaves the previous state standing instead of emptying it — and while they are unknown, nothing is written. Before, one hiccup could drop an alias out of every room and function
|
|
722
|
-
* A load error on your own templates is reported instead of swallowed; otherwise the next save would have replaced an existing template with version 1
|
|
723
|
-
|
|
724
|
-
**Connection and display**
|
|
725
|
-
* The tab works again after a dropped connection. The admin's WebSocket fires `connect` once per page lifetime and `reconnect` afterwards — nobody listened, and neither object nor state changes arrived
|
|
726
|
-
* Template mode no longer rebuilds itself every second, and where the selection goes, its subscriptions go too
|
|
727
|
-
* “Differs from the alias” now also shows in alias mode — where it says the most
|
|
728
|
-
* Switching sources quickly no longer fetches the wrong value; the source jump list never appears twice
|
|
729
|
-
* Object names follow the admin language; the function match looks at every language and no longer creates a duplicate
|
|
730
|
-
|
|
731
|
-
**Templates**
|
|
732
|
-
* A broken name hint no longer takes down the whole source view — including the nested form `(a+)+` where the expression engine stalls
|
|
733
|
-
* The formula of a fallback source survives updating, an unknown device type no longer throws
|
|
734
|
-
* Importing checks more than id and states; a hand-typed id no longer replaces someone else's template
|
|
735
|
-
* The `%N%` placeholder only hits the output number now, not every trailing digit
|
|
736
|
-
* The blind gets its STOP: a button press has no state to read, and that case was unknown to template application — **not a single** blind alias ever had one
|
|
737
|
-
* ON_TIME finds its slot (four templates carried the wrong role)
|
|
738
|
-
|
|
739
|
-
**MQTT and Tasmota**
|
|
740
|
-
* An empty `custom` entry no longer takes anything down, `enabled: false` counts as switched off
|
|
741
|
-
* No more false “cannot publish” for ioBroker.mqtt and sonoff — there, publishing capability is simply unknown, not denied
|
|
742
|
-
* “Answer received” only for a real answer; `Vcc` and `Command` are not commands
|
|
743
|
-
|
|
744
|
-
**Speed, measured on a production system with 24,786 objects**
|
|
745
|
-
* The search box no longer blocks: **236 ms per keystroke → 0**, the whole tree **263 → 67 ms**
|
|
746
|
-
* A redraw no longer costs half a second — binary search instead of linear scans: drawing a source **15.8 → 1.6 ms**, an alias with 50 points **51.9 → 14.2 ms**
|
|
747
|
-
* A read formula can no longer freeze the tab for good
|
|
748
|
-
* What is subscribed is what is read — before, a single alias could subscribe to half an adapter
|
|
749
|
-
|
|
750
|
-
### 0.9.0
|
|
751
|
-
* The role list is complete again: the detector hands out the expressions of its slots as text WITH slashes (`/^indicator…$/`), not as a regular expression. Take the slashes for part of the expression and you find neither start nor end afterwards — 210 roles instead of 232, and `indicator.lowbat` of all things was missing, the role every Homematic device writes. In the role picker, no slot of the pattern was offered at all any more, only the line "show all roles"
|
|
752
|
-
* From the same cause, BRIGHTNESS lost its role in six colour-light patterns — the slot could be added over and over and could not be filled by any route. Seven places in the code read a slot expression; they all go through one function now, and a test checks the role list against what the detector actually delivers instead of against hand-written expressions
|
|
753
|
-
* The deviation card tells the truth again when a point is deselected: it claimed "would not have counted anyway" even for points that do have a slot in the pattern (same cause)
|
|
754
|
-
* A point the template lists under a different name now keeps its role and its caption at the source: the workbench has two functions for the same job, and the second one bailed out when a template had matched. At the alias it said `state` and "Lavalampe ACTUAL", at the source `sensor.light` and nothing at all — updating would have overwritten both. What the template wanted instead now shows as a mark on the row, as everywhere else, and can be taken over field by field
|
|
755
|
-
* On load, the workbench no longer fetches two files that do not exist: it searched the admin's directory for file names and put `assets/` in front, although whole paths are listed there — and two entries expressly do not live in that folder (`"path": ""`). That produced two 404s in the browser console. It now looks for paths instead of names and strips a leading `./`: the manifest writes `assets/…`, the `index.html` `./assets/…`, and without that step the same file would sit twice in a list that ends after 25 entries
|
|
756
|
-
* The readme now mentions two things it used to keep quiet about: that the workbench proposes the read formula itself from recognised JSON — guarded against missing fields, and readable in both directions — and that it maintains roles, the channel role, room and function along with their pictures
|
|
757
|
-
* Values now keep running in the alias view: the workbench subscribed to the alias points but displays the values of their sources, so the numbers were fetched once and then stood still. It now subscribes to the sources as well. The header shows how many subscriptions are running — a subscription covers a whole branch, and its tooltip lists them, so it is visible right away if one is ever left behind
|
|
758
|
-
* The caption of a row now lives in a tooltip on its id instead of standing next to it — with the marks a row can carry, it had become so crowded that role and value were pushed off to the right. A dotted underline shows where a tooltip waits
|
|
759
|
-
* An alias whose points read from more than one node now says so: a chip "n sources" next to "to the source", listing every node with its number of points; the jump button asks where to go instead of silently taking the majority; and the individual rows that read from elsewhere carry a mark naming their adapter. Before, the only way to notice was to open every row. The way back holds too: from a secondary source, "to the alias" is there again — it used to require being at the majority source. Spartas of one and the same device (a Tasmota `stat` and `tele`) do not count as a second source. The choice appears only under "to the source" — jumping to the alias has exactly one destination. Spartas next to each other are merged as well now, not just against the main source — a Tasmota read through `stat` and `tele` counted as two. And both the way back and the row marks now go by the source you are standing at: "to the alias" is there at every source of an alias, including the device above a sparte, and a row is marked when it does not come from here. At the alias itself every row carries its tag — there is no place you are standing, so no source is the normal one; a tie no longer decides anything. The tag names the source, not the adapter, and no entry in the list is highlighted
|
|
760
|
-
* Nodes without datapoints are no longer left out of the tree: a channel, device or folder that exists but is empty now stands there greyed out, without a count and not clickable, with a tooltip saying so. Left out, it looked like the node did not exist at all — while in truth the adapter had not created its datapoints. They do not count as hits when filtering
|
|
761
|
-
|
|
762
|
-
### 0.8.3
|
|
763
|
-
* The dry run now shows enumerations as a comparison as well: the "before" column stayed empty for them, because enumerations live in their own store and the dry run only looked in the object store. Everything appeared as new, so it was impossible to see that eleven of twelve members were already there
|
|
764
|
-
* …and the interface no longer announces a creation where it changes: on such an alias the chip said "will be newly created", the button offered "create alias", the dry run was titled "what would come into being", the room and function were guessed instead of read, orphaned points went unnoticed and move/swap/remove did nothing. All of them asked whether the channel is an object instead of whether the alias exists
|
|
765
|
-
* An alias whose channel exists only as an id, not as an object — the usual result of adding points by hand in the admin — is now compared against the stored state at all. Before, the whole comparison bailed out there, and updating would have replaced captions with the bare point names and dropped roles, formulas and write direction along with them
|
|
766
|
-
* The same rule was missing a third time, for aliases where several points read from one and the same source datapoint — a blind, where OPEN, CLOSE, SET and pct all go to `level`. Only the first of them kept its write source; the others lost it, and updating would have made the blind unreachable through its alias
|
|
767
|
-
* Updating an existing alias no longer overwrites its caption with the bare row name, and no longer turns a read-only alias into a writable one: the function that takes the stored alias over into the draft was missing both rules its twin already had. The false "differs from the stored alias" mark that came with it is gone too
|
|
768
|
-
* A line that comes from the stored alias and reads from a source outside the selected node now gets its value: the values were fetched before that line even existed, so it claimed "source delivers nothing" while the alias was working fine. Only showed on aliases assembled from several adapters, and only until the node was clicked a second time
|
|
769
|
-
|
|
770
|
-
### 0.8.2
|
|
771
|
-
* A source that already has an alias now says so when the target points elsewhere: "This source already has alias.0.… — that one stays where it is", with a button "move it instead …" that opens the move dialog prefilled. Nothing is forbidden — two aliases on one source remain possible, they are no longer silent
|
|
772
|
-
* The same line appears in the dry run, right above what cannot be written
|
|
773
|
-
* The offer to take the typed folder as the room now also appears on a device that already has an alias — the very case where the room is meant to come along
|
|
774
|
-
* Escape in the target bar's folder and name fields now discards what was typed and puts the old value back; before, the folder field only closed its list and both kept the typed text, which was then taken over on leaving the field
|
|
775
|
-
* Tooling: the identifier check script now resolves a relative acorn path against the working directory
|
|
776
|
-
* A line whose role the workbench adapted on a pattern or template switch now says so: "differs from the stored alias", with the stored value spelled out below the field and a button to take it back
|
|
777
|
-
* A line that takes its name from an existing alias no longer shows a false "no place in the … pattern" mark for one draw
|
|
778
|
-
* Switching to a template that finds no source at all now works instead of failing silently — the field no longer shows a template that is not in use
|
|
779
|
-
* Swap source: the name of the current source is shown next to its id
|
|
780
|
-
* Datapoints without a slot in the pattern get a tinted row; the explanation stands once above the list instead of in every row
|
|
781
|
-
* Switching the selection while changes are pending — in the tree, through "to the source →", or in the folder overview — now asks first instead of discarding them silently
|
|
782
|
-
* Where the template wants something else, the affected field is tinted in the opened row, the template value is spelled out below it, and a button takes over that one value
|
|
783
|
-
* The role list now also offers the other spellings a slot accepts (indicator.lowbat next to indicator.maintenance.lowbat), minus the deprecated ones
|
|
784
|
-
* New adapter icon: two offset cards — behind the raw datapoints, in front the finished alias, sorted and named
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
### 0.8.1
|
|
788
|
-
* Published through npm trusted publishing (OIDC); releases are signed with provenance
|
|
789
|
-
|
|
790
|
-
### 0.8.0
|
|
791
|
-
* Settings page in eleven languages
|
|
792
|
-
* ESLint and a CI workshop; checks run before every commit
|
|
793
|
-
* The buttons at the bottom follow the mode
|
|
794
|
-
* New description
|
|
754
|
+
Older entries: [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
|
|
795
755
|
|
|
796
756
|
## License
|
|
797
757
|
|
package/admin/css/werkbank.css
CHANGED
|
@@ -191,6 +191,10 @@
|
|
|
191
191
|
.tree .node.leer { opacity:.45; font-style:italic; }
|
|
192
192
|
.tree .node.leer .kind { background:transparent; border:1px solid var(--line); }
|
|
193
193
|
.tree .node.sel { background:var(--accent); color:var(--accent-ink); font-weight:600; }
|
|
194
|
+
/* Der gemeinsame Elternknoten einer Mehrfachauswahl: markiert, aber
|
|
195
|
+
schwaecher als die Zweige selbst. Er ist der Ort, auf dem der
|
|
196
|
+
Entwurf steht - angeklickt hat ihn niemand. */
|
|
197
|
+
.tree .node.selEltern { background:var(--accent-soft); font-weight:600; }
|
|
194
198
|
.tree .node.sel .kind { background:rgba(255,255,255,.22); color:inherit; }
|
|
195
199
|
/* Die Vorlagenliste benutzt dieselben Knotenzeilen, hat aber statt
|
|
196
200
|
`kind`/`nam`/`cnt` ein Abzeichen, einen Namen und rechts die Kennung.
|
|
@@ -633,6 +637,19 @@
|
|
|
633
637
|
.rat { font-family:var(--sans); font-size:8px; font-weight:700; letter-spacing:.05em;
|
|
634
638
|
text-transform:uppercase; background:var(--accent-soft); color:var(--accent);
|
|
635
639
|
padding:0 6px; border-radius:999px; margin-left:6px; white-space:nowrap; }
|
|
640
|
+
/* Name und Marke im Tauschdialog untereinander. Die Namensspalte ist
|
|
641
|
+
120 Pixel breit; „ERKANNT" hinter `ELECTRIC_POWER` lief sonst in die
|
|
642
|
+
Pfade der Nachbarzeile (Ricardo, 13.10.2026). */
|
|
643
|
+
#swap-body .slot .zuname { display:flex; flex-direction:column;
|
|
644
|
+
align-items:flex-start; gap:3px; }
|
|
645
|
+
#swap-body .slot .zuname .rat,
|
|
646
|
+
#swap-body .slot .zuname .herk { margin-left:0; }
|
|
647
|
+
/* Herkunftsmarke am Quellentausch: dieselbe Form wie „vermutet", aber
|
|
648
|
+
grau statt farbig - sie warnt nicht, sie sagt nur, woher die
|
|
649
|
+
Zuordnung kommt (Stufe 4, ueber den Alias-Punkt). */
|
|
650
|
+
.herk { font-family:var(--sans); font-size:8px; font-weight:700; letter-spacing:.05em;
|
|
651
|
+
text-transform:uppercase; background:var(--surface-3); color:var(--ink-3);
|
|
652
|
+
padding:0 6px; border-radius:999px; margin-left:6px; white-space:nowrap; }
|
|
636
653
|
.erow .nm3 .ratknopf { font-family:var(--sans); font-size:11px; cursor:pointer; margin-left:5px;
|
|
637
654
|
color:var(--ink-3); padding:0 4px; border-radius:var(--r-sm); }
|
|
638
655
|
.erow .nm3 .ratknopf:hover { background:var(--surface-3); color:var(--ink); }
|
|
@@ -1161,3 +1178,74 @@
|
|
|
1161
1178
|
.vorschlaege .vz.gruppe .tiefer.rbelegt:hover { color:var(--bad); }
|
|
1162
1179
|
.vorschlaege .vz.zurueck:hover { background:var(--surface-2); color:var(--ink); }
|
|
1163
1180
|
|
|
1181
|
+
|
|
1182
|
+
/* Der Hinweis, waehrend der Katalog geholt wird.
|
|
1183
|
+
|
|
1184
|
+
Beim ersten Oeffnen nach einer Admin-Aktualisierung laedt die
|
|
1185
|
+
Werkbank ein Buendel von mehreren Megabyte. Das dauert ein paar
|
|
1186
|
+
Sekunden und sieht ohne ein Wort dazu wie ein Haenger aus
|
|
1187
|
+
(Ricardo, 07.10.2026). Unten rechts, damit er nichts verdeckt, und
|
|
1188
|
+
er geht von allein wieder weg. */
|
|
1189
|
+
.katalog-laedt {
|
|
1190
|
+
position:fixed; right:16px; bottom:16px; z-index:30; max-width:320px;
|
|
1191
|
+
padding:10px 14px; border:1px solid var(--line-strong); border-radius:6px;
|
|
1192
|
+
background:var(--surface); box-shadow:0 2px 10px rgba(0,0,0,.18);
|
|
1193
|
+
}
|
|
1194
|
+
.katalog-laedt .kl-kopf { font-weight:600; font-size:12.5px; color:var(--ink); }
|
|
1195
|
+
.katalog-laedt .kl-text { margin-top:3px; font-size:11.5px; color:var(--ink-3); }
|
|
1196
|
+
|
|
1197
|
+
/* Das Menue am Baum (Rechtsklick). Liegt am body, nicht in der Zeile:
|
|
1198
|
+
der Baum scrollt, und ein Kind der Zeile wuerde am Rand abgeschnitten. */
|
|
1199
|
+
.baummenue {
|
|
1200
|
+
position:fixed; z-index:200; min-width:190px;
|
|
1201
|
+
background:var(--surface); border:1px solid var(--line-strong);
|
|
1202
|
+
border-radius:var(--r); box-shadow:var(--shadow-hoch); padding:4px 0;
|
|
1203
|
+
}
|
|
1204
|
+
.baummenue .bm-zeile {
|
|
1205
|
+
padding:6px 13px; font-size:12.5px; color:var(--ink); cursor:pointer;
|
|
1206
|
+
white-space:nowrap;
|
|
1207
|
+
}
|
|
1208
|
+
.baummenue .bm-zeile:hover { background:var(--hover); color:var(--hover-ink); }
|
|
1209
|
+
|
|
1210
|
+
/* Die Vorschau vor dem Ausgeben einer Attrappe. */
|
|
1211
|
+
.mk-kopf { margin-bottom:10px; }
|
|
1212
|
+
.mk-kopf .mk-wurzel { font:12.5px var(--mono); color:var(--ink); word-break:break-all; }
|
|
1213
|
+
.mk-kopf .mk-zahlen { margin-top:3px; font-size:11.5px; color:var(--ink-3); }
|
|
1214
|
+
.mk-kopf .mk-ohne { margin-top:3px; font-size:11.5px; color:var(--ink-2); }
|
|
1215
|
+
.mk-warn {
|
|
1216
|
+
margin:0 0 10px; padding:7px 10px; border-radius:var(--r);
|
|
1217
|
+
background:var(--warn-soft); color:var(--warn); font-size:11.5px;
|
|
1218
|
+
}
|
|
1219
|
+
.mk-warn .mk-warn-kopf { font-weight:600; }
|
|
1220
|
+
.mk-warn .mk-warn-liste { margin:4px 0 0; padding-left:16px; }
|
|
1221
|
+
.mk-warn .mk-warn-liste li { font:11px var(--mono); word-break:break-all; }
|
|
1222
|
+
table.mk-tab { width:100%; border-collapse:collapse; font-size:12px; }
|
|
1223
|
+
table.mk-tab th {
|
|
1224
|
+
text-align:left; font-weight:600; font-size:11px; color:var(--ink-3);
|
|
1225
|
+
border-bottom:1px solid var(--line); padding:4px 7px; position:sticky; top:0;
|
|
1226
|
+
background:var(--surface);
|
|
1227
|
+
}
|
|
1228
|
+
table.mk-tab td { padding:3px 7px; border-bottom:1px solid var(--line); vertical-align:top; }
|
|
1229
|
+
table.mk-tab tr.mk-virt { color:var(--ink-3); }
|
|
1230
|
+
table.mk-tab tr.mk-aus .mk-wtext { text-decoration:line-through; color:var(--ink-3); }
|
|
1231
|
+
.mk-wert label { display:flex; gap:5px; align-items:baseline; cursor:pointer; }
|
|
1232
|
+
.mk-wtext { font:11.5px var(--mono); word-break:break-all; }
|
|
1233
|
+
.mk-wtext.auff { background:var(--warn-soft); color:var(--warn); border-radius:3px; padding:0 3px; }
|
|
1234
|
+
.mk-pfad { font:11.5px var(--mono); }
|
|
1235
|
+
.mk-name { color:var(--ink-2); }
|
|
1236
|
+
.mk-fehler {
|
|
1237
|
+
padding:8px 11px; border-radius:var(--r);
|
|
1238
|
+
background:var(--bad-soft); color:var(--bad); font-size:12px;
|
|
1239
|
+
}
|
|
1240
|
+
.mk-namenszeile { display:flex; gap:7px; align-items:center; margin:7px 0 3px; }
|
|
1241
|
+
.mk-namenszeile .mk-lbl { font-size:11.5px; color:var(--ink-3); }
|
|
1242
|
+
.mk-namenszeile input.tx { max-width:260px; }
|
|
1243
|
+
.mk-schon { color:var(--ink-3); font-size:11px; }
|
|
1244
|
+
/* Von welcher Zeile das Baummenue spricht. Bewusst anders als die
|
|
1245
|
+
Auswahl `.sel`: ein Rechtsklick waehlt nicht aus, und zwei gleich
|
|
1246
|
+
aussehende Zeilen waeren irrefuehrend. */
|
|
1247
|
+
.tree .node.menueziel {
|
|
1248
|
+
outline:2px solid var(--accent); outline-offset:-2px; border-radius:var(--r);
|
|
1249
|
+
}
|
|
1250
|
+
.mk-warn.mk-gross { background:var(--warn-soft); }
|
|
1251
|
+
.mk-mehr { margin-top:6px; font-size:11.5px; color:var(--ink-3); }
|