diff --git a/.coveragerc b/.coveragerc
index eb60f320a749dd73e008aa8e3f5ef8eca24ea38a..84f061fbd35b166adb3bd2f6ed3edf8a554b55d7 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -953,6 +953,8 @@ omit =
     homeassistant/components/overkiz/sensor.py
     homeassistant/components/overkiz/siren.py
     homeassistant/components/overkiz/switch.py
+    homeassistant/components/overkiz/water_heater.py
+    homeassistant/components/overkiz/water_heater_entities/*
     homeassistant/components/ovo_energy/__init__.py
     homeassistant/components/ovo_energy/const.py
     homeassistant/components/ovo_energy/sensor.py
diff --git a/homeassistant/components/overkiz/const.py b/homeassistant/components/overkiz/const.py
index 70477bbcdb2d8da6e250125ea8f74dc07aac451a..4645b058182aedd79cba37c5206437cfb9b45442 100644
--- a/homeassistant/components/overkiz/const.py
+++ b/homeassistant/components/overkiz/const.py
@@ -32,6 +32,7 @@ PLATFORMS: list[Platform] = [
     Platform.SENSOR,
     Platform.SIREN,
     Platform.SWITCH,
+    Platform.WATER_HEATER,
 ]
 
 IGNORED_OVERKIZ_DEVICES: list[UIClass | UIWidget] = [
@@ -64,6 +65,7 @@ OVERKIZ_DEVICE_TO_PLATFORM: dict[UIClass | UIWidget, Platform | None] = {
     UIWidget.ATLANTIC_ELECTRICAL_HEATER: Platform.CLIMATE,  # widgetName, uiClass is HeatingSystem (not supported)
     UIWidget.ATLANTIC_ELECTRICAL_TOWEL_DRYER: Platform.CLIMATE,  # widgetName, uiClass is HeatingSystem (not supported)
     UIWidget.ATLANTIC_HEAT_RECOVERY_VENTILATION: Platform.CLIMATE,  # widgetName, uiClass is HeatingSystem (not supported)
+    UIWidget.ATLANTIC_PASS_APC_DHW: Platform.WATER_HEATER,  # widgetName, uiClass is WaterHeatingSystem (not supported)
     UIWidget.ATLANTIC_PASS_APC_HEATING_AND_COOLING_ZONE: Platform.CLIMATE,  # widgetName, uiClass is HeatingSystem (not supported)
     UIWidget.ATLANTIC_PASS_APC_ZONE_CONTROL: Platform.CLIMATE,  # widgetName, uiClass is HeatingSystem (not supported)
     UIWidget.DOMESTIC_HOT_WATER_TANK: Platform.SWITCH,  # widgetName, uiClass is WaterHeatingSystem (not supported)
diff --git a/homeassistant/components/overkiz/water_heater.py b/homeassistant/components/overkiz/water_heater.py
new file mode 100644
index 0000000000000000000000000000000000000000..e22f442c2662e378aeec8682df94c92712093404
--- /dev/null
+++ b/homeassistant/components/overkiz/water_heater.py
@@ -0,0 +1,28 @@
+"""Support for Overkiz water heater devices."""
+from __future__ import annotations
+
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.const import Platform
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity_platform import AddEntitiesCallback
+
+from . import HomeAssistantOverkizData
+from .const import DOMAIN
+from .water_heater_entities import WIDGET_TO_WATER_HEATER_ENTITY
+
+
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: ConfigEntry,
+    async_add_entities: AddEntitiesCallback,
+) -> None:
+    """Set up the Overkiz DHW from a config entry."""
+    data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]
+
+    async_add_entities(
+        WIDGET_TO_WATER_HEATER_ENTITY[device.widget](
+            device.device_url, data.coordinator
+        )
+        for device in data.platforms[Platform.WATER_HEATER]
+        if device.widget in WIDGET_TO_WATER_HEATER_ENTITY
+    )
diff --git a/homeassistant/components/overkiz/water_heater_entities/__init__.py b/homeassistant/components/overkiz/water_heater_entities/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e03585da56d93c07d2062d36935b191ac79544a9
--- /dev/null
+++ b/homeassistant/components/overkiz/water_heater_entities/__init__.py
@@ -0,0 +1,8 @@
+"""Water heater entities for the Overkiz (by Somfy) integration."""
+from pyoverkiz.enums.ui import UIWidget
+
+from .atlantic_pass_apc_dhw import AtlanticPassAPCDHW
+
+WIDGET_TO_WATER_HEATER_ENTITY = {
+    UIWidget.ATLANTIC_PASS_APC_DHW: AtlanticPassAPCDHW,
+}
diff --git a/homeassistant/components/overkiz/water_heater_entities/atlantic_pass_apc_dhw.py b/homeassistant/components/overkiz/water_heater_entities/atlantic_pass_apc_dhw.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c2ea6ff2d8d647980be4fd7f89874ab0f5a4c60
--- /dev/null
+++ b/homeassistant/components/overkiz/water_heater_entities/atlantic_pass_apc_dhw.py
@@ -0,0 +1,145 @@
+"""Support for Atlantic Pass APC DHW."""
+
+from typing import Any, cast
+
+from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState
+
+from homeassistant.components.water_heater import (
+    STATE_ECO,
+    STATE_HEAT_PUMP,
+    STATE_OFF,
+    STATE_PERFORMANCE,
+    WaterHeaterEntity,
+    WaterHeaterEntityFeature,
+)
+from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
+
+from ..entity import OverkizEntity
+
+
+class AtlanticPassAPCDHW(OverkizEntity, WaterHeaterEntity):
+    """Representation of Atlantic Pass APC DHW."""
+
+    _attr_temperature_unit = TEMP_CELSIUS
+    _attr_supported_features = (
+        WaterHeaterEntityFeature.TARGET_TEMPERATURE
+        | WaterHeaterEntityFeature.OPERATION_MODE
+        | WaterHeaterEntityFeature.AWAY_MODE
+    )
+    _attr_operation_list = [STATE_OFF, STATE_HEAT_PUMP, STATE_PERFORMANCE]
+
+    @property
+    def target_temperature(self) -> float:
+        """Return the temperature corresponding to the PRESET."""
+        if self.is_boost_mode_on:
+            return cast(
+                float,
+                self.executor.select_state(
+                    OverkizState.CORE_COMFORT_TARGET_DWH_TEMPERATURE
+                ),
+            )
+
+        if self.is_eco_mode_on:
+            return cast(
+                float,
+                self.executor.select_state(
+                    OverkizState.CORE_ECO_TARGET_DWH_TEMPERATURE
+                ),
+            )
+
+        return cast(
+            float,
+            self.executor.select_state(OverkizState.CORE_TARGET_DWH_TEMPERATURE),
+        )
+
+    async def async_set_temperature(self, **kwargs: Any) -> None:
+        """Set new temperature."""
+        temperature = kwargs[ATTR_TEMPERATURE]
+
+        if self.is_eco_mode_on:
+            await self.executor.async_execute_command(
+                OverkizCommand.SET_ECO_TARGET_DHW_TEMPERATURE, temperature
+            )
+            await self.executor.async_execute_command(
+                OverkizCommand.REFRESH_ECO_TARGET_DWH_TEMPERATURE
+            )
+        else:
+            await self.executor.async_execute_command(
+                OverkizCommand.SET_COMFORT_TARGET_DHW_TEMPERATURE, temperature
+            )
+            await self.executor.async_execute_command(
+                OverkizCommand.REFRESH_COMFORT_TARGET_DWH_TEMPERATURE
+            )
+        await self.executor.async_execute_command(
+            OverkizCommand.REFRESH_TARGET_DWH_TEMPERATURE
+        )
+
+    @property
+    def is_boost_mode_on(self) -> bool:
+        """Return true if boost mode is on."""
+        return (
+            self.executor.select_state(OverkizState.CORE_BOOST_ON_OFF)
+            == OverkizCommandParam.ON
+        )
+
+    @property
+    def is_eco_mode_on(self) -> bool:
+        """Return true if eco mode is on."""
+        return (
+            self.executor.select_state(OverkizState.IO_PASS_APCDWH_MODE)
+            == OverkizCommandParam.ECO
+        )
+
+    @property
+    def is_away_mode_on(self) -> bool:
+        """Return true if away mode is on."""
+        return (
+            self.executor.select_state(OverkizState.CORE_DWH_ON_OFF)
+            == OverkizCommandParam.OFF
+        )
+
+    @property
+    def current_operation(self) -> str:
+        """Return current operation."""
+        if self.is_boost_mode_on:
+            return STATE_PERFORMANCE
+        if self.is_eco_mode_on:
+            return STATE_ECO
+        if self.is_away_mode_on:
+            return STATE_OFF
+        return STATE_HEAT_PUMP
+
+    async def async_set_operation_mode(self, operation_mode: str) -> None:
+        """Set new operation mode."""
+        boost_state = OverkizCommandParam.OFF
+        regular_state = OverkizCommandParam.OFF
+        if operation_mode == STATE_PERFORMANCE:
+            boost_state = OverkizCommandParam.ON
+            regular_state = OverkizCommandParam.ON
+        elif operation_mode == STATE_HEAT_PUMP:
+            regular_state = OverkizCommandParam.ON
+
+        await self.executor.async_execute_command(
+            OverkizCommand.SET_BOOST_ON_OFF_STATE, boost_state
+        )
+        await self.executor.async_execute_command(
+            OverkizCommand.SET_DHW_ON_OFF_STATE, regular_state
+        )
+
+    async def async_turn_away_mode_on(self) -> None:
+        """Turn away mode on."""
+        await self.executor.async_execute_command(
+            OverkizCommand.SET_BOOST_ON_OFF_STATE, OverkizCommandParam.OFF
+        )
+        await self.executor.async_execute_command(
+            OverkizCommand.SET_DHW_ON_OFF_STATE, OverkizCommandParam.OFF
+        )
+
+    async def async_turn_away_mode_off(self) -> None:
+        """Turn away mode off."""
+        await self.executor.async_execute_command(
+            OverkizCommand.SET_BOOST_ON_OFF_STATE, OverkizCommandParam.OFF
+        )
+        await self.executor.async_execute_command(
+            OverkizCommand.SET_DHW_ON_OFF_STATE, OverkizCommandParam.ON
+        )