Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ A small web page to adjust the heating per room from a phone on the home network
The service keeps no saved state, so a restart during airing forgets it: **that room stays off until someone taps "Heat again"**. A target waiting to be sent is lost too. The thermostat's own frost protection still applies.

- A target changed during airing is applied when it ends.
- A thermostat leaving off during airing gets off once more. If it leaves off again, someone is at the radiator, so airing ends.
- A thermostat leaving off during airing gets off once more. If it leaves off again, someone is at the radiator, so airing ends. So turning it on by hand during airing takes two tries.
- Commands repeat until the thermostat confirms them, every 30 s for about 5 minutes. A target then gives up and shows the thermostat's value. Off and heat-again keep trying every 5 minutes and show a problem on the page, because giving up would mean heating with the window open or a cold room.
- A thermostat that is off with no airing is left alone, because it can turn itself off and come back. The page offers "Heat again" for it.
- A thermostat that is off with no airing is left alone, because someone may have turned it off on purpose. The page offers "Heat again" for it.

## Requirements

Expand Down
9 changes: 5 additions & 4 deletions internal/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@
// All state is in memory. After a restart a room that was airing stays off until
// someone taps "Heat again" on the page.
//
// Four behaviours of the Sonoff TRVZB shape this code. They were measured on a
// Three behaviours of the Sonoff TRVZB shape this code. They were measured on a
// real device (firmware 1.3.0):
// - In system_mode off it reports its frost protection temperature as the
// setpoint, and briefly keeps reporting it after going back to heat. That
// value is never a target the user chose.
// - Writing a setpoint while it is off switches it back to heat, so a target
// changed during that time is held until it can be sent.
// - After a write it can still send a few reports with the old setpoint.
// - It can go off on its own and return by itself, so "off" doesn't mean this
// program turned it off. A room is only turned back on if this program turned
// it off, or someone asks for it.
//
// Someone can also turn a thermostat off by hand, so "off" doesn't mean this
// program turned it off. A room is only turned back on if this program turned it
// off, or someone asks for it.
package controller

import (
Expand Down
8 changes: 4 additions & 4 deletions internal/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,8 @@ func TestAiringRestoresTheModeFromBefore(t *testing.T) {
}
}

// The thermostat is already in its own pause, so off isn't the mode to restore.
func TestAiringDuringAThermostatPauseRestoresHeat(t *testing.T) {
// The thermostat was already off, so off isn't the mode to restore.
func TestAiringWhileAlreadyOffRestoresHeat(t *testing.T) {
h := newHarness(t)
h.report("heat", 20)
h.report("off", 7)
Expand All @@ -564,7 +564,7 @@ func TestAiringDuringAThermostatPauseRestoresHeat(t *testing.T) {
t.Fatalf("state = %s, want active", got)
}

// Its pause ends, and off goes out again.
// It leaves off, and off goes out again.
h.report("heat", 7)
h.wantKinds("off")
h.report("off", 7)
Expand Down Expand Up @@ -682,7 +682,7 @@ func TestLostRestoreKeepsGoing(t *testing.T) {
}
}

// The thermostat can go off by itself, so only a tap turns it back on.
// Someone may have turned it off on purpose, so only a tap turns it back on.
func TestRoomThatIsOffIsLeftAlone(t *testing.T) {
h := newHarness(t)
h.report("off", 7)
Expand Down
5 changes: 3 additions & 2 deletions internal/controller/room.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ const (
// giving up would leave it heating with the window open, or cold.
slowRetryInterval = 5 * time.Minute
// maxFlips is how often a thermostat may leave off during airing. The first
// time could be its own pause ending, so off is sent again. The second time
// someone at the radiator wants heat, so airing ends.
// time off is sent again, because a single report could have another cause,
// such as the TRV's open window detection ending if that's turned on. The
// second time someone at the radiator wants heat, so airing ends.
maxFlips = 2
// settleTime is how long a thermostat back from off gets to restore its own
// setpoint. After that a setpoint at the frost value is simply what it's set to.
Expand Down
Loading