Energy Monitoring Guide¶
This guide explains how to monitor energy consumption and usage data from Navien NWP500 water heaters.
Overview¶
The NWP500 provides energy monitoring data through real-time
status updates via MQTT. All energy-related data is available through
the DeviceStatus object returned by the
subscribe_device_status() callback.
Real-Time Power Consumption¶
Total Instantaneous Power¶
The most important metric for energy monitoring:
from nwp500 import NavienMqttClient, DeviceStatus
def on_status(status: DeviceStatus):
# Total power consumption in Watts
power_watts = status.current_inst_power
print(f"Current Power: {power_watts} W")
current_inst_powerfloatComponent Status¶
Know which heating components are currently active:
def on_status(status: DeviceStatus):
if status.comp_use:
print("Heat pump compressor is running")
if status.heat_upper_use:
print("Upper electric heater is running")
if status.heat_lower_use:
print("Lower electric heater is running")
Fields:
comp_use(bool): Heat pump compressor activeheat_upper_use(bool): Upper electric heating element activeheat_lower_use(bool): Lower electric heating element active
Cumulative Usage Statistics¶
Track total runtime for each heating component:
def on_status(status: DeviceStatus):
# Convert minutes to hours
comp_hours = status.comp_running_minute_total / 60
heater1_hours = status.heater1_running_minute_total / 60
heater2_hours = status.heater2_running_minute_total / 60
print(f"Heat Pump Runtime: {comp_hours:.1f} hours")
print(f"Upper Heater Runtime: {heater1_hours:.1f} hours")
print(f"Lower Heater Runtime: {heater2_hours:.1f} hours")
Fields:
comp_running_minute_total(int): Total heat pump compressor runtime in minutesheater1_running_minute_total(int): Total upper electric heater runtime in minutesheater2_running_minute_total(int): Total lower electric heater runtime in minutes
Historical Energy Usage¶
Request detailed daily energy usage data for specific months:
from nwp500 import NavienMqttClient, EnergyUsageResponse
def on_energy_usage(energy: EnergyUsageResponse):
print(f"Total Usage: {energy.total.total_usage} Wh")
print(f"Heat Pump: {energy.total.heat_pump_percentage:.1f}%")
print(f"Electric: {energy.total.heat_element_percentage:.1f}%")
# Daily breakdown
for day in energy.daily:
print(f"Day {day.day}: {day.total_usage} Wh")
# Subscribe to energy usage responses
await mqtt_client.subscribe_energy_usage(device, on_energy_usage)
# Request energy usage for September 2025
await mqtt_client.request_energy_usage(device, year=2025, months=[9])
# Request multiple months
await mqtt_client.request_energy_usage(device, year=2025, months=[7, 8, 9])
Methods:
request_energy_usage(device, year, months): Request historical datasubscribe_energy_usage(device, callback): Subscribe to energy usage responses
Response Fields:
total.total_usage(int): Total energy consumption in Whtotal.heat_pump_percentage(float): Percentage from heat pumptotal.heat_element_percentage(float): Percentage from electric heatersdaily(list): Daily breakdown of usage per day
Energy Capacity¶
Warning
The device’s two energy fields do not report stored energy, and the names in the protocol are misleading. See Tank Energy for the evidence.
Monitor the tank’s heating deficit:
def on_status(status: DeviceStatus):
needed = status.energy_to_setpoint
print(f"Energy still needed: {needed:.0f} Wh")
if needed < 200:
print("Tank is essentially fully charged")
energy_to_setpoint (protocol: availableEnergyCapacity)floatfull_recovery_energy (protocol: totalEnergyCapacity)floatTemperature Monitoring¶
Water Temperature¶
def on_status(status: DeviceStatus):
# Current water temperature
current_temp = status.dhw_temperature
target_temp = status.dhw_temperature_setting
print(f"Water Temperature: {current_temp}°F (Target: {target_temp}°F)")
Fields:
dhw_temperature(float): Current water temperaturedhw_temperature_setting(int): Target temperature settingdhw_temperature_min(int): Minimum allowed temperaturedhw_temperature_max(int): Maximum allowed temperature
Component Temperatures¶
Monitor individual heating component temperatures:
def on_status(status: DeviceStatus):
print(f"Discharge Temp: {status.discharge_temperature}°F")
print(f"Upper Tank Temp: {status.tank_upper_temperature}°F")
print(f"Lower Tank Temp: {status.tank_lower_temperature}°F")
print(f"Ambient Temp: {status.ambient_temperature}°F")
Complete Energy Monitoring Example¶
import asyncio
from nwp500 import NavienAuthClient, NavienAPIClient, NavienMqttClient, DeviceStatus
def calculate_power_cost(power_watts: float, hours: float, cost_per_kwh: float = 0.12) -> float:
"""Calculate energy cost based on power consumption."""
kwh = (power_watts / 1000) * hours
return kwh * cost_per_kwh
async def monitor_energy():
async with NavienAuthClient("email@example.com", "password") as auth_client:
api_client = NavienAPIClient(auth_client=auth_client)
device = await api_client.get_first_device()
# Create MQTT client inside the auth context
mqtt_client = NavienMqttClient(auth_client)
await mqtt_client.connect()
# Energy monitoring callback
def on_status(status: DeviceStatus):
print("\n" + "="*50)
print("ENERGY MONITORING")
print("="*50)
# Real-time power
print(f"\nCurrent Power: {status.current_inst_power} W")
# Active components
components = []
if status.comp_use:
components.append("Heat Pump")
if status.heat_upper_use:
components.append("Upper Heater")
if status.heat_lower_use:
components.append("Lower Heater")
if components:
print(f"Active: {', '.join(components)}")
else:
print("Active: None (Standby)")
# Cumulative runtime
print(f"\nCumulative Runtime:")
print(f" Heat Pump: {status.comp_running_minute_total / 60:.1f} hours")
print(f" Upper Heater: {status.heater1_running_minute_total / 60:.1f} hours")
print(f" Lower Heater: {status.heater2_running_minute_total / 60:.1f} hours")
# Heating deficit and temperature
print(f"\nEnergy to setpoint: {status.energy_to_setpoint:.0f} Wh")
print(f"Water Temp: {status.dhw_temperature}°F "
f"(Target: {status.dhw_temperature_setting}°F)")
# Estimated hourly cost (if running continuously at current power)
if status.current_inst_power > 0:
hourly_cost = calculate_power_cost(status.current_inst_power, 1.0)
print(f"\nEstimated Cost (if sustained): ${hourly_cost:.3f}/hour")
# Subscribe to device status
await mqtt_client.subscribe_device_status(device, on_status)
# Request initial status
await mqtt_client.request_device_status(device)
# Monitor for 5 minutes
print("Monitoring energy consumption for 5 minutes...")
await asyncio.sleep(300)
await mqtt_client.disconnect()
if __name__ == "__main__":
asyncio.run(monitor_energy())
Energy Data Fields Reference¶
Power Consumption¶
Field |
Type |
Units |
Description |
|---|---|---|---|
|
float |
W |
Total instantaneous power consumption |
|
bool |
Heat pump compressor active |
|
|
bool |
Upper electric heater active |
|
|
bool |
Lower electric heater active |
Cumulative Usage¶
Field |
Type |
Units |
Description |
|---|---|---|---|
|
int |
minutes |
Total heat pump runtime |
|
minutes |
Total upper heater runtime |
|
|
minutes |
Total lower heater runtime |
|
Energy Capacity¶
Field |
Type |
Units |
Description |
|---|---|---|---|
|
float |
Wh |
Energy still needed to reach setpoint |
|
float |
Wh |
Cost of a full recovery to the setpoint |
|
float |
% |
Device’s own charge estimate |
Temperature¶
Field |
Type |
Units |
Description |
|---|---|---|---|
|
float |
°F |
Current water temperature |
|
float |
°F |
Target temperature setting |
|
float |
°F |
Compressor discharge temperature |
|
float |
°F |
Upper tank temperature |
|
float |
°F |
Lower tank temperature |
|
float |
°F |
Air intake temperature |
Notes¶
All power values are in Watts (W)
All temperatures are in Fahrenheit (°F)
Status updates are sent automatically by the device approximately every few seconds
Cumulative runtime values persist across device power cycles
The device’s energy fields are heating deficits, not stored energy
See Also¶
Tank Energy - What the energy fields really mean
Device Status Fields - Complete list of all status fields
MQTT Client - How to connect and subscribe to device updates
MQTT Protocol - Message format reference