diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5c222a48dcd223050f203a69d7b4f4b4d99ccdb7..fcecc7c684ba15b7c8437b5c38b92276d70aaf6f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -86,11 +86,13 @@ docker_build_image_all:
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh grafana latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh jupyter latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh apsct-sim latest
+    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh ccd-sim latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh apspu-sim latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh recv-sim latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh sdptr-sim latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh unb2-sim latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apsct latest
+    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-ccd latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apspu latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-tilebeam latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-beamlet latest
@@ -191,6 +193,17 @@ docker_build_image_apsct_sim:
   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 apsct-sim $tag
+docker_build_image_ccd_sim:
+  extends: .base_docker_images_except
+  only:
+    refs:
+      - merge_requests
+    changes:
+      - docker-compose/ccd-sim.yml
+      - docker-compose/pypcc-sim-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 ccd-sim $tag
 docker_build_image_apspu_sim:
   extends: .base_docker_images_except
   only:
@@ -246,6 +259,17 @@ docker_build_image_device_apsct:
   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-aspct $tag
+docker_build_image_device_ccd:
+  extends: .base_docker_images_except
+  only:
+    refs:
+      - merge_requests
+    changes:
+      - docker-compose/device-ccd.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-ccd $tag
 docker_build_image_device_apspu:
   extends: .base_docker_images_except
   only:
diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json
index 2ba1ebe751f6397710f82e8d246c74fe9eaae8dd..e7af81cae189b00800053ea1c24ed43faf243ba9 100644
--- a/CDB/LOFAR_ConfigDb.json
+++ b/CDB/LOFAR_ConfigDb.json
@@ -169,6 +169,16 @@
                 }
             }
         },
+        "CCD": {
+            "STAT": {
+                "CCD": {
+                    "STAT/CCD/1": {
+                        "properties": {
+                        }
+                    }
+                }
+            }
+        },
         "APSPU": {
             "STAT": {
                 "APSPU": {
diff --git a/CDB/stations/DTS_Outside_ConfigDb.json b/CDB/stations/DTS_Outside_ConfigDb.json
index 523f2eb8d88e55ec42d1881d4c7de728881ef64f..cbfa8255c171cb2c47c81de6dd372105d7413cb0 100644
--- a/CDB/stations/DTS_Outside_ConfigDb.json
+++ b/CDB/stations/DTS_Outside_ConfigDb.json
@@ -24,6 +24,7 @@
                                 "STAT/PCON/1",
                                 "STAT/APSPU/1",
                                 "STAT/APSCT/1",
+                                "STAT/CCD/1",
                                 "STAT/RECV/1",
                                 "STAT/UNB2/1",
                                 "STAT/SDP/1",
@@ -60,6 +61,25 @@
                 }
             }
         },
