Repository navigation
Releases: mayerwin/HA-Merge-Sensor-History
Release list
v1.4.2 - Bulk add finds deleted and disabled entities
Improvement
Paste the old ids, and Bulk add finds them
When a sensor has been renamed or removed, its old id no longer exists as a live entity. Bulk add used to accept such ids only if Show deleted/disabled entities was already ticked, and otherwise reported them as unknown without saying why.
Bulk add now looks unknown ids up among deleted and disabled entities by itself. If it finds them all, it turns Show deleted/disabled entities on and adds the pairs, so pasting the old ids just works.
If some ids still cannot be found, nothing is added and the error says they are neither current entities nor deleted or disabled ones Home Assistant still has data for, so it is worth checking their spelling.
Notes
- A deleted sensor is found when Home Assistant still keeps statistics for it. One that only ever recorded raw states (for example a sensor without a state class) and has since been removed from Home Assistant cannot be found this way.
- Nothing changes about what an import writes. Back up your database before importing, as always.
v1.4.1 - Imports are admin-only everywhere
Improvement
The import service is now admin-only, like the panel
The Merge History sidebar panel has always been shown only to administrators: users without admin rights do not see it in their sidebar and cannot open it by its URL.
The merge_sensor_history.import_history service now follows the same rule. A call made by a user without admin rights, for example through the API, is refused. Automations and scripts are unaffected, since they do not run as a user.
Notes
- No change for administrators, and nothing changes about what an import writes.
- To keep someone out of the panel, make sure their Home Assistant user is not an administrator (Settings > People > Users, untick Administrator).
v1.4.0 - Pick by device, and the panel keeps your work
Pick by device
Replacing a whole device, such as a smart plug? Tick Pick by device, choose the old device and the new one, and each of the old device's entities is matched to one of the new device's.
- Matches are based on what the integration calls each entity, their names without the device's name, and whether both hold the same kind of data. A power sensor is never matched to an energy one, and "L1" is never matched to "L2".
- Each suggestion says why it was made. Anything unclear is left for you to pick, and you can change or skip any row.
- Add pairs puts them in the normal list, where Preview and Import work as usual.
- Disabled entities of the old device are included. A device you already deleted is not listed: pick its entities one by one with Show deleted/disabled entities instead.
The panel keeps your work
Home Assistant rebuilds a panel when you switch to another page, or when its browser tab has been in the background for 5 minutes, and the panel used to come back empty. It now keeps your pairs, options and results while the page stays open. An import still running at that point carries on, and its results are shown when you come back. Reloading the page still starts afresh.
Previews no longer look like imports
Preview results are shown in blue, dashed cards marked Preview. Import results are marked Imported, Nothing to import, Imported with errors or Failed.
Documentation
The usage steps no longer say that units are converted automatically. Values are imported exactly as stored, and when the two sensors store different units, the result suggests the usual conversion (since 1.3.5).
v1.3.5 - Suggest the conversion between different units
Improvement
A suggested conversion when the two sensors store different units
When the source and the destination store their statistics in different units, the import result already warned you and imported the values exactly as stored. It now also shows the usual conversion between the two units, with a button that fills it in under Adjust imported values:
kWhtoWh: ×1000WtokW: ×0.001°Cto°F: f(v) = v * 1.8 + 32, since temperature needs an offset as well as a factor
It is only a suggestion. Nothing is applied until you run the import with it, and you can change it first if your sensors need something else. After clicking, run Preview again to check the result before importing.
When no suggestion is offered
- The two units measure different things, or Home Assistant has no conversion between them.
- Either sensor's statistics are recorded as a different kind of quantity. Temperature and temperature difference share the same units but convert differently, so a wrong
+ 32is never suggested. - Several pairs are imported in one run. Adjust imported values applies to every pair, so the button is left out and the result tells you to import that pair on its own.
Notes
- Nothing changes about what is written to your database unless you use the suggestion.
- The suggestion converts between the units your statistics are stored in. If you changed the source sensor's display unit in its entity settings, its History states are recorded in that display unit instead, and the suggested conversion may not suit them. The Energy dashboard uses the statistics, which the suggestion does suit.
- Back up your database before importing, as always.
v1.3.4 - Explain Utility Meter destinations
Improvements
Importing into a Utility Meter is now explained
A Utility Meter helper keeps its running value inside the helper, counting from the moment it was created, and no import can change that value. After importing older history into one, the Energy dashboard shows a single continuous series, because it reads statistics. The History graph, which shows the meter's state, can still show a drop where the imported history ends and the meter's own readings begin.
That drop is harmless, but it looks like the meter restarted from zero. When the destination is a Utility Meter, the import result now says so and explains why.
It also warns against the obvious workaround. Lifting the meter with Utility Meter: Calibrate after importing is recorded by Home Assistant as consumption, so the imported history would be counted twice.
Fixes
- A preview or import with no statistics rows to write no longer announces a cumulative-sum offset that "would be applied". With nothing imported, nothing is shifted, and the line was misleading.
- The README described automatic conversion between units, which the integration has never done. Two sensors stored in different units are imported as stored, the result tells you, and Adjust imported values rescales them, as before.
Notes
- Nothing changes about what is written to your database. This release only changes what the import result tells you.
- Back up your database before importing, as always.
v1.3.3 - Always realign the running total on a head-fill import
Fix
The running total is now always realigned when you import history in front of an existing series
When you import older energy history in front of a destination that already has statistics, the two cumulative series start from different baselines. The import lifts the destination's running total, its existing rows and its future ones, by a constant so the two halves join seamlessly and the lifetime total stays true.
That lift was being skipped whenever the same run also backfilled 5-minute statistics, which is what happens when Fill gaps or Overwrite is ticked. The imported history was shifted down to meet the destination instead. The join was still smooth and per-hour and per-day figures were still right, but the lifetime total read far too low, and the oldest imported hour carried the whole offset.
The effect landed on exactly the wrong people: importing once plainly gave the correct lift, while re-running with Overwrite after a first attempt looked wrong did not.
The lift now runs whatever the 5-minute step did. It starts at the oldest imported hour, so every row in both statistics tables moves by the same amount and none move relative to each other. It is only ever planned for a pure head-fill, where the hourly and the 5-minute series join the destination at the same instant and therefore share one offset, so a single constant is correct for both.
Notes
- Affects you only if you imported energy history in front of a destination that already had statistics, with Fill gaps or Overwrite enabled. Re-run the same import and the lift is applied. A second run on an already-aligned destination still does nothing.
- The import summary now reports the lift on these runs, where it previously reported a cumulative-sum offset and a note about the oldest hour.
- Nothing changes for imports into a destination with no statistics of its own. Those are seeded, which already worked.
- If your destination is a Utility Meter helper, note that its own state is kept inside the helper rather than in the database, so no import can move it. Home Assistant's Utility Meter: Calibrate action sets it. Calibrate before importing, because calibrating afterwards is recorded as consumption and would count the imported history twice.
- Back up your database before importing, as always.
v1.3.2 - Read statistics in their stored unit
Fix
Statistics are read in the unit they are stored in, not the unit they are displayed in
Home Assistant keeps a sensor's statistics in the unit they were first compiled in. That stored unit is fixed for the life of the statistic: Home Assistant converts incoming readings into it. The unit shown on the entity is only a display unit, which you can change in the entity settings, and Home Assistant converts storage to display when something reads the statistics back.
The import was reading the displayed values and writing them straight back into the stored column. If a sensor's display unit differed from its stored unit, imported statistics and the running-total adjustment were wrong by exactly the conversion factor. An energy sensor stored in kWh but displayed in Wh would have had a correction a thousand times too large.
Both the source's and the destination's statistics are now read directly from the stored values, so a display setting cannot skew an import. This also puts them in the same terms as the restart detection and the repair, which already read the stored values.
Sensors stored in different units
If the two sensors' statistics are stored in different units, nothing is converted for you. The import result says which units they are and points you at Adjust imported values under Options, which is the one setting that rescales, and which applies to states and statistics alike so both halves of an import stay consistent.
Notes
- Affects you only if one of the sensors has a display unit that differs from the unit its statistics are stored in, which happens when you pick a different unit in the entity settings. If you have never done that, this release changes nothing about your imports.
- A destination with no statistics and no loaded state, such as a disabled entity, again takes the source's unit for the metadata it creates. That fallback had been lost.
- Back up your database before importing, as always.
v1.3.1 - Never lock the recorder out; keep energy totals continuous
Fixes
The import can no longer lock the recorder out of its database
Reported in #15. On SQLite only one thing can write at a time, and the import was taking a second database connection to do its work. While it ran, Home Assistant's recorder could not commit its own events. On a large import that lasted long enough for the recorder to give up and discard what it had queued, which is lost history, and the only way to stop it was restarting Home Assistant.
The import no longer takes a second connection. It is queued onto Home Assistant's recorder thread and runs on the recorder's own connection, the same way Home Assistant's own bulk statistics import does. With no second writer there is nothing to lock out, however long the import takes. Events simply queue while it runs and are written immediately afterwards.
It is also considerably faster. Rows now go in with a multi-row insert rather than one at a time, roughly an order of magnitude quicker: about a second per 100,000 states.
Imports stay all-or-nothing at any size. Either the whole import lands or the database is left exactly as it was.
An import can now be stopped. Reloading or disabling the integration, or shutting Home Assistant down, cancels one that is running. Since nothing is committed until the end, a cancelled import writes nothing.
Energy history no longer restarts the destination from zero
Reported in #16. You could import an energy sensor's history correctly and still see the destination meter drop back to zero for everything recorded after the import.
Home Assistant continues a sensor's running total from that sensor's own most recent 5-minute statistics row, and starts again from zero when there is none. The import only ever looked at the destination's hourly rows to work out where to join the two series. A destination too new to have an hourly row got no join point at all, so its live readings stayed anchored at zero right after the imported history.
The destination's 5-minute rows are now used as the join point when there is no hourly row, and a destination with no statistics of its own gets its running total seeded at the end of the imported history so its new readings continue from there.
Repairing a meter that already restarted
If an earlier version left your destination with its history intact but its own later rows counting up from zero, re-run the import, or just click Preview. The result explains what happened and when, and offers a Repair running total button.
Repairing lifts every statistics row from the restart point onwards so the two halves line up and future readings continue from the corrected total. Rows before that point are left alone, and per-hour and per-day figures do not change: only the running total moves. You do not need to re-import anything, and it works even if the old sensor is long gone.
Nothing is repaired unless you click it, it re-checks your database when you click rather than trusting what the panel showed, and clicking twice cannot double the correction. It is only offered when the series shows a single unambiguous restart, so a sensor whose total legitimately goes down, such as a bidirectional one, is never flagged.
Notes
- Verified against a SQLite database mirroring Home Assistant's schema: a mid-import failure leaves it byte-identical, including for overwrite mode, where a crash previously had to leave part of the replaced window deleted.
- Behaviour was checked against Home Assistant's own recorder and sensor statistics source, not inferred.
- Back up your database before importing, as always.
Thanks to @PioThePio for the precise report on #15, including the BEGIN IMMEDIATE test that pinned down what was holding the lock, and to @janorn for #16.
v1.3.0 - Overwrite mode for destinations holding known-bad data
New feature
⚠️ Overwrite mode, for destinations holding known-bad data
Requested in #14. Until now the import never touched data the destination already had: it filled in front of the oldest entry, and with gap-fill it filled empty stretches. That is the right default, but it cannot help when the destination's existing data is itself wrong. A new sensor that recorded zeros while it was being commissioned alongside the old one looks fully covered, because a stored 0 is a real value, not a hole. The same applies after an import made with the wrong unit: the destination now has data, so a corrected re-run has nothing to fill.
Under Options there is now an
What it does
- Destination state rows inside the source's time span are deleted and replaced by the source's states, whatever the gap-fill setting says.
- Destination statistics values are overwritten, hourly and 5-minute, for every column the source provides. Columns the source does not provide keep their existing values.
- Data outside the source's time span is never touched, and the most recent slots Home Assistant may still be compiling are still skipped.
- For energy sensors the splice offset is computed against the destination rows that survive the overwrite. Without that, a corrected series would be pulled down to line up with the very values it is replacing.
Guard rails
Deleted state rows cannot be recovered without a database backup, so the option is deliberately hard to trigger by accident:
- Ticking the box unfolds a full warning explaining exactly what will be removed.
- Starting an import with it on asks for a second confirmation, listing the destination entities that will lose data.
- Preview works as usual and reports the number of rows that would be replaced along with the exact time window, so you can check the range before committing.
- The results panel shows the same counts and window after the run, and the deletion is logged as a warning.
- The deletes happen in the same transaction as the inserts. If anything fails, the deletes roll back too.
Also available on the service call as overwrite: true.
Notes
- Verified against a SQLite database mirroring Home Assistant's
statesschema with foreign keys enforced: rows outside the span and other entities stay untouched, references from surviving rows into the deleted range are cleared the same way Home Assistant's own purge does, and a simulated mid-run failure restores every row. - Re-running an overwrite is stable: the second run replaces its own rows with identical values.
- Back up your database before using this. It is the one option in the integration that deletes existing data.
Thanks to @Ryeera for the suggestion and the clear description of the case.
v1.2.17 - Merge recent raw states blocked by hidden unavailable rows
Fix
Recent raw states no longer blocked by hidden unavailable rows
The states import only brings in data older than the destination's oldest entry, to avoid duplicates. Until now that cutoff counted every stored row, including hidden unavailable/unknown markers that Home Assistant never shows in the History panel. If the destination entity id had existed before (for example as a leftover ghost entity logging an unavailable marker at every restart), those invisible rows silently blocked the import of the source's recent raw states: long-term statistics came through, but the recorder window stayed empty.
The cutoff is now the destination's oldest good (visible) entry. Hidden rows no longer count as coverage, and exact-timestamp duplicates are still skipped, so imports remain idempotent. If a previous merge left the recent period empty, update and run the same pair again: the missing states are imported as long as they are still within your recorder retention (states age out daily, so do this soon).
Reported on the community forum, thank you!
Improvements
Disabled entities as sources
The Show deleted entities toggle is now Show deleted/disabled entities. It lists every entity with no live state, using the entity registry to tag each one:
[deleted, statistics only]: gone from Home Assistant; only hourly statistics remain.[disabled]/[not loaded]: still registered; their recent raw states are merged too, while those remain within your recorder retention.
Registered entities without any statistics (raw states only) are now listed as well, so a disabled sensor that never had long-term statistics can still be merged.
Panel polish
- When states are skipped because they fall inside the destination's existing range, the results now point to the gap-fill option (with a Preview) as the way to inspect and import them.
- Friendly names containing
<,>or&now display correctly in dropdowns and results. - README: documented that the source entity is never modified, with cleanup guidance once a merge is verified (delete the old entity, optionally run
recorder.purge_entities).