Device Management¶
Manage and interact with discovered and known Samsung HVAC devices.
Device Types¶
NasaDevice¶
The base class for all devices:
device = nasa.devices["100000"]
print(device.address) # Device address (string)
print(device.device_type) # Device type (AddressClass enum)
print(device.last_packet_time) # Last update time
print(device.attributes) # All attributes dict
print(device.config) # Configuration object
OutdoorNasaDevice¶
Represents outdoor units (typically address 100000):
outdoor = nasa.devices["100000"]
# Check if it's an outdoor device
if isinstance(outdoor, OutdoorNasaDevice):
# Access outdoor-specific attributes
print(outdoor.outdoor_temperature)
print(outdoor.power_consumption)
IndoorNasaDevice¶
Represents indoor units (typically addresses 200020, 200021, etc.):
indoor = nasa.devices["200020"]
# Check if it's an indoor device
if isinstance(indoor, IndoorNasaDevice):
# Access indoor-specific attributes
if indoor.climate_controller:
print(indoor.climate_controller.current_mode)
if indoor.dhw_controller:
print(indoor.dhw_controller.target_temperature)
Discovering Devices¶
Automatic Discovery¶
When you start the connection, devices advertise themselves:
nasa = SamsungNasa(
host="192.168.1.100",
port=8000
)
await nasa.start()
# Wait for devices to appear
await asyncio.sleep(2)
# List discovered devices
for address, device in nasa.devices.items():
print(f"{address}: {device.device_type}")
Known Devices¶
Pre-configure devices you want to monitor:
nasa = SamsungNasa(
host="192.168.1.100",
port=8000,
config={
"device_addresses": ["200000", "200020"]
}
)
await nasa.start()
# Devices will be immediately available
outdoor = nasa.devices["100000"]
indoor = nasa.devices["200020"]
New Device Handler¶
Get notified when new devices appear:
async def on_new_device(device):
print(f"New device found: {device.address}")
print(f"Type: {device.device_type}")
# Request its configuration
await device.get_configuration()
nasa = SamsungNasa(
host="192.168.1.100",
port=8000,
new_device_event_handler=on_new_device
)
await nasa.start()
Device Attributes¶
Universal Attributes¶
All devices have:
device = nasa.devices["100000"]
device.address # Address string (e.g., "100000")
device.device_type # AddressClass enum
device.last_packet_time # datetime of last update
device.attributes # Dict of all attributes
device.config # NasaConfig object
device.fsv_config # FSV configuration dict
Reading Device Attributes¶
Using get_attribute()¶
Read specific attributes from a device. If the attribute isn't cached, it will be automatically requested:
from pysamsungnasa.protocol.factory.messages.outdoor import (
OutdoorAirTemperature,
HeatPumpVoltage,
OutdoorCompressorFrequency
)
from pysamsungnasa.protocol.factory.messages.indoor import (
InTargetTemperature,
InCurrentTemperature,
InOperationPowerMessage
)
outdoor = nasa.devices["100000"]
# Read outdoor temperature (will fetch if not cached)
temp_msg = await outdoor.get_attribute(OutdoorAirTemperature)
print(f"Outdoor temperature: {temp_msg.VALUE}°C")
# Read voltage
voltage_msg = await outdoor.get_attribute(HeatPumpVoltage)
print(f"Voltage: {voltage_msg.VALUE}V")
# Force a fresh read even if cached
freq_msg = await outdoor.get_attribute(
OutdoorCompressorFrequency,
requires_read=True
)
print(f"Compressor frequency: {freq_msg.VALUE}Hz")
Reading Indoor Unit Attributes¶
indoor = nasa.devices["200020"]
# Get current temperature
current_temp = await indoor.get_attribute(InCurrentTemperature)
print(f"Current temperature: {current_temp.VALUE}°C")
# Get target temperature
target_temp = await indoor.get_attribute(InTargetTemperature)
print(f"Target temperature: {target_temp.VALUE}°C")
# Get power state
power = await indoor.get_attribute(InOperationPowerMessage)
print(f"Power: {power.VALUE}")
Accessing Cached Attributes¶
Access previously received attributes directly from the cache:
device = nasa.devices["100000"]
# Check if attribute exists in cache
if OutdoorAirTemperature.MESSAGE_ID in device.attributes:
cached_msg = device.attributes[OutdoorAirTemperature.MESSAGE_ID]
print(f"Cached temperature: {cached_msg.VALUE}°C")
else:
print("Temperature not yet received")
# Or use get_attribute which handles this automatically
temp_msg = await device.get_attribute(OutdoorAirTemperature)
print(f"Temperature: {temp_msg.VALUE}°C")
Writing Device Attributes¶
Using write_attribute()¶
Write a single attribute to a device:
from pysamsungnasa.protocol.factory.messages.indoor import (
InTargetTemperature,
InOperationPowerMessage,
InOperationModeMessage,
)
from pysamsungnasa.protocol.enum import DataType
indoor = nasa.devices["200020"]
# Set target temperature to 22°C
await indoor.write_attribute(InTargetTemperature, 22.0)
# Turn on the device
await indoor.write_attribute(InOperationPowerMessage, 1) # 1 = On, 0 = Off
# Set operation mode
from pysamsungnasa.protocol.enum import InOperationMode
await indoor.write_attribute(InOperationModeMessage, InOperationMode.COOL)
Using write_attributes()¶
Write multiple attributes in a single packet (up to 10 messages):
from pysamsungnasa.protocol.factory.messages.indoor import (
InTargetTemperature,
InOperationPowerMessage,
InOperationModeMessage,
)
from pysamsungnasa.protocol.enum import InOperationMode
indoor = nasa.devices["200020"]
# Set multiple attributes at once
await indoor.write_attributes({
InOperationPowerMessage: 1, # Turn on
InOperationModeMessage: InOperationMode.COOL, # Set to cooling mode
InTargetTemperature: 22.0, # Set temperature
})
Using Different Write Modes¶
Some attributes require a REQUEST mode instead of WRITE:
from pysamsungnasa.protocol.enum import DataType
# Some messages may require DataType.REQUEST
await indoor.write_attribute(
InTargetTemperature,
22.0,
mode=DataType.REQUEST
)
# Default is DataType.WRITE
await indoor.write_attribute(InTargetTemperature, 22.0) # Uses WRITE mode
Accessing Device Configuration¶
Get the FSV (Feature/Setting/Value) configuration:
device = nasa.devices["200020"]
# Get all FSV settings
fsv_config = device.fsv_config
# FSV is a dictionary of message ID to values
for msg_id, value in fsv_config.items():
print(f"Message 0x{msg_id:04X}: {value}")
Device State Management¶
Getting Raw Attributes¶
Access the raw attribute dictionary:
device = nasa.devices["100000"]
# Get all attributes
all_attrs = device.attributes
print(f"Total attributes: {len(all_attrs)}")
# Access a specific attribute by message ID
if 0x4203 in device.attributes:
value = device.attributes[0x4203]
print(f"Message 0x4203: {value}")
Checking Last Update¶
Monitor device responsiveness:
import time
from datetime import datetime, timezone
device = nasa.devices["100000"]
# Check when last updated
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("No data yet")
Device Callbacks¶
Device Update Callbacks¶
Register functions to be called whenever any packet is received for a device:
def on_update(device):
print(f"Device {device.address} updated at {device.last_packet_time}")
print(f"Total attributes: {len(device.attributes)}")
device = nasa.devices["100000"]
device.add_device_callback(on_update)
# Later, remove it
device.remove_device_callback(on_update)
Message-Specific Callbacks¶
Listen for specific message types using packet callbacks:
from pysamsungnasa.protocol.factory.messages.indoor import InCurrentTemperature
from pysamsungnasa.protocol.factory.messages.outdoor import OutdoorAirTemperature
def on_indoor_temp(device, **kwargs):
"""Called when indoor temperature message is received."""
message = kwargs['packet']
msg_number = kwargs['messageNumber']
print(f"Indoor temp update: {message.VALUE}°C (msg {msg_number})")
def on_outdoor_temp(device, **kwargs):
"""Called when outdoor temperature message is received."""
message = kwargs['packet']
print(f"Outdoor temp: {message.VALUE}°C")
indoor = nasa.devices["200020"]
outdoor = nasa.devices["100000"]
# Add callback for specific message type
indoor.add_packet_callback(InCurrentTemperature, on_indoor_temp)
outdoor.add_packet_callback(OutdoorAirTemperature, on_outdoor_temp)
# Later, remove them
indoor.remove_packet_callback(InCurrentTemperature, on_indoor_temp)
outdoor.remove_packet_callback(OutdoorAirTemperature, on_outdoor_temp)
Complete Example with Callbacks¶
import asyncio
from pysamsungnasa import SamsungNasa
from pysamsungnasa.protocol.factory.messages.indoor import (
InCurrentTemperature,
InTargetTemperature
)
async def main():
nasa = SamsungNasa(
host="192.168.1.100",
port=8000
)
def on_temp_change(device, **kwargs):
message = kwargs['packet']
print(f"Temperature changed to {message.VALUE}°C")
await nasa.start()
await asyncio.sleep(2) # Wait for devices
indoor = nasa.devices["200020"]
# Listen for temperature changes
indoor.add_packet_callback(InCurrentTemperature, on_temp_change)
# Set new target temperature
await indoor.write_attribute(InTargetTemperature, 23.0)
# Keep running to receive updates
await asyncio.sleep(60)
await nasa.stop()
asyncio.run(main())
Multiple Device Management¶
Iterate Over All Devices¶
for address, device in nasa.devices.items():
print(f"\nDevice: {address}")
print(f" Type: {device.device_type}")
print(f" Last update: {device.last_packet_time}")
# Register callbacks
device.add_device_callback(lambda d: print(f" Updated: {d.address}"))
Find Devices by Type¶
from pysamsungnasa.device import OutdoorNasaDevice, IndoorNasaDevice
outdoor_units = [d for d in nasa.devices.values() if isinstance(d, OutdoorNasaDevice)]
indoor_units = [d for d in nasa.devices.values() if isinstance(d, IndoorNasaDevice)]
print(f"Outdoor units: {len(outdoor_units)}")
print(f"Indoor units: {len(indoor_units)}")
Synchronize Multiple Devices¶
async def set_all_targets(nasa, temperature):
"""Set target temperature on all indoor units."""
for device in nasa.devices.values():
if isinstance(device, IndoorNasaDevice):
if device.climate_controller:
await device.climate_controller.set_target_temperature(temperature)
print(f"Set {device.address} to {temperature}°C")
Device Information Display¶
Print Device Summary¶
def print_device_summary(device):
print(f"Device: {device.address}")
print(f" Type: {device.device_type}")
print(f" Attributes: {len(device.attributes)}")
print(f" Last update: {device.last_packet_time}")
if hasattr(device, 'outdoor_temperature'):
print(f" Outdoor temp: {device.outdoor_temperature}°C")
if hasattr(device, 'climate_controller') and device.climate_controller:
cc = device.climate_controller
print(f" Climate power: {cc.power}")
print(f" Current mode: {cc.current_mode}")
print(f" Target temp: {cc.f_target_temperature}°C")
for device in nasa.devices.values():
print_device_summary(device)
print()
Troubleshooting Device Issues¶
Device Not Responding¶
async def check_device_health(device):
"""Check if a device is responding."""
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
for device in nasa.devices.values():
await check_device_health(device)
Missing Attributes¶
from pysamsungnasa.protocol.factory.messages.indoor import (
InCurrentTemperature,
InTargetTemperature
)
async def check_attributes(device):
"""Verify expected attributes exist and request if missing."""
try:
# Try to get current temperature (will fetch if not cached)
current = await device.get_attribute(InCurrentTemperature)
print(f"✓ Current Temperature: {current.VALUE}°C")
except TimeoutError:
print("✗ Current Temperature: TIMEOUT")
try:
# Try to get target temperature
target = await device.get_attribute(InTargetTemperature)
print(f"✓ Target Temperature: {target.VALUE}°C")
except TimeoutError:
print("✗ Target Temperature: TIMEOUT")
# Check cached attributes
print(f"\nTotal cached attributes: {len(device.attributes)}")
await check_attributes(indoor)
Next Steps¶
- Learn how to control devices with Controllers
- Read about Basic Usage
- Check the API Reference