diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8bbc48ec8e58a29303e516874f4d44c174e20cae..ffa80d4f794dba8d2d4ae923911bce61e977fd7d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -117,13 +117,6 @@ docker_build_image_all:
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh loki latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh logstash latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh jupyter-lab 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 recvh-sim latest
-    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh recvl-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 grafana latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh prometheus latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh tango-prometheus-exporter latest
@@ -206,83 +199,6 @@ docker_build_image_jupyter:
   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 jupyter-lab $tag
-docker_build_image_apsct_sim:
-  extends: .base_docker_images_except
-  only:
-    refs:
-      - merge_requests
-    changes:
-      - docker-compose/aspct-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 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:
-    refs:
-      - merge_requests
-    changes:
-      - docker-compose/apspu-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 apspu-sim $tag
-docker_build_image_recvh_sim:
-  extends: .base_docker_images_except
-  only:
-    refs:
-      - merge_requests
-    changes:
-      - docker-compose/recvh-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 recvh-sim $tag
-docker_build_image_recvl_sim:
-  extends: .base_docker_images_except
-  only:
-    refs:
-      - merge_requests
-    changes:
-      - docker-compose/recvl-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 recvl-sim $tag
-docker_build_image_sdptr_sim:
-  extends: .base_docker_images_except
-  only:
-    refs:
-      - merge_requests
-    changes:
-      - docker-compose/sdptr-sim.yml
-      - docker-compose/sdptr-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 sdptr-sim $tag
-docker_build_image_unb2_sim:
-  extends: .base_docker_images_except
-  only:
-    refs:
-      - merge_requests
-    changes:
-      - docker-compose/unb2-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 unb2-sim $tag
 newline_at_eof:
   stage: linting
   before_script:
diff --git a/docker-compose/Makefile b/docker-compose/Makefile
index 51a74085d4e85c0f039d4ba1c6be6ddb9831b01e..92240df541107275120d87cfff9f40fa2c03110a 100644
--- a/docker-compose/Makefile
+++ b/docker-compose/Makefile
@@ -166,7 +166,7 @@ DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) \
 .DEFAULT_GOAL := help
 
 pull: ## pull the images from the Docker hub
-	$(DOCKER_COMPOSE_ARGS) $(DOCKER_COMPOSE) $(COMPOSE_FILE_ARGS) pull
+	$(DOCKER_COMPOSE_ARGS) $(DOCKER_COMPOSE) $(COMPOSE_FILE_ARGS) pull --ignore-pull-failures
 
 base: context ## Build base lofar device image
 	$(DOCKER_COMPOSE_ARGS) $(DOCKER_COMPOSE) $(COMPOSE_FILE_ARGS) build --progress=plain lofar-device-base
@@ -271,5 +271,9 @@ clean: down  ## clear all TANGO database entries, and all containers
 	docker volume rm $(BASEDIR)_tangodb
 	$(DOCKER_COMPOSE_ARGS) $(DOCKER_COMPOSE) $(COMPOSE_FILE_ARGS) rm -f
 
+nuke: down
+	- docker rmi  -f $(shell $(DOCKER_COMPOSE_ARGS) $(DOCKER_COMPOSE) $(COMPOSE_FILE_ARGS) config --images)
+	- docker volume rm $(shell $(DOCKER_COMPOSE_ARGS) $(DOCKER_COMPOSE) $(COMPOSE_FILE_ARGS) config --format json | jq '.volumes | .[] | .name' -r)
+
 help:   ## show this help.
 	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
diff --git a/docker-compose/README.md b/docker-compose/README.md
index 4b57a0b08e65b6bfc99701e38fff9db9c386f9fa..05882d6ad8bdd4aeafd4554cc07dfbad7bd47f62 100644
--- a/docker-compose/README.md
+++ b/docker-compose/README.md
@@ -8,12 +8,12 @@ contains developer expectations that they should uphold to.
 ## Index
 
 1. [Station services]()