+        "CCD": {
+            "STAT": {
+                "CCD": {
+                    "STAT/CCD/1": {
+                        "properties": {
+                            "OPC_Server_Name": [
+                                "10.87.6.67 "
+                            ],
+                            "OPC_Server_Port": [
+                                "4843"
+                            ],
+                            "OPC_Time_Out": [
+                                "5.0"
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "APSPU": {
             "STAT": {
                 "APSPU": {
diff --git a/CDB/stations/simulators_ConfigDb.json b/CDB/stations/simulators_ConfigDb.json
index 7cd92391917029be134fdc9fd4846b5540153663..bb686ecf733a7925bafa3883bb86ed132fe89d90 100644
--- a/CDB/stations/simulators_ConfigDb.json
+++ b/CDB/stations/simulators_ConfigDb.json
@@ -32,6 +32,25 @@
                 }
             }
         },
+        "CCD": {
+            "STAT": {
+                "CCD": {
+                    "STAT/CCD/1": {
+                        "properties": {
+                            "OPC_Server_Name": [
+                                "ccd-sim"
+                            ],
+                            "OPC_Server_Port": [
+                                "4843"
+                            ],
+                            "OPC_Time_Out": [
+                                "5.0"
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "APSPU": {
             "STAT": {
                 "APSPU": {
@@ -125,7 +144,7 @@
                                 "RECV, HBAT_LED_on_RW"
                             ],
                             "Shutdown_Device_List":[
-                                "STAT/SDP/1", "STAT/UNB2/1", "STAT/RECV/1", "STAT/APSCT/1", "STAT/APSPU/1"
+                                "STAT/SDP/1", "STAT/UNB2/1", "STAT/RECV/1", "STAT/APSCT/1", "STAT/CCD/1","STAT/APSPU/1"
                             ]
                         }
                     }
diff --git a/bin/start-ds.sh b/bin/start-ds.sh
index 66389714f17770339ee645129adc9dcb26fa21d7..71cb29a29bfa977fbf6033c8479c9e59435485b5 100755
--- a/bin/start-ds.sh
+++ b/bin/start-ds.sh
@@ -37,6 +37,8 @@ else
   rm -rf /tmp/tangostationcontrol
   cp -R /opt/lofar/tango/tangostationcontrol /tmp/
   cd /tmp/tangostationcontrol || exit 1
+  # Remove the build directory if copied from the source
+  rm -rf build
   pip -vvv install --upgrade --force-reinstall ./
 fi
 
diff --git a/docker-compose/ccd-sim.yml b/docker-compose/ccd-sim.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b02d3693abc28ad95fde8b57515613c8cae09204
--- /dev/null
+++ b/docker-compose/ccd-sim.yml
@@ -0,0 +1,25 @@
+#
+# Docker compose file that launches an APSCT simulator
+#
+# Defines:
+#   - apsct-sim 
+#
+version: '2.1' 
+
+services:
+  ccd-sim:
+    build:
+        context: pypcc-sim-base
+        args:
+         - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
+         - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    container_name: ${CONTAINER_NAME_PREFIX}ccd-sim
+    logging:
+      driver: "json-file"
+      options:
+        max-size: "100m"
+        max-file: "10"
+    networks:
+      - control
+    entrypoint: hwtr --simulator --port 4843 --config CCDTR
+    restart: on-failure
diff --git a/docker-compose/device-ccd.yml b/docker-compose/device-ccd.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ffbfafcf31c9cfaea3ead633787b5bb0b9f69c47
--- /dev/null
+++ b/docker-compose/device-ccd.yml
@@ -0,0 +1,47 @@
+#
+# Docker compose file that launches an interactive iTango session.
+#
+# Connect to the interactive session with 'docker attach itango'.
+# Disconnect with the Docker deattach sequence: <CTRL>+<P> <CTRL>+<Q>
+#
+# Defines:
+#   - itango: iTango interactive session
+#
+# Requires:
+#   - lofar-device-base.yml
+#
+version: '2.1'
+
+services:
+  device-ccd:
+    image: device-ccd
+    # build explicitly, as docker-compose does not understand a local image
+    # being shared among services.
+    build:
+        context: .
+        dockerfile: lofar-device-base/Dockerfile
+        args:
+            SOURCE_IMAGE: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-itango:${TANGO_ITANGO_VERSION}
+    container_name: ${CONTAINER_NAME_PREFIX}device-ccd
+    logging:
+      driver: "json-file"
+      options:
+        max-size: "100m"
+        max-file: "10"
+    networks:
+      - control
+    ports:
+      - "5721:5721" # 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-ccd Ccd STAT -v -ORBendPoint giop:tcp:device-ccd:5721 -ORBendPointPublish giop:tcp:${HOSTNAME}:5721
+    restart: on-failure
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 af329f05b03ae4bdc3b10542e96949c2f5e2b604..350ecb1e87f4829ddd60698831bbf75d941782a9 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
@@ -1,5 +1,6 @@
 # Create shortcuts for our devices
 apsct = DeviceProxy("STAT/APSCT/1")
+ccd = DeviceProxy("STAT/CCD/1")
 apspu = DeviceProxy("STAT/APSPU/1")
 recv = DeviceProxy("STAT/RECV/1")
 sdp = DeviceProxy("STAT/SDP/1")
@@ -17,4 +18,4 @@ docker = DeviceProxy("STAT/Docker/1")
 temperaturemanager = DeviceProxy("STAT/TemperatureManager/1")
 
 # Put them in a list in case one wants to iterate
-devices = [apsct, apspu, recv, sdp, bst, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, temperaturemanager, docker]
+devices = [apsct, ccd, apspu, recv, sdp, bst, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, temperaturemanager, docker]
diff --git a/docker-compose/tango-prometheus-exporter/lofar2-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-policy.json
index 5d4ef40e092dd820d851cac7d8e152d45add336a..606f06499472aa11324b7566739efd6de37fdcab 100644
--- a/docker-compose/tango-prometheus-exporter/lofar2-policy.json
+++ b/docker-compose/tango-prometheus-exporter/lofar2-policy.json
@@ -15,6 +15,8 @@
         },
         "stat/apsct/1": {
         },
+        "stat/ccd/1": {
+        },
         "stat/apspu/1": {
         },
         "stat/beamlet/1": {
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 65beb8bc65ef32c79d29794281e5f3da2023456a..3047557a3678940748746acc6f7e7e3a59ea6090 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -73,9 +73,9 @@ 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-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control"
+DEVICES="device-boot device-apsct device-ccd device-apspu device-sdp device-recv device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control"
 
-SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim"
+SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim ccd-sim"
 
 # Build only the required images, please do not build everything that makes CI
 # take really long to finish, especially grafana / jupyter / prometheus.
diff --git a/sbin/tag_and_push_docker_image.sh b/sbin/tag_and_push_docker_image.sh
index d12bee575e594e0264e39c8eca6013704eb4a805..44605c52c7eed433cf89d0fab66d51946ce305cd 100755
--- a/sbin/tag_and_push_docker_image.sh
+++ b/sbin/tag_and_push_docker_image.sh
@@ -64,11 +64,13 @@ LOCAL_IMAGES=(
   "lofar-device-base lofar-device-base y"
 
   "apsct-sim docker-compose_apsct-sim y" "apspu-sim docker-compose_apspu-sim y"
+  "ccd-sim docker-compose_ccd-sim y"
   "recv-sim docker-compose_recv-sim y" "sdptr-sim docker-compose_sdptr-sim y"
-  "unb2-sim docker-compose_unb2-sim y"
+  "unb2-sim docker-compose_unb2-sim y" 
 
   "device-antennafield device-antennafield y"
   "device-apsct device-apsct y" "device-apspu device-apspu y"
+  "device-ccd device-ccd y"
   "device-boot device-boot y" "device-docker device-docker y"
   "device-observation device-observation y"
   "device-observation-control device-observation-control y"
@@ -159,13 +161,13 @@ if [ ! -z "${1+x}" ] && [ "${1}" != "pull" ]; then
       local_url="${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/${2}"
 
       # If tag is not latest, than it is not a tagged master build and we can
-      # pull the latest image as cache.
+      # pull the latest image as cache (if it already exists).
       if [ "${tag}" != "latest" ]; then
-        docker pull "${local_url}:latest"
+        docker pull "${local_url}:latest" || true
       fi
 
       make build "${1}"
-      docker tag "${2}" "${local_url}:${tag}"
+      docker tag "${2}" "${local_url}:${tag}" || docker tag "${2/_/-}" "${local_url}:${tag}"
       docker push "${local_url}:${tag}"
     fi
   done
diff --git a/tangostationcontrol/docs/source/devices/ccd.rst b/tangostationcontrol/docs/source/devices/ccd.rst
new file mode 100644
index 0000000000000000000000000000000000000000..a419254829f659ddf09cedf99a7e76cd9382b61e
--- /dev/null
+++ b/tangostationcontrol/docs/source/devices/ccd.rst
@@ -0,0 +1,6 @@
+.. _ccd:
+
+CCD
+--------------------
+
+The ``ccd == DeviceProxy("STAT/CCD/1")`` Clock Control Device controls the clock
diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst
index 07c5fb4ac45444e941b31b3869198b2504284389..6bd156c2b7f9d3cda99ad3af8a7e01bbc33c45c8 100644
--- a/tangostationcontrol/docs/source/index.rst
+++ b/tangostationcontrol/docs/source/index.rst
@@ -29,6 +29,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st
    devices/boot
    devices/docker
    devices/psoc
+   devices/ccd
    devices/temperature-manager
    devices/configure
    configure_station
diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg
index 127f89141b4fc26fd283816923d9b1708bfa8a26..510034a343b89b2bc2a24bd212bafe77a4565a67 100644
--- a/tangostationcontrol/setup.cfg
+++ b/tangostationcontrol/setup.cfg
@@ -35,6 +35,7 @@ where=.
 [options.entry_points]
 console_scripts =
     l2ss-apsct = tangostationcontrol.devices.apsct:main
+	l2ss-ccd = tangostationcontrol.devices.ccd:main
     l2ss-apspu = tangostationcontrol.devices.apspu:main
     l2ss-psoc = tangostationcontrol.devices.psoc:main
     l2ss-pcon = tangostationcontrol.devices.pcon:main
diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md
index cb4efc08e5345657f96db0cc9afbf74e6a0c7d0f..4d5bc3a070be1340c26db626ef7dde9235df87c4 100644
--- a/tangostationcontrol/tangostationcontrol/devices/README.md
+++ b/tangostationcontrol/tangostationcontrol/devices/README.md
@@ -18,4 +18,4 @@ If a new device is added, it will (likely) need to be referenced in several plac
 - Add to `sbin/tag_and_push_docker_image.sh` the LOCAL_IMAGES device name, imagine name and build for integration boolean triple,
 - 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/`.
-
+- Adjust `docker-compose/tango-prometheus-exporter/lofar2-policy.json` to include this device in the prometheus exporter
diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
index d9ea40ea3bc9dbf1c3e08d80caabbfaca2ddd55f..25b58719c287c4a6fe6e4b690f0228187ac17989 100644
--- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
@@ -90,7 +90,8 @@ class AntennaField(lofar_device):
     Antenna_Names = device_property(
         doc="Name of each antenna",
         dtype='DevVarStringArray',
-        mandatory=False
+        mandatory=False,
+        default_value = [f'Antenna{n+1}' for n in range(MAX_NUMBER_OF_HBAT)]
     )
 
     # ----- Antenna states
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index cb172c34d3b4249691518609f18bd5a7ceced613..8d51d269f3e83eb2eb0a45442cec4209e00ecf13 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -238,6 +238,7 @@ class Boot(lofar_device):
                        "STAT/PCON/1",  # PCON boot early because it is responsible for power delivery.
                        "STAT/APSPU/1",  # APS Power Units control other hardware we want to initialise
                        "STAT/APSCT/1",
+                       "STAT/CCD/1",
                        "STAT/RECV/1",   # RCUs are input for SDP, so initialise them first
                        "STAT/UNB2/1",   # Uniboards host SDP, so initialise them first
                        "STAT/SDP/1",    # SDP controls the mask for SST/XST/BST/Beamlet, so initialise it first
diff --git a/tangostationcontrol/tangostationcontrol/devices/ccd.py b/tangostationcontrol/tangostationcontrol/devices/ccd.py
new file mode 100644
index 0000000000000000000000000000000000000000..e053d26c4e879fca236a4277742c96c0f119d350
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/devices/ccd.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the RECV project
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+""" CCD Device Server for LOFAR2.0
+
+"""
+
+# PyTango imports
+from tango import DebugIt
+from tango.server import command, attribute, device_property
+from tango import AttrWriteType
+import numpy
+# Additional import
+
+from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.lofar_logging import device_logging_to_python
+from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
+from tangostationcontrol.devices.device_decorators import only_in_states
+from tangostationcontrol.devices.opcua_device import opcua_device
+
+import logging
+logger = logging.getLogger()
+
+__all__ = ["CCD", "main"]
+
+
+@device_logging_to_python()
+class CCD(opcua_device):
+    # -----------------
+    # Device Properties
+    # -----------------
+
+    CCDTR_monitor_rate_RW_default = device_property(
+        dtype='DevLong64',
+        mandatory=False,
+        default_value=1
+    )
+
+    # ----- Timing values
+
+    CCD_On_Off_timeout = device_property(
+        doc='Maximum amount of time to wait after turning CCD on or off',
+        dtype='DevFloat',
+        mandatory=False,
+        default_value=10.0
+    )
+
+    # ----------
+    # Attributes
+    # ----------
+    CCDTR_I2C_error_R =         attribute_wrapper(comms_annotation=["CCDTR_I2C_error_R"         ], datatype=numpy.int64)
+    CCDTR_monitor_rate_RW =     attribute_wrapper(comms_annotation=["CCDTR_monitor_rate_RW"     ], datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
+    CCDTR_translator_busy_R =   attribute_wrapper(comms_annotation=["CCDTR_translator_busy_R"   ], datatype=bool)
+    CCD_clear_lock_R =          attribute_wrapper(comms_annotation=["CCD_clear_lock_R"          ], datatype=bool)
+    CCD_clear_lock_RW =         attribute_wrapper(comms_annotation=["CCD_clear_lock_RW"         ], datatype=bool, access=AttrWriteType.READ_WRITE)
+    CCD_FAN_RPM_R =             attribute_wrapper(comms_annotation=["CCD_FAN_RPM_R"             ], datatype=numpy.float64)
+    CCD_INPUT_10MHz_good_R =    attribute_wrapper(comms_annotation=["CCD_INPUT_10MHz_good_R"    ], datatype=bool)
+    CCD_INPUT_PPS_good_R =      attribute_wrapper(comms_annotation=["CCD_INPUT_PPS_good_R"      ], datatype=bool)
+    CCD_loss_lock_R =           attribute_wrapper(comms_annotation=["CCD_loss_lock_R"           ], datatype=bool)
+    CCD_PCB_ID_R =              attribute_wrapper(comms_annotation=["CCD_PCB_ID_R"              ], datatype=numpy.int64)
+    CCD_PCB_number_R =          attribute_wrapper(comms_annotation=["CCD_PCB_number_R"          ], datatype=str)
+    CCD_PCB_version_R =         attribute_wrapper(comms_annotation=["CCD_PCB_version_R"         ], datatype=str)
+    CCD_PLL_locked_R =          attribute_wrapper(comms_annotation=["CCD_PLL_locked_R"          ], datatype=bool)
+    CCD_PWR_CLK_DIST_3V3_R =    attribute_wrapper(comms_annotation=["CCD_PWR_CLK_DIST_3V3_R"    ], datatype=numpy.float64)
+    CCD_PWR_CLK_INPUT_3V3_R =   attribute_wrapper(comms_annotation=["CCD_PWR_CLK_INPUT_3V3_R"   ], datatype=numpy.float64)
+    CCD_PWR_CTRL_3V3_R =        attribute_wrapper(comms_annotation=["CCD_PWR_CTRL_3V3_R"        ], datatype=numpy.float64)
+    CCD_PWR_OCXO_INPUT_3V3_R =  attribute_wrapper(comms_annotation=["CCD_PWR_OCXO_INPUT_3V3_R"  ], datatype=numpy.float64)
+    CCD_PWR_on_R =              attribute_wrapper(comms_annotation=["CCD_PWR_on_R"              ], datatype=bool)
+    CCD_PWR_PLL_INPUT_3V3_R =   attribute_wrapper(comms_annotation=["CCD_PWR_PLL_INPUT_3V3_R"   ], datatype=numpy.float64)
+    CCD_PWR_PPS_INPUT_3V3_R =   attribute_wrapper(comms_annotation=["CCD_PWR_PPS_INPUT_3V3_R"   ], datatype=numpy.float64)
+    CCD_PWR_PPS_OUTPUT_3V3_R =  attribute_wrapper(comms_annotation=["CCD_PWR_PPS_OUTPUT_3V3_R"  ], datatype=numpy.float64)
+    CCD_TEMP_R =                attribute_wrapper(comms_annotation=["CCD_TEMP_R"                ], datatype=numpy.float64)
+    # ----------
+    # Summarising Attributes
+    # ----------
+    CCD_error_R                 = attribute(dtype=bool, fisallowed="is_attribute_access_allowed")
+
+    def read_CCD_error_R(self):
+        errors = [self.read_attribute("CCDTR_I2C_error_R") > 0,
+                self.alarm_val("CCD_loss_lock_R"),
+                self.read_attribute("CCD_INPUT_10MHz_good_R"),
+                not self.read_attribute("CCD_INPUT_10MHz_good_R"),
+                not self.read_attribute("CCD_INPUT_PPS_good_R") and not self.read_attribute("CCD_clear_lock_R"),
+                not self.read_attribute("CCD_PLL_locked_R")]
+        return any(errors)
+
+    CCD_TEMP_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=1000)
+    CCD_VOUT_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed")
+
+    def read_CCD_TEMP_error_R(self):
+        return (self.alarm_val("CCD_TEMP_R"))
+
+    def read_CCD_VOUT_error_R(self):
+        return ( self.alarm_val("CCD_PWR_CLK_DIST_3V3_R")
+               or self.alarm_val("CCD_PWR_CLK_INPUT_3V3_R")
+               or self.alarm_val("CCD_PWR_CTRL_3V3_R")
+               or self.alarm_val("CCD_PWR_OCXO_INPUT_3V3_R")
+               or self.alarm_val("CCD_PWR_PLL_INPUT_3V3_R")
+               or self.alarm_val("CCD_PWR_PPS_INPUT_3V3_R")
+               or self.alarm_val("CCD_PWR_PPS_OUTPUT_3V3_R")
+               or (not self.read_attribute("CCD_PWR_on_R"))
+               )
+
+    # --------
+    # overloaded functions
+    # --------
+
+    @command()
+    @DebugIt()
+    @only_in_states(DEFAULT_COMMAND_STATES)
+    def reset_hardware(self):
+        """ Initialise the CCD hardware. """
+
+        # Cycle clock
+        self.CCD_off()
+        self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout)
+        self.CCD_on()
+        self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout)
+
+        if not self.read_attribute("CCD_PLL_locked_R"):
+            if self.read_attribute("CCDTR_I2C_error_R"):
+                raise Exception("I2C is not working. Maybe power cycle subrack to restart CLK board and translator?")
+            else:
+                raise Exception("CCD clock is not locked")
+
+    def _disable_hardware(self):
+        """ Disable the CCD hardware. """
+
+        # Turn off the CCD
+        self.CCD_off()
+        self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout)
+
+    # --------
+    # Commands
+    # --------
+
+    @command()
+    @DebugIt()
+    @only_in_states(DEFAULT_COMMAND_STATES)
+    def CCD_off(self):
+        """
+
+        :return:None
+        """
+        self.opcua_connection.call_method(["CCD_off"])
+
+    @command()
+    @DebugIt()
+    @only_in_states(DEFAULT_COMMAND_STATES)
+    def CCD_on(self):
+        """
+
+        :return:None
+        """
+        self.opcua_connection.call_method(["CCD_on"])
+
+
+
+# ----------
+# Run server
+# ----------
+def main(**kwargs):
+    """Main function of the ObservationControl module."""
+    return entry(CCD, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_ccd.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_ccd.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f259be1c3d11269fc387fe85e42b5f05b9e8764
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_ccd.py
@@ -0,0 +1,16 @@
+# -*- 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 TestDeviceCCD(AbstractTestBases.TestDeviceBase):
+
+    def setUp(self):
+        super().setUp("STAT/CCD/1")