diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 499c952..0447a29 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,32 @@ Changelog Unreleased ========== +Documentation +------------- +- **New: what the heating elements actually do** + (``docs/explanation/heating-elements.rst``). The four + ``he*TempSetting`` fields do not describe when an element runs: in + Electric and High Demand the on and off settings are the same value, + and every ``he*DiffTempSetting`` reads 0. Measured on one unit by + commanding the modes and watching, the start differential is + **mode-dependent**, one bracket per mode: ``ELECTRIC`` at most + **0.3 degC** below the setpoint, ``HIGH_DEMAND`` within + **(0.2, 0.7] degC**, ``ENERGY_SAVER`` within **(0.8, 1.0] degC**. + Whether the first two share one threshold is an open question, not a + finding. At 0.7 degC short, High Demand runs the element and Energy + Saver does not. These + are **entry** thresholds, not thermostats: in High Demand's steady + state this unit's history has the element on in 1 of 47 minutes + 0.2-0.3 degC short and 168 of 169 more than 2.2 degC short. + Neither differential is published anywhere in the status message. Also documents Energy + Saver's entry behaviour (the element engages although + ``heUpperOnTempSetting`` rests 33 degC below the tank), Electric's + upper-to-lower handover and the upper probe **falling** 1.9 degC while + the lower element runs, measured element power of 5,219 W against the + 5,000 W rating, and that a mode write may not take effect while a TOU + window is in force. ``device_status.rst``'s Heating Elements notes now + point at it. + Version 9.4.2 (2026-09-17) ========================== diff --git a/docs/explanation/heating-elements.rst b/docs/explanation/heating-elements.rst new file mode 100644 index 0000000..efb5609 --- /dev/null +++ b/docs/explanation/heating-elements.rst @@ -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. diff --git a/docs/explanation/index.rst b/docs/explanation/index.rst index 64a5a97..4891baf 100644 --- a/docs/explanation/index.rst +++ b/docs/explanation/index.rst @@ -9,6 +9,7 @@ Understanding-oriented deep dives into the library's design and advanced feature advanced-features architecture + heating-elements tank-energy tou-recovery-cap unknown-values diff --git a/docs/reference/protocol/data_conversions.rst b/docs/reference/protocol/data_conversions.rst index 339ffd3..d2bebd4 100644 --- a/docs/reference/protocol/data_conversions.rst +++ b/docs/reference/protocol/data_conversions.rst @@ -164,6 +164,21 @@ Heating Element Control Temperatures Electric heating elements are controlled via thermostat ranges. Two sensors (upper and lower tank) allow two-stage heating: +.. warning:: + + **These fields do not predict when an element runs.** The + descriptions below are the protocol's own semantics for each field. + Measured against the device, they do not hold: in ``ELECTRIC`` and + ``HIGH_DEMAND`` the ON and OFF settings are **the same value** (no + hysteresis at all, which cannot be how the device behaves), in + ``HEAT_PUMP`` and ``ENERGY_SAVER`` the ON setting rests at the + 40.5 degC device minimum while the element still runs, and **every** + ``he*DiffTempSetting`` reads 0 rather than the 2-5 degF below. + + The differential the device actually uses is mode-dependent and is + published nowhere in the status message. See + :doc:`/explanation/heating-elements` for the measured values. + .. list-table:: :header-rows: 1 :widths: 30 10 15 45 @@ -191,7 +206,7 @@ Electric heating elements are controlled via thermostat ranges. Two sensors (upp * - ``heUpperOnDiffTempSetting`` - div_10_celsius_delta - °F - - **Upper element differential** (ON-OFF hysteresis width). Temperature delta to prevent rapid cycling. Typically 2-5°F. This is a DELTA value, not an absolute temperature (0 delta = 0°F difference). + - **Upper element differential** (ON-OFF hysteresis width). Temperature delta to prevent rapid cycling. Nominally 2-5°F, but **measured as 0 on a 9.x-firmware unit in every mode**, while the device nonetheless applied a differential - see the warning above. This is a DELTA value, not an absolute temperature (0 delta = 0°F difference). * - ``heUpperOffDiffTempSetting`` - div_10_celsius_delta - °F diff --git a/docs/reference/protocol/device_status.rst b/docs/reference/protocol/device_status.rst index a38447b..17885d0 100644 --- a/docs/reference/protocol/device_status.rst +++ b/docs/reference/protocol/device_status.rst @@ -735,8 +735,17 @@ Technical Notes **Heating Elements:** * Upper and lower heating elements: 3,755W @ 208V or 5,000W @ 240V -* Elements do not operate simultaneously in Electric mode + (measured 5,219 W upper / 5,200 W lower on one 240 V unit) +* Elements do not operate simultaneously in Electric mode - upper first, + then lower, with the handover in a single status message * Heating elements activate for freeze protection when tank < 43°F (6°C) +* The ``he*TempSetting`` fields do **not** describe when an element + runs: in Electric and High Demand the on and off settings are equal + and every ``he*DiffTempSetting`` reads 0. The measured start + differential is **mode-dependent** - at most 0.3 degC in + ``ELECTRIC``, within (0.2, 0.7] degC in ``HIGH_DEMAND``, and within + (0.8, 1.0] degC in ``ENERGY_SAVER``, all measured on entry to the + mode. See :doc:`/explanation/heating-elements`. **Heat Pump Specifications:**