diff --git a/docker/.make/.make-release-support b/docker/.make/.make-release-support
new file mode 100644
index 0000000000000000000000000000000000000000..f1f3a2cb9fb3ea0ce3a173a35c3c9fe316d75156
--- /dev/null
+++ b/docker/.make/.make-release-support
@@ -0,0 +1,106 @@
+#!/bin/bash
+#
+#   Copyright 2015  Xebia Nederland B.V.
+#   Modifications copyright 2019 SKA Organisation
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+function hasChanges() {
+	test -n "$(git status -s .)"
+}
+
+function getRelease() {
+	awk -F= '/^release=/{print $2}' .release
+}
+
+function getBaseTag() {
+		sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release
+}
+
+function getTag() {
+	if [ -z "$1" ] ; then
+		awk -F= '/^tag/{print $2}' .release
+	else
+		echo "$(getBaseTag)$1"
+	fi
+}
+
+function setRelease() {
+	if [ -n "$1" ] ; then
+		sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release
+		sed -i.x -e "s/^release=.*/release=$1/g" .release
+		rm -f .release.x
+		runPreTagCommand "$1"
+	else
+		echo "ERROR: missing release version parameter " >&2
+		return 1
+	fi
+}
+
+function runPreTagCommand() {
+	if [ -n "$1" ] ; then
+		COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release)
+		if [ -n "$COMMAND" ] ; then
+			if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi
+		fi
+	else
+		echo "ERROR: missing release version parameter " >&2
+		return 1
+	fi
+}
+
+function tagExists() {
+	tag=${1:-$(getTag)}
+	test -n "$tag" && test -n "$(git tag | grep "^$tag\$")"
+}
+
+function differsFromRelease() {
+	tag=$(getTag)
+	! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)"
+}
+
+function getVersion() {
+	result=$(getRelease)
+
+	if differsFromRelease; then
+		result="$result-$(git log -n 1 --format=%h .)"
+	fi
+
+	if hasChanges ; then
+		result="$result-dirty"
+	fi
+	echo $result
+}
+
+function nextPatchLevel() {
+	version=${1:-$(getRelease)}
+	major_and_minor=$(echo $version | cut -d. -f1,2)
+	patch=$(echo $version | cut -d. -f3)
+	version=$(printf "%s.%d" $major_and_minor $(($patch + 1)))
+	echo $version
+}
+
+function nextMinorLevel() {
+	version=${1:-$(getRelease)}
+	major=$(echo $version | cut -d. -f1);
+	minor=$(echo $version | cut -d. -f2);
+	version=$(printf "%d.%d.0" $major $(($minor + 1))) ;
+	echo $version
+}
+
+function nextMajorLevel() {
+	version=${1:-$(getRelease)}
+	major=$(echo $version | cut -d. -f1);
+	version=$(printf "%d.0.0" $(($major + 1)))
+	echo $version
+}
diff --git a/docker/.make/Makefile.mk b/docker/.make/Makefile.mk
new file mode 100644
index 0000000000000000000000000000000000000000..c8196593ee69d4cdb75be9779299b1955cd6025c
--- /dev/null
+++ b/docker/.make/Makefile.mk
@@ -0,0 +1,137 @@
+#
+#   Copyright 2015  Xebia Nederland B.V.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+ifeq ($(strip $(PROJECT)),)
+  NAME=$(shell basename $(CURDIR))
+else
+  NAME=$(PROJECT)
+endif
+
+RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support
+
+ifeq ($(strip $(DOCKER_REGISTRY_HOST)),)
+  DOCKER_REGISTRY_HOST = nexus.engageska-portugal.pt
+endif
+
+ifeq ($(strip $(DOCKER_REGISTRY_USER)),)
+  DOCKER_REGISTRY_USER = ska-docker
+endif
+
+IMAGE=$(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(NAME)
+
+#VERSION = release version + git sha
+VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion)
+
+#BASE_VERSION
+BASE_VERSION=$(shell . $(RELEASE_SUPPORT) ; getRelease)
+
+#TAG = project name + release version
+TAG=$(shell . $(RELEASE_SUPPORT); getTag)
+
+#DEFAULT_TAG = image name + BASE_VERSION
+DEFAULT_TAG=$(IMAGE):$(BASE_VERSION)
+
+
+SHELL=/bin/bash
+
+DOCKER_BUILD_CONTEXT=..
+DOCKER_FILE_PATH=Dockerfile
+
+.PHONY: pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \
+	push pre-push do-push post-push
+
+build: pre-build docker-build post-build  ## build the application image
+
+pre-build:
+
+post-build:
+
+pre-push:
+
+post-push:
+
+docker-build: .release
+	@echo "Building image: $(IMAGE):$(VERSION)"
+	@echo "NAME: $(NAME)"
+	docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH) --build-arg DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) --build-arg DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER)
+	@DOCKER_MAJOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f1) ; \
+	DOCKER_MINOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f2) ; \
+	if [ $$DOCKER_MAJOR -eq 1 ] && [ $$DOCKER_MINOR -lt 10 ] ; then \
+		echo docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\
+		docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\
+	else \
+		echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ;\
+		docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ; \
+	fi
+
+release: check-status check-release build push
+
+push: pre-push do-push post-push  ## push the image to the Docker registry
+
+do-push: ## Push the image tagged as $(IMAGE):$(VERSION) and $(DEFAULT_TAG)
+	@echo -e "Tagging: $(IMAGE):$(VERSION) -> $(DEFAULT_TAG)"
+	docker tag $(IMAGE):$(VERSION) $(DEFAULT_TAG)
+	@echo -e "Pushing: $(IMAGE):$(VERSION)"
+	docker push $(IMAGE):$(VERSION)
+	@echo -e "Pushing: $(DEFAULT_TAG)"
+	docker push $(DEFAULT_TAG)
+
+tag_latest: do-push ## Tag the images as latest
+	@echo "Tagging: $(DEFAULT_TAG) -> $(IMAGE):latest"
+	@docker tag $(DEFAULT_TAG) $(IMAGE):latest
+
+push_latest: tag_latest ## Push the image tagged as :latest
+	@echo "Pushing: $(IMAGE):latest"
+	@docker push $(IMAGE):latest
+
+snapshot: build push
+
+showver: .release
+	@. $(RELEASE_SUPPORT); getVersion
+
+bump-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel)
+bump-patch-release: .release tag
+
+bump-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel)
+bump-minor-release: .release tag
+
+bump-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel)
+bump-major-release: .release tag
+
+patch-release: tag-patch-release release
+	@echo $(VERSION)
+
+minor-release: tag-minor-release release
+	@echo $(VERSION)
+
+major-release: tag-major-release release
+	@echo $(VERSION)
+
+tag: TAG=$(shell . $(RELEASE_SUPPORT); getTag $(VERSION))
+tag: check-status
+#	@. $(RELEASE_SUPPORT) ; ! tagExists $(TAG) || (echo "ERROR: tag $(TAG) for version $(VERSION) already tagged in git" >&2 && exit 1) ;
+	@. $(RELEASE_SUPPORT) ; setRelease $(VERSION)
+#	git add .
+#	git commit -m "bumped to version $(VERSION)" ;
+#	git tag $(TAG) ;
+#	@ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi
+
+check-status:
+	@. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ;
+
+check-release: .release
+	@. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ;
+	@. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1)
diff --git a/docker/.release b/docker/.release
new file mode 100644
index 0000000000000000000000000000000000000000..87dca79f7d33c662b775fc4365b82a6e9e2af259
--- /dev/null
+++ b/docker/.release
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the CSP.LMC prototype project
+#
+#
+# Distributed under the terms of the BSD-3-Clause license.
+# See LICENSE.txt for more info.
+
+"""Release information for Python Package"""
+
+name = """csplmc-subelement"""
+version = "0.1.0"
+version_info = version.split(".")
+description = """SKA CSP.LMC Subelement Classes"""
+author = "E.G"
+author_email = "elisabetta.giani@inaf.it"
+license = """BSD-3-Clause"""
+url = """www.tango-controls.org"""
+copyright = """"""
+
+release=0.1.0
+tag=csp-lmc-subelement-0.1.0
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..11f75668e4981db977a215ee9cf095f711561453
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,11 @@
+FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.1 AS buildenv
+FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:9.3.1 AS runtime
+
+# create ipython profile to so that itango doesn't fail if ipython hasn't run yet
+RUN ipython profile create
+#RUN python3 -m pip install --user pytest-forked
+ENV PATH=/home/tango/.local/bin:$PATH
+#install csp-lmc-common with dependencies
+RUN python3 -m pip install -e . --user --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
+
+CMD ["/venv/bin/python", "/app/cspse/lmc/SubElementMaster.py" ]
diff --git a/docker/Makefile b/docker/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..540912c95d020cc24b529552240d9d024f54ffbb
--- /dev/null
+++ b/docker/Makefile
@@ -0,0 +1,197 @@
+#
+# Project makefile for a Tango project. You should normally only need to modify
+# DOCKER_REGISTRY_USER and PROJECT below.
+#
+
+#
+# DOCKER_REGISTRY_HOST, DOCKER_REGISTRY_USER and PROJECT are combined to define
+# the Docker tag for this project. The definition below inherits the standard
+# value for DOCKER_REGISTRY_HOST (=rnexus.engageska-portugal.pt) and overwrites
+# DOCKER_REGISTRY_USER and PROJECT to give a final Docker tag of
+# nexus.engageska-portugal.pt/tango-example/csplmc
+#
+
+DOCKER_REGISTRY_USER:=ska-docker
+PROJECT = csp-lmc-subelement
+
+#
+# include makefile to pick up the standard Make targets, e.g., 'make build'
+# build, 'make push' docker push procedure, etc. The other Make targets
+# ('make interactive', 'make test', etc.) are defined in this file.
+#
+include .make/Makefile.mk
+
+#
+# IMAGE_TO_TEST defines the tag of the Docker image to test
+#
+IMAGE_TO_TEST = $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(PROJECT):latest
+
+#
+# CACHE_VOLUME is the name of the Docker volume used to cache eggs and wheels
+# used during the test procedure. The volume is not used during the build
+# procedure
+#
+CACHE_VOLUME = $(PROJECT)-test-cache
+
+# optional docker run-time arguments
+DOCKER_RUN_ARGS =
+
+#
+# Never use the network=host mode when running CI jobs, and add extra
+# distinguishing identifiers to the network name and container names to
+# prevent collisions with jobs from the same project running at the same
+# time.
+#
+ifneq ($(CI_JOB_ID),)
+NETWORK_MODE := tangonet-$(CI_JOB_ID)
+CONTAINER_NAME_PREFIX := $(PROJECT)-$(CI_JOB_ID)-
+else
+CONTAINER_NAME_PREFIX := $(PROJECT)-
+endif
+
+COMPOSE_FILES := $(wildcard *.yml)
+COMPOSE_FILE_ARGS := $(foreach yml,$(COMPOSE_FILES),-f $(yml))
+
+ifeq ($(OS),Windows_NT)
+    $(error Sorry, Windows is not supported yet)
+else
+	UNAME_S := $(shell uname -s)
+	ifeq ($(UNAME_S),Linux)
+		DISPLAY ?= :0.0
+		NETWORK_MODE ?= host
+		XAUTHORITY_MOUNT := /tmp/.X11-unix:/tmp/.X11-unix
+		XAUTHORITY ?= /hosthome/.Xauthority
+		# /bin/sh (=dash) does not evaluate 'docker network' conditionals correctly
+		SHELL := /bin/bash
+	endif
+	ifeq ($(UNAME_S),Darwin)
+		IF_INTERFACE := $(shell netstat -nr | awk '{ if ($$1 ~/default/) { print $$6} }')
+		DISPLAY := $(shell ifconfig $(IF_INTERFACE) | awk '{ if ($$1 ~/inet$$/) { print $$2} }'):0
+		# network_mode = host doesn't work on MacOS, so fix to the internal network
+		NETWORK_MODE := tangonet
+		XAUTHORITY_MOUNT := $(HOME):/hosthome:ro
+		XAUTHORITY := /hosthome/.Xauthority
+	endif
+endif
+
+#
+# When running in network=host mode, point devices at a port on the host
+# machine rather than at the container.
+#
+ifeq ($(NETWORK_MODE),host)
+TANGO_HOST := $(shell hostname):10000
+MYSQL_HOST := $(shell hostname):3306
+else
+# distinguish the bridge network from others by adding the project name
+NETWORK_MODE := $(NETWORK_MODE)-$(PROJECT)
+TANGO_HOST := $(CONTAINER_NAME_PREFIX)databaseds:10000
+MYSQL_HOST := $(CONTAINER_NAME_PREFIX)tangodb:3306
+endif
+
+
+DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) XAUTHORITY=$(XAUTHORITY) TANGO_HOST=$(TANGO_HOST) \
+		NETWORK_MODE=$(NETWORK_MODE) XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) MYSQL_HOST=$(MYSQL_HOST) \
+		DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) \
+		CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) COMPOSE_IGNORE_ORPHANS=true
+
+#
+# Defines a default make target so that help is printed if make is called
+# without a target
+#
+.DEFAULT_GOAL := help
+
+#
+# defines a function to copy the ./test-harness directory into the container
+# and then runs the requested make target in the container. The container is:
+#
+#   1. attached to the network of the docker-compose test system
+#   2. uses a persistent volume to cache Python eggs and wheels so that fewer
+#      downloads are required
+#   3. uses a transient volume as a working directory, in which untarred files
+#      and test output can be written in the container and subsequently copied
+#      to the host
+#
+make = tar -c test-harness/ | \
+	   docker run -i --rm --network=$(NETWORK_MODE) \
+	   -e TANGO_HOST=$(TANGO_HOST) \
+	   -v $(CACHE_VOLUME):/home/tango/.cache \
+	   -v /build -w /build -u tango $(DOCKER_RUN_ARGS) $(IMAGE_TO_TEST) \
+	   bash -c "sudo chown -R tango:tango /build && \
+	   tar x --strip-components 1 --warning=all && \
+	   make TANGO_HOST=$(TANGO_HOST) $1"
+
+test: DOCKER_RUN_ARGS = --volumes-from=$(BUILD)
+test: build up ## test the application
+	@echo "BUILD: $(BUILD)"
+	$(INIT_CACHE)
+	$(call make,test); \
+	  status=$$?; \
+	  rm -fr build; \
+          #docker-compose $(COMPOSE_FILE_ARGS) logs;
+	  docker cp $(BUILD):/build .; \
+	  docker rm -f -v $(BUILD); \
+	  $(MAKE) down; \
+	  exit $$status
+
+lint: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) 
+lint: build up ## lint the application (static code analysis)
+	$(INIT_CACHE)
+	$(call make,lint); \
+	status=$$?; \
+	docker cp $(BUILD):/build .; \
+	$(MAKE) down; \
+	exit $$status	  
+
+pull:  ## download the application image
+	docker pull $(IMAGE_TO_TEST)
+
+up: build  ## start develop/test environment
+ifneq ($(NETWORK_MODE),host)
+	docker network inspect $(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create $(NETWORK_MODE))
+endif
+	#$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) pull
+	#to pull only the mid-cbf-mcs image remove comment on row below.
+	#docker pull $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/mid-cbf-mcs:latest
+	$(DOCKER_COMPOSE_ARGS) docker-compose -f se-tangodb.yml up -d
+	# put a sleep to wait TANGO DB 
+	@sleep 10
+	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up -d 
+
+piplock: build  ## overwrite Pipfile.lock with the image version
+	docker run $(IMAGE_TO_TEST) cat /app/Pipfile.lock > $(CURDIR)/Pipfile.lock
+
+interactive: up
+interactive:  ## start an interactive session using the project image (caution: R/W mounts source directory to /app)
+	docker run --rm -it -p 3000:3000 --name=$(CONTAINER_NAME_PREFIX)dev -e TANGO_HOST=$(TANGO_HOST) --network=$(NETWORK_MODE) \
+	  -v $(CURDIR):/app $(IMAGE_TO_TEST) /bin/bash
+
+down:  ## stop develop/test environment and any interactive session
+	docker ps | grep $(CONTAINER_NAME_PREFIX)dev && docker stop $(PROJECT)-dev || true
+	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down
+ifneq ($(NETWORK_MODE),host)
+	docker network inspect $(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm $(NETWORK_MODE)) || true
+endif
+
+dsconfigdump: up ## dump the entire configuration to the file dsconfig.json
+	docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump
+	docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump > dsconfig.json
+
+dsconfigadd: up ## Add a configuration json file (environment variable DSCONFIG_JSON_FILE) to the database
+	-docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -u -w -a $(DSCONFIG_JSON_FILE)
+
+dsconfigcheck: up ## check a json file (environment variable DSCONFIG_JSON_FILE) according to the project lib-maxiv-dsconfig json schema
+	-docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -a $(DSCONFIG_JSON_FILE)
+
+help:  ## show this help.
+	@grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+.PHONY: all test up down help
+
+# Creates Docker volume for use as a cache, if it doesn't exist already
+INIT_CACHE = \
+	docker volume ls | grep $(CACHE_VOLUME) || \
+	docker create --name $(CACHE_VOLUME) -v $(CACHE_VOLUME):/cache $(IMAGE_TO_TEST)
+
+# http://cakoose.com/wiki/gnu_make_thunks
+BUILD_GEN = $(shell docker create -v /build $(IMAGE_TO_TEST))
+BUILD = $(eval BUILD := $(BUILD_GEN))$(BUILD)
diff --git a/docker/config/csplmc_dsconfig.json b/docker/config/csplmc_dsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..83dbae68ba3d9bf32fe5e2e589b86ba3bf171144
--- /dev/null
+++ b/docker/config/csplmc_dsconfig.json
@@ -0,0 +1,240 @@
+{
+    "servers": {
+        "CspSubElementMaster": {
+            "master": {
+                "CspSubElementMaster": {
+                    "subelement/sub_elt/master": {
+                        "attribute_properties": {
+                            "adminMode": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ],
+				"__value": [
+				    "0"
+				]
+                            }, 
+                            "healthState": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ]
+                            } 
+                        }, 
+                        "properties": {
+			    "Rack": [
+				"subelement/rack/01",
+				"subelement/rack/02",
+				"subelement/rack/03",
+				"subelement/rack/04"
+			    ],
+                            "polled_attr": [
+                                "healthstate", 
+                                "1000", 
+                                "adminmode", 
+                                "1000", 
+                                "state", 
+				"1000",
+                                "oncommandprogress", 
+                                "2000", 
+                                "offcommandprogress", 
+                                "2000", 
+                                "standbycommandprogress", 
+                                "2000", 
+                                "oncmdtimeoutexpired", 
+                                "1000", 
+                                "offcmdtimeoutexpired", 
+                                "1000", 
+                                "standbycmdtimeoutexpired", 
+                                "1000", 
+                                "oncmdfailure", 
+                                "1000", 
+                                "offcmdfailure", 
+                                "1000", 
+                                "standbycmdfailure", 
+                                "1000" 
+                            ]
+                        }
+                    }
+                }
+            }
+        }, 
+        "CspCapabilityMonitor": {
+            "searchbeams": {
+                "CspCapabilityMonitor": {
+                    "subelement/capability/pss_pipeline_monitor": {
+                        "attribute_properties": {
+                            "adminMode": {
+				"__value": [
+				    "0"
+				]
+                            } 
+                        }, 
+                        "properties": {
+			    "CapabilityDevices": [
+				"subelement/pipelines/0001",
+				"subelement/pipelines/0002",
+				"subelement/pipelines/0003"
+			    ]
+                        }
+                    }
+                }
+            },
+            "timingbeams": {
+                "CspCapabilityMonitor": {
+                    "subelement/capability/pstbeams_monitor": {
+                        "attribute_properties": {
+                            "adminMode": {
+				"__value": [
+				    "0"
+				]
+                            } 
+                        }, 
+                        "properties": {
+			    "CapabilityDevices": [
+				"subelement/pstbeam/01",
+				"subelement/pstbeam/02",
+				"subelement/pstbeam/03"
+			    ]
+                        }
+                    }
+                }
+            },
+            "vlbibeams": {
+                "CspCapabilityMonitor": {
+                    "subelement/capability/vlbi_beams_monitor": {
+                        "attribute_properties": {
+                            "adminMode": {
+				"__value": [
+				    "0"
+				]
+                            } 
+                        }, 
+                        "properties": {
+			    "CapabilityDevices": [
+				"subelement/vlbi_beam/01",
+				"subelement/vlbi_beam/02",
+				"subelement/vlbi_beam/03"
+			    ]
+                        }
+                    }
+                }
+            }
+	},
+        "CspSubElementSubarray": {
+            "subarray1": {
+                "CspSubElementSubarray": {
+                    "subelement/sub_elt/subarray_01": {
+                        "attribute_properties": {
+                            "adminMode": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ],
+				"__value": [
+				    "0"
+				]
+                            }, 
+                            "healthState": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ]
+                            }, 
+                            "obsState": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ]
+                            } 
+                        }, 
+                        "properties": {
+                            "SubID": [
+                                "1"
+                            ], 
+                            "polled_attr": [
+                                "state", 
+                                "1000", 
+                                "healthstate", 
+                                "1000", 
+                                "adminmode", 
+                                "1000", 
+                                "obsstate", 
+                                "1000",
+                                "obsmode", 
+                                "1000"
+                            ]
+                        }
+                    }
+                }
+            },
+            "subarray2": {
+                "SubElementSubarray": {
+                    "subelement/sub_elt/subarray_02": {
+                        "attribute_properties": {
+                            "adminMode": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ],
+				"__value": [
+				    "0"
+				]
+                            }, 
+                            "healthState": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ]
+                            }, 
+                            "obsState": {
+                                "abs_change": [
+                                    "-1", 
+                                    "1"
+                                ]
+                            } 
+                        }, 
+                        "properties": {
+                            "SubID": [
+                                "2"
+                            ], 
+                            "polled_attr": [
+                                "state", 
+                                "1000", 
+                                "healthstate", 
+                                "1000", 
+                                "adminmode", 
+                                "1000", 
+                                "obsstate", 
+                                "1000",
+                                "obsmode", 
+                                "1000"
+                            ]
+                        }
+                    }
+                }
+            }
+        }, 
+        "DataBaseds": {
+            "2": {
+                "DataBase": {
+                    "sys/database/2": {}
+                }
+            }
+        }, 
+        "TangoAccessControl": {
+            "1": {
+                "TangoAccessControl": {
+                    "sys/access_control/1": {}
+                }
+            }
+        }, 
+        "TangoTest": {
+            "test": {
+                "TangoTest": {
+                    "sys/tg_test/1": {}
+                }
+            }
+        }
+    }
+}
diff --git a/docker/se-lmc.yml b/docker/se-lmc.yml
new file mode 100644
index 0000000000000000000000000000000000000000..af6db57a2492da01ab2e6d467551c0db3822d105
--- /dev/null
+++ b/docker/se-lmc.yml
@@ -0,0 +1,67 @@
+#
+# Docker compose file for TANGO database and database device server
+#
+# Defines:
+#   - tangodb: MariaDB database with TANGO schema
+#   - databaseds: TANGO database device server
+#   - rsyslog-csplmc: rsyslog service for logger
+#   - cspmaster: CspMaster device
+#
+# Requires:
+#   - None
+#
+version: '2.2'
+
+services:
+  se_dsconfig:
+    image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest
+    network_mode: ${NETWORK_MODE}
+    container_name: ${CONTAINER_NAME_PREFIX}se_dsconfig
+    depends_on:
+      - databaseds
+    environment:
+      - TANGO_HOST=${TANGO_HOST}
+    command: >
+      sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict --
+             json2tango -w -a -u data/config/csplmc_dsconfig.json && sleep infinity"
+    volumes:
+      - .:/data
+
+  sesubarray01:
+    image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest
+    network_mode: ${NETWORK_MODE}
+    container_name: ${CONTAINER_NAME_PREFIX}sesubarray01
+    depends_on:
+      - se_dsconfig
+      - semaster
+    environment:
+      - TANGO_HOST=${TANGO_HOST}
+    command: >
+      sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict --
+             retry --max=5 -- tango_admin --ping-device subelement/sub_elt/master &&\
+             /venv/bin/python -m cspse.lmc.SubElementSubarray subarray1"
+  sesubarray02:
+    image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest
+    network_mode: ${NETWORK_MODE}
+    container_name: ${CONTAINER_NAME_PREFIX}sesubarray02
+    depends_on:
+      - se_dsconfig
+      - semaster
+    environment:
+      - TANGO_HOST=${TANGO_HOST}
+    command: >
+      sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict --
+             retry --max=5 -- tango_admin --ping-device subelement/sub_elt/master &&\
+             /venv/bin/python -m cspse.lmc.SubElementSubarray subarray2"
+
+  semaster:
+    image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest
+    network_mode: ${NETWORK_MODE}
+    container_name: ${CONTAINER_NAME_PREFIX}semaster
+    depends_on:
+      - se_dsconfig
+    environment:
+      - TANGO_HOST=${TANGO_HOST}
+    command: >
+      sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- CspSubElementMaster master"
+
diff --git a/docker/se-tangodb.yml b/docker/se-tangodb.yml
new file mode 100644
index 0000000000000000000000000000000000000000..72090df60df3c46b64a78aa810ee6c5b07ca5629
--- /dev/null
+++ b/docker/se-tangodb.yml
@@ -0,0 +1,50 @@
+#
+# Docker compose file for TANGO database and database device server
+#
+# Defines:
+#   - tangodb: MariaDB database with TANGO schema
+#   - databaseds: TANGO database device server
+#
+# Requires:
+#   - None
+#
+version: '2.2'
+volumes:
+  se-tangodb: {}
+
+services:
+  tangodb:
+    image: nexus.engageska-portugal.pt/ska-docker/tango-db:latest
+    network_mode: ${NETWORK_MODE}
+    container_name: ${CONTAINER_NAME_PREFIX}tangodb
+    environment:
+      - MYSQL_ROOT_PASSWORD=secret
+      - MYSQL_DATABASE=tango
+      - MYSQL_USER=tango
+      - MYSQL_PASSWORD=tango
+    volumes:
+      - se-tangodb:/var/lib/mysql
+
+  databaseds:
+    image: nexus.engageska-portugal.pt/ska-docker/tango-cpp:latest
+    depends_on:
+      - tangodb
+    network_mode: ${NETWORK_MODE}
+    container_name: ${CONTAINER_NAME_PREFIX}databaseds
+    environment:
+      - MYSQL_HOST=${MYSQL_HOST}
+      - MYSQL_DATABASE=tango
+      - MYSQL_USER=tango
+      - MYSQL_PASSWORD=tango
+      - TANGO_HOST=${TANGO_HOST}
+    entrypoint:
+      - /usr/local/bin/wait-for-it.sh
+      - ${MYSQL_HOST}
+      - --timeout=70
+      - --strict
+      - --
+      - /usr/local/bin/DataBaseds
+      - "2"
+      - -ORBendPoint
+      - giop:tcp::10000
+
diff --git a/docker/test-harness/Makefile b/docker/test-harness/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f951fe00248c44767e0e81434564b7c0f5f6512d
--- /dev/null
+++ b/docker/test-harness/Makefile
@@ -0,0 +1,31 @@
+# Use bash shell with pipefail option enabled so that the return status of a
+# piped command is the value of the last (rightmost) commnand to exit with a
+# non-zero status. This lets us pipe output into tee but still exit on test
+# failures.
+SHELL = /bin/bash
+.SHELLFLAGS = -o pipefail -c
+
+all: test lint
+
+# wait for the device to be available before beginning the test
+# A temporary volume is mounted at /build when 'make test' is executing.
+# The following steps copy across useful output to this volume which can
+# then be extracted to form the CI summary for the test procedure.
+test:
+	# option -k 'dir_name' excludes 'dir_name' contents 
+	cd /app && python setup.py test | tee setup_py_test.stdout
+	mkdir -p /build/reports && \
+        if [ -d /build ]; then \
+                mv /app/setup_py_test.stdout /build/csp-lmc-subelement-setup-test.stdout; \
+                mv /app/htmlcov /build/csp-lmc-subelement_htmlcov; \
+                mv /app/build/reports/csp-lmc-subelement-unit-tests.xml /build/reports; \
+                mv /app/coverage.xml /build; \
+        fi;
+lint:
+	pip3 install pylint2junit; \
+        mkdir -p /build/reports; \
+        cd /app && pylint --output-format=parseable csp_lmc_common | tee /build/csp-lmc-subelement-code-analysis.stdout; \
+        cd /app && pylint --output-format=pylint2junit.JunitReporter cspse/lmc > /build/reports/csp-lmc-subelement-linting.xml;
+
+.PHONY: all test lint
+
diff --git a/docker/test-harness/README.md b/docker/test-harness/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a3c9a496bbd5104392d08378de98af67f349183f
--- /dev/null
+++ b/docker/test-harness/README.md
@@ -0,0 +1,3 @@
+This directory is uploaded to the container when 'make test' is executed. Files
+in this directory will be found inside /build once uploaded to the container.
+
diff --git a/setup.cfg b/setup.cfg
index 428ca67b3a5faefd4367cd0cd16a75311aee9d45..90ecf5789f9198495ae56daa35e81460c6f240bf 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -11,8 +11,16 @@ source = cspse
 
 [tool:pytest]
 testpaths = tests
