NASA Device API¶
Reference for NasaDevice and its subclasses.
NasaDevice (Base Class)¶
The base class for all devices discovered on the NASA network.
Class Definition¶
class NasaDevice:
"""Represents a NASA protocol device."""
def __init__(
self,
address: str,
device_type: AddressClass,
packet_parser: NasaPacketParser,
config: NasaConfig,
client: NasaClient,
) -> None:
...
Properties¶
address: str¶
The device's network address (e.g., "100000").
device = nasa.devices["100000"]
print(device.address) # "100000"
device_type: AddressClass¶
The type of device (enumeration).
from pysamsungnasa.protocol.enum import AddressClass
if device.device_type == AddressClass.OUTDOOR:
print("This is an outdoor unit")
elif device.device_type == AddressClass.INDOOR:
print("This is an indoor unit")
attributes: dict[int, BaseMessage]¶
All received message attributes, indexed by message ID.
# Check what attributes we have
for msg_id, msg_data in device.attributes.items():
print(f"Message 0x{msg_id:04X}: {msg_data}")
# Access specific attribute
if 0x4203 in device.attributes:
temp_data = device.attributes[0x4203]
last_packet_time: datetime | None¶
Timestamp of the last received packet.
from datetime import datetime, timezone, timedelta
if device.last_packet_time:
elapsed = datetime.now(timezone.utc) - device.last_packet_time
print(f"Last update: {elapsed.total_seconds():.1f} seconds ago")
else:
print("Device has not sent any data yet")
config: NasaConfig¶
Reference to the active configuration object.
print(f"Client address: {device.config.client_address}")
print(f"Retry enabled: {device.config.enable_read_retries}")
fsv_config: dict¶
FSV (Feature/Setting/Value) configuration for the device.
# Get all FSV settings
for msg_id, value in device.fsv_config.items():
print(f"FSV 0x{msg_id:04X}: {value}")
Methods¶
add_device_callback(callback: Callable) -> None¶
Register a callback to be called whenever the device is updated.
def on_update(device):
print(f"Device {device.address} was updated!")
print(f"Attributes: {len(device.attributes)}")
device.add_device_callback(on_update)
The callback receives the device object as its only parameter.
remove_device_callback(callback: Callable) -> None¶
Unregister a device callback.
device.remove_device_callback(on_update)
add_packet_callback(message: type[BaseMessage], callback: Callable) -> None¶
Register a callback for a specific message type.
from pysamsungnasa.protocol.factory.messages.indoor import IndoorCurrentTemperature
def on_temp_change(device, **kwargs):
message = kwargs['packet']
print(f"Temperature: {message.VALUE}°C")
# Listen for temperature messages
device.add_packet_callback(IndoorCurrentTemperature, on_temp_change)
The callback receives:
- device - The device object
- **kwargs - Additional data including packet and messageNumber
remove_packet_callback(message: type[BaseMessage], callback: Callable) -> None¶
Unregister a packet-specific callback.
from pysamsungnasa.protocol.factory.messages.indoor import IndoorCurrentTemperature
device.remove_packet_callback(IndoorCurrentTemperature, on_temp_change)
async get_configuration() -> None¶
Request device FSV configuration from the device.
# Request configuration
await device.get_configuration()
# Wait for response
await asyncio.sleep(2)
# Check configuration
print(device.fsv_config)
This is typically called automatically for newly discovered indoor units.
handle_packet(**kwargs) -> None¶
Internal method called by the packet parser when data is received. Users should not call this directly.
Monitoring Device Health¶
async def check_device_health(device):
"""Check if a device is responsive."""
if device.last_packet_time is None:
print(f"{device.address}: Never received data")
return False
from datetime import datetime, timezone, timedelta
elapsed = datetime.now(timezone.utc) - device.last_packet_time
if elapsed > timedelta(minutes=5):
print(f"{device.address}: No update for {elapsed.total_seconds():.0f}s")
return False
print(f"{device.address}: OK (updated {elapsed.total_seconds():.0f}s ago)")
return True
# Check all devices
for device in nasa.devices.values():
await check_device_health(device)
OutdoorNasaDevice¶
Subclass for outdoor heat pump units (typically address 100000).
Additional Properties¶
outdoor_temperature: float | None¶
Outside air temperature (°C).
outdoor = nasa.devices["100000"]
if hasattr(outdoor, 'outdoor_temperature'):
print(f"Outside: {outdoor.outdoor_temperature}°C")
water_outlet_temperature: float | None¶
Water outlet temperature (°C) - for water-based systems.
power_consumption: float | None¶
Current instantaneous power consumption (W).
power_current: float | None¶
Current draw (Amps).
power_produced: float | None¶
Power being generated/produced (W).
power_generated_last_minute: float | None¶
Energy generated in the last minute (Wh).
cumulative_energy: float | None¶
Total cumulative energy usage/generation (kWh).
heatpump_voltage: float | None¶
Operating voltage (V).
compressor_frequency: float | None¶
Compressor speed (Hz).
fan_speed: float | None¶
Fan speed (RPM).
cop_rating: float | None¶
Coefficient of Performance - efficiency metric.
Example Usage¶
outdoor = nasa.devices["100000"]
print(f"Temperature: {outdoor.outdoor_temperature}°C")
print(f"Power: {outdoor.power_consumption}W")
print(f"Frequency: {outdoor.compressor_frequency}Hz")
print(f"Efficiency: {outdoor.cop_rating}")
print(f"Total Energy: {outdoor.cumulative_energy}kWh")
IndoorNasaDevice¶
Subclass for indoor wall-mounted units (typically addresses 200020 and above).
Additional Properties¶
climate_controller: ClimateController | None¶
Climate/HVAC control interface (if available).
dhw_controller: DhwController | None¶
Domestic hot water control interface (if available).
Example Usage¶
indoor = nasa.devices["200020"]
# Check what's available
if indoor.climate_controller:
cc = indoor.climate_controller
print(f"Climate: {cc.current_mode} mode, {cc.f_current_temperature}°C")
if indoor.dhw_controller:
dhw = indoor.dhw_controller
print(f"DHW: {dhw.target_temperature}°C")
Message Attributes¶
The attributes dictionary contains parsed messages from the device. Each entry maps a message ID to a message object:
device = nasa.devices["200020"]
for msg_id, msg_object in device.attributes.items():
# msg_object has properties like:
# - msg_object.VALUE - The actual value
# - msg_object.is_fsv_message - Whether it's an FSV config message
# - str(msg_object) - Human readable representation
if hasattr(msg_object, 'VALUE'):
print(f"Message 0x{msg_id:04X}: {msg_object.VALUE}")
Type Checking¶
Use isinstance() to check device types:
from pysamsungnasa.device import OutdoorNasaDevice, IndoorNasaDevice
for device in nasa.devices.values():
if isinstance(device, OutdoorNasaDevice):
print(f"Outdoor unit: {device.address}")
elif isinstance(device, IndoorNasaDevice):
print(f"Indoor unit: {device.address}")
else:
print(f"Other device: {device.address} ({device.device_type})")
Practical Examples¶
Monitor All Outdoor Units¶
async def monitor_outdoor():
"""Monitor all outdoor units."""
from pysamsungnasa.device import OutdoorNasaDevice
nasa = SamsungNasa(...)
await nasa.start()
outdoor_units = [
d for d in nasa.devices.values()
if isinstance(d, OutdoorNasaDevice)
]
def log_outdoor(device):
print(f"\n{device.address}:")
print(f" Temp: {device.outdoor_temperature}°C")
print(f" Power: {device.power_consumption}W")
print(f" COP: {device.cop_rating}")
for unit in outdoor_units:
unit.add_device_callback(log_outdoor)
await asyncio.sleep(300)
await nasa.stop()
asyncio.run(monitor_outdoor())
Sync All Indoor Units¶
async def sync_all_zones():
"""Synchronize all zones to same temperature."""
from pysamsungnasa.device import IndoorNasaDevice
nasa = SamsungNasa(...)
await nasa.start()
target_temp = 22
for device in nasa.devices.values():
if not isinstance(device, IndoorNasaDevice):
continue
if device.climate_controller:
await device.climate_controller.set_target_temperature(target_temp)
print(f"{device.address}: Set to {target_temp}°C")
await nasa.stop()
asyncio.run(sync_all_zones())
Next Steps¶
- Read Basic Usage
- Learn about Device Management
- Check Controllers