diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cc246b077bca48b5e6616a5ac7d2d2b55c4e2370..7378f8d0c6d68cc59ff1d8b916427ca3c999a711 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -99,7 +99,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 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-observation-control latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-psoc 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
@@ -339,11 +339,11 @@ docker_build_image_device_observation_control:
     refs:
       - merge_requests
     changes:
-      - docker-compose/device-observation_control.yml
+      - docker-compose/device-observation-control.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-observation_control $tag
+    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation-control $tag
 docker_build_image_device_antennafield:
   extends: .base_docker_images_except
   only:
diff --git a/docker-compose/device-boot.yml b/docker-compose/device-boot.yml
index 0388c08229c38f9abd475d4e59efd46ce7a14548..cbeb916536845b47aa0ded5dba2900fa1fa5d7f5 100644
--- a/docker-compose/device-boot.yml
+++ b/docker-compose/device-boot.yml
@@ -4,7 +4,7 @@
 # created Observation devices.
 #
 # Defines:
-#   - device-observation_control: LOFAR2.0 station ObvservationControl
+#   - device-observation-control: LOFAR2.0 station ObvservationControl
 #
 # Requires:
 #   - lofar-device-base.yml
diff --git a/docker-compose/device-observation_control.yml b/docker-compose/device-observation-control.yml
similarity index 87%
rename from docker-compose/device-observation_control.yml
rename to docker-compose/device-observation-control.yml
index 4c84af7921444ab0923757ccff43d681d7120cb3..197d192a54ca10360439f41cfd6aeb0adeca70e3 100644
--- a/docker-compose/device-observation_control.yml
+++ b/docker-compose/device-observation-control.yml
@@ -4,7 +4,7 @@
 # created Observation devices.
 #
 # Defines:
-#   - device-observation_control: LOFAR2.0 station ObvservationControl
+#   - device-observation-control: LOFAR2.0 station ObvservationControl
 #
 # Requires:
 #   - lofar-device-base.yml
@@ -12,8 +12,8 @@
 version: '2.1'
 
 services:
-  device-observation_control:
-    image: device-observation_control
+  device-observation-control:
+    image: device-observation-control
     # build explicitly, as docker-compose does not understand a local image
     # being shared among services.
     build:
@@ -21,7 +21,7 @@ services:
         dockerfile: docker-compose/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-observation_control
+    container_name: ${CONTAINER_NAME_PREFIX}device-observation-control
     logging:
       driver: "json-file"
       options:
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 617744dd3988835d0d7923a18357f65f10c2b1dd..f879e8d9ddb97a62bd9bac15b893621a3d8739f0 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -69,7 +69,7 @@ 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-antennafield device-temperature-manager device-observation"
+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-antennafield device-temperature-manager device-observation device-observation-control"
 SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim"
 
 # Build only the required images, please do not build everything that makes CI
diff --git a/sbin/tag_and_push_docker_image.sh b/sbin/tag_and_push_docker_image.sh
index e3053a31fd874061c69099c49338f4204f3eaf83..d12bee575e594e0264e39c8eca6013704eb4a805 100755
--- a/sbin/tag_and_push_docker_image.sh
+++ b/sbin/tag_and_push_docker_image.sh
@@ -71,7 +71,7 @@ LOCAL_IMAGES=(
   "device-apsct device-apsct y" "device-apspu device-apspu y"
   "device-boot device-boot y" "device-docker device-docker y"
   "device-observation device-observation y"
-  "device-observation_control device-observation_control y"
+  "device-observation-control device-observation-control y"
   "device-recv device-recv y"
   "device-temperature-manager device-temperature-manager y"
   "device-sdp device-sdp y" "device-sst device-sst y"
diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py
index bc30872734ba2006c1d7245281cfb04dfd6fb0ba..555000fca0ca13b2ca49efed0784a45be2f5287c 100644
--- a/tangostationcontrol/tangostationcontrol/devices/observation.py
+++ b/tangostationcontrol/tangostationcontrol/devices/observation.py
@@ -91,25 +91,26 @@ class Observation(lofar_device):
 
         # Set a reference of AntennaField device that is correlated to this device
         util = Util.instance()
-        instance_number = self.get_name().split('/')[2]
+        #TODO(Stefano): set a proper policy for the devices instance number
+        # It cannot be inherited from the Observation instance number (i.e. Observation_id)
         self.antennafield_proxy = DeviceProxy(
-            f"{util.get_ds_inst_name()}/AntennaField/{instance_number}")
+            f"{util.get_ds_inst_name()}/AntennaField/1")
         self.antennafield_proxy.set_source(DevSource.DEV)
 
         # Set a reference of RECV device that is correlated to this device
