diff --git a/homeassistant/components/iron_os/__init__.py b/homeassistant/components/iron_os/__init__.py
index 11d99a1558a9a12d176eee6ce2ac5b8eb21ddb94..43691c8594a77148a5f11b3ccc0c1e782aef4d36 100644
--- a/homeassistant/components/iron_os/__init__.py
+++ b/homeassistant/components/iron_os/__init__.py
@@ -2,9 +2,11 @@
 
 from __future__ import annotations
 
+from dataclasses import dataclass
 import logging
 from typing import TYPE_CHECKING
 
+from aiogithubapi import GitHubAPI
 from pynecil import Pynecil
 
 from homeassistant.components import bluetooth
@@ -12,13 +14,23 @@ from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import CONF_NAME, Platform
 from homeassistant.core import HomeAssistant
 from homeassistant.exceptions import ConfigEntryNotReady
+from homeassistant.helpers.aiohttp_client import async_get_clientsession
 
 from .const import DOMAIN
-from .coordinator import IronOSCoordinator
+from .coordinator import IronOSFirmwareUpdateCoordinator, IronOSLiveDataCoordinator
 
-PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR]
+PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR, Platform.UPDATE]
 
-type IronOSConfigEntry = ConfigEntry[IronOSCoordinator]
+
+@dataclass
+class IronOSCoordinators:
+    """IronOS data class holding coordinators."""
+
+    live_data: IronOSLiveDataCoordinator
+    firmware: IronOSFirmwareUpdateCoordinator
+
+
+type IronOSConfigEntry = ConfigEntry[IronOSCoordinators]
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -39,10 +51,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: IronOSConfigEntry) -> bo
 
     device = Pynecil(ble_device)
 
-    coordinator = IronOSCoordinator(hass, device)
+    coordinator = IronOSLiveDataCoordinator(hass, device)
     await coordinator.async_config_entry_first_refresh()
 
-    entry.runtime_data = coordinator
+    session = async_get_clientsession(hass)
+    github = GitHubAPI(session=session)
+
+    firmware_update_coordinator = IronOSFirmwareUpdateCoordinator(hass, device, github)
+    await firmware_update_coordinator.async_config_entry_first_refresh()
+
+    entry.runtime_data = IronOSCoordinators(
+        live_data=coordinator,
+        firmware=firmware_update_coordinator,
+    )
     await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
 
     return True
diff --git a/homeassistant/components/iron_os/coordinator.py b/homeassistant/components/iron_os/coordinator.py
index aefb14b689ba1e002c70b1db7d049fece8bdc382..175de484870210511818f0d4cade89b91b616fb3 100644
--- a/homeassistant/components/iron_os/coordinator.py
+++ b/homeassistant/components/iron_os/coordinator.py
@@ -4,7 +4,9 @@ from __future__ import annotations
 
 from datetime import timedelta
 import logging
+from typing import TYPE_CHECKING
 
+from aiogithubapi import GitHubAPI, GitHubException, GitHubReleaseModel
 from pynecil import CommunicationError, DeviceInfoResponse, LiveDataResponse, Pynecil
 
 from homeassistant.config_entries import ConfigEntry
@@ -16,24 +18,43 @@ from .const import DOMAIN
 _LOGGER = logging.getLogger(__name__)
 
 SCAN_INTERVAL = timedelta(seconds=5)
+SCAN_INTERVAL_GITHUB = timedelta(hours=3)
 
 
-class IronOSCoordinator(DataUpdateCoordinator[LiveDataResponse]):
-    """IronOS coordinator."""
+class IronOSBaseCoordinator[_DataT](DataUpdateCoordinator[_DataT]):
+    """IronOS base coordinator."""
 
     device_info: DeviceInfoResponse
     config_entry: ConfigEntry
 
-    def __init__(self, hass: HomeAssistant, device: Pynecil) -> None:
+    def __init__(
+        self,
+        hass: HomeAssistant,
+        device: Pynecil,
+        update_interval: timedelta,
+    ) -> None:
         """Initialize IronOS coordinator."""
         super().__init__(
             hass,
             _LOGGER,
             name=DOMAIN,
-            update_interval=SCAN_INTERVAL,
+            update_interval=update_interval,
         )
         self.device = device
 
+    async def _async_setup(self) -> None:
+        """Set up the coordinator."""
+
+        self.device_info = await self.device.get_device_info()
+
+
+class IronOSLiveDataCoordinator(IronOSBaseCoordinator):
+    """IronOS live data coordinator."""
+
+    def __init__(self, hass: HomeAssistant, device: Pynecil) -> None:
+        """Initialize IronOS coordinator."""
+        super().__init__(hass, device=device, update_interval=SCAN_INTERVAL)
+
     async def _async_update_data(self) -> LiveDataResponse:
         """Fetch data from Device."""
 
