Repository navigation
docs: what the heating elements actually do #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
97d0d13
docs: what the heating elements actually do
eman 3f373f6
docs: the start differential is mode-dependent
eman de342ed
docs: bracket High Demand too, and put the three modes side by side
eman 6f1333c
docs: these are entry thresholds, and two paragraphs said the wrong n…
eman 4395026
docs: High Demand's bracket is its own, and the reference contradicte…
eman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,335 @@ | ||
| ==================== | ||
| The Heating Elements | ||
| ==================== | ||
|
|
||
| The NWP500 publishes four element thermostat settings - | ||
| ``heUpperOnTempSetting``, ``heUpperOffTempSetting`` and their lower-zone | ||
| pair - plus a differential for each. Read literally they do not describe | ||
| when the elements actually run: in Electric and High Demand the on and | ||
| off settings are **the same value**, and every ``he*DiffTempSetting`` | ||
| reads 0. The device nevertheless has a differential, and this page | ||
| gives the measured one. | ||
|
|
||
| **The start thresholds** here were measured on one unit by commanding | ||
| the modes and watching - not inferred from historical logs. That | ||
| distinction matters: two earlier values came from "the smallest deficit | ||
| ever seen to start an element" in a passive record, and both were wrong, | ||
| because such a figure measures where the tank happened to sit rather | ||
| than where the device decides. | ||
|
|
||
| Two things on this page are *not* from commanded runs, and are labelled | ||
| where they appear: High Demand's **steady-state** re-engagement, which | ||
| is this unit's history, and the mid-stint behaviour it is contrasted | ||
| with. Everything else is a bounded run. | ||
|
|
||
| .. contents:: | ||
| :local: | ||
| :depth: 2 | ||
|
|
||
|
|
||
| The short version | ||
| ================= | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 34 66 | ||
|
|
||
| * - Observation | ||
| - Value | ||
| * - Element start differential | ||
| - **Mode-dependent, one bracket per mode.** ``ELECTRIC`` at most | ||
| **0.3 degC (0.54 degF)** below the setpoint; ``HIGH_DEMAND`` | ||
| somewhere in **(0.2, 0.7] degC** ((0.36, 1.26] degF); | ||
| ``ENERGY_SAVER`` in **(0.8, 1.0] degC** ((1.44, 1.80] degF). | ||
| Each bracket has a run on either side of it - except Electric's | ||
| lower edge, whose only negative sits *above* the setpoint. | ||
| * - Where that differential is published | ||
| - **Nowhere.** ``heUpperOnDiffTempSetting`` and its three siblings | ||
| read 0 on this unit while the behaviour above holds. | ||
| * - ``heUpperOnTempSetting`` by mode | ||
| - ``ELECTRIC`` and ``HIGH_DEMAND``: the setpoint, same as | ||
| ``heUpperOffTempSetting``. ``HEAT_PUMP`` and ``ENERGY_SAVER``: | ||
| 40.5 degC (104.9 degF), the device minimum. | ||
| * - Energy Saver on entry | ||
| - Switching into ``ENERGY_SAVER`` engages the upper element even | ||
| though ``heUpperOnTempSetting`` rests 33 degC below the tank, so | ||
| whatever drives it, that field is not it. Its bracket also sits | ||
| higher than the other two modes'. Why the two differ is **not** | ||
| established: the Energy Saver runs had the compressor running | ||
| and the others did not. | ||
| * - Electric ordering | ||
| - Upper element to the setpoint, then the lower element, never | ||
| both, as the protocol reference already states. The handover | ||
| takes one poll. | ||
| * - Element power | ||
| - 5,200-5,242 W over three measurements (two upper, one lower), | ||
| metered with the compressor off. The reference gives 5,000 W at | ||
| 240 V. | ||
| * - Zone coupling | ||
| - While the lower element runs, the **upper** probe falls about | ||
| 1.9 degC (3.4 degF) before recovering. The zones are not | ||
| independent. | ||
|
|
||
|
|
||
| The start differential | ||
| ====================== | ||
|
|
||
| Three modes, three brackets, and no two of them the same width. Each | ||
| run holds a fixed deficit and watches for one to two minutes; the | ||
| setpoint quantises to 0.5 degC, so the deficit is set by choosing a | ||
| setpoint step relative to the tank. | ||
|
|
||
| ``ENERGY_SAVER`` | ||
| ---------------- | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 30 30 40 | ||
|
|
||
| * - Deficit below setpoint | ||
| - Upper element | ||
| - Poll at which it engaged | ||
| * - 0.3 degC (0.54 degF) | ||
| - **off** for the whole watch | ||
| - n/a | ||
| * - 0.8 degC (1.44 degF) | ||
| - **off** for the whole watch | ||
| - n/a | ||
| * - 1.0 degC (1.80 degF) | ||
| - **on** | ||
| - first poll after the mode landed | ||
| * - 1.2 degC (2.16 degF) | ||
| - **on** | ||
| - first poll after the mode landed | ||
|
|
||
| So the boundary lies in (0.8, 1.0] degC, and 1.0 degC is the device's | ||
| own storage granularity - settings are held in half-degree Celsius | ||
| steps - which makes a one-degree differential the natural parameter. | ||
|
|
||
| A further run put the element on at 2.0 degC (3.6 degF) short, so | ||
| nothing above the boundary has been seen to decline. | ||
|
|
||
| ``ELECTRIC`` | ||
| ------------ | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 30 30 40 | ||
|
|
||
| * - Deficit below setpoint | ||
| - Upper element | ||
| - Poll at which it engaged | ||
| * - 0.6 degC **above** the setpoint | ||
| - **off** for the whole watch | ||
| - n/a | ||
| * - 0.3 degC (0.54 degF) | ||
| - **on** | ||
| - first poll after the mode landed | ||
| * - 0.4 degC (0.72 degF) | ||
| - **on** | ||
| - first poll after the mode landed | ||
|
|
||
| ``HIGH_DEMAND`` | ||
| --------------- | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 30 30 40 | ||
|
|
||
| * - Deficit below setpoint | ||
| - Upper element | ||
| - Poll at which it engaged | ||
| * - 0.2 degC (0.36 degF) | ||
| - **off** for the whole watch | ||
| - n/a | ||
| * - 0.7 degC (1.26 degF) | ||
| - **on** | ||
| - first poll after the mode landed | ||
|
|
||
| ``heUpperOnTempSetting`` moved to the new setpoint in the same status | ||
| message the mode landed in, as it does in Electric. | ||
|
|
||
| Putting the three together | ||
| -------------------------- | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 24 26 24 26 | ||
|
|
||
| * - Mode | ||
| - Element off at | ||
| - Element on at | ||
| - Bracket | ||
| * - ``ELECTRIC`` | ||
| - 0.6 degC above setpoint | ||
| - 0.3, 0.4 degC | ||
| - at most 0.3 degC [#electric]_ | ||
| * - ``HIGH_DEMAND`` | ||
| - 0.2 degC | ||
| - 0.7 degC | ||
| - (0.2, 0.7] degC | ||
| * - ``ENERGY_SAVER`` | ||
| - 0.3, 0.8 degC | ||
| - 1.0, 1.2 degC | ||
| - (0.8, 1.0] degC | ||
|
|
||
| **These are entry thresholds, not thermostats.** Every run measured what | ||
| happens within a poll of switching *into* a mode. In ``HIGH_DEMAND``'s | ||
| steady state this unit's history has the upper element on in 1 of 47 | ||
| minutes 0.2-0.3 degC short and 168 of 169 minutes more than 2.2 degC | ||
| short - so a stint already running re-engages on something much larger | ||
| than the entry figure. Do not use one for the other. | ||
|
|
||
| .. [#electric] Electric's own negative is 0.6 degC *above* the setpoint, | ||
| so nothing at all was observed between there and 0.3 below it. Its | ||
| bracket is open at the bottom: no run has shown Electric declining | ||
| to heat a tank that is short of the setpoint by any amount. | ||
|
|
||
| **Electric and High Demand may share one entry threshold. That is an | ||
| inference, not a measurement.** Their brackets overlap in | ||
| (0.2, 0.3] degC and the two modes handle ``heUpperOnTempSetting`` | ||
| identically, which is a real argument for one number covering both - | ||
| but High Demand has never been watched between 0.2 and 0.7 degC, so | ||
| nothing here measures where its boundary falls inside that span. | ||
| Energy Saver's band does not intersect either of them: at 0.7 degC | ||
| short, High Demand runs the element and Energy Saver does not. One | ||
| caveat on that last comparison: the Energy Saver runs had the | ||
| compressor running and the others did not, so mode is not the only | ||
| difference between them. | ||
|
|
||
| A consumer wanting one number per mode should take the **top of that | ||
| mode's own bracket** - 0.3 degC for ``ELECTRIC``, **0.7 degC** for | ||
| ``HIGH_DEMAND``, 1.0 degC for ``ENERGY_SAVER``. Each is the **smallest | ||
| deficit at which that mode was seen to start an element**, so assuming | ||
| it contradicts no observation of that mode - where anything lower | ||
| contradicts that mode's own negative. Borrowing Electric's 0.3 degC for High Demand predicts an | ||
| element at, say, 0.4 degC short that High Demand has never been seen to | ||
| run; if your consumer is deciding whether hot water will be ready, | ||
| that is the expensive direction to be wrong in. | ||
|
|
||
| **The differential is not in the protocol.** A ``status --raw`` taken | ||
| between these runs shows:: | ||
|
|
||
| "heUpperOnTempSetting": 81, # 40.5 degC | ||
| "heUpperOffTempSetting": 122, # 61.0 degC | ||
| "heUpperOnDiffTempSetting": 0, | ||
| "heUpperOffDiffTempSetting": 0, | ||
| "heLowerOnTDiffempSetting": 0, | ||
| "heLowerOffDiffTempSetting": 0, | ||
|
|
||
| A consumer that wants to predict when an element will run therefore | ||
| cannot read it from the status message; it has to assume the per-mode | ||
| figures above - 0.3 degC for ``ELECTRIC``, 0.7 for ``HIGH_DEMAND``, | ||
| 1.0 for ``ENERGY_SAVER`` - and treat a tank inside the corresponding | ||
| bracket as a case where the device may go either way. High Demand's | ||
| bracket is the widest, so that "either way" span is widest there too. | ||
|
|
||
|
|
||
| What the on-setting does and does not tell you | ||
| ============================================== | ||
|
|
||
| ``heUpperOnTempSetting`` tracks the **mode**, not the moment: | ||
|
|
||
| * In ``ELECTRIC`` and ``HIGH_DEMAND`` it equals ``heUpperOffTempSetting`` | ||
| and both equal the DHW setpoint. Taken literally that is a thermostat | ||
| with no hysteresis at all, which cannot be how the device behaves; on | ||
| entry the measured differential is at most 0.3 degC in Electric and | ||
| within (0.2, 0.7] degC in High Demand. | ||
| * In ``HEAT_PUMP`` and ``ENERGY_SAVER`` it rests at 40.5 degC, the | ||
| device minimum, which is 33 degC below a normally charged tank. | ||
|
|
||
| The second case is the one that misleads. In ``ENERGY_SAVER`` the upper | ||
| element **does** run, and it runs with the on-setting far below the tank | ||
| - so the element is not being driven by that field. Switching into the | ||
| mode with the tank 1.0 degC or more short brought the element on within | ||
| one poll in both runs tested, and ``heUpperOnTempSetting`` dropped from | ||
| the setpoint to 40.5 degC in the *same* status message. Watching that | ||
| field for an explanation of the element will not find one. | ||
|
|
||
| That is as far as the observation goes. It does not explain *why* | ||
| Energy Saver's bracket sits higher than Electric's; the runs differ in | ||
| compressor state as well as mode, and nothing here separates the two. | ||
|
|
||
|
|
||
| Electric: the handover, and what happens to the upper zone | ||
| =========================================================== | ||
|
|
||
| The protocol reference states that elements do not operate | ||
| simultaneously in Electric mode. Confirmed, and the order is upper | ||
| first: in a six-minute run the upper element stopped and the lower one | ||
| appeared in the next poll, with no overlap. | ||
|
|
||
| Two details a consumer modelling the tank should know: | ||
|
|
||
| **The upper probe falls while the lower element runs.** It peaked at | ||
| 63.3 degC (145.9 degF), fell to 61.4 (142.5) over the following three | ||
| minutes, then recovered to 62.3 (144.1) as the tank mixed. Anything | ||
| that treats "upper zone reached X" as monotonic during an Electric | ||
| recovery will be wrong by about 1.9 degC for several minutes. | ||
|
|
||
| **The off point lags in both directions.** The upper element switched | ||
| off with the probe 0.8 degC (1.4 degF) *below* the setpoint, and the | ||
| probe then coasted 1.3 degC (2.3 degF) *past* it. The device's decision | ||
| and the probe are not the same instant. | ||
|
|
||
|
|
||
| Element power | ||
| ============= | ||
|
|
||
| Metered at the whole-unit power reading with the compressor off, so it | ||
| is the element alone: | ||
|
|
||
| * upper element: 5,219 W on one run (5,205-5,242 over 33 samples) and | ||
| 5,242 W on a second | ||
| * lower element: 5,200 W | ||
|
|
||
| The reference gives 3,755 W at 208 V or 5,000 W at 240 V. The measured | ||
| figure is 4 % above the 240 V rating on this unit, which is one unit at | ||
| one supply voltage - a nudge for anyone integrating energy, not a | ||
| correction to the specification. | ||
|
|
||
| For the record, the upper zone rose at 0.87-0.89 degC/min | ||
| (1.56-1.61 degF/min) end to end over 5.8 minutes on a 63.2 gal tank - | ||
| the spread is sampling resolution, the higher figure from 10-second | ||
| polls and the lower from a one-minute grid - and the lower zone at | ||
| 0.66-0.86 degC/min depending on where the fit starts; the probe lags the | ||
| element for the first 40-60 seconds, which is most of the difference. | ||
| Those are tank-specific and are offered as an order of magnitude only. | ||
|
|
||
|
|
||
| Writing the mode while a TOU window is in force | ||
| =============================================== | ||
|
|
||
| Relevant when planning any of this: with TOU scheduling enabled and a | ||
| window in force, a mode write may not take effect. Measured on the same | ||
| unit, four minutes with no change and nothing logged, twice - and the | ||
| command was not discarded either: it took effect one poll after the TOU | ||
| switch was turned off, with nothing else commanded. | ||
|
|
||
| Whether the device queues the command or accepts it and masks the | ||
| read-back is undetermined. Either way, **confirm a mode write by reading | ||
| the mode back, and do not treat an unconfirmed one as failed.** | ||
|
|
||
| Reservation entries are a separate case and fire normally in a window; | ||
| see issue #141 for the documentation fix covering that. | ||
|
|
||
|
|
||
| Limits | ||
| ====== | ||
|
|
||
| One unit, one supply voltage, 2026-09-19 and 2026-09-20. **Twenty-two** | ||
| bounded runs in all: thirteen on the elements and the thresholds, nine | ||
| on mode writes and reservation entries under TOU. Specifically **not** | ||
| established: | ||
|
|
||
| * **where inside (0.2, 0.7] degC ``HIGH_DEMAND``'s boundary falls.** It | ||
| has a run on each side, so it is bracketed - but that bracket is more | ||
| than twice Electric's width, and one run at 0.4 degC would halve it. | ||
| Until then, whether the two modes share a threshold is unresolved. | ||
| * what engages the element **later** in an Energy Saver stint, as | ||
| opposed to on entry. | ||
| * anything about runs longer than six minutes. | ||
| * whether either differential is firmware-dependent. The unit reported | ||
| ``heUpperOnDiffTempSetting`` as 0 throughout; if another unit reports | ||
| it as non-zero, that field is the better answer and this page is a | ||
| description of one firmware's default. | ||
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
data_conversions.rstnow opens the Heating Element Control Temperatures section with a warning that the field descriptions below are the protocol's own semantics and do not hold against the device, naming all three ways they fail. TheheUpperOnDiffTempSettingrow's "Typically 2-5°F" now reads "Nominally 2-5°F, but measured as 0 on a 9.x-firmware unit in every mode, while the device nonetheless applied a differential". Two reference pages contradicting each other was the worst outcome here.