-   1. [Types of container services and specific strategies](#types-of-containers-and-specific-strategies)
+    1. [Types of container services and specific strategies](#types-of-containers-and-specific-strategies)
 2. [HDB++ image updates](#hdb-image-updates)
 3. [Gitlab CI/CD](#gitlab-cicd)
-   1. [Image tagging and change detection](#image-tagging-and-change-detection)
-      1. [Setup and maintenance](#setup-and-maintenance)
-   2. [Gitlab CI phases](#gitlab-ci-phases)
+    1. [Image tagging and change detection](#image-tagging-and-change-detection)
+        1. [Setup and maintenance](#setup-and-maintenance)
+    2. [Gitlab CI phases](#gitlab-ci-phases)
 
 ## Station Services
 
@@ -23,35 +23,34 @@ are used in production.
 
 - [Devices \[external\]](https://lofar20-station-control.readthedocs.io/en/latest/devices/overview.html)
 - Simulators
-  - [sdptr \[external\]](https://git.astron.nl/lofar2.0/sdptr)
-    - [sdptr-sim](sdptr-sim.yml)
-  - [pypcc \[external\]](https://git.astron.nl/lofar2.0/pypcc)
-    -  [pypcc-sim-base](pypcc-sim-base/Dockerfile)
-      - [apsct-sim](apsct-sim.yml)
-      - [apspu-sim](apspu-sim.yml)
-      - [ccd-sim](ccd-sim.yml)
-      - [recvh-sim](recvh-sim.yml)
-      - [recvl-sim](recvl-sim.yml)
-      - [unb2-sim](unb2-sim.yml)
+    - [sdptr \[external\]](https://git.astron.nl/lofar2.0/sdptr)
+        - [sdptr-sim](sdptr-sim.yml)
+    - [pypcc \[external\]](https://git.astron.nl/lofar2.0/pypcc)
+        - [apsct-sim](apsct-sim.yml)
+        - [apspu-sim](apspu-sim.yml)
+        - [ccd-sim](ccd-sim.yml)
+        - [recvh-sim](recvh-sim.yml)
+        - [recvl-sim](recvl-sim.yml)
+        - [unb2-sim](unb2-sim.yml)
 - Base images
-  - [ci-runner](ci-runner/Dockerfile)
-  - [lofar-device-base](lofar-device-base.yml)
+    - [ci-runner](ci-runner/Dockerfile)
+    - [lofar-device-base](lofar-device-base.yml)
 - Services
-  - databases
-    - dsconfig
-    - prometheus
-  - webservers / user interfaces
-    - jupyterlab
-    - [grafana](grafana/README.md)
-    - [http-json-schemas](http-json-schemas/README.md)
-  - logging / monitoring
-    - prometheus-node-exporter
-    - [tango-prometheus-exporter](tango-prometheus-exporter/README.md)
-    - logstash (grafana-logstash-output-loki)
-    - loki
-  - tango
-    - itango
-    - tango-rest
+    - databases
+        - dsconfig
+        - prometheus
+    - webservers / user interfaces
+        - jupyterlab
+        - [grafana](grafana/README.md)
+        - [http-json-schemas](http-json-schemas/README.md)
+    - logging / monitoring
+        - prometheus-node-exporter
+        - [tango-prometheus-exporter](tango-prometheus-exporter/README.md)
+        - logstash (grafana-logstash-output-loki)
+        - loki
+    - tango
+        - itango
+        - tango-rest
 
 ### Types of containers and specific strategies
 
diff --git a/docker-compose/apsct-sim.yml b/docker-compose/apsct-sim.yml
index d6ef5b9a579976c0952020030a829bef637f087f..e1c1fdf722aaf1e724f4a6b1ec57b51f47e4ddf3 100644
--- a/docker-compose/apsct-sim.yml
+++ b/docker-compose/apsct-sim.yml
@@ -10,11 +10,7 @@ version: '2.1'
 
 services:
   apsct-sim:
-    build:
-      context: pypcc-sim-base
-      args:
-        - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
-        - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
     hostname: apsct-sim
     container_name: apsct-sim
     logging:
diff --git a/docker-compose/apspu-sim.yml b/docker-compose/apspu-sim.yml
index ebfddbaa8bb2963441fe93f239256bc8bb98c88e..be0e38fd8fbdb42cd25ae9fee0d1efb672117dcb 100644
--- a/docker-compose/apspu-sim.yml
+++ b/docker-compose/apspu-sim.yml
@@ -10,11 +10,7 @@ version: '2.1'
 
 services:
   apspu-sim:
-    build:
-      context: pypcc-sim-base
-      args:
-        - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
-        - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
     hostname: apspu-sim
     container_name: apspu-sim
     logging:
diff --git a/docker-compose/ccd-sim.yml b/docker-compose/ccd-sim.yml
index 1580b222ec4be3f86de7d3df057efcb3a01e6ce6..89a711ea871516bf83686b5ffdfbf6f9c1473a54 100644
--- a/docker-compose/ccd-sim.yml
+++ b/docker-compose/ccd-sim.yml
@@ -10,11 +10,7 @@ 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}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
     hostname: ccd-sim
     container_name: ccd-sim
     logging:
diff --git a/docker-compose/jupyter-lab/Dockerfile b/docker-compose/jupyter-lab/Dockerfile
index 32cc522bd553d3d839487fdab9afe2ea32240c2d..1ac48fd3656247bedcc573242e7c140eb4c2b05a 100644
--- a/docker-compose/jupyter-lab/Dockerfile
+++ b/docker-compose/jupyter-lab/Dockerfile
@@ -61,7 +61,7 @@ RUN sudo chmod +x /usr/bin/tini
 
 # Needed to perform certain migration actions during startup
 RUN sudo mkdir -p /home/tango/.jupyter/lab/workspaces
-RUN sudo chmod 0777 /home/tango/.jupyter
+RUN sudo chmod -R 0777 /home/tango/.jupyter
 
 USER ${CONTAINER_EXECUTION_UID}
 # pyppeteer-install installs in the homedir, so run it as the user that will execute the notebook
diff --git a/docker-compose/pypcc-sim-base/Dockerfile b/docker-compose/pypcc-sim-base/Dockerfile
deleted file mode 100644
index be2b00841cde80cedbe867323d0203d90c36a879..0000000000000000000000000000000000000000
--- a/docker-compose/pypcc-sim-base/Dockerfile
+++ /dev/null
@@ -1,6 +0,0 @@
-ARG LOCAL_DOCKER_REGISTRY_HOST
-ARG LOCAL_DOCKER_REGISTRY_LOFAR
-
-FROM ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
-
-CMD ["hwtr", "--simulator", "--port","4843"]
diff --git a/docker-compose/recvh-sim.yml b/docker-compose/recvh-sim.yml
index d6d3dec7e365389ce676081a5b8c7867c116a8e9..3cbd437f083ebe32308f57b2e0e22a57d7814da3 100644
--- a/docker-compose/recvh-sim.yml
+++ b/docker-compose/recvh-sim.yml
@@ -10,11 +10,7 @@ version: '2.1'
 
 services:
   recvh-sim:
-    build:
-      context: pypcc-sim-base
-      args:
-        - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
-        - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
     hostname: recvh-sim
     container_name: recvh-sim
     logging:
diff --git a/docker-compose/recvl-sim.yml b/docker-compose/recvl-sim.yml
index ee95f45583df79a0cc48090552147eb366aedb03..d257992bc4b4e37b026804dcec19b298c44e6f29 100644
--- a/docker-compose/recvl-sim.yml
+++ b/docker-compose/recvl-sim.yml
@@ -10,11 +10,7 @@ version: '2.1'
 
 services:
   recvl-sim:
-    build:
-      context: pypcc-sim-base
-      args:
-        - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
-        - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
     hostname: recvl-sim
     container_name: recvl-sim
     logging:
diff --git a/docker-compose/sdptr-sim.yml b/docker-compose/sdptr-sim.yml
index 68c91fff0fd39f06c96ca6dbb4e100e8ac44bd89..740f37613000f822050ca728a15f21ba00b46450 100644
--- a/docker-compose/sdptr-sim.yml
+++ b/docker-compose/sdptr-sim.yml
@@ -10,11 +10,7 @@ version: '2.1'
 
 services:
   sdptr-sim:
-    build:
-      context: sdptr-sim
-      args:
-        - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
-        - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/sdptr:latest
     hostname: sdptr-sim
     container_name: sdptr-sim
     logging:
@@ -22,6 +18,8 @@ services:
       options:
         max-size: "100m"
         max-file: "10"
+
+    command: /usr/local/bin/sdptr --ip_prefix=127.0. --nodaemon
     networks:
       - control
     restart: unless-stopped
diff --git a/docker-compose/sdptr-sim/Dockerfile b/docker-compose/sdptr-sim/Dockerfile
deleted file mode 100644
index 678b79ecef5d9425f2993fb26a2163b7c50036f7..0000000000000000000000000000000000000000
--- a/docker-compose/sdptr-sim/Dockerfile
+++ /dev/null
@@ -1,7 +0,0 @@
-ARG LOCAL_DOCKER_REGISTRY_HOST
-ARG LOCAL_DOCKER_REGISTRY_LOFAR
-
-FROM ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/sdptr:latest
-
-WORKDIR /sdptr/src
-CMD ["sdptr", "--ip_prefix=127.0.", "--nodaemon"]
diff --git a/docker-compose/unb2-sim.yml b/docker-compose/unb2-sim.yml
index 89abb8ce69d70a0aac09f9ba8d30c30a1aa9ec93..1a99e5fddeef499fe6ae8901ef2811c3f6b7189e 100644
--- a/docker-compose/unb2-sim.yml
+++ b/docker-compose/unb2-sim.yml
@@ -10,11 +10,7 @@ version: '2.1'
 
 services:
   unb2-sim:
-    build:
-      context: pypcc-sim-base
-      args:
-        - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST}
-        - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR}
+    image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_LOFAR}/pypcc:latest
     hostname: unb2-sim
     container_name: unb2-sim
     logging:
diff --git a/sbin/container_logs.sh b/sbin/container_logs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..16eee53ea73217be43e47fc163df785514b9227a
--- /dev/null
+++ b/sbin/container_logs.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+# SPDX-License-Identifier: Apache-2.0
+
+trap "echo Exited!; exit;" SIGINT SIGTERM
+while :
+do
+  docker logs "$1" -f
+  sleep 1
+done
diff --git a/sbin/tag_and_push_docker_image.sh b/sbin/tag_and_push_docker_image.sh
index d852c4386295464c2309e08cee78e1e1be4a216d..9ee815ee16653a2ee64b565afe5f3476d85d8f51 100755
--- a/sbin/tag_and_push_docker_image.sh
+++ b/sbin/tag_and_push_docker_image.sh
@@ -70,12 +70,6 @@ LOCAL_IMAGES=(
   "logstash logstash y"
   "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"
-  "recvh-sim docker-compose_recvh-sim y" "recvl-sim docker-compose_recvl-sim y"
-  "sdptr-sim docker-compose_sdptr-sim y"
-  "unb2-sim docker-compose_unb2-sim y"
-
   "itango docker-compose_itango y"
 
   "grafana grafana n" "prometheus prometheus n"
diff --git a/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy.py b/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy.py
index a6c72933a1a41804e7fbc655f8b5d350d2cf30be..e3e8723f9d12de3ac4af0a124628830c7d075b95 100644
--- a/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy.py
+++ b/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy.py
@@ -1,22 +1,26 @@
-# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy)
-# SPDX-License-Identifier: Apache-2.0
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
 
 """Abstract Hierarchy for PyTango devices"""
 
+import fnmatch
+import logging
 from abc import ABC
 from enum import Enum
 from typing import Callable
 from typing import Dict
 from typing import List
-from typing import Union
 from typing import Optional
+from typing import Union
 
-import fnmatch
-
-from tango import DevState, DeviceProxy
+import tango
+from tango import DevState
+from tango import DeviceProxy
 
 from tangostationcontrol.common.proxy import create_device_proxy
 
+logger = logging.getLogger()
+
 
 class HierarchyMatchingFilter(Enum):
     """Select to filter by exact match, substring or regex"""
@@ -302,6 +306,53 @@ class AbstractHierarchy(ABC):
             child_filter, self.children(depth=-1), self._get_filter(filter_type)
         )
 
+    def branch_child(
+        self,
+        child_filter: child_filter_input_type,
+        filter_type: HierarchyMatchingFilter,
+    ) -> Optional[DeviceProxy]:
+        child = self.child(child_filter, filter_type)
+
+        if child:
+            return child
+
+        db = tango.Database()
+        children = db.get_device_property(self.parents()[0], self._child_property_name)[
+            self._child_property_name
+        ]
+        return AbstractHierarchy(
+            self._child_property_name, children, self.parents()[1:], self._proxies
+        ).branch_child(child_filter, filter_type)
+
+    def branch_children_names(
+        self,
+        child_filter: child_filter_input_type,
+        filter_type: HierarchyMatchingFilter,
+    ) -> List[str]:
+        """Retrieve Device children names matching child_filter substring located in
+        the same branch of the hierarchy
+
+        :param child_filter: Substring of the device to retrieve device names list
+                                 for
+        :param filter_type: Type of filter such as exact, substring or regex
+        :return A list of device names matching the child filter substring
+        """
+        if isinstance(child_filter, Enum):
+            child_filter = child_filter.value
+
+        children = self.children_names(child_filter, filter_type)
+
+        if len(children) > 0:
+            return children
+
+        db = tango.Database()
+        children = db.get_device_property(self.parents()[0], self._child_property_name)[
+            self._child_property_name
+        ]
+        return AbstractHierarchy(
+            self._child_property_name, children, self.parents()[1:], self._proxies
+        ).branch_children_names(child_filter, filter_type)
+
     def _match_parent(self, parent_name: str):
         """Try to find an exact match for one of our parents
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy_device.py b/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy_device.py
index 586611fb2440f8e4dcd3dcf75ad53c9842d43c3f..fca7b3e95c2dea1a4b769ea3b44e10194e8a186f 100644
--- a/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/interfaces/hierarchy_device.py
@@ -1,16 +1,16 @@
-# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy)
-# SPDX-License-Identifier: Apache-2.0
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
 
 """Abstract Hierarchy Device for PyTango devices"""
 
+import logging
 from typing import Dict
 from typing import List
 from typing import Optional
-import logging
 
 from tango import Database
-from tango import DeviceProxy
 from tango import DevState
+from tango import DeviceProxy
 
 from tangostationcontrol.devices.interfaces.hierarchy import AbstractHierarchy
 from tangostationcontrol.devices.interfaces.hierarchy import HierarchyMatchingFilter
@@ -29,7 +29,7 @@ class AbstractHierarchyDevice:
     """
 
     def __init__(self):
-        self._hierarchy = None
+        self._hierarchy: Optional[AbstractHierarchy] = None
 
     @staticmethod
     def _find_parents(device_name: str, child_property: str):
@@ -108,7 +108,21 @@ class AbstractHierarchyDevice:
     ) -> Optional[DeviceProxy]:
         return self._hierarchy.child(child_filter_str, matching_filter)
 
-    def parent(self):
+    def branch_child(
+        self,
+        child_filter_str: str,
+        matching_filter: HierarchyMatchingFilter = HierarchyMatchingFilter.Find,
+    ) -> Optional[DeviceProxy]:
+        return self._hierarchy.branch_child(child_filter_str, matching_filter)
+
+    def branch_children_names(
+        self,
+        child_filter_str: str,
+        matching_filter: HierarchyMatchingFilter = HierarchyMatchingFilter.Find,
+    ) -> List[str]:
+        return self._hierarchy.branch_children_names(child_filter_str, matching_filter)
+
+    def parent(self) -> Optional[str]:
         _parents = self.parents()
         if len(_parents) > 1 or len(_parents) == 0:
             return None
diff --git a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
index 3743acabb9c0bfcafe820e3c9c1a279082f3805c..dd78812fad20393f69512a1a2608a54b31409797 100644
--- a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
@@ -1,5 +1,5 @@
-# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy)
-# SPDX-License-Identifier: Apache-2.0
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
 
 """ TileBeam Device Server for LOFAR2.0
 
@@ -12,15 +12,15 @@ import numpy
 
 # Additional import
 from tangostationcontrol.beam.delays import Delays
-from tangostationcontrol.common.constants import N_xyz, N_elements, N_pol
+from tangostationcontrol.common.constants import N_xyz, N_elements, N_pol, MAX_ANTENNA
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import (
     device_logging_to_python,
     log_exceptions,
 )
-from tangostationcontrol.common.proxy import create_device_proxy
-from tangostationcontrol.devices.interfaces.beam_device import BeamDevice
 from tangostationcontrol.devices.device_decorators import TimeIt
+from tangostationcontrol.devices.interfaces.beam_device import BeamDevice
+from tangostationcontrol.devices.types import DeviceTypes
 
 logger = logging.getLogger()
 
@@ -60,29 +60,26 @@ class TileBeam(BeamDevice):
     def configure_for_initialise(self):
         parent = self.control.parent()
 
-        # TODO(L2SS-1364): Ensure tilebeam does not need direct access to antennafield
-        self.antennafield_proxy = create_device_proxy(parent)
-
         # We maintain the same number of tiles as the AntennaField
         self._nr_tiles = self.control.read_parent_attribute(parent, "nr_antennas_R")
         super().configure_for_initialise(self._nr_tiles)
 
         # Retrieve positions from AntennaField device
-        Antenna_Reference_itrf = self.control.read_parent_attribute(
+        antenna_reference_itrf = self.control.read_parent_attribute(
             parent, "Antenna_Reference_itrf_R"
         )
-        HBAT_antenna_itrf_offsets = self.control.read_parent_attribute(
+        hbat_antenna_itrf_offsets = self.control.read_parent_attribute(
             parent, "HBAT_antenna_itrf_offsets_R"
         ).reshape(self._nr_tiles, N_elements, N_xyz)
 
         # a delay calculator for each tile
         self.HBAT_delay_calculators = [
-            Delays(reference_itrf) for reference_itrf in Antenna_Reference_itrf
+            Delays(reference_itrf) for reference_itrf in antenna_reference_itrf
         ]
 
         # absolute positions of each antenna element
         self.HBAT_antenna_positions = [
-            Antenna_Reference_itrf[tile] + HBAT_antenna_itrf_offsets[tile]
+            antenna_reference_itrf[tile] + hbat_antenna_itrf_offsets[tile]
             for tile in range(self._nr_tiles)
         ]
 
@@ -124,9 +121,42 @@ class TileBeam(BeamDevice):
         delays = self._delays(pointing_direction, timestamp)
 
         # Convert delays into beam weights
-        delays = delays.flatten()
-        # TODO(L2SS-1364): Ensure tilebeam does not need to execute antennafield command
-        bf_delay_steps = self.antennafield_proxy.calculate_HBAT_bf_delay_steps(delays)
+        delays = delays.flatten().reshape(self._nr_tiles, N_elements)
+
+        result_values = numpy.zeros(
+            (self._nr_tiles, N_elements * N_pol), dtype=numpy.int64
+        )
+        control_mapping = numpy.reshape(
+            self.control.read_parent_attribute(
+                self.control.parent(), "Control_to_RECV_mapping_R"
+            ),
+            (-1, N_pol),
+        )
+
+        recv_proxies = []
+        for recv in self.control.branch_children_names(DeviceTypes.RECV):
+            recv_proxies.append(self.control.branch_child(recv))
+
+        for recv_idx, recv_proxy in enumerate(recv_proxies):
+            # collect all delays for this recv_proxy
+            recv_result_indices = numpy.where(control_mapping[:, 0] == (recv_idx + 1))
+            recv_delays = delays[recv_result_indices]
+
+            if not recv_result_indices:
+                # no RCUs are actually used from this recv_proxy
+                continue
+
+            # convert them into delay steps
+            flatten_delay_steps = numpy.array(
+                recv_proxy.calculate_HBAT_bf_delay_steps(recv_delays.flatten()),
+                dtype=numpy.int64,
+            )
+            delay_steps = numpy.reshape(flatten_delay_steps, (-1, N_elements * N_pol))
+
+            # write back into same positions we collected them from
+            result_values[recv_result_indices] = delay_steps
+
+        bf_delay_steps = result_values.flatten()
 
         return bf_delay_steps
 
@@ -139,12 +169,42 @@ class TileBeam(BeamDevice):
     ):
         parent = self.control.parent()
 
-        # Write weights to RECV through the AntennaToRecvMapper
-        # TODO(L2SS-1364): Ensure tilebeam does not need to write antennafield attribute
-        self.antennafield_proxy.HBAT_bf_delay_steps_RW = bf_delay_steps.reshape(
-            self._nr_tiles, N_elements * N_pol
+        control_mapping = numpy.reshape(
+            self.control.read_parent_attribute(parent, "Control_to_RECV_mapping_R"),
+            (-1, N_pol),
         )
 
+        recv_proxies = []
+        for recv in self.control.branch_children_names(DeviceTypes.RECV):
+            recv_proxies.append(self.control.branch_child(recv))
+
+        mapped_values = []
+
+        for _ in range(len(recv_proxies)):
+            mapped_values.append(numpy.full((MAX_ANTENNA, N_elements * N_pol), None))
+
+        mapped_values = numpy.array(mapped_values)
+
+        bf_delay_steps2 = bf_delay_steps.reshape(self._nr_tiles, N_elements * N_pol)
+
+        for idx, mapping in enumerate(control_mapping):
+            recv = mapping[0]
+            rcu = mapping[1]
+            if recv > 0:
+                mapped_values[recv - 1, rcu] = bf_delay_steps2[idx]
+
+        mapped_values = mapped_values.reshape(
+            (len(recv_proxies), MAX_ANTENNA, N_elements * N_pol)
+        )
+
+        for idx, recv_proxy in enumerate(recv_proxies):
+            self.atomic_read_modify_write_attribute(
+                mapped_values[idx],
+                recv_proxy,
+                "HBAT_bf_delay_steps_RW",
+                cast_type=numpy.int64,
+            )
+
         # Record where we now point to, now that we've updated the weights.
         # Only the entries within the mask have been updated
         mask = self.control.read_parent_attribute(parent, "ANT_mask_RW")