diff --git a/devices/util/hardware_device.py b/devices/util/hardware_device.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0c9154c703a7cb82c42e9cdd7db76d68a011e05
--- /dev/null
+++ b/devices/util/hardware_device.py
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the PCC project
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+""" PCC Device Server for LOFAR2.0
+
+"""
+
+# PyTango imports
+from tango.server import Device, command
+from tango import DevState, DebugIt
+# Additional import
+
+from util.attribute_wrapper import attribute_wrapper
+from util.lofar_logging import log_exceptions
+
+__all__ = ["hardware_device"]
+
+from util.wrappers import only_in_states, fault_on_error
+
+#@log_exceptions()
+class hardware_device(Device):
+    """
+
+    **Properties:**
+
+    States are as follows:
+        INIT    = Device is initialising.
+        STANDBY = Device is initialised, but pends external configuration and an explicit turning on,
+        ON      = Device is fully configured, functional, controls the hardware, and is possibly actively running,
+        FAULT   = Device detected an unrecoverable error, and is thus malfunctional,
+        OFF     = Device is turned off, drops connection to the hardware,
+
+    The following state transitions are implemented:
+        boot -> OFF:     Triggered by tango.  Device will be instantiated,
+        OFF  -> INIT:    Triggered by device. Device will initialise (connect to hardware, other devices),
+        INIT -> STANDBY: Triggered by device. Device is initialised, and is ready for additional configuration by the user,
+        STANDBY -> ON:   Triggered by user.   Device reports to be functional,
+        * -> FAULT:      Triggered by device. Device has degraded to malfunctional, for example because the connection to the hardware is lost,
+        * -> FAULT:      Triggered by user.   Emulate a forced malfunction for integration testing purposes,
+        * -> OFF:        Triggered by user.   Device is turned off. Triggered by the Off() command,
+        FAULT -> INIT:   Triggered by user.   Device is reinitialised to recover from an error,
+
+        The user triggers their transitions by the commands reflecting the target state (Initialise(), On(), Fault()).
+    """
+
+    @classmethod
+    def attr_list(cls):
+        """ Return a list of all the attribute_wrapper members of this class. """
+        return [v for k, v in cls.__dict__.items() if type(v) == attribute_wrapper]
+
+    def setup_value_dict(self):
+        """ set the initial value for all the attribute wrapper objects"""
+
+        self.value_dict = {i: i.initial_value() for i in self.attr_list()}
+
+    def init_device(self):
+        """ Instantiates the device in the OFF state. """
+
+        # NOTE: Will delete_device first, if necessary
+        Device.init_device(self)
+
+        self.set_state(DevState.OFF)
+
+    # --------
+    # Commands
+    # --------
+
+    @command()
+    @only_in_states([DevState.FAULT, DevState.OFF])
+    @DebugIt()
+    @fault_on_error()
+    @log_exceptions()
+    def Initialise(self):
+        """
+        Command to ask for initialisation of this device. Can only be called in FAULT or OFF state.
+
+        :return:None
+        """
+        self.set_state(DevState.INIT)
+        self.setup_value_dict()
+
+        self.configure_for_initialise()
+
+        self.set_state(DevState.STANDBY)
+
+    @command()
+    @only_in_states([DevState.STANDBY])
+    @DebugIt()
+    @fault_on_error()
+    @log_exceptions()
+    def On(self):
+        """
+        Command to ask for initialisation of this device. Can only be called in FAULT or OFF state.
+
+        :return:None
+        """
+        self.configure_for_on()
+        self.set_state(DevState.ON)
+
+    @command()
+    @DebugIt()
+    @log_exceptions()
+    def Off(self):
+        """
+        Command to ask for shutdown of this device.
+
+        :return:None
+        """
+        if self.get_state() == DevState.OFF:
+            # Already off. Don't complain.
+            return
+
+        # Turn off
+        self.set_state(DevState.OFF)
+
+        self.configure_for_off()
+
+        # Turn off again, in case of race conditions through reconnecting
+        self.set_state(DevState.OFF)
+
+    @command()
+    @only_in_states([DevState.ON, DevState.INIT, DevState.STANDBY])
+    @DebugIt()
+    @log_exceptions()
+    def Fault(self):
+        """
+        FAULT state is used to indicate our connection with the OPC-UA server is down.
+
+        This device will try to reconnect once, and transition to the ON state on success.
+
+        If reconnecting fails, the user needs to call Initialise() to retry to restart this device.
+
+        :return:None
+        """
+        self.configure_for_fault()
+        self.set_state(DevState.FAULT)
+
+
+    # functions that can be overloaded
+    def configure_for_fault(self):
+        pass
+    def configure_for_off(self):
+        pass
+    def configure_for_on(self):
+        pass
+    def configure_for_initialise(self):
+        pass
+
+    def always_executed_hook(self):
+        """Method always executed before any TANGO command is executed."""
+        pass
+
+    def delete_device(self):
+        """Hook to delete resources allocated in init_device.
+
+        This method allows for any memory or other resources allocated in the
+        init_device method to be released.  This method is called by the device
+        destructor and by the device Init command (a Tango built-in).
+        """
+        self.debug_stream("Shutting down...")
+
+        self.Off()
+        self.debug_stream("Shut down.  Good bye.")