diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8f2357ca9880bb6e384c069e31df9c43d71ffe5d..5c6e486d84dde4fcd4c4c02db86bc0cc72152c39 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -103,6 +103,7 @@ docker_build_image_all:
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-boot latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-docker latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation_control latest
+    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-recv latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sdp latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sst latest
@@ -253,6 +254,17 @@ docker_build_image_device_apspu:
   script:
 #    Do not remove 'bash' or statement will be ignored by primitive docker shell
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apspu $tag
+docker_build_image_device_pdu:
+  extends: .base_docker_images_except
+  only:
+    refs:
+      - merge_requests
+    changes:
+      - docker-compose/device-pdu.yml
+      - docker-compose/lofar-device-base/*
+  script:
+#    Do not remove 'bash' or statement will be ignored by primitive docker shell
+    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu $tag
 docker_build_image_device_tilebeam:
   extends: .base_docker_images_except
   only:
diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json
index 75da3c1142f40bb4034d7100812bd5dbe3ecf983..2032c4de777aa785dc8bfcff70c73da0bfc197b3 100644
--- a/CDB/LOFAR_ConfigDb.json
+++ b/CDB/LOFAR_ConfigDb.json
@@ -14,6 +14,13 @@
                 }
             }
         },
+        "PDU": {
+            "STAT": {
+                "PDU": {
+                    "STAT/PDU/1": {}
+                }
+            }
+        },
         "TileBeam": {
             "STAT": {
                 "TileBeam": {
diff --git a/docker-compose/archiver-timescale.yml b/docker-compose/archiver-timescale.yml
index a154b96d3338a039237b5d6f1933933c0969ecb3..a0f3e02f27a40cfe49009002026ecc2ebed68f47 100644
--- a/docker-compose/archiver-timescale.yml
+++ b/docker-compose/archiver-timescale.yml
@@ -1,5 +1,8 @@
 version: '2'
 
+volumes:
+  archiver-timescale-data: {}
+
 services:
   archiver-timescale:
     image: timescaledb
@@ -12,6 +15,8 @@ services:
       - "5432:5432/tcp"
     extra_hosts:
       - "host.docker.internal:host-gateway"
+    volumes:
+      - alerta-postgres-data:/var/lib/postgresql/data
     depends_on:
       - databaseds
     environment:
diff --git a/docker-compose/device-pdu.yml b/docker-compose/device-pdu.yml
new file mode 100644
index 0000000000000000000000000000000000000000..524748d14dff00d69a35f219c702f095da4b2d2a
--- /dev/null
+++ b/docker-compose/device-pdu.yml
@@ -0,0 +1,42 @@
+#
+# Requires:
+#   - lofar-device-base.yml
+#
+version: '2'
+
+volumes:
+  iers-data: {}
+
+services:
+  device-pdu:
+    image: device-pdu
+    # build explicitly, as docker-compose does not understand a local image
+    # being shared among services.
+    build:
+        context: ..
+        dockerfile: docker-compose/lofar-device-base/Dockerfile
+        args:
+            SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION}
+    container_name: ${CONTAINER_NAME_PREFIX}device-pdu
+    logging:
+      driver: "json-file"
+      options:
+        max-size: "100m"
+        max-file: "10"
+    networks:
+      - control
+    ports:
+      - "5714:5714" # unique port for this DS
+    extra_hosts:
+      - "host.docker.internal:host-gateway"
+    volumes:
+      - ..:/opt/lofar/tango:rw
+    environment:
+      - TANGO_HOST=${TANGO_HOST}
+    working_dir: /opt/lofar/tango
+    entrypoint:
+      - bin/start-ds.sh
+      # configure CORBA to _listen_ on 0:port, but tell others we're _reachable_ through ${HOSTNAME}:port, since CORBA
+      # can't know about our Docker port forwarding
+      - l2ss-pdu PDU STAT -v -ORBendPoint giop:tcp:0:5714 -ORBendPointPublish giop:tcp:${HOSTNAME}:5714
+    restart: unless-stopped
diff --git a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py
index cf3e092e8f3b8a58ada27252a7862a00f49ad870..1434393a85f0ed506d30303964f43c6c5ee0fa33 100644
--- a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py
+++ b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py
@@ -8,6 +8,7 @@ xst = DeviceProxy("STAT/XST/1")
 unb2 = DeviceProxy("STAT/UNB2/1")
 boot = DeviceProxy("STAT/Boot/1")
 tilebeam = DeviceProxy("STAT/TileBeam/1")
+pdu = DeviceProxy("STAT/PDU/1")
 beamlet = DeviceProxy("STAT/Beamlet/1")
 digitalbeam = DeviceProxy("STAT/DigitalBeam/1")
 docker = DeviceProxy("STAT/Docker/1")
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index aec2d1d4082c04460a52476ac506597c28aa45eb..b703eae61fb5572463f58c3079d133ed30ad37ee 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -20,12 +20,13 @@ sleep 1 # dsconfig container must be up and running...
 # shellcheck disable=SC2016
 echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true' | make run dsconfig bash -
 
-DEVICES="device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam"
+DEVICES="device-boot device-apsct device-apspu device-sdp device-pdu device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-pdu"
 SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim"
 
 # Build only the required images, please do not build everything that makes CI
 # take really long to finish, especially grafana / jupyter / prometheus.
 # jupyter is physically large > 2.5gb and overlayfs is really slow.
+
 # shellcheck disable=SC2086
 make build $DEVICES $SIMULATORS
 make build elk integration-test
diff --git a/tangostationcontrol/docs/source/devices/pdu.rst b/tangostationcontrol/docs/source/devices/pdu.rst
new file mode 100644
index 0000000000000000000000000000000000000000..ca78ad3c5b890bb53e422f11df17ff1530ec5376
--- /dev/null
+++ b/tangostationcontrol/docs/source/devices/pdu.rst
@@ -0,0 +1,7 @@
+.. _pdu:
+
+PDU
+====================
+
+The ``pdu == DeviceProxy("STAT/PDU/1")`` device controls the Power Distribution
+Unit (PDU)
diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst
index 97f8272100311a1b4cb758a4b47d3b9fc93d4e28..c0b64b2a83975abf0636157347354506c0532d9d 100644
--- a/tangostationcontrol/docs/source/index.rst
+++ b/tangostationcontrol/docs/source/index.rst
@@ -24,6 +24,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st
    devices/digitalbeam
    devices/boot
    devices/docker
+   devices/pdu
    devices/recv
    devices/sdp
    devices/sst-xst
diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg
index e9d1b0ada4513e0973785c5e2f99e5d78ada9350..997b7947d27f34b8c30db7eb320bb5384b546d38 100644
--- a/tangostationcontrol/setup.cfg
+++ b/tangostationcontrol/setup.cfg
@@ -35,6 +35,7 @@ where=./
 console_scripts =
     l2ss-apsct = tangostationcontrol.devices.apsct:main
     l2ss-apspu = tangostationcontrol.devices.apspu:main
+    l2ss-pdu = tangostationcontrol.devices.pdu:main
     l2ss-tilebeam = tangostationcontrol.devices.tilebeam:main
     l2ss-beamlet = tangostationcontrol.devices.sdp.beamlet:main
     l2ss-digitalbeam = tangostationcontrol.devices.sdp.digitalbeam:main
diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md
index 08eaf1f67e6f47f9f323e387f5714cf2ff5359a6..19d72e35c4f09d06d500d997d5255c1abdd53b77 100644
--- a/tangostationcontrol/tangostationcontrol/devices/README.md
+++ b/tangostationcontrol/tangostationcontrol/devices/README.md
@@ -10,10 +10,11 @@ If a new device is added, it will (likely) need to be referenced in several plac
 - Adjust `docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py` to make an alias for it available in Jupyter,
 - Adjust `tangostationcontrol/tangostationcontrol/devices/boot.py` to add the device to the station initialisation sequence,
 - Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned,
+                            current _unused_ port value: 5715
 - Adjust `tangostationcontrol/setup.cfg` to add an entry point for the device in the package installation,
 - Add to `tangostationcontrol/tangostationcontrol/integration_test/default/devices/` to add an integration test,
 - Adjust `sbin/run_integration_test.sh` to have the device started when running the integration tests,
 - Adjust `.gitlab-ci.yml` to add the device to the `docker_build_image_all` step and to create a `docker_build_image_device_XXX` step, 
-- Add to `docs/source/devices/` to mention the device in the end-user documentation.
-- Adjust `docs/source/index.rst` to include the newly created file in `docs/source/devices/`.
+- Add to `tangostationcontrol/docs/source/devices/` to mention the device in the end-user documentation.
+- Adjust `tangostationcontrol/docs/source/index.rst` to include the newly created file in `docs/source/devices/`.
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index 47dcc3741e2f5e72aa3bb7fa2c6fb35f551d9fdc..450df1b6fc233219168d3320a8acd8591361cb13 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -233,6 +233,7 @@ class Boot(lofar_device):
         dtype='DevVarStringArray',
         mandatory=False,
         default_value=["STAT/Docker/1", # Docker controls the device containers, so it goes before anything else
+                       "STAT/PDU/1",  # PDU boot early to detect power delivery failure as fast as possible
                        "STAT/APSPU/1",  # APS Power Units control other hardware we want to initialise
                        "STAT/APSCT/1",
                        "STAT/RECV/1",   # RCUs are input for SDP, so initialise them first
diff --git a/tangostationcontrol/tangostationcontrol/devices/pdu.py b/tangostationcontrol/tangostationcontrol/devices/pdu.py
new file mode 100644
index 0000000000000000000000000000000000000000..88a1af8d1d8264fc6214fc8db779a5cb10e684a2
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/devices/pdu.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+""" PDU Device Server for LOFAR2.0
+
+"""
+
+# Additional import
+from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
+
+import logging
+
+logger = logging.getLogger()
+
+__all__ = ["PDU", "main"]
+
+
+@device_logging_to_python()
+class PDU(lofar_device):
+    # -----------------
+    # Device Properties
+    # -----------------
+
+    # ----------
+    # Attributes
+    # ----------
+
+    # --------
+    # overloaded functions
+    # --------
+
+    def init_device(self):
+        super().init_device()
+
+    @log_exceptions()
+    def configure_for_initialise(self):
+        super().configure_for_initialise()
+
+    @log_exceptions()
+    def configure_for_on(self):
+        super().configure_for_on()
+
+    @log_exceptions()
+    def configure_for_off(self):
+        super().configure_for_off()
+
+
+# ----------
+# Run server
+# ----------
+def main(**kwargs):
+    """Main function of the PDU module."""
+    return entry(PDU, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index dd4179e47840488b1033d9612a4a5015f0ec2a49..f356c0dfc0e70632d8f57d40dbf32b31d90a49c4 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -98,8 +98,8 @@ class SDP(opcua_device):
     # ----------
 
     FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=numpy.str, dims=(16,))
-    FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.uint32, dims=(16,), doc="Active FPGA image (0=factory, 1=user)")
-    FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(16,), doc="Active FPGA image (0=factory, 1=user)")
+    FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_global_node_index_R = attribute_wrapper(comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(16,))
     FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["FPGA_hardware_version_R"], datatype=numpy.str, dims=(16,))
     FPGA_pps_present_R = attribute_wrapper(comms_annotation=["FPGA_pps_present_R"], datatype=numpy.bool_, dims=(16,))
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_pdu.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_pdu.py
new file mode 100644
index 0000000000000000000000000000000000000000..8ffefd83a8bba8fe1a04b8d929a5c403cb0d8262
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_pdu.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the LOFAR 2.0 Station Software
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+from .base import AbstractTestBases
+
+
+class TestDevicePDU(AbstractTestBases.TestDeviceBase):
+
+    def setUp(self):
+        """Intentionally recreate the device object in each test"""
+        super().setUp("STAT/PDU/1")