@@ -43,11 +64,27 @@ class IronOSCoordinator(DataUpdateCoordinator[LiveDataResponse]):
         except CommunicationError as e:
             raise UpdateFailed("Cannot connect to device") from e
 
-    async def _async_setup(self) -> None:
-        """Set up the coordinator."""
+
+class IronOSFirmwareUpdateCoordinator(IronOSBaseCoordinator):
+    """IronOS coordinator for retrieving update information from github."""
+
+    def __init__(self, hass: HomeAssistant, device: Pynecil, github: GitHubAPI) -> None:
+        """Initialize IronOS coordinator."""
+        super().__init__(hass, device=device, update_interval=SCAN_INTERVAL_GITHUB)
+        self.github = github
+
+    async def _async_update_data(self) -> GitHubReleaseModel:
+        """Fetch data from Github."""
 
         try:
-            self.device_info = await self.device.get_device_info()
+            release = await self.github.repos.releases.latest("Ralim/IronOS")
 
-        except CommunicationError as e:
-            raise UpdateFailed("Cannot connect to device") from e
+        except GitHubException as e:
+            raise UpdateFailed(
+                "Failed to retrieve latest release data from Github"
+            ) from e
+
+        if TYPE_CHECKING:
+            assert release.data
+
+        return release.data
diff --git a/homeassistant/components/iron_os/entity.py b/homeassistant/components/iron_os/entity.py
index 5a24b0a55671efbdf77196e495185684369e9b89..d1c9a9aa0ee362a855cdd5b6d76fad47d986423a 100644
--- a/homeassistant/components/iron_os/entity.py
+++ b/homeassistant/components/iron_os/entity.py
@@ -9,17 +9,17 @@ from homeassistant.helpers.entity import EntityDescription
 from homeassistant.helpers.update_coordinator import CoordinatorEntity
 
 from .const import MANUFACTURER, MODEL
-from .coordinator import IronOSCoordinator
+from .coordinator import IronOSBaseCoordinator
 
 
-class IronOSBaseEntity(CoordinatorEntity[IronOSCoordinator]):
+class IronOSBaseEntity(CoordinatorEntity[IronOSBaseCoordinator]):
     """Base IronOS entity."""
 
     _attr_has_entity_name = True
 
     def __init__(
         self,
-        coordinator: IronOSCoordinator,
+        coordinator: IronOSBaseCoordinator,
         entity_description: EntityDescription,
     ) -> None:
         """Initialize the sensor."""
diff --git a/homeassistant/components/iron_os/manifest.json b/homeassistant/components/iron_os/manifest.json
index cfaf36880f2db9ddeb4fc3d7bef26e395a53eae8..9fcb84e0f6a0597421d36eba10ce443088614ac4 100644
--- a/homeassistant/components/iron_os/manifest.json
+++ b/homeassistant/components/iron_os/manifest.json
@@ -12,6 +12,6 @@
   "dependencies": ["bluetooth_adapters"],
   "documentation": "https://www.home-assistant.io/integrations/iron_os",
   "iot_class": "local_polling",
-  "loggers": ["pynecil"],
-  "requirements": ["pynecil==0.2.0"]
+  "loggers": ["pynecil", "aiogithubapi"],
+  "requirements": ["pynecil==0.2.0", "aiogithubapi==24.6.0"]
 }
diff --git a/homeassistant/components/iron_os/number.py b/homeassistant/components/iron_os/number.py
index 9230faec1f13ff761ed989abdae2aef544eb4fb1..bc8da968187f90b43c4caeba4abbad9ddcdea071 100644
--- a/homeassistant/components/iron_os/number.py
+++ b/homeassistant/components/iron_os/number.py
@@ -61,7 +61,7 @@ async def async_setup_entry(
     async_add_entities: AddEntitiesCallback,
 ) -> None:
     """Set up number entities from a config entry."""
