Skip to content

A new action finds the threshold that fits a yes/no sensor, from its recorded history - #25

Merged
AboveColin merged 3 commits into
feature/1.16from
calibrate
Sep 24, 2026
Merged

AboveColin merged 3 commits into
feature/1.16from
calibrate

Conversation

@AboveColin

Copy link
Copy Markdown
Owner

A new action, jev.calibrate, finds a threshold for a noul sensor from what happened in the house.

It reads the recorder for two entities over the last days (default 7):

  • entity_id is a probability sensor, such as a Jev noul sensor.
  • truth_entity_id shows what was really true, such as a door contact or a plug that reports when a machine runs. truth_state (default on) is the state that means yes.

The action cuts the window at every change of either entity. For each threshold from 0.01 to 0.99 it measures, weighted by time:

  • precision: of the time the threshold said yes, the part that was true.
  • recall: of the time that was true, the part where the threshold said yes.

It returns the threshold with the highest F1. When several thresholds tie, it returns the middle one. The response also has hours, hours_true, times_true, probability_changes, and a table at 0.1 steps, so the caller can see how much evidence the result has.

The action does not call TypeSafe, so it costs no tokens. The test asserts that ask is not awaited.

The default of 7 days is inside the recorder's default purge_keep_days of 10. The action has no upper limit, because a longer window only reads further back.

Errors, with text in strings.json and all 13 translations:

  • calibrate_needs_recorder: the recorder is not running.
  • calibrate_no_history: no time in the window has both a number and a truth state.
  • calibrate_never_true and calibrate_always_true: with only one side, every threshold gives the same score.

recorder is added to after_dependencies.

Gate (ruff, mypy --strict, pytest, mkdocs --strict, hassfest): exit 0. 418 passed, 12 skipped, coverage 97.03%. calibrate.py is at 100%, and config_flow.py is at 100%.

A test window with the door open for two minutes returned hours_true 0.0
beside times_true 1, which read as the never-true refusal failing to
fire. Both hour counts now keep two places, so the same window reads
0.03.
@AboveColin
AboveColin merged commit efbd856 into feature/1.16 Sep 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant