Add Device Manager for exisiting devices - #600
Merged
Merged
Conversation
Devices connecting via MQTT (server or bridge mode) now show up as auto-discovered cards in the admin's Device Manager tab, mirroring the flexible, data-driven approach used by ioBroker.shelly's deviceManager. - Devices are grouped (relays, lights/dimmers, covers, Zigbee bridges, energy meters, sensors) by scanning which data points a device actually created, since Tasmota/Sonoff devices have no fixed model registry. - Main tile shows connection/RSSI/battery status plus sensor readouts and power draw; the details panel adds network/firmware info (from INFO.*), energy metering breakdown and digital inputs. - Controls are auto-generated from the device's writable states: relay/Zigbee/OpenBeken switches, dimmer/color-temperature/shutter sliders, RGB(W) color pickers, and a "Settings" group for any other writable data point. - Device rename and "open web interface" actions. - Wired into the adapter via objectChange/stateChange forwarding and a new admin "Device manager" tab.
Extends the Device Manager's power metering, following the approach from ioBroker.shelly PR #1562: instead of only looking at the built-in ENERGY.* group, every state of a device is matched against a table of known power/voltage/current/energy data points by name. This also picks up power values from bridged external meters (SML smart-meter heads, PZEM sensors, ...), which Tasmota publishes under their own custom group name (e.g. "SML_Total_in") rather than under ENERGY. When a device has more than one meter, the details panel now groups the values per meter; the main tile bolds the "Power" (W) reading(s) the same way as before. Also fills in MARGINS.* (power thresholds) and the German-named duplicate data points (Leistung, Spannung, Strom, Frequenz, ...) that were previously not shown at all.
When a device's INFO.Module isn't known yet, the card showed the literal fallback text "Tasmota device" next to the identifier (e.g. "messdose-trockner Tasmota device"). Just omit the model in that case so only the identifier is shown.
With the "Create object tree" adapter option enabled, Tasmota's SENSOR/STATE payloads (which is where ENERGY, Wifi.RSSI and Uptime usually live) get nested under an extra "SENSOR."/"STATE." group, e.g. "SENSOR.ENERGY.Power" or "STATE.Wifi.RSSI" instead of the flat/ single-level state IDs the device manager assumed. That made power values, RSSI, uptime and other sensor readouts silently disappear from the tiles for anyone using that option. State lookups for these data points now match by their last path segment (the actual data point name) instead of a fixed suffix, so they find the value no matter how many groups it is nested under.
When "Create object tree" (OBJ_TREE) is toggled, a data point's state ID changes (e.g. ENERGY.Power vs. SENSOR.ENERGY.Power), but the old state is never deleted. Both then showed up as separate "meters", duplicating the whole power metering section. Power entries are now grouped by their channel with any SENSOR./STATE./RESULT./WAKEUP. prefix stripped, keeping only the one entry per meter/data point that matches the adapter's current OBJ_TREE setting. Also fixes two sizing issues from a misread of dm-utils' item types: "size" on a state/staticInfo item is a font size, not a grid width - the sensor readouts on the tile were rendered at a fixed 12px, making them look smaller than everything else. And "size" on a header item is a heading level (1 biggest), so the section headers in the Information tab used a fairly large heading (4) - shrunk to 6.
The previous dedup grouped entries by their literal data point name
(e.g. "Power"), which doesn't merge a reading that also exists under
a different, German-named alias for the same value (e.g. "Leistung"
mapping to the same "Power" label). Grouping by the resolved label
instead - which is what's actually rendered - catches that case too,
so the same meter no longer shows up twice with the raw channel name
("ENERGY") as a stand-in label.
Also format the tile's power reading like the other sensor readouts
(dimmed, regular weight) instead of bold, and fix a stray embedded
NUL byte that had ended up in the grouping key.
Guessing which of two duplicate power states is "the current one" from the adapter's OBJ_TREE setting didn't hold up: a leftover ENERGY.* state from before OBJ_TREE was toggled kept showing up next to the live one, since Tasmota can apparently keep the old topic around independently of that setting. Deleting the leftover object tree manually made the duplicate go away, confirming it really is a stale, no-longer-updated state rather than a second live meter. Now the entry with the most recently updated state (`ts`) wins per meter and metric - the leftover simply stops receiving updates once its topic is no longer published, so it naturally loses out to the live one without needing to know why it's stale. Also: the built-in ENERGY group's label is now translated to "Power"/ "Leistung" (via i18n) instead of showing the raw "ENERGY" group name, both on the tile (when a device has more than one meter) and in the Information tab's per-meter header. A bridged external meter's group name (e.g. "SML") has no fixed translation and is still shown as-is.
Toggling "Create object tree" (OBJ_TREE) moves a data point to a different state ID (e.g. RSSI: "Wifi_RSSI" -> "STATE.Wifi.RSSI"), but the adapter never deleted the old one - it just kept existing next to the live one, most visibly duplicating every power-metering value. The device manager now runs a cleanup once at startup and every hour after that: for every data point that exists more than once for the same device and meter/value, it deletes the copy/copies that don't match the *current* OBJ_TREE setting - but only once a copy that does match already exists, so nothing is ever deleted before its live replacement is confirmed to be there. Since this restarts on every adapter start (which js-controller does whenever the config is saved), the leftover from before a config change is cleaned up automatically without any manual object-tree surgery. Covers power metering, RSSI, uptime, battery and the sensor readouts (temperature, humidity, ...) - the data points that move around under OBJ_TREE the same way.
The automatic cleanup after an OBJ_TREE change (from the previous commit) needed to special-case more and more data points that must never be touched (the POWER switch itself, for one) to stay safe, which made it fragile and hard to fully trust. Simpler and safer: a "Delete and recreate all data points of this device" action on each device card. It deletes every data point of the device (keeping the channel object, so a custom name via "rename" survives) - the MQTT handling recreates them from scratch, in whatever shape the current adapter configuration produces, the next time the device reports its state. Requires confirmation since it's destructive.
Some Tasmota firmware reports energy readings both nested inside its regular "SENSOR" telemetry (which "Create object tree" nests further under "SENSOR.ENERGY") and via its own dedicated "ENERGY" topic (a bare "ENERGY.*" state, handled separately in mqttBase.ts) - so both can be live and continuously updated at the same time, not just one stale and one current. The freshness-based dedup couldn't tell those apart reliably. A device that also sends its own dedicated topic still sends the regular telemetry too, so whenever a SENSOR/STATE/RESULT/WAKEUP-nested copy of a reading exists, it is now always preferred over a bare one, independent of timestamps. Freshness is only used as a fallback when no nested copy exists (or more than one nested copy exists, e.g. two aliased data point names).
Found from the reported log line: "stat/Trockner/STATUS10 =
{"StatusSNS":{"ENERGY":{...}}}". Requesting Status 10 mirrors the
same data as the periodic tele/.../SENSOR telemetry, but its handler
always passed an empty prefix to checkData(), regardless of the
"Create object tree" (OBJ_TREE) option - unlike every other call site
in this file, which switches to a named prefix ("SENSOR"/"STATE"/...)
when OBJ_TREE is on.
With OBJ_TREE on, checkData() builds the prefix for a nested object
(here "ENERGY") as `${prefix}.${group}`; with an empty prefix that
produces the malformed id "<device>..ENERGY.<field>" (leading dot) -
a separate, bogus state from the real "<device>.SENSOR.ENERGY.<field>"
one, which is what the "duplicate ENERGY folder" the user kept seeing
actually was: not a device sending two independent topics, but this
one topic's handler misplacing its data every time a client (Home
Assistant discovery, a script, ...) requests Status 10.
"Period" (Tasmota's energy accounting period counter) was mapped as
if it were a power reading (unit "W"), but it isn't one and stayed
empty for most users - dropped from the power metering section.
findDataPointSuffix picked whichever matching state happened to come
first in object iteration order, which could be a one-off echo (e.g.
"RESULT.Uptime", only ever set once as part of a command response)
instead of the periodic telemetry ("STATE.Uptime") that actually keeps
updating - showing a frozen value. When a data point exists in more
than one group, the periodic telemetry groups (STATE, then SENSOR)
are now preferred, fixing this for Uptime and any other data point
read through this helper (RSSI, battery, sensor readouts).
…-hi62gu Add ioBroker Device Manager support
Contributor
Author
Contributor
Author
|
@GermanBluefox Release 4.1.0 failed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an ioBroker Device Manager for the Sonoff adapter and, over the course of the PR, fixes several real-world issues found while testing it against live Tasmota devices.
Device Manager
Devices connecting via MQTT (server or bridge mode) show up as auto-discovered cards in admin's Device Manager tab, mirroring the flexible, data-driven approach used by ioBroker.shelly's deviceManager - Sonoff/Tasmota devices have no fixed model registry, so everything is derived from whichever data points a device actually reports.
Devices are grouped (relays, lights/dimmers, covers, Zigbee bridges, energy meters, sensors) by scanning their data points.
The main tile shows connection/RSSI/battery status plus sensor readouts and power draw; the details panel adds network/firmware info (from INFO.), a power metering breakdown and digital inputs.
Controls are auto-generated from the device's writable states: relay/Zigbee/OpenBeken switches, dimmer/color-temperature/shutter sliders, RGB(W) color pickers, and a "Settings" group for any other writable data point.
Actions: rename, open the device's web interface, and "Delete and recreate all data points" - a manual, confirmation-gated reset that clears a device's data points (keeping its name) so they get recreated from scratch the next time it reports its state. Useful after a structural adapter setting (like "Create object tree") changed, or if a device's data points otherwise ended up in a stale/inconsistent shape.
Power metering
Power/voltage/current/energy readings are found by data point name rather than one fixed state ID, so they're picked up wherever they actually exist: the built-in ENERGY. group, a bridged external meter under its own group name (e.g. SML_Total_in), or German-named aliases (Leistung, Spannung, Strom, ...). When the same reading exists more than once for a device, a deterministic priority resolves it to a single value instead of showing duplicates:
A copy nested under SENSOR/STATE/RESULT/WAKEUP (created by the "Create object tree" option) is preferred over a bare one.
Otherwise, the most recently updated copy wins.
The built-in energy group is labeled "Power"/"Leistung" (translated) instead of the raw "ENERGY" group name.
Bug fixes found along the way
Root cause of a duplicated ENERGY folder: the STATUS10 response handler (stat/.../STATUS10, e.g. requested by Home Assistant discovery) always used an empty prefix, regardless of the "Create object tree" setting - unlike every other handler in mqttBase.ts. With that option on, this produced a malformed state ID with a leading dot (..ENERGY.) instead of the correct .SENSOR.ENERGY., which looked like a second, independent "ENERGY" folder. Fixed, with a regression test.
Data points that can exist under more than one topic group (e.g. Uptime as a one-off echo in a RESULT response vs. the periodic STATE telemetry) now prefer the periodic telemetry group, so the shown value keeps updating instead of getting stuck on a stale echo.
Removed "Period" (Tasmota's internal energy-accounting counter) from the power metering section - it was mislabeled as a Watt reading and empty for most users.
The model shown on a device's tile no longer falls back to a "Tasmota device" placeholder when INFO.Module isn't known yet - just the identifier is shown.
Fixed two sizing issues from a misread of the dm-utils item schema: the sensor/power readouts on the tile were rendered at a fixed, too-small 12px font instead of the default size, and the "Power metering"/"Digital inputs" section headers used a fairly large heading level.