BREAKING CHANGES: two independent corrections land together.
Tank energy values were wrong in two ways - a 2.5x unit-scale error and
two actively misleading field names - and both are corrected. Reported
tank energy is now 2.5x smaller and two public field names are removed.
Separately, eight status flags change type from bool to
bool | None so the device's "unknown" state is no longer reported as
a definite OFF.
Changed
-
Energy unit scale corrected.
totalEnergyCapacityandavailableEnergyCapacitywere
scaled by 10 on the assumption the device reported 10 Wh units. It does
not. BecausetotalEnergyCapacityis a whole-tank quantity, its slope
against the setpoint measures the quantum with no stratification
assumption: on a 65-gallon NWP500 that is 70.25 raw counts per Kelvin.
The field turns out to be bimodal - at a fixed setpoint it takes one of
two values exactly 2 degC apart - but both branches give the same slope
to within 0.2%, so the quantum is unaffected. Converting to Watt-hours needs a
water mass, and a "65 gallon" tank does not hold 65 gallons - so taking
the quantum to be round, as every other conversion in this protocol is,
4 Wh/count is the only candidate implying a water volume below the
nameplate (241.7 L). Two further checks agree: 183 individual heating
recoveries give 4.11 Wh/count by a noisier route, and integrating
currentInstPowerover them implies a heat-pump COP of 2.89 at the new
scale against 7.02 at the old, the latter being physically impossible.
Reported tank energy is now 2.5x smaller.
Historical series logged from earlier versions need rescaling by 0.4 to
be comparable. -
Energy fields renamed.
availableEnergyCapacityis not available energy - it is the energy
still needed to reach the setpoint. It falls as the tank heats and
reaches zero when the tank is fully charged, so code treating it as
stored energy had the signal backwards (regression against mean tank
temperature: negative slope, R-squared 0.93, zero crossing at the
setpoint). LikewisetotalEnergyCapacityis not a fixed tank size but
the cost of a full recovery to the current setpoint, measured from the
device's own minimum setpoint of 104.9 degF; it moves by about 140 Wh
per 0.5 degC of setpoint change... code-block:: python
OLD (removed)
status.total_energy_capacity # 15800.0
status.available_energy_capacity # 11660.0NEW
status.full_recovery_energy # 6320.0
status.energy_to_setpoint # 4664.0The protocol field names on the wire are unchanged. CLI rows are
relabelled from "Total Capacity"/"Available Capacity" to
"Full Recovery"/"Energy to Setpoint". -
Status flags now preserve the device's unknown state. The protocol
encodes these flags as0 = unknown, 1 = OFF, 2 = ON, and the library
was collapsing 0 toFalse- inventing an OFF the device never claimed.
Confirmed against Navien's own NaviLink app (2.03.00, versionCode 141),
which decodes exactly this set of fields through an enum declared
UNKNOWN(0), OFF(1), ON(2); two sibling enums render their zero as
"-"and"Not Applied"rather than as an off state.Affected:
operation_busy,comp_use,anti_legionella_use,
anti_legionella_operation_busy,heat_upper_use,heat_lower_use,
air_filter_alarm_use,recirc_reservation_use.Noneis falsy, soif status.comp_use:is unaffected. Code that
distinguishesis Falsefrom "not reported", or does arithmetic or
formatting on these fields, needs aNonecheck. For Home Assistant
this is the wanted shape:Nonerenders as "Unknown" instead of writing
a fabricated OFF into the recorder database. -
OnOffFlaggains the vendor'sUNKNOWN = 0member. It previously
started atOFF = 1, leaving the device's reserved value unrepresented. -
The CLI renders these flags as
Unknownrather thanNo. Both
affected rows are updated: "Busy" under OPERATION STATUS and
"Operation Busy" under ANTI-LEGIONELLA.
Added
-
DeviceStatus.usable_energy: drawable energy in Watt-hours,
computed asfull_recovery_energy - energy_to_setpoint. Both raw
fields are measured from the setpoint, so neither is a state of charge;
subtracting them cancels the setpoint and leaves the tank's heat above
the device's minimum operating temperature (104.9 degF), which is about
the lowest temperature usable for a shower. Robust despite
full_recovery_energybeing bimodal, since both fields shift
together: the implied tank temperature tracks the thermistor mean to a
standard deviation of 0.57 degF over 12275 samples. Rendered by the CLI
as "Usable Energy". -
converters.device_tristate_to_pythonand
models.status.DeviceTriStatefor flags the device may decline to
report.converters.device_bool_to_pythonis unchanged and remains
correct for capability flags. -
New
docs/explanation/unknown-values.rstrecording which field families
use 0 as a sentinel and which do not, with the app evidence for each.
Removed
-
Misnamed energy fields: removed
DeviceStatus.total_energy_capacity
andDeviceStatus.available_energy_capacityoutright rather than
aliasing them, so a missed rename fails withAttributeErrorinstead
of silently returning a number 2.5x too large. Use
full_recovery_energyandenergy_to_setpoint. -
Incorrect converter: removed
converters.mul_10, which existed
only to apply the wrong 10 Wh scale. Use
converters.energy_count_to_whandconverters.WH_PER_ENERGY_COUNT.
Fixed
-
Documentation contradicted itself and the code on energy capacity.
Three incompatible descriptions were published: Watt-hours with no
conversion (protocol reference), Watt-hours with a x10 scale (the code),
and a 0-100 percentage (how-to/track-energy.rst,
reference/python_api/models.rst,project/history.rst). The
percentage claim was never true of any library version. All are now
consistent. -
how-to/track-energy.rstdocumented four fields that do not exist on
DeviceStatus(dhw_tank_upper_temp,dhw_tank_lower_temp,
comp_temp,dhw_heatex_out_temp); replaced with the real names. -
dhwTemperatureis documented as an outlet temperature but is
measured inside the tank: it trackstankUpperTemperatureto within
one 0.5 degC step, and the device has no sensor downstream of itself.
Navien's own app agrees, labelling it "DHW Temp." beside the tank
thermistors and showingdischargeTemperatureseparately. -
docs/explanation/tank-energy.rsttabulatedtotalEnergyCapacity
andavailableEnergyCapacityat ten times their raw wire values,
under column headings naming the raw protocol fields. The series had
been logged through the pre-fix library, which multiplied by 10. The
prose beside the tables ("70.25 raw counts per Kelvin", "35 counts")
was already in true raw counts, so the page contradicted itself by
exactly the factor it exists to correct. Tables are now in raw counts;
1580 counts at a 145.4 degF setpoint matches the test fixtures and the
6320 Wh the CLI reports. No numeric conclusion changes. -
docs/explanation/tank-energy.rstreferred to a field
hpUpperOnTemperatureSetting; the protocol name is
hpUpperOnTempSetting. -
The setpoint-per-0.5-degC figure is 140 Wh, not 143 Wh, which is what
the documented slope of 70.25 counts/K gives at 4 Wh/count. Corrected
in the changelog, the model field description and the protocol
reference. -
New
docs/explanation/tank-energy.rstrecords what the two fields
actually measure and the calibration evidence behind the scale change,
including that Navien's own NaviLink app (2.03.00, versionCode 141)
reads neither field, so no vendor-side corroboration exists. -
Documented that temperature fields carry no sentinel at all. The app
has no out-of-band constant (no0xFFFF/-999/-1), no zero-guard
in any display path, and formats whatever arrives - so a temperature of
zero means zero. This closes a recurring source of bugs where zero-as-none
was applied to temperature converters and reported working sensors as
missing during cold-weather operation. -
Documented that capability flags are a distinct case: the app hides a
feature's entire UI when its DIDUseflag reads 0, so 0 there means
"not fitted" and the existingboolmapping is correct.