-        self.recv_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/RECV/{instance_number}")
+        self.recv_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/RECV/1")
         self.recv_proxy.set_source(DevSource.DEV)
 
         # Set a reference of Beamlet device that is correlated to this device
-        self.beamlet_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/Beamlet/{instance_number}")
+        self.beamlet_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/Beamlet/1")
         self.beamlet_proxy.set_source(DevSource.DEV)
 
         # Set a reference of DigitalBeam device that is correlated to this device
-        self.digitalbeam_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/DigitalBeam/{instance_number}")
+        self.digitalbeam_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/DigitalBeam/1")
         self.digitalbeam_proxy.set_source(DevSource.DEV)
 
         # Set a reference of TileBeam device that is correlated to this device
-        self.tilebeam_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/Tilebeam/{instance_number}")
+        self.tilebeam_proxy = DeviceProxy(f"{util.get_ds_inst_name()}/Tilebeam/1")
         self.tilebeam_proxy.set_source(DevSource.DEV)
 
         logger.info(
diff --git a/tangostationcontrol/tangostationcontrol/devices/observation_control.py b/tangostationcontrol/tangostationcontrol/devices/observation_control.py
index f29c2032ca0df6e0275d1e594f7ff7ef4ecee9ca..a2521d4511d84483a0530c7c748522f461bd49ac 100644
--- a/tangostationcontrol/tangostationcontrol/devices/observation_control.py
+++ b/tangostationcontrol/tangostationcontrol/devices/observation_control.py
@@ -5,17 +5,18 @@
 # Distributed under the terms of the APACHE license.
 # See LICENSE.txt for more info.
 
-from datetime import datetime
 from json import loads
+import jsonschema
+from jsonschema import Draft7Validator, FormatChecker
 import logging
 import time
 
+from datetime import datetime
 import numpy
 from tango import Except, DevFailed, DevState, AttrWriteType, DebugIt, DeviceProxy, Util, DevBoolean, DevString
 from tango.server import Device, command, attribute
 from tango import EventType
 
-from tangostationcontrol import __version__ as version
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 from tangostationcontrol.devices.device_decorators import only_when_on, fault_on_error
@@ -70,6 +71,44 @@ class ObservationControl(lofar_device):
     - array[int] running_observations
     - string version
     """
+    # JSON Schema
+    OBSERVATION_SETTINGS_SCHEMA = {
+        "$schema": "http://json-schema.org/draft-07/schema",
+        "type": "object",
+        "required": [],
+        "properties": {
+            "observation_id": {"type": "number", "minimum": 1},
+            "stop_time": {"type": "string", "format": "date-time"},
+            "antenna_mask": {"type": "array"},
+            "filter": {"type": "string"},
+            "SAPs": {"type": "array",
+                    "minItems": 1,
+                    "items": {
+                        "type": "object",
+                        "properties": {
+                            "subbands": {"type": "array"},
+                            "pointing": {"type": "object",
+                                        "properties": {
+                                            "angle1" : {"type": "number"},
+                                            "angle2" : {"type": "number"},
+                                            "direction_type": {"type": "string"}
+                                        }
+                            }
+                        }
+                    }
+            },
+            "tile_beam": {"type": "object",
+                        "properties": {
+                            "angle1" : {"type": "number"},
+                            "angle2" : {"type": "number"},
+                            "direction_type": {"type": "string"}
+                        }
+            },
+            "first_beamlet": {"type": "number", "minimum": 0}
+        },
+    }
+    VALIDATOR = Draft7Validator(OBSERVATION_SETTINGS_SCHEMA, format_checker=FormatChecker())
+
     # Attributes
     version_R = attribute(dtype = str, access = AttrWriteType.READ, fget = lambda self: version)
     running_observations_R = attribute(dtype = (numpy.int64, ), access = AttrWriteType.READ)
@@ -118,7 +157,6 @@ class ObservationControl(lofar_device):
     @log_exceptions()
     def read_running_observations_R(self):
         obs = [ key for key in self.running_observations ]
-        logger.debug("{}".format(obs))
         return obs
 
     @log_exceptions()
@@ -132,7 +170,7 @@ class ObservationControl(lofar_device):
         """
         if event.err:
             # Something is fishy with this event.
-            logger.warning("The Observation device {} sent an event but the event signals an error.  It is advised to check the logs for any indication that something went wrong in that device.  Event data={} ".format(event.device, event))
+            logger.warning(f"The Observation device {event.device} sent an event but the event signals an error.  It is advised to check the logs for any indication that something went wrong in that device.  Event data={event}")
             return
 
         # Get the Observation ID from the sending device.
@@ -142,10 +180,10 @@ class ObservationControl(lofar_device):
         running_obs = self.running_observations.copy()
         if not running_obs:
             # No obs is running???
-            logger.warning("Received an observation_running event for the observation with ID={}.  According to the records in ObservationControl, this observation is not supposed to run.  Please check previous logs, especially around the time an observation with this ID was started.  Will continue and ignore this event.".format(obs_id))
+            logger.warning(f"Received an observation_running event for the observation with ID={obs_id}.  According to the records in ObservationControl, this observation is not supposed to run.  Please check previous logs, especially around the time an observation with this ID was started.  Will continue and ignore this event.")
             return
 
-        if id in running_obs:
+        if obs_id in running_obs:
             # Get the Observation's stop_time from the Observation device.
             obs_stop_time = event.device.stop_time_R
             current_obs_time = event.attr_value.value
@@ -157,8 +195,12 @@ class ObservationControl(lofar_device):
                 # The observation has not finished yet and is
                 # more than 1.0 seconds past its scheduled stop
                 # time. Tell the observation to finish and clean up.
-                obs = running_obs[id]
+                obs = running_obs[obs_id]
                 self.stop_observation(obs_id)
+        else:
+            # The observation that we are trying to process is not part of the running_obs dictionary
+            logger.warning(f"Received an observation_running event for the observation with ID={obs_id}.  According to the records in ObservationControl, this observation is not supposed to run.  Please check previous logs, especially around the time an observation with this ID was started.  Will continue and ignore this event.")
+            return
 
     @only_when_on()
     @log_exceptions()
@@ -173,57 +215,22 @@ class ObservationControl(lofar_device):
         # Convert the input parameter to a dict.
         parameter_dict = loads(parameters)
 
-        logger.debug("incoming parameter_array = {}, parameter_dict = {}".format(parameters, parameter_dict))
+        logger.debug("incoming parameter_array = %s, parameter_dict = %s", parameters, parameter_dict)
 
         # Parameter check, do not execute an observation in case
         # the parameters are not sufficiently defined.
         obs_id = int(parameter_dict["observation_id"])
         stop_datetime = datetime.fromisoformat(parameter_dict["stop_time"])
-        # TODO(Jan David): Once ticket https://support.astron.nl/jira/browse/L2SS-254
-        #                  is done, this needs to be replaced by a proper JSON
-        #                  verification against a schema.
-        if obs_id is None or obs_id < 1:
-            # Do not execute
-            error = "Cannot start an observation with ID={} because the observation ID is invalid.  The ID must be any integer >= 1.".format(obs_id)
-            Except.throw_exception("IllegalCommand", error, __name__)
-        elif stop_datetime is None or stop_datetime <= datetime.now():
-            error = "Cannot start an observation with ID={} because the parameter stop_time parameter value=\"{}\" is invalid.  It needs to be expressed in ISO 8601 format.".format(obs_id, stop_datetime)
+        try:
+            self.VALIDATOR.validate(parameter_dict)
+        except jsonschema.exceptions.ValidationError as error:
             Except.throw_exception("IllegalCommand", error, __name__)
-        elif len(parameters) == 0:
-            error = "Cannot start an observation with ID={} because the parameter set is empty.".format(obs_id)
+        # Check further properties that cannot be validated through a JSON schema
+        if stop_datetime <= datetime.now():
+            error = f"Cannot start an observation with ID={obs_id} because the parameter stop_time parameter value=\"{stop_datetime}\" is invalid. Set a stop_time parameter later in time than the start time."
             Except.throw_exception("IllegalCommand", error, __name__)
         return parameter_dict
 
-    def delete_dynamic_device(self, class_name: str = None, device_name: str = None):
-        """
-        Remove a Tango device from the Tango DB.  This calls delete_device().
-        """
-        if class_name is not None and device_name is not None:
-            try:
-                # Remove the device from the Tango DB.
-                self.tango_util.delete_device(class_name, device_name)
-            except DevFailed as ex:
-                # It is OK if this fails.  This likely means that the device did
-                # never exist in the Tango DB.  Still add a warning to the logs.
-                logger.warning("Something went wrong when it was attempted to remove the device {} from the Tango DB.  You should better go and check the logs.  Exception: {}".format(device_name, ex))
-                pass
-        else:
-            logger.error("Cannot delete a device from the Tango DB if the device's class name or the device name are not provided: class_name={}, device_name={}".format(class_name, device_name))
-
-    def create_dynamic_device(self, class_name: str = None, device_name: str = None):
-        """
-        Create a Tango device instance for a Device class in the Tango DB.
-        This will automatically instantiate the device and also call
-        init_device.
-        """
-        try:
-            self.tango_util.create_device(class_name, device_name)
-        except DevFailed as ex:
-            self.delete_dynamic_device(class_name, device_name)
-            error_string = "Cannot start the device {} for the device class {}. Exception: {}".format(device_name, class_name, ex)
-            logger.exception(error_string)
-            Except.re_throw_exception(ex, "DevFailed", error_string, __name__)
-
     # API
     @command(dtype_in = DevString)
     @only_when_on()
@@ -245,11 +252,17 @@ class ObservationControl(lofar_device):
 
         try:
             # Create the Observation device and instantiate it.
-            self.create_dynamic_device(class_name, device_name)
+            self.tango_util.create_device(class_name, device_name)
         except DevFailed as ex:
-            error_string = "Cannot create the Observation device instance {} for ID={}.  This means that the observation did not start.".format(device_name, observation_id)
-            logger.exception(error_string)
-            Except.re_throw_exception(ex, "DevFailed", error_string, __name__)
+            if ex.args[0].desc == f"The device {device_name.lower()} is already defined in the database" and self.is_observation_running(observation_id) is False :
+                self.tango_util.delete_device(class_name, device_name)
+                error_string = f"Cannot create the Observation device {device_name} because it is already present in the Database but it is not running. Try to re-run the start_observation command"
+                logger.exception(error_string)
+                Except.re_throw_exception(ex, "DevFailed", error_string, __name__)
+            else:
+                error_string = f"Cannot create the Observation device instance {device_name} for ID={observation_id}.  This means that the observation did not start."
+                logger.exception(error_string)
+                Except.re_throw_exception(ex, "DevFailed", error_string, __name__)
 
         try:
             # Instantiate a dynamic Tango Device "Observation".
@@ -270,8 +283,8 @@ class ObservationControl(lofar_device):
             device_proxy.On()
         except DevFailed as ex:
             # Remove the device again.
-            self.delete_dynamic_device(class_name, device_name)
-            error_string = "Cannot access the Observation device instance for observation ID={} with device class name={} and device instance name={}.  This means that the observation likely did not start but certainly cannot be controlled and/or forcefully be stopped.".format(observation_id, class_name, device_name)
+            self.tango_util.delete_device(class_name, device_name)
+            error_string = f"Cannot access the Observation device instance for observation ID={observation_id} with device class name={class_name} and device instance name={device_name}.  This means that the observation likely did not start but certainly cannot be controlled and/or forcefully be stopped."
             logger.exception(error_string)
             Except.re_throw_exception(ex, "DevFailed", error_string, __name__)
 
@@ -280,7 +293,7 @@ class ObservationControl(lofar_device):
             #
             # Generate the name for the Observation.observation_running
             # MP.
-            attribute_name = "{}/observation_running_R".format(device_name)
+            attribute_name = f"{device_name}/observation_running_R"
             observation["attribute_name"] = attribute_name
 
             # Turn on the polling for the attribute.
@@ -304,9 +317,9 @@ class ObservationControl(lofar_device):
             self.running_observations[observation_id] = observation
             logger.info(f"Successfully started an observation with ID={observation_id}.")
         except DevFailed as ex:
-            self.delete_dynamic_device(class_name, device_name)
-            error_string = "Cannot access the Observation device instance for observation ID={} with device class name={} and device instance name={}.  This means that the observation cannot be controlled and/or forcefully be stopped.".format(observation_id, Observation.__name__, device_name)
-            logger.exception(error_string)
+            self.tango_util.delete_device(class_name, device_name)
+            error_string = "Cannot access the Observation device instance for observation ID=%s with device class name=%s and device instance name=%s.  This means that the observation cannot be controlled and/or forcefully be stopped."
+            logger.exception(error_string, observation_id, Observation.__name__, device_name)
             Except.re_throw_exception(ex, "DevFailed", error_string, __name__)
 
     @command(dtype_in = numpy.int64)
@@ -317,13 +330,13 @@ class ObservationControl(lofar_device):
         # the parameters are not sufficient.
         if obs_id < 1:
             # Do not execute
-            error = "Cannot stop an observation with ID={}, because the observation ID is invalid.".format(obs_id)
+            error = f"Cannot stop an observation with ID={obs_id}, because the observation ID is invalid."
             Except.throw_exception("IllegalCommand", error, __name__)
         elif self.is_observation_running(obs_id) is False:
-            error = "Cannot stop an observation with ID={}, because the observation is not running.".format(obs_id)
+            error = f"Cannot stop an observation with ID={obs_id}, because the observation is not running."
             Except.throw_exception("IllegalCommand", error, __name__)
 
-        logger.info("Stopping the observation with ID={}.".format(obs_id))
+        logger.info(f"Stopping the observation with ID={obs_id}.")
         # Fetch the obs data and remove it from the dict of
         # currently running observations.
         observation = self.running_observations.pop(obs_id)
@@ -333,7 +346,7 @@ class ObservationControl(lofar_device):
         try:
             device_proxy.ping()
         except DevFailed:
-            logger.warning("The device for the Observation with ID={} has unexpectedly already disappeared.  It is advised to check the logs up to 10s prior to this message to see what happened.".format(obs_id))
+            logger.warning(f"The device for the Observation with ID={obs_id} has unexpectedly already disappeared.  It is advised to check the logs up to 10s prior to this message to see what happened.")
         else:
             # Unsubscribe from the subscribed event.
             event_id = observation.pop("event_id")
@@ -358,15 +371,15 @@ class ObservationControl(lofar_device):
                 remaining_wait_time = remaining_wait_time - sleep_time
             # Check if the observation object is really in OFF state.
             if stopped:
-                logger.info("Successfully stopped the observation with ID={}.".format(obs_id))
+                logger.info(f"Successfully stopped the observation with ID={obs_id}")
             else:
-                logger.warning("Could not shut down the Observation device (\"{}\") for observation ID={}.  This means that there is a chance for a memory leak.  Will continue anyway and forcefully delete the Observation object.".format(observation["device_name"], obs_id))
+                logger.warning(f"Could not shut down the Observation device ( {observation['device_name']} ) for observation ID={obs_id}.  This means that there is a chance for a memory leak.  Will continue anyway and forcefully delete the Observation object.")
 
         # Finally remove the device object from the Tango DB.
         try:
-            self.delete_dynamic_device(observation["class_name"], observation["device_name"])
+            self.tango_util.delete_device(observation["class_name"], observation["device_name"])
         except DevFailed:
-            logger.warning("Something went wrong when the device {} was removed from the Tango DB.  There is nothing that can be done about this here at this moment but you should check the Tango DB yourself.".format(observation["device_name"]))
+            logger.warning(f"Something went wrong when the device {observation['device_name']} was removed from the Tango DB.  There is nothing that can be done about this here at this moment but you should check the Tango DB yourself.")
 
     @command()
     @only_when_on()
@@ -388,16 +401,10 @@ class ObservationControl(lofar_device):
         # Parameter check, do not execute if obs_id is invalid
         if obs_id < 1:
             # Do not execute
-            error = "Cannot check if an observation with ID={} is running, because the observation ID is invalid".format(obs_id)
+            error = f"Cannot check if an observation with ID={obs_id} is running, because the observation ID is invalid"
             Except.throw_exception("IllegalCommand", error, __name__)
-
         observation = self.running_observations.get(obs_id)
-        info = "An observation with ID={} is".format(obs_id)
-        if observation is not None:
-            logger.debug("{} running.".format(info))
-            return True
-        logger.debug("{} not running.".format(info))
-        return False
+        return observation is not None
 
     @command(dtype_out = DevBoolean)
     @only_when_on()
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py
new file mode 100644
index 0000000000000000000000000000000000000000..055c86470de831df946b7994bfdc6d760624b83c
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py
@@ -0,0 +1,239 @@
+# -*- 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 tango import DevState
+from tango import DevFailed
+
+import numpy
+import json
+from datetime import datetime
+from datetime import timedelta
+
+from tangostationcontrol.test.devices.test_observation_base import TestObservationBase
+from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
+from .base import AbstractTestBases
+
+class TestObservationControlDevice(AbstractTestBases.TestDeviceBase):
+
+    NUM_TILES = 48
+    NUM_BEAMLETS_CTRL = 488
+    NUM_INPUTS = 96
+    INPUT_TO_ANTENNA_MAPPING = [
+                                 "0",  "1",  "2",  "3",  "4",  "5",
+                                 "6",  "7",  "8",  "9", "10", "11",
+                                "12", "13", "14", "15", "16", "17",
+                                "18", "19", "20", "21", "22", "23",
+                                "24", "25", "26", "27", "28", "29",
+                                "30", "31", "32", "33", "34", "35",
+                                "36", "37", "38", "39", "40", "41",
+                                "42", "43", "44", "45", "46", "47",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1",
+                                "-1", "-1", "-1", "-1", "-1", "-1"
+                                ]
+
+    def setUp(self):
+        super().setUp("STAT/ObservationControl/1")
+        self.VALID_JSON = TestObservationBase.VALID_JSON
+        self.recv_proxy = self.setup_recv_proxy()
+        self.antennafield_proxy = self.setup_antennafield_proxy()
+        self.beamlet_proxy = self.setup_beamlet_proxy()
+        self.sdp_proxy = self.setup_sdp_proxy()
+        self.digitalbeam_proxy = self.setup_digitalbeam_proxy()
+        self.tilebeam_proxy = self.setup_tilebeam_proxy()
+    
+    def setup_recv_proxy(self):
+        # setup RECV
+        recv_proxy = TestDeviceProxy("STAT/RECV/1")
+        recv_proxy.off()
+        recv_proxy.warm_boot()
+        recv_proxy.set_defaults()
+        return recv_proxy
+    
+    def setup_sdp_proxy(self):
+        # setup SDP
+        sdp_proxy = TestDeviceProxy("STAT/SDP/1")
+        sdp_proxy.off()
+        sdp_proxy.warm_boot()
+        return sdp_proxy
+    
+    def setup_antennafield_proxy(self):
+        # setup AntennaField
+        antennafield_proxy = TestDeviceProxy("STAT/AntennaField/1")
+        control_mapping = [[1,i] for i in range(self.NUM_TILES)]
+        antennafield_proxy.put_property({"RECV_devices": ["STAT/RECV/1"],
+                                 "HBAT_Power_to_RECV_mapping": numpy.array(control_mapping).flatten()})
+        antennafield_proxy.off()
+        antennafield_proxy.warm_boot()
+        antennafield_proxy.set_defaults()
+        return antennafield_proxy
+    
+    def setup_beamlet_proxy(self):
+        # setup Digitalbeam
+        beamlet_proxy = TestDeviceProxy("STAT/Beamlet/1")
+        beamlet_proxy.off()
+        beamlet_proxy.warm_boot()
+        beamlet_proxy.set_defaults()
+        return beamlet_proxy
+
+    def setup_digitalbeam_proxy(self):
+        # setup Digitalbeam
+        digitalbeam_proxy = TestDeviceProxy("STAT/DigitalBeam/1")
+        digitalbeam_proxy.put_property({"Input_to_Antenna_Mapping": numpy.array(self.INPUT_TO_ANTENNA_MAPPING).flatten()})
+        digitalbeam_proxy.off()
+        digitalbeam_proxy.warm_boot()
+        digitalbeam_proxy.set_defaults()
+        return digitalbeam_proxy
+    
+    def setup_tilebeam_proxy(self):
+        # Setup Tilebeam
+        tilebeam_proxy = TestDeviceProxy("STAT/TileBeam/1")
+        tilebeam_proxy.off()
+        tilebeam_proxy.warm_boot()
+        tilebeam_proxy.set_defaults()
+        return tilebeam_proxy
+
+    def on_device_assert(self, proxy):
+        """Transition the device to ON and assert intermediate states"""
+
+        proxy.Off()
+        self.assertEqual(DevState.OFF, proxy.state())
+        proxy.Initialise()
+        self.assertEqual(DevState.STANDBY, proxy.state())
+        proxy.On()
+        self.assertEqual(DevState.ON, proxy.state())
+
+    def test_device_on(self):
+        """Transition the ObservationControl device to ON state"""
+        self.on_device_assert(self.proxy)
+
+    def test_no_observation_running(self):
+        """Assert no current observations on fresh boot"""
+
+        self.on_device_assert(self.proxy)
+        self.assertFalse(self.proxy.is_any_observation_running())
+        self.assertFalse(self.proxy.is_observation_running(12345))
+        self.assertFalse(self.proxy.is_observation_running(54321))
+
+    def test_check_and_convert_parameters_invalid_id(self):
+        """Test invalid parameter detection"""
+
+        parameters = json.loads(self.VALID_JSON)
+        parameters['observation_id'] = -1
+
+        
+        self.on_device_assert(self.proxy)
+        self.assertRaises(
+            DevFailed, self.proxy.start_observation, json.dumps(parameters))
+
+    def test_check_and_convert_parameters_invalid_time(self):
+        """Test invalid parameter detection"""
+
+        parameters = json.loads(self.VALID_JSON)
+        parameters['stop_time'] = (datetime.now() - timedelta(seconds=1)).isoformat()
+
+        self.on_device_assert(self.proxy)
+        self.assertRaises(
+            DevFailed, self.proxy.start_observation, json.dumps(parameters))
+
+    def test_check_and_convert_parameters_invalid_empty(self):
+        """Test empty parameter detection"""
+
+        self.on_device_assert(self.proxy)
+        self.assertRaises(
+            DevFailed, self.proxy.start_observation, "{}")
+
+    def test_start_observation(self):
+        """Test starting an observation"""
+
+        self.on_device_assert(self.proxy)
+
+        self.proxy.start_observation(self.VALID_JSON)
+
+        self.assertTrue(self.proxy.is_any_observation_running())
+        self.assertTrue(self.proxy.is_observation_running(12345))
+
+        self.proxy.stop_observation(12345)
+
+    def test_start_observation_multiple(self):
+        """Test starting multiple observations"""
+
+        second_observation_json = json.loads(self.VALID_JSON)
+        second_observation_json['observation_id'] = 54321
+
+        self.on_device_assert(self.proxy)
+
+        self.proxy.start_observation(self.VALID_JSON)
+        self.proxy.start_observation(json.dumps(second_observation_json))
+
+        self.assertTrue(self.proxy.is_any_observation_running())
+        self.assertTrue(self.proxy.is_observation_running(12345))
+        self.assertTrue(self.proxy.is_observation_running(54321))
+
+        self.proxy.stop_observation(12345)
+        self.proxy.stop_observation(54321)
+
+    def test_stop_observation_invalid_id(self):
+        """Test stop_observation exceptions for invalid ids"""
+
+        self.on_device_assert(self.proxy)
+
+        self.assertRaises(DevFailed, self.proxy.stop_observation, -1)
+
+    def test_stop_observation_invalid_running(self):
+        """Test stop_observation exceptions for not running"""
+
+        self.on_device_assert(self.proxy)
+
+        self.assertRaises(DevFailed, self.proxy.stop_observation, 2)
+
+    def test_is_any_observation_running_after_stop_all_observations(self):
+        """Test whether is_any_observation_running conforms when we start & stop an observation"""
+
+        self.on_device_assert(self.proxy)
+
+        self.proxy.start_observation(self.VALID_JSON)
+        self.proxy.stop_all_observations()
+
+        # Test false
+        self.assertFalse(self.proxy.is_any_observation_running())
+
+    def test_start_stop_observation(self):
+        """Test starting and stopping an observation"""
+
+        self.on_device_assert(self.proxy)
+
+        # uses ID 12345
+        self.proxy.start_observation(self.VALID_JSON)
+        self.proxy.stop_observation(12345)
+
+        # Test false
+        self.assertFalse(self.proxy.is_observation_running(12345))
+
+    def test_start_multi_stop_all_observation(self):
+        """Test starting and stopping multiple observations"""
+
+        second_observation_json = json.loads(self.VALID_JSON)
+        second_observation_json['observation_id'] = 54321
+
+        self.on_device_assert(self.proxy)
+
+        # uses ID 12345
+        self.proxy.start_observation(self.VALID_JSON)
+        self.proxy.start_observation(json.dumps(second_observation_json))
+        self.proxy.stop_all_observations()
+
+        # Test false
+        self.assertFalse(self.proxy.is_observation_running(12345))
+        self.assertFalse(self.proxy.is_observation_running(54321))
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_observation_control_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_observation_control_device.py
index 93420364a8e8d28f2cea790a9be177f590a9ffea..1d5e2af773252e2e28ad789e6a9ccccb75468a91 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_observation_control_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_observation_control_device.py
@@ -7,18 +7,6 @@
 # Distributed under the terms of the APACHE license.
 # See LICENSE.txt for more info.
 
-import mock
-
-from tango.test_context import DeviceTestContext
-from tango import DevState
-from tango import DevFailed
-
-import json
-from datetime import datetime
-from datetime import timedelta
-
-from tangostationcontrol.devices import observation_control
-
 from tangostationcontrol.test import base
 from tangostationcontrol.test.devices import test_observation_base
 
@@ -28,183 +16,4 @@ class TestObservationControlDevice(base.TestCase, test_observation_base.TestObse
     def setUp(self):
         super(TestObservationControlDevice, self).setUp()
 
-    def on_device_assert(self, proxy):
-        """Transition the device to ON and assert intermediate states"""
-
-        proxy.Off()
-        self.assertEqual(DevState.OFF, proxy.state())
-        proxy.Initialise()
-        self.assertEqual(DevState.STANDBY, proxy.state())
-        proxy.On()
-        self.assertEqual(DevState.ON, proxy.state())
-
-    def mock_dynamic_devices(self):
-        observation_proxy = mock.patch.object(
-            observation_control, 'DeviceProxy')
-        self.m_observation_control = observation_proxy.start()
-        self.addCleanup(observation_proxy.stop)
-
-        observation_dynamic_device = mock.patch.object(
-            observation_control.ObservationControl, 'create_dynamic_device',
-            autospec=True)
-        self.m_observation_dynamic_device = observation_dynamic_device.start()
-        self.addCleanup(observation_dynamic_device.stop)
-
-    def test_device_on(self):
-        """Transition the ObservationControl device to ON state"""
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-    def test_no_observation_running(self):
-        """Assert no current observations on fresh boot"""
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            self.assertFalse(proxy.is_any_observation_running())
-            self.assertFalse(proxy.is_observation_running(12345))
-            self.assertFalse(proxy.is_observation_running(54321))
-
-    def test_check_and_convert_parameters_invalid_id(self):
-        """Test invalid parameter detection"""
-        self.mock_dynamic_devices()
-
-        parameters = json.loads(self.VALID_JSON)
-        parameters['observation_id'] = -1
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            self.assertRaises(
-                DevFailed, proxy.start_observation, json.dumps(parameters))
-
-    def test_check_and_convert_parameters_invalid_time(self):
-        """Test invalid parameter detection"""
-        self.mock_dynamic_devices()
-
-        parameters = json.loads(self.VALID_JSON)
-        parameters['stop_time'] = (datetime.now() - timedelta(seconds=1)).isoformat()
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            self.assertRaises(
-                DevFailed, proxy.start_observation, json.dumps(parameters))
-
-    def test_check_and_convert_parameters_invalid_empty(self):
-        """Test empty parameter detection"""
-        self.mock_dynamic_devices()
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            self.assertRaises(
-                DevFailed, proxy.start_observation, "{}")
-
-    @mock.patch.object(
-        observation_control.ObservationControl, 'delete_dynamic_device')
-    def test_start_observation(self, m_delete_device):
-        """Test starting an observation"""
-        self.mock_dynamic_devices()
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            proxy.start_observation(self.VALID_JSON)
-
-            self.assertTrue(proxy.is_any_observation_running())
-            self.assertTrue(proxy.is_observation_running(12345))
-
-    @mock.patch.object(
-        observation_control.ObservationControl, 'delete_dynamic_device')
-    def test_start_observation_multiple(self, m_delete_device):
-        """Test starting multiple observations"""
-        self.mock_dynamic_devices()
-
-        second_observation_json = json.loads(self.VALID_JSON)
-        second_observation_json['observation_id'] = 54321
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            proxy.start_observation(self.VALID_JSON)
-            proxy.start_observation(json.dumps(second_observation_json))
-
-            self.assertTrue(proxy.is_any_observation_running())
-            self.assertTrue(proxy.is_observation_running(12345))
-            self.assertTrue(proxy.is_observation_running(54321))
-
-    def test_stop_observation_invalid_id(self):
-        """Test stop_observation exceptions for invalid ids"""
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            self.assertRaises(DevFailed, proxy.stop_observation, -1)
-
-    def test_stop_observation_invalid_running(self):
-        """Test stop_observation exceptions for not running"""
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            self.assertRaises(DevFailed, proxy.stop_observation, 2)
-
-    def test_is_any_observation_running_after_stop_all_observations(self):
-        """Test whether is_any_observation_running conforms when we start & stop an observation"""
-        self.mock_dynamic_devices()
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            proxy.start_observation(self.VALID_JSON)
-            proxy.stop_all_observations()
-
-            # Test false
-            self.assertFalse(proxy.is_any_observation_running())
-
-    def test_start_stop_observation(self):
-        """Test starting and stopping an observation"""
-        self.mock_dynamic_devices()
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            # uses ID 12345
-            proxy.start_observation(self.VALID_JSON)
-            proxy.stop_observation(12345)
-
-            # Test false
-            self.assertFalse(proxy.is_observation_running(12345))
-
-    def test_start_multi_stop_all_observation(self):
-        """Test starting and stopping multiple observations"""
-        self.mock_dynamic_devices()
-
-        second_observation_json = json.loads(self.VALID_JSON)
-        second_observation_json['observation_id'] = 54321
-
-        with DeviceTestContext(observation_control.ObservationControl,
-                               process=True) as proxy:
-            self.on_device_assert(proxy)
-
-            # uses ID 12345
-            proxy.start_observation(self.VALID_JSON)
-            proxy.start_observation(json.dumps(second_observation_json))
-            proxy.stop_all_observations()
-
-            # Test false
-            self.assertFalse(proxy.is_observation_running(12345))
-            self.assertFalse(proxy.is_observation_running(54321))
+    # Moved to Integration Test