-addopts = --cov --json-report --json-report-file=htmlcov/report.json --cov-report term --cov-report html --cov-report xml --pylint --pylint-error-types=EF --junitxml=./build/reports/unit-tests.xml
+addopts = --cov=cspse 
+          --json-report 
+          --json-report-file=htmlcov/report.json 
+          --cov-report=term 
+          --cov-report=html 
+          --cov-report=xml 
+          --junitxml=build/reports/csp-lmc-subelement-unit-tests.xml
 
+junit_family=legacy
+console_output_style = progress
 # Define `python setup.py build_sphinx`
 [build_sphinx]
 source-dir = docs
diff --git a/setup.py b/setup.py
index 0f0f99b65bf5829eea247102e0b000f28d65f84a..25947e60b6af751f95f34c693e69441b56e50bae 100644
--- a/setup.py
+++ b/setup.py
@@ -1,16 +1,25 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-from setuptools import setup
+import os
+import sys
+from setuptools import setup, find_packages
+
+setup_dir = os.path.dirname(os.path.abspath(__file__))
+
+# make sure we use latest info from local code
+sys.path.insert(0, setup_dir)
+
+INFO = {}
 
 with open('README.md') as readme_file:
-    readme = readme_file.read()
+    long_description = readme_file.read()
 
 RELEASE_FILENAME = os.path.join(setup_dir, 'cspse','lmc','release.py')
 exec(open(RELEASE_FILENAME).read(), INFO)
 setup(
-    name=INFO['name']
-    version=INFO['version']
+    name=INFO['name'],
+    version=INFO['version'],
     description=INFO['description'],
     author=INFO['author'],
     author_email=INFO['author_email'],
@@ -20,7 +29,6 @@ setup(
     long_description=long_description,
     keywords="csp lmc ska tango",
     include_package_data=True,
-    license="BSD license",
     zip_safe=False,
     classifiers=[
         'Development Status :: 3 - Alpha',
@@ -34,7 +42,7 @@ setup(
     install_requires=[
         'pytango >=9.3.1',
         'future',
-        'lmcbaseclasses > 0.5.0',
+        'csp-lmc-common > 0.5.0',
     ],  
     setup_requires=[
         # dependency for `python setup.py test`
@@ -50,6 +58,11 @@ setup(
         'pycodestyle',
         'mock'
     ],
+    entry_points={
+        "console_scripts": [
+            "CspSubElementMaster=cspse.lmc.subelement_master:main",
+        ]
+    },
     extras_require={
         'dev':  ['prospector[with_pyroma]', 'yapf', 'isort'],
     }