-    coordinator = entry.runtime_data
+    coordinator = entry.runtime_data.live_data
 
     async_add_entities(
         IronOSNumberEntity(coordinator, description)
diff --git a/homeassistant/components/iron_os/sensor.py b/homeassistant/components/iron_os/sensor.py
index 095ffd254df96bb873f6ef303fa7378c0514cafe..a44e61c4de35dd827bcf2560faeaaae7bcbfd5bf 100644
--- a/homeassistant/components/iron_os/sensor.py
+++ b/homeassistant/components/iron_os/sensor.py
@@ -180,7 +180,7 @@ async def async_setup_entry(
     async_add_entities: AddEntitiesCallback,
 ) -> None:
     """Set up sensors from a config entry."""
-    coordinator = entry.runtime_data
+    coordinator = entry.runtime_data.live_data
 
     async_add_entities(
         IronOSSensorEntity(coordinator, description)
diff --git a/homeassistant/components/iron_os/update.py b/homeassistant/components/iron_os/update.py
new file mode 100644
index 0000000000000000000000000000000000000000..9086dc0b7b5951ce0c6f82da8a6649c1c4554288
--- /dev/null
+++ b/homeassistant/components/iron_os/update.py
@@ -0,0 +1,76 @@
+"""Update platform for IronOS integration."""
+
+from __future__ import annotations
+
+from homeassistant.components.update import (
+    UpdateDeviceClass,
+    UpdateEntity,
+    UpdateEntityDescription,
+    UpdateEntityFeature,
+)
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity_platform import AddEntitiesCallback
+
+from . import IronOSConfigEntry
+from .coordinator import IronOSBaseCoordinator
+from .entity import IronOSBaseEntity
+
+UPDATE_DESCRIPTION = UpdateEntityDescription(
+    key="firmware",
+    device_class=UpdateDeviceClass.FIRMWARE,
+)
+
+
+async def async_setup_entry(
+    hass: HomeAssistant,
+    entry: IronOSConfigEntry,
+    async_add_entities: AddEntitiesCallback,
+) -> None:
+    """Set up IronOS update platform."""
+
+    coordinator = entry.runtime_data.firmware
+
+    async_add_entities([IronOSUpdate(coordinator, UPDATE_DESCRIPTION)])
+
+
+class IronOSUpdate(IronOSBaseEntity, UpdateEntity):
+    """Representation of an IronOS update entity."""
+
+    _attr_supported_features = UpdateEntityFeature.RELEASE_NOTES
+
+    def __init__(
+        self,
+        coordinator: IronOSBaseCoordinator,
+        entity_description: UpdateEntityDescription,
+    ) -> None:
+        """Initialize the sensor."""
+        super().__init__(coordinator, entity_description)
+
+    @property
+    def installed_version(self) -> str | None:
+        """IronOS version on the device."""
+
+        return self.coordinator.device_info.build
+
+    @property
+    def title(self) -> str | None:
+        """Title of the IronOS release."""
+
+        return f"IronOS {self.coordinator.data.name}"
+
+    @property
+    def release_url(self) -> str | None:
+        """URL to the full release notes of the latest IronOS version available."""
+
+        return self.coordinator.data.html_url
+
+    @property
+    def latest_version(self) -> str | None:
+        """Latest IronOS version available for install."""
+
+        return self.coordinator.data.tag_name
+
+    async def async_release_notes(self) -> str | None:
+        """Return the release notes."""
+
+        return self.coordinator.data.body
diff --git a/requirements_all.txt b/requirements_all.txt
index 1fa221b60fe56f7a67e624575650239c2f07462a..69e3ed97e74f23e1316a70975a918304f25688c9 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -249,6 +249,7 @@ aioflo==2021.11.0
 aioftp==0.21.3
 
 # homeassistant.components.github
+# homeassistant.components.iron_os
 aiogithubapi==24.6.0
 
 # homeassistant.components.guardian
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index e5b2ea0b9731fb2ceb8cfef2620b74f16730ab46..5a1daaad5d62af4589f7c1ed470b341ba304a702 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -234,6 +234,7 @@ aioesphomeapi==27.0.0
 aioflo==2021.11.0
 
 # homeassistant.components.github
+# homeassistant.components.iron_os
 aiogithubapi==24.6.0
 
 # homeassistant.components.guardian
diff --git a/tests/components/iron_os/conftest.py b/tests/components/iron_os/conftest.py
index f489d7b7bb53cdf3e0057efa55c5556834832a18..a7c3592ae7343a3da3496cbfa4c776f363c396e1 100644
--- a/tests/components/iron_os/conftest.py
+++ b/tests/components/iron_os/conftest.py
@@ -107,6 +107,29 @@ def mock_ble_device() -> Generator[MagicMock]:
         yield ble_device
 
 
+@pytest.fixture(autouse=True)
+def mock_githubapi() -> Generator[AsyncMock]:
+    """Mock aiogithubapi."""
+
+    with patch(
+        "homeassistant.components.iron_os.GitHubAPI",
+        autospec=True,
+    ) as mock_client:
+        client = mock_client.return_value
+        client.repos.releases.latest = AsyncMock()
+
+        client.repos.releases.latest.return_value.data.html_url = (
+            "https://github.com/Ralim/IronOS/releases/tag/v2.22"
+        )
+        client.repos.releases.latest.return_value.data.name = (
+            "V2.22 | TS101 & S60 Added | PinecilV2 improved"
+        )
+        client.repos.releases.latest.return_value.data.tag_name = "v2.22"
+        client.repos.releases.latest.return_value.data.body = "**RELEASE_NOTES**"
+
+        yield client
+
+
 @pytest.fixture
 def mock_pynecil() -> Generator[AsyncMock]:
     """Mock Pynecil library."""
diff --git a/tests/components/iron_os/snapshots/test_update.ambr b/tests/components/iron_os/snapshots/test_update.ambr
new file mode 100644
index 0000000000000000000000000000000000000000..fbfc490e121ac37fded90ac64753ff2fc5ed2fba
--- /dev/null
+++ b/tests/components/iron_os/snapshots/test_update.ambr
@@ -0,0 +1,62 @@
+# serializer version: 1
+# name: test_update.2
+  '**RELEASE_NOTES**'
+# ---
+# name: test_update[update.pinecil_firmware-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'update',
+    'entity_category': <EntityCategory.CONFIG: 'config'>,
+    'entity_id': 'update.pinecil_firmware',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <UpdateDeviceClass.FIRMWARE: 'firmware'>,
+    'original_icon': None,
+    'original_name': 'Firmware',
+    'platform': 'iron_os',
+    'previous_unique_id': None,
+    'supported_features': <UpdateEntityFeature: 16>,
+    'translation_key': None,
+    'unique_id': 'c0:ff:ee:c0:ff:ee_firmware',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_update[update.pinecil_firmware-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'auto_update': False,
+      'device_class': 'firmware',
+      'entity_picture': 'https://brands.home-assistant.io/_/iron_os/icon.png',
+      'friendly_name': 'Pinecil Firmware',
+      'in_progress': False,
+      'installed_version': 'v2.22',
+      'latest_version': 'v2.22',
+      'release_summary': None,
+      'release_url': 'https://github.com/Ralim/IronOS/releases/tag/v2.22',
+      'skipped_version': None,
+      'supported_features': <UpdateEntityFeature: 16>,
+      'title': 'IronOS V2.22 | TS101 & S60 Added | PinecilV2 improved',
+      'update_percentage': None,
+    }),
+    'context': <ANY>,
+    'entity_id': 'update.pinecil_firmware',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'off',
+  })
+# ---
diff --git a/tests/components/iron_os/test_update.py b/tests/components/iron_os/test_update.py
new file mode 100644
index 0000000000000000000000000000000000000000..70336e6962045b94059bd67326827638b042e22b
--- /dev/null
+++ b/tests/components/iron_os/test_update.py
@@ -0,0 +1,73 @@
+"""Tests for IronOS update platform."""
+
+from collections.abc import AsyncGenerator
+from unittest.mock import AsyncMock, patch
+
+from aiogithubapi import GitHubException
+import pytest
+from syrupy.assertion import SnapshotAssertion
+
+from homeassistant.config_entries import ConfigEntryState
+from homeassistant.const import Platform
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers import entity_registry as er
+
+from tests.common import MockConfigEntry, snapshot_platform
+from tests.typing import WebSocketGenerator
+
+
+@pytest.fixture(autouse=True)
+async def update_only() -> AsyncGenerator[None]:
+    """Enable only the update platform."""
+    with patch(
+        "homeassistant.components.iron_os.PLATFORMS",
+        [Platform.UPDATE],
+    ):
+        yield
+
+
+@pytest.mark.usefixtures("mock_pynecil", "ble_device", "mock_githubapi")
+async def test_update(
+    hass: HomeAssistant,
+    config_entry: MockConfigEntry,
+    snapshot: SnapshotAssertion,
+    entity_registry: er.EntityRegistry,
+    hass_ws_client: WebSocketGenerator,
+) -> None:
+    """Test the IronOS update platform."""
+    ws_client = await hass_ws_client(hass)
+
+    config_entry.add_to_hass(hass)
+    await hass.config_entries.async_setup(config_entry.entry_id)
+    await hass.async_block_till_done()
+
+    assert config_entry.state is ConfigEntryState.LOADED
+
+    await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
+
+    await ws_client.send_json(
+        {
+            "id": 1,
+            "type": "update/release_notes",
+            "entity_id": "update.pinecil_firmware",
+        }
+    )
+    result = await ws_client.receive_json()
+    assert result["result"] == snapshot
+
+
+@pytest.mark.usefixtures("ble_device", "mock_pynecil")
+async def test_config_entry_not_ready(
+    hass: HomeAssistant,
+    config_entry: MockConfigEntry,
+    mock_githubapi: AsyncMock,
+) -> None:
+    """Test config entry not ready."""
+
+    mock_githubapi.repos.releases.latest.side_effect = GitHubException
+
+    config_entry.add_to_hass(hass)
+    await hass.config_entries.async_setup(config_entry.entry_id)
+    await hass.async_block_till_done()
+
+    assert config_entry.state is ConfigEntryState.SETUP_RETRY