Skip to content

Occupancy heat gain drives solar-shading deployment — entering a room lowers the blind #418

Closed

Description

@Luke2105-Loft59

RoomMind: 1.7.6 HA: 2026.8.3 (HAOS)

What happens

Every morning, a few seconds after I enter my bathroom, RoomMind lowers the
external roller shutter. The room is small (6 m², SE-facing Velux roof
window). It happens during the morning sun window, so it looks like solar
shading — but the trigger is me walking in, not the sun.

Why (traced through the code)

RoomMind now estimates an occupancy heat gain (Q_occupancy; ≈ 1.46 °C for
this room per diagnostics). That gain is fed into the peak-temperature
prediction that the cover logic uses to decide shading:

  1. control/mpc_controller.py: occupancy_series = [self.q_occupancy] * horizon_blocks
    — held constant over the entire ~8 h lookahead.
  2. It goes into optimizer.optimize(...) → plan.temperatures.
  3. predicted_peak_temp = max(plan.temperatures[1:]) — includes the
    occupancy gain.
  4. coordinator.py passes exactly this value:
    cover_orchestrator.async_process(predicted_peak_temp=controller.predicted_peak_temp, ...).
  5. cover_manager.evaluate(): excess = predicted_peak_temp - target_temp;
    excess > covers_deploy_threshold (default 1.5) → deploy → blind closes.

So the moment the occupancy sensor goes on, q_occupancy becomes 1.0, the
predicted peak jumps ~1.5 °C, the threshold is crossed, and the shutter
deploys on the next 30 s cycle.

This is a category error: external shading attenuates solar gain only;
it cannot counteract metabolic/occupancy heat. The project already feeds
unshaded solar into the MPC to avoid the deploy↔retract oscillation — the
same decoupling should apply to occupancy.

Compounding factor: cover target in heat_only rooms

cover_orchestrator.async_process:

cover_target = (
    targets.cool if mode == MODE_COOLING and targets.cool is not None
    else targets.heat if targets.heat is not None
    else 22.0
)

A heat_only room never reaches MODE_COOLING, so overheat shading is
compared against the heating setpoint (~22 °C here). That makes the
threshold trivially easy to cross — the occupancy bump alone is enough.
Against a cooling/upper-comfort value (24–27 °C) it would not fire on
occupancy.

Setup

climate_mode: heat_only, single 135° (SE) Velux shutter,
covers_auto_enabled: true, covers_deploy_threshold: 1.5,
covers_min_position: 0, covers_snap_deploy: false,
covers_outdoor_min_temp: 10. Diagnostics at report time:
current_temp 23.2, outdoor 15.8, heat_target 22, cool_target 22,
model Q_occupancy ≈ 1.46, n_idle > 40000.

Proposed fix

  1. Primary: compute the peak used for the cover decision with
    occupancy excluded (occupancy_series = [0.0] * horizon), e.g. expose
    MPCController.predicted_peak_temp_unoccupied and pass that into
    cover_orchestrator.async_process. Mirrors the existing "unshaded solar
    for the cover decision" approach. (The trajectory still starts from the
    measured current_temp, which carries a small already-realised
    occupancy offset — acceptable; the constant horizon term is the
    dominant effect.)
  2. Secondary: derive cover_target from an upper comfort bound
    (comfort_cool / eco_cool / a dedicated covers_comfort_max_temp),
    independent of climate_mode, so a heat_only room isn't shaded toward
    its heating setpoint.

Related (lower priority)

  • occupancy_series is constant over the full horizon; a decay (like
    _build_residual_series) or a bounded dwell window would reduce
    over-prediction for climate control too.

Workaround

Disable switch.roommind_<room>_cover_auto, or raise
covers_deploy_threshold to ~4–5 °C for the affected room.

In the meantime I've had to teach my bathroom light automation to switch the
lights on the instant the room goes dark, so that a shutter dropping to 0%
mid-morning doesn't leave anyone stranded in pitch black during
time-sensitive, bathroom-relevant activities. It works — but a predictive
thermostat integration probably shouldn't be a load-bearing dependency for
reliably seeing what you're doing on your own toilet. 🙂

Activity

  1. snazzybean commented on Sep 16, 2026

    @snazzybean
    Owner

    v1.7.7 keeps body heat out of the shading prediction and now compares it against the comfort cooling temperature instead of the heating setpoint. Feedback welcome!

  2. Luke2105-Loft59 commented on Sep 19, 2026

    @Luke2105-Loft59
    Author

    Thanks for the quick fix! Confirming on v1.7.7 (HAOS, bathroom, heat_only, covers_auto_enabled: true, covers_deploy_threshold: 1.5 — default, no workaround applied): over the last ~2 days the presence sensor triggered ~45 times, including several times during the morning sun window, and the roller shutter stayed open every time. Before the update it lowered within seconds of entering the room. Looks fixed on my side, so from my perspective the issue can be closed.

    I'm keeping my bathroom light automation as a safety net, since RoomMind's solar shading can still legitimately close the shutter on sunny mornings.

  3. added
    needs-attentionIssue author responded, needs review
    and removed
    waiting for feedbackWaiting for feedback from issuer after release
    on Sep 19, 2026
  4. snazzybean commented on Oct 10, 2026

    @snazzybean
    Owner

    Addressed in v1.7.7

  5. github-actions commented on Oct 10, 2026

    @github-actions

    @Luke2105-Loft59 This issue was closed. If you believe it should be reopened, just include /reopen in a comment and it will be reopened automatically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-attentionIssue author responded, needs review

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions