ESPHome external component for Samsung systems using the NASA (Network Attached Samsung Appliance) protocol. Supports air conditioning, heat pumps, DHW (domestic hot water) tanks, underfloor heating, and other equipment connected via the RS-485 bus.
- NASA protocol only — clean, focused implementation
- Easy to extend — add new entities by editing one line in
const.py, no C++ needed - FSV auto-read — Field Setting Values are polled on startup in batches with configurable delay and periodic re-poll
- Proper device types — hydro units get individual entities, ACs get a climate entity with modes and fan speeds
- AC climate — Cool, Heat, Dry, Fan Only, Auto modes with Auto, Low, Medium, High, Turbo fan speeds
- Custom sensors — read any NASA message code without modifying the component
Tested with:
- Samsung EHS TDM Plus heat pump (hydro unit) with underfloor heating
- Samsung ducted AC indoor units
- DHW (Domestic Hot Water) tank
- 3-way valve
Should work with any Samsung equipment using the NASA protocol via RS-485 bus.
See the Hardware Installation wiki for wiring instructions, recommended boards, and RS-485 transceiver options.
external_components:
- source: github://paolostivanin/nasactl@main
components: [nasactl]
uart:
tx_pin: GPIO19
rx_pin: GPIO22
baud_rate: 9600
parity: EVEN
nasactl:
devices:
- address: "20.00.00"
type: hydro
water_temperature:
name: "DHW Temperature"
water_heater_power:
name: "DHW Enabled"
- address: "20.00.01"
type: ac
climate:
name: "AC Bedroom"
- address: "10.00.00"
type: outdoor
outdoor_temperature:
name: "Outdoor Temperature"See example.yaml for a complete configuration.
nasactl:
# Optional RS-485 flow control pin (active-high = TX mode)
flow_control_pin: GPIO23
# Communication tuning
silence_interval: 100 # ms silence after RX before TX (50-1000)
retry_interval: 500 # ms between retries (200-5000)
min_retries: 1 # min retry attempts (1-10)
send_timeout: 4000 # ms total timeout per packet (1000-10000)
# FSV auto-read configuration
fsv_read:
startup_delay: 5s # wait after boot before first poll
batch_size: 10 # codes per NASA read packet (1-50)
batch_delay: 200ms # delay between batches
interval: 24h # periodic re-poll (0s = startup only)
# Debug
debug_log_messages: false # log all received messages
debug_log_undefined: false # log messages with no registered entity
devices: [...]Each device requires an address (format XX.XX.XX) and a type:
| Type | Description | Climate Entity |
|---|---|---|
hydro |
Heat pump / hydro unit | No (individual entities only) |
ac |
Air conditioning indoor unit | Yes (with modes + fan speeds) |
outdoor |
Outdoor unit | No (sensors only) |
Entity-to-device-type compatibility is validated at compile time: indoor entities (0x4xxx codes) cannot be used on outdoor devices, and outdoor entities (0x8xxx codes) cannot be used on hydro/ac devices. System codes (0x0xxx/0x2xxx) are allowed on any device type.
AC devices support a climate entity with modes (Cool, Heat, Dry, Fan Only, Auto) and fan speeds (Auto, Low, Medium, High, Turbo).
Read any NASA message code without modifying the component. Useful for codes not yet defined in const.py:
- address: "10.00.00"
type: outdoor
custom_sensor:
- name: "Condenser Mid Temperature"
message: 0x8206
device_class: temperature
state_class: measurement
unit_of_measurement: "°C"
accuracy_decimals: 1
divisor: 10 # optional: raw value / 10
signed: true # optional: treat as int16The packages/heatpump.yaml file provides Home Assistant template sensors and integration helpers that split aggregate power/energy readings by valve direction into separate Heating and DHW metrics:
- Per-type instantaneous power — consumed and generated power attributed to heating (valve = "Room") or DHW (valve = "Tank")
- Per-type cumulative energy — Riemann sum integration of the power sensors into kWh counters
- Per-type COP — instantaneous coefficient of performance for heating, DHW, and overall
To use it, copy packages/heatpump.yaml into your HA config directory and add to configuration.yaml:
homeassistant:
packages:
heatpump: !include packages/heatpump.yamlPrerequisites: the 3_way_valve_direction, hp_consumed_power_last_minute, and hp_generated_power_last_minute entities must be configured in your ESPHome YAML.
Edit components/nasactl/const.py. No C++ changes needed.
"my_new_sensor": {
"type": "sensor",
"code": 0x4XXX, # NASA message hex code
"unit": "°C",
"device_class": "temperature",
"state_class": "measurement",
"accuracy": 1,
"icon": "mdi:thermometer",
"divisor": 10, # raw / 10
"signed": True, # treat as int16
},"my_new_number": {
"type": "number",
"code": 0x4XXX,
"min": 0, "max": 100, "step": 1,
"unit": "°C",
"device_class": "temperature",
"icon": "mdi:thermometer",
"divisor": 10,
"signed": True,
"fsv": True, # polled on startup (not broadcast)
"entity_category": "config",
},"my_new_select": {
"type": "select",
"code": 0x4XXX,
"options": ["Option A", "Option B", "Option C"],
"icon": "mdi:format-list-bulleted",
"offset": 0, # NASA value = option_index + offset
"fsv": True,
"entity_category": "config",
},"my_new_switch": {
"type": "switch",
"code": 0x4XXX,
"icon": "mdi:toggle-switch",
"fsv": True,
"entity_category": "config",
},"my_new_binary_sensor": {
"type": "binary_sensor",
"code": 0x4XXX,
"icon": "mdi:check-circle",
},"my_new_text_sensor": {
"type": "text_sensor",
"code": 0x4XXX,
"icon": "mdi:information",
"mapping": {
0: "Off",
1: "Running",
2: "Error",
},
},Then use it in your YAML:
- address: "20.00.00"
type: hydro
my_new_sensor:
name: "My New Sensor"Most entities need no transformation (1:1 mapping). For those that do:
| Field | Read (device → HA) | Write (HA → device) | Example |
|---|---|---|---|
divisor: 10 |
x / 10 |
x * 10 |
Temperatures: raw 250 → 25.0°C |
multiplier: 10 |
x * 10 |
x / 10 |
FSV 3052: raw 18 → 180 min |
| Neither | x |
x |
Direct 1:1 mapping |
The signed: True flag treats the raw value as a signed 16-bit integer before applying transformations (important for negative temperatures).
Field Setting Values (FSVs) are persistent device settings that are not broadcast automatically. The component polls them:
- On startup — after
startup_delay, reads all FSV-flagged codes - In batches — packs up to
batch_sizecodes into a single NASA read packet - With delay — waits
batch_delaybetween batches to avoid flooding the bus - Periodically — re-reads all FSVs every
interval(if > 0)
This is useful because FSVs can be changed externally (e.g., from a Samsung wired remote), and periodic polling keeps HA in sync.
components/nasactl/
├── __init__.py # Schema generation + code generation
├── const.py # Entity definitions (EDIT THIS FILE)
├── nasa.py # C++ class references
│
├── nasa_address.h # Address parsing
├── nasa_command.h # Command structure
├── nasa_message.h # MessageSet structure
├── nasa_crc.h # CRC-16 CCITT
├── nasa_packet.h/.cpp # Packet encode/decode
├── nasa_queue.h # BatchDispatcher + LimitedQueue
├── nasa_device.h # Device abstraction
├── nasa_base.h # Base entity classes
├── nasa_client.h/.cpp # UART communication
├── nasa_controller.h/.cpp # Message routing + FSV polling
│
├── sensor/ # NasactlSensor (read-only numeric)
├── number/ # NasactlNumber (read-write numeric)
├── select/ # NasactlSelect (read-write enum)
├── switch_/ # NasactlSwitch (read-write boolean)
├── binary_sensor/ # NasactlBinarySensor (read-only boolean)
├── text_sensor/ # NasactlTextSensor (read-only mapped)
└── climate/ # NasactlClimate (AC climate entity)
This project combines ideas from:
- Beormund/esphome-samsung-nasa — Python dictionary approach, FSV auto-read, clean config style
- paolostivanin/esphome_samsung_hvac_bus — C++ NASA protocol implementation, production reliability
MIT