diff --git a/docker-compose/.env b/docker-compose/.env
index de1f54725ceedea52e8dd6ded8849327627cf7bf..c1956e315f8cde0d48b4b5279807025bede69261 100644
--- a/docker-compose/.env
+++ b/docker-compose/.env
@@ -13,3 +13,8 @@ TANGO_JAVA_VERSION=9.3.6
 TANGO_POGO_VERSION=9.6.34
 TANGO_REST_VERSION=1.14.6
 TANGO_STARTER_VERSION=2021-05-28
+
+PG_SUPERUSER_PASSWORD=password
+PG_HDB_PASSWORD=hdbpp
+MYSQL_ROOT_PASSWORD=secret
+MYSQL_PASSWORD=tango
diff --git a/docker-compose/archiver-timescale.yml b/docker-compose/archiver-timescale.yml
index 8b7c78263f658ee2bd3d2a25ee9ad681550d6d84..056016b55e4098bc6d3fd0c3fa27607ebacf0d2c 100644
--- a/docker-compose/archiver-timescale.yml
+++ b/docker-compose/archiver-timescale.yml
@@ -13,7 +13,8 @@ services:
     depends_on:
       - databaseds
     environment:
-      - POSTGRES_PASSWORD=password
+      - POSTGRES_PASSWORD=${PG_SUPERUSER_PASSWORD}
+      - PG_HDB_PASSWORD=${PG_HDB_PASSWORD}
       - TANGO_HOST=${TANGO_HOST}
     logging:
       driver: syslog
diff --git a/docker-compose/archiver.yml b/docker-compose/archiver.yml
index e0d5583a5924639127615d1ec85aa57ac44569b5..f1f2a1ec65dd4259b99e675c43cb7500862049f4 100644
--- a/docker-compose/archiver.yml
+++ b/docker-compose/archiver.yml
@@ -11,11 +11,11 @@ services:
     depends_on:
       - databaseds
     environment:
-      - MYSQL_ROOT_PASSWORD=secret
+      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
       - MYSQL_DATABASE=hdbpp
       - MYSQL_HOST=archiver-maria-db:3306
       - MYSQL_USER=tango
-      - MYSQL_PASSWORD=tango
+      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
       - TANGO_HOST=${TANGO_HOST}
     logging:
       driver: syslog
diff --git a/docker-compose/timescaledb/Dockerfile b/docker-compose/timescaledb/Dockerfile
index 5a8ecde23c3d69b9b665ac28dea3d5d7d5714ffd..86e7a820c3fc4e4ba0eaa8edaa9c7e421c87231f 100644
--- a/docker-compose/timescaledb/Dockerfile
+++ b/docker-compose/timescaledb/Dockerfile
@@ -1,7 +1,7 @@
 FROM timescale/timescaledb:latest-pg12
 
 
-COPY resources/01_admin.sql docker-entrypoint-initdb.d/002_admin.sql
+COPY resources/01_admin.sh docker-entrypoint-initdb.d/002_admin.sh
 COPY resources/02_hdb_schema.sql docker-entrypoint-initdb.d/003_hdb_schema.sql
 COPY resources/03_hdb_roles.sql docker-entrypoint-initdb.d/004_hdb_roles.sql
 COPY resources/04_hdb_ext_aggregates.sql docker-entrypoint-initdb.d/005_hdb_ext_aggregates.sql
diff --git a/docker-compose/timescaledb/resources/01_admin.sql b/docker-compose/timescaledb/resources/01_admin.sh
similarity index 50%
rename from docker-compose/timescaledb/resources/01_admin.sql
rename to docker-compose/timescaledb/resources/01_admin.sh
index 51848f45f786225fe226bf21be024599b73534eb..5cf506b30d9a992e47520b98ae23aa8a41dc98a3 100644
--- a/docker-compose/timescaledb/resources/01_admin.sql
+++ b/docker-compose/timescaledb/resources/01_admin.sh
@@ -1,4 +1,8 @@
-CREATE ROLE hdb_admin WITH LOGIN PASSWORD 'hdbpp';
+#!/bin/bash
+
+psql << EOF
+CREATE ROLE hdb_admin WITH LOGIN PASSWORD '${PG_HDB_PASSWORD}';
 ALTER USER hdb_admin CREATEDB;
 ALTER USER hdb_admin CREATEROLE;
 ALTER USER hdb_admin SUPERUSER;
+EOF
diff --git a/docs/source/devices/boot.rst b/docs/source/devices/boot.rst
index 84f2f5a0ad4ed7f21148ed24555a27f8e8c15181..cbb76e4877e767f87893956d99a782dc99122633 100644
--- a/docs/source/devices/boot.rst
+++ b/docs/source/devices/boot.rst
@@ -6,7 +6,7 @@ Boot
 The ``boot == DeviceProxy("STAT/Boot/1")`` device is responsible for (re)starting and initialising the other devices. Devices which are not reachable, for example because their docker container is explicitly stopped, are skipped during initialisation. This device provides the following commands:
 
 :boot(): Stop and start the other devices in the correct order, set their default values, and command them to initialise their hardware. This procedure runs asynchronously, causing this command to return immediately. Initialisation is aborted if an error is encountered.
-wwww
+
   :returns: ``None``
 
 :resume(): Resume an earlier boot attempt: start initialising devices from the first one that failed to initialise, instead of from scratch.
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
index 1ed4fceacb85e6862c6f49d725fd4c53eb096081..631c6fa3a3f17571970c2debd638c6c0bf5c7624 100644
--- a/docs/source/faq.rst
+++ b/docs/source/faq.rst
@@ -63,6 +63,8 @@ You should now be able to run X11 applications from WSL and Docker. Try running
 SSTs/XSTs
 --------------------------------------------------------------------------------------------------------------
 
+.. _statistics-debugging:
+
 Some SSTs/XSTs packets do arrive, but not all, and/or the matrices remain zero?
 ``````````````````````````````````````````````````````````````````````````````````````````````````````````````
 
diff --git a/docs/source/index.rst b/docs/source/index.rst
index b81b9c631131a08319d1ec2e07f868455a9a956a..119d95164313538606e9f310f2e65ca6aca233d8 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -26,6 +26,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st
    devices/sst-xst
    devices/configure
    configure_station
+   signal_chain
    developer
    faq
 
diff --git a/docs/source/signal_chain.rst b/docs/source/signal_chain.rst
new file mode 100644
index 0000000000000000000000000000000000000000..4dc110c9430214916d068830f71b952551797de4
--- /dev/null
+++ b/docs/source/signal_chain.rst
@@ -0,0 +1,112 @@
+Signal Chain
+====================================
+
+The station hardware collectively processes the analog signals received by the antena dipoles, resulting in either statistics (SST/BST/XST) or beamlets. This signal chain can be monitored as it flows through the hardware as follows:
+
+RECV: Data reception
+------------------------------------
+
+The RCU boards can receive input from three sources: an LBA, an HBA tile, and a signal or noise generator. 
+
+A typical station has ``rcu == 32`` RCUs, each of which has ``antenna == 3`` inputs.
+
+Input
+```````````
+
+* ``recv.RCU_PWR_ANT_on_R[rcu][antenna]`` indicates whether each antenna is powered. If not, the RCU will emit *zeroes* if an LBA or HBA tile is attached.
+
+* ``recv.RCU_PWR_ANALOG_on_R[rcu]`` indicates whether the analog power is enabled to each RCU. If not, the RCU will emit *zeroes* if an LBA or HBA tile is attached.
+
+* ``recv.RCU_PWR_DIGITAL_on_R[rcu]`` indicates whether the digital power is enabled to each RCU. If not, the RCU will emit *zeroes*.
+
+Processing
+```````````
+
+* ``recv.RCU_band_select_R[rcu][antenna]`` indicates which band is selected for each antenna (1 = 10MHz, 2 = 30MHz), which affects its sensitivity.
+
+* ``recv.RCU_attenuator_dB_R[rcu][antenna]`` is the antennuation for each antenna, which affects its *amplitude*.
+
+* ``recv.RCU_DTH_ON_R[rcu][antenna]`` indicates whether the dither source is on, which affects the signal quality:
+
+    * ``recv.RCU_DTH_freq_R[rcu][antenna]`` is the frequency of the dither source, in Hz.
+
+SDP: Digital signal processing
+------------------------------------
+
+The SDP can process three kinds of input: antenna data, generated waveforms, and no input, and process this into four kinds of output: beamlets, BSTs, SSTs, and XSTs.
+
+A typical station has ``fpga == 16`` FPGAs, each of which has ``input == 12`` inputs.
+
+Input
+```````````
+
+* ``sdp.FPGA_wg_enable_R[fpga][input]``, indicates whether waveforms are generated (True) or antenna input is used (False):
+
+    * ``sdp.FPGA_wg_frequency_R[fpga][input]`` indicates the frequency of the generated wave,
+    * ``sdp.FPGA_wg_amplitude_R[fpga][input]`` indicates the amplitude of the generated wave,
+    * ``sdp.FPGA_wg_phase_R[fpga][input]`` indicates the phase of the generated wave.
+
+* ``sdp.FPGA_signal_input_mean_R[fpga][input]`` shows the input signal strength compared to full scale (FS) = 8192.
+
+* ``sdp.FPGA_signal_input_rms_R[fpga][input]`` shows the root means square of the input.
+
+The signal input mean and rms behave as follows:
+
++--------------------+----------------+--------------------------+----------------------------+
+| Input              | Configuration  | Signal Mean              | Signal RMS                 |
++====================+================+==========================+============================+
+| None               |                | 0                        | 0                          |
++--------------------+----------------+--------------------------+----------------------------+
+| Waveform Generator | frequency = 0  | amplitude * sin(phase)   | amplitude * 8192 / √2      |
++--------------------+----------------+--------------------------+----------------------------+
+| Waveform Generator | frequency > 0  | 0                        | amplitude * 8192 / √2      |
++--------------------+----------------+--------------------------+----------------------------+
+| Antenna            |                | > 0                      | > 0                        |
++--------------------+----------------+--------------------------+----------------------------+
+
+Processing
+```````````
+
+* ``sdp.FPGA_processing_enable_R[fpga]`` indicates whether the FPGA processes its input. If not, *zeroes* are produced for all outputs.
+
+* ``sdp.FPGA_signal_input_samples_delay_R[fpga][input]`` indicates a per-input delay to be applied, in units of 5 ns. This results in a frequency-dependent *phase* change of the input.
+
+* ``sdp.FPGA_subband_weights_R[fpga][input * subband]`` indicates a per-subband and per-input weight factor. 8192 is unit weight, 0 means the input will be erased. Anything else results in a *phase* and/or *amplitude* change of the input.
+
+SST output
+```````````
+
+* ``sst.FPGA_sst_offload_enable_R`` indicates whether SSTs are emitted at all.
+
+* ``sst.nof_valid_payloads_R[fpga]`` is the number of packets received from each FPGA.
+
+* ``sst.sst_R[fpga * input][subband]`` is the *amplitude* of the signal over the configured integration interval:
+
+    * ``sst.FPGA_sst_offload_weighted_subbands_R[fpga * input]`` indicates whether the ``sdp.FPGA_subband_weights_R`` are applied when calculating the SSTs,
+    * ``sst.integration_interval_R[fpga * input]`` is the integration interval of the provided SSTs,
+    * ``sst.sst_timestamp_R[fpga * input]`` is when the SSTs were received,
+    * ``sst.last_packet_timestamp_R`` is when the last SST from any FPGA was received.
+
+If the SSTs are not received, or filled with zeroes, see also :ref:`statistics-debugging`.
+
+XST output
+```````````
+
+* ``xst.FPGA_xst_offload_enable_R`` indicates whether XSTs are emitted at all.
+
+* ``xst.FPGA_xst_processing_enable_R`` indicates whether XSTs are computed. If not, *zeroes* are produced.
+
+* ``xst.nof_valid_payloads_R[fpga]`` is the number of packets received from each FPGA.
+
+* ``xst.xst_phase_R[fpga * input][fpga * input]`` is the *phase* angle between each pair of inputs, and is defined only for ``[a][b]`` with ``a <= b``:
+
+    * ``xst.FPGA_xst_subband_select_R[fpga][8]`` contains the subband for which to compute the XSTs. Currently, one subband is supported, which should be on index ``[fpga][1]``,
+    * ``xst.FPGA_integration_interval_R[fpga]`` is the integration interval for the XSTs,
+    * ``xst.xst_timestamp_R[136]`` is when the XSTs were received, per block (see below),
+    * ``xst.last_packet_timestamp_R`` is when the last XST from any FPGA was received.
+
+* ``xst.xst_amplitude_R[fpga * input][fpga * input]`` is the correlated *amplitude* between two inputs, and is subject to the same restrictions as ``xst.xst_phase_R``.
+
+If the XSTs are not received at, or filled with zeroes, see also :ref:`statistics-debugging`.
+
+Each block contains 12x12 XSTs, and are indexed in the same order baselines are, see https://git.astron.nl/lofar2.0/tango/-/blob/master/tangostationcontrol/tangostationcontrol/common/baselines.py on how to convert baseline indices to and from input pairs.
diff --git a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
index 4dd07132621f660b825b57c2ff0683fa3b6b85d4..cc0b35730427440bec8b34c2afde756b1b461557 100644
--- a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
+++ b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
@@ -29,7 +29,7 @@ class attribute_wrapper(attribute):
         # see also https://pytango.readthedocs.io/en/stable/server_api/server.html?highlight=devlong#module-tango.server for
         # more details about type conversion Python/numpy -> PyTango
         if "numpy" not in str(datatype) and datatype != str:
-            raise ValueError("Attribute needs to be a Tango-supported numpy or str type, but has type \"%s\"" % (datatype,))
+            raise ValueError(f"Attribute needs to be a Tango-supported numpy or str type, but has type {datatype}")
 
         """
         Numpy has a depracated string type called numpy.str_.
@@ -82,8 +82,7 @@ class attribute_wrapper(attribute):
                 try:
                     return device.value_dict[self]
                 except Exception as e:
-                    raise Exception("Attribute read_RW function error, attempted to read value_dict with key: `%s`, are you sure this exists?",
-                                    self) from e
+                    raise Exception(f"Attribute read_RW function error, attempted to read value_dict with key: `{self}`, are you sure this exists?") from e
 
             @only_in_states([DevState.STANDBY, DevState.ON], log=False)
             @fault_on_error()
diff --git a/tangostationcontrol/tangostationcontrol/clients/opcua_client.py b/tangostationcontrol/tangostationcontrol/clients/opcua_client.py
index f0c246a691ea163a7549715bee5d15393cc6674d..75d7da17007e12e06379fe9a96986f86310a5c3a 100644
--- a/tangostationcontrol/tangostationcontrol/clients/opcua_client.py
+++ b/tangostationcontrol/tangostationcontrol/clients/opcua_client.py
@@ -106,7 +106,7 @@ class OPCUAConnection(AsyncCommClient):
             # so cannot be used here. see https://reference.opcfoundation.org/v104/Core/docs/Part6/7.1.3/
             _ = await self.client.get_namespace_array()
         except Exception as e:
-            raise IOError("Lost connection to server %s: %s", self._servername(), e)
+            raise IOError(f"Lost connection to server {self._servername()}: {e}")
 
     def get_node_path(self, annotation):
         """
@@ -116,13 +116,13 @@ class OPCUAConnection(AsyncCommClient):
         if isinstance(annotation, dict):
             # check if required path inarg is present
             if annotation.get('path') is None:
-                raise Exception("OPC-ua mapping requires a path argument in the annotation, was given: %s", annotation)
+                raise Exception(f"OPC-ua mapping requires a path argument in the annotation, was given: {annotation}")
 
             path = annotation.get("path")  # required
         elif isinstance(annotation, list):
             path = annotation
         else:
-            raise Exception("OPC-ua mapping requires either a list of the path or dict with the path. Was given %s type containing: %s", type(annotation), annotation)
+            raise Exception(f"OPC-ua mapping requires either a list of the path or dict with the path. Was given {type(annotation)} type containing: {annotation}")
 
 
         # add path prefix
@@ -169,8 +169,8 @@ class OPCUAConnection(AsyncCommClient):
         try:
             node = await self.get_node(path)
         except Exception as e:
-            logger.exception("Could not get node: %s on server %s", path, self._servername())
-            raise Exception("Could not get node: %s on server %s", path, self._servername()) from e
+            logger.exception(f"Could not get node: {path} on server {self._servername()}")
+            raise Exception(f"Could not get node: {path} on server {self._servername()}") from e
 
         # get all the necessary data to set up the read/write functions from the attribute_wrapper
         dim_x = attribute.dim_x
diff --git a/tangostationcontrol/tangostationcontrol/clients/statistics_client.py b/tangostationcontrol/tangostationcontrol/clients/statistics_client.py
index 2790197bdb90f2483d872f0dfd5978fa088d4980..16d46bc71bbeba33c66aa8aa590f301cd0de0fa8 100644
--- a/tangostationcontrol/tangostationcontrol/clients/statistics_client.py
+++ b/tangostationcontrol/tangostationcontrol/clients/statistics_client.py
@@ -109,7 +109,7 @@ class StatisticsClient(AsyncCommClient):
                 def read_function():
                     return numpy.uint64(self._queue_fill_percentage(self.tcp.queue))
             else:
-                raise ValueError("Unknown queue parameter requested: %s" % parameter)
+                raise ValueError(f"Unknown queue parameter requested: {parameter}")
         elif annotation["type"] == "replicator":
             if parameter == "clients":
                 def read_function():
@@ -124,7 +124,7 @@ class StatisticsClient(AsyncCommClient):
                 def read_function():
                     return numpy.uint64(self.tcp.nof_tasks_pending)
             else:
-                raise ValueError("Unknown replicator parameter requested: %s" % parameter)
+                raise ValueError(f"Unknown replicator parameter requested: {parameter}")
 
         def write_function(value):
             """
diff --git a/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py b/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py
index 8b820cc765daa193fe142f4a3f49ef7a3f643c76..ec895fed7bc357bc03f2ade1866066756d23b1ba 100644
--- a/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py
+++ b/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py
@@ -346,7 +346,7 @@ class TCPReplicator(Thread, StatisticsClientThread):
     def clients(self):
         """ Return the list of connected clients. """
 
-        return ["%s:%s" % client.transport.get_extra_info('peername') for client in self._connected_clients]
+        return [f"{client.transport.get_extra_info('peername')}" for client in self._connected_clients]
 
     @property
     def nof_tasks_pending(self):
diff --git a/tangostationcontrol/tangostationcontrol/common/lofar_logging.py b/tangostationcontrol/tangostationcontrol/common/lofar_logging.py
index cfff61966f11a06c2fcf0e336da32eba24bfbfe2..673af8f959edbdc748545bdcf6f08388c3fa944b 100644
--- a/tangostationcontrol/tangostationcontrol/common/lofar_logging.py
+++ b/tangostationcontrol/tangostationcontrol/common/lofar_logging.py
@@ -208,7 +208,7 @@ def log_exceptions(logger: logging.Logger=None):
             try:
                 return func(self, *args, **kwargs)
             except Exception as e:
-                (logger or logging.getLogger()).exception("Unhandled exception: %s: %s", e.__class__.__name__, e)
+                (logger or logging.getLogger()).exception(f"Unhandled exception: {e.__class__.__name__}: {e}")
 
                 # we can log but we cannot hide
                 raise
diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0c87cc56c040ce971ac012fcee534a61bb711ecf
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/devices/README.md
@@ -0,0 +1,15 @@
+# Devices
+
+This directory contains the sources for our custom Tango devices.
+
+## Adding a new device
+
+If a new device is added, it will (likely) need to be referenced in several places. Adjust or add the following files (referenced from the repository root), following the pattern shown by the devices already there:
+
+- Adjust `CDB/LOFAR_ConfigDb.json` to create the device in the Tango device database,
+- Adjust `docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py` to make an alias for it available in Jupyter,
+- Adjust `tangostationcontrol/tangostationcontrol/devices/boot.py` to add the device to the station initialisation sequence,
+- Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned,
+- Add to `tangostationcontrol/tangostationcontrol/integration_test/devices/` to add an integration test,
+- Adjust `sbin/run_integration_test.sh` to have the device started when running the integration tests,
+- Add to `docs/source/devices/` to mention the device in the end-user documentation.
diff --git a/tangostationcontrol/tangostationcontrol/devices/device_decorators.py b/tangostationcontrol/tangostationcontrol/devices/device_decorators.py
index bb04cdbca5026c9485026856faf80b59fcae4c18..bf6340fc55edeec0d0c44da7cc139aeb297f2176 100644
--- a/tangostationcontrol/tangostationcontrol/devices/device_decorators.py
+++ b/tangostationcontrol/tangostationcontrol/devices/device_decorators.py
@@ -19,9 +19,9 @@ def only_in_states(allowed_states, log=True):
                 return func(self, *args, **kwargs)
 
             if log:
-                logger.warning("Illegal command: Function %s can only be called in states %s. Current state: %s" % (func.__name__, allowed_states, self.get_state()))
+                logger.warning(f"Illegal command: Function {func.__name__} can only be called in states {allowed_states}. Current state: {self.get_state()}")
 
-            Except.throw_exception("IllegalCommand", "Function can only be called in states %s. Current state: %s" % (allowed_states, self.get_state()), func.__name__)
+            Except.throw_exception(f"IllegalCommand: Function {func.__name__} can only be called in states {allowed_states}. Current state: {self.get_state()}")
 
         return state_check_wrapper
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index 5070b8cef0f54e5d4165701ccaefe0a637faf2d7..e6f0d1f36ed16790f5532b7f9cafce3419ff8579 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -61,6 +61,9 @@ class RECV(opcua_device):
     RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=32, fget=lambda self: (2 * self.proxy.RCU_LED_green_on_R + 4 * self.proxy.RCU_LED_red_on_R).astype(numpy.uint32))
 
     ANT_mask_RW                  = attribute_wrapper(comms_annotation=["ANT_mask_RW"               ],datatype=numpy.bool_  , dims=(3,32), access=AttrWriteType.READ_WRITE)
+
+    # The HBAT beamformer delays represent 32 delays for each of the 96 inputs.
+    # The 32 delays deconstruct as delays[polarisation][dipole], and each delay is the number of 'delay steps' to apply (0.5ns for HBAT1).
     HBAT_BF_delays_R             = attribute_wrapper(comms_annotation=["HBAT_BF_delays_R"          ],datatype=numpy.int64  , dims=(32,96))
     HBAT_BF_delays_RW            = attribute_wrapper(comms_annotation=["HBAT_BF_delays_RW"         ],datatype=numpy.int64  , dims=(32,96), access=AttrWriteType.READ_WRITE)
     HBAT_LED_on_R                = attribute_wrapper(comms_annotation=["HBAT_LED_on_R"             ],datatype=numpy.bool_  , dims=(32,96))
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index ed970bc5681ec341a0bc62d0f37c82523f595f50..b613a3af451c1e8ecb1ae6d120aff5c042c200d8 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -78,6 +78,12 @@ class SDP(opcua_device):
         default_value=[0] * 16
     )
 
+    FPGA_signal_input_samples_delay_RW_default = device_property(
+        dtype='DevVarULongArray',
+        mandatory=False,
+        default_value=[[0] * 12] * 16
+    )
+
     FPGA_subband_weights_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
index 18f000697b5351487ce4c75c0796e2cc81c28740..640ea13015fe712fff54c122efd9ebeeff406957 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
@@ -97,7 +97,8 @@ class SST(Statistics):
     nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(SSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
     # latest SSTs
     sst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(SSTCollector.MAX_SUBBANDS, SSTCollector.MAX_INPUTS), datatype=numpy.uint64)
-    # reported timestamp for each row in the latest SSTs
+    # reported timestamp
+    # for each row in the latest SSTs
     sst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.uint64)
     # integration interval for each row in the latest SSTs
     integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.float32)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py
index 29503ca58ef25fcd3cb0b4ced4ff09ddaa62ecc6..5c00c90b1dff70e5aa281ee84093454c44b4ef96 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py
@@ -158,11 +158,11 @@ class XSTCollector(StatisticsCollector):
         for antenna in (0,1):
             if fields.first_baseline[antenna] + fields.nof_signal_inputs >= self.MAX_INPUTS:
                 # packet describes an input that is out of bounds for us
-                raise ValueError("Packet describes {0} x {0} baselines starting at {1}, but we are limited to describing MAX_INPUTS={2}".format(fields.nof_signal_inputs, fields.first_baseline, self.MAX_INPUTS))
+                raise ValueError(f"Packet describes {fields.nof_signal_inputs} x {fields.nof_signal_inputs} baselines starting at {fields.first_baseline}, but we are limited to describing MAX_INPUTS={self.MAX_INPUTS}")
 
             # the blocks of baselines need to be tightly packed, and thus be provided at exact intervals
             if fields.first_baseline[antenna] % self.BLOCK_LENGTH != 0:
-                raise ValueError("Packet describes baselines starting at %s, but we require a multiple of BLOCK_LENGTH=%d" % (fields.first_baseline, self.MAX_INPUTS))
+                raise ValueError(f"Packet describes baselines starting at {fields.first_baseline}, but we require a multiple of BLOCK_LENGTH={self.MAX_INPUTS}")
 
         # Make sure we always have a baseline (a,b) with a>=b. If not, we swap the indices and mark that the data must be conjugated and transposed when processed.
         first_baseline = fields.first_baseline
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py
index c98ae9b5bdc604e8a55480cc5473e658b10cefa1..59c74e296c2eebdd677d448bdae523be8d149934 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py
@@ -75,13 +75,13 @@ class StatisticsPacket(object):
                 "Invalid SDP statistics packet: packet marker (first byte) is {}, not one of 'SBX'.".format(
                     self.marker))
 
+    # format string for the header, see unpack below
+    header_format = ">cBL HHB BHL BBH HQ"
+    header_size = struct.calcsize(header_format)
+
     def unpack(self):
         """ Unpack the packet into properties of this object. """
 
-        # format string for the header, see unpack below
-        self.header_format = ">cBL HHB BHL BBH HQ"
-        self.header_size = struct.calcsize(self.header_format)
-
         # unpack fields
         try:
             (self.marker_raw,
@@ -335,11 +335,35 @@ def main(args=None, **kwargs):
     import sys
     import pprint
 
-    # read all of stdin, even though we only parse the first packet. we're too lazy to intelligently decide when
-    # the packet is complete and can stop reading.
-    data = sys.stdin.buffer.read()
-    packet = SSTPacket(data)
-
-    # print header & payload
-    pprint.pprint(packet.header())
-    pprint.pprint(packet.payload)
+    # packet counter
+    nr = 0
+
+    # byte offset in the stream
+    offset = 0
+
+    while True:
+        # read just the header
+        header = sys.stdin.buffer.read(StatisticsPacket.header_size)
+        if not header:
+            break
+
+        # read the payload
+        packet = StatisticsPacket(header)
+        payload_size = packet.expected_size() - len(header)
+        payload = sys.stdin.buffer.read(payload_size)
+
+        # construct the packet based on type
+        if packet.marker == 'S':
+            packet = SSTPacket(header + payload)
+        elif packet.marker == 'X':
+            packet = XSTPacket(header + payload)
+        elif packet.marker == 'B':
+            packet = BSTPacket(header + payload)
+
+        # print header
+        print(f"# Packet {nr} starting at offset {offset}")
+        pprint.pprint(packet.header())
+
+        # increment counters
+        nr += 1
+        offset += len(header) + len(payload)
diff --git a/tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py b/tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py
index 7c18baa9a6954e03ab07eb85fe35b6e342867650..9a0919457bb692c614a5edc6f425664202435d9b 100644
--- a/tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py
+++ b/tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py
@@ -60,7 +60,7 @@ class SNMP_client(CommClient):
         """
         Try to connect to the client
         """
-        logger.debug("Connecting to community: %s, host: %s", self.community, self.host)
+        logger.debug(f"Connecting to community: {self.community}, host: {self.host}")
 
         self.connected = True
         return True
diff --git a/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py b/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py
index 67ff6377cdf90326d7a9fa33a015c1ac5861064d..eaaa2d13ef1c139e7b924c474810ae2e18b29bf0 100644
--- a/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py
+++ b/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py
@@ -28,7 +28,7 @@ def timeit(method):
         sizeMb = process.memory_info().rss / 1024 / 1024
         sizeMbStr = "{0:,}".format(round(sizeMb, 2))
 
-        logger.debug('Time taken = %s,  %s  ,size = %s MB' % (e - s, method.__name__,  sizeMbStr))
+        logger.debug(f'Time taken = {e - s},  {method.__name__}  ,size = {sizeMbStr} MB')
         return RESULT
     return timed
 
diff --git a/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_server.py b/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_server.py
index 45624761519287b13bbce5c73cf8d8cb7dff9201..3f114bad951334f76db8c111c710a9771903643b 100644
--- a/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_server.py
+++ b/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_server.py
@@ -20,7 +20,7 @@ class UDP_Server:
         server_address = (self.ip, self.port)
         s.bind(server_address)
         print("Do Ctrl+c to exit the program !!")
-        print("\n\n####### Server is listening on %s - port %s #######" % (self.ip,self.port))
+        print(f"\n\n####### Server is listening on {self.ip} - port {self.port} #######")
 
         while True:
             
diff --git a/tangostationcontrol/tangostationcontrol/toolkit/archiver_base.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver_base.py
index 1b63db5f5389a00e56decc88f901c5b0ee461f01..4440957bb8546a9e42638a0a6b441e43119fa601 100644
--- a/tangostationcontrol/tangostationcontrol/toolkit/archiver_base.py
+++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver_base.py
@@ -31,8 +31,7 @@ class Attribute(Base):
     
     
     def __repr__(self):
-        return "<Attribute(fullname='%s',data_type ='%s',ttl='%s',facility ='%s',domain ='%s',family ='%s',member ='%s',name ='%s')>" \
-                % (self.att_name,self.att_conf_data_type_id,self.att_ttl,self.facility,self.domain,self.family,self.member,self.name)
+        return f"<Attribute(fullname='{self.att_name}',data_type ='{self.att_conf_data_type_id}',ttl='{self.att_ttl}',facility ='{elf.facility}',domain ='{self.domain}',family ='{self.family}',member ='{self.member}',name ='{self.name}')>"
     
 class DataType(Base):
     """
@@ -45,8 +44,7 @@ class DataType(Base):
     data_type = Column(String)
     
     def __repr__(self):
-        return "<DataType(type='%s')>" \
-                % (self.data_type)
+        return f"<DataType(type='{self.data_type}')>"
 
 class Scalar(Base):
     """
@@ -83,8 +81,7 @@ class Scalar_Boolean_RO(Scalar_Boolean):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Scalar_Boolean_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Boolean_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Boolean_RW(Scalar_Boolean):
     """
@@ -95,8 +92,7 @@ class Scalar_Boolean_RW(Scalar_Boolean):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Scalar_Boolean_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Boolean_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_UChar(Scalar):
     """
@@ -115,8 +111,7 @@ class Scalar_UChar_RO(Scalar_UChar):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Scalar_UChar_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_UChar_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_UChar_RW(Scalar_UChar):
     """
@@ -127,8 +122,7 @@ class Scalar_UChar_RW(Scalar_UChar):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Scalar_UChar_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_UChar_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Double(Scalar):
     """
@@ -147,8 +141,7 @@ class Scalar_Double_RO(Scalar_Double):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Double_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Double_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Double_RW(Scalar_Double):
     """
@@ -159,8 +152,7 @@ class Scalar_Double_RW(Scalar_Double):
     value_w = Column(DOUBLE)
 
     def __repr__(self):
-        return "<Scalar_Double_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Double_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Encoded(Scalar):
     """
@@ -179,8 +171,7 @@ class Scalar_Encoded_RO(Scalar_Encoded):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Encoded_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Encoded_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Encoded_RW(Scalar_Encoded):
     """
@@ -191,8 +182,7 @@ class Scalar_Encoded_RW(Scalar_Encoded):
     value_w = Column(BLOB)
 
     def __repr__(self):
-        return "<Scalar_Encoded_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Encoded_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Enum(Scalar):
     """
@@ -211,8 +201,7 @@ class Scalar_Enum_RO(Scalar_Enum):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Enum_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Enum_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Enum_RW(Scalar_Enum):
     """
@@ -223,8 +212,7 @@ class Scalar_Enum_RW(Scalar_Enum):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Scalar_Enum_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Enum_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Float(Scalar):
     """
@@ -243,8 +231,7 @@ class Scalar_Float_RO(Scalar_Float):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Float_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Float_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Float_RW(Scalar_Float):
     """
@@ -255,8 +242,7 @@ class Scalar_Float_RW(Scalar_Float):
     value_w = Column(FLOAT)
 
     def __repr__(self):
-        return "<Scalar_Float_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Float_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Long64(Scalar):
     """
@@ -275,8 +261,7 @@ class Scalar_Long64_RO(Scalar_Long64):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Long64_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Long64_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Long64_RW(Scalar_Long64):
     """
@@ -287,8 +272,7 @@ class Scalar_Long64_RW(Scalar_Long64):
     value_w = Column(BIGINT)
 
     def __repr__(self):
-        return "<Scalar_Long64_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Long64_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_ULong64(Scalar):
     """
@@ -307,8 +291,7 @@ class Scalar_ULong64_RO(Scalar_ULong64):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_ULong64_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_ULong64_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_ULong64_RW(Scalar_ULong64):
     """
@@ -319,8 +302,7 @@ class Scalar_ULong64_RW(Scalar_ULong64):
     value_w = Column(INTEGER)
 
     def __repr__(self):
-        return "<Scalar_ULong64_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_ULong64_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 
 class Scalar_Long(Scalar):
@@ -340,8 +322,7 @@ class Scalar_Long_RO(Scalar_Long):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Long_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Long_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Long_RW(Scalar_Long):
     """
@@ -352,8 +333,7 @@ class Scalar_Long_RW(Scalar_Long):
     value_w = Column(INTEGER)
 
     def __repr__(self):
-        return "<Scalar_Long_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Long_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_ULong(Scalar):
     """
@@ -372,8 +352,7 @@ class Scalar_ULong_RO(Scalar_ULong):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_ULong_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_ULong_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_ULong_RW(Scalar_ULong):
     """
@@ -384,8 +363,7 @@ class Scalar_ULong_RW(Scalar_ULong):
     value_w = Column(INTEGER)
 
     def __repr__(self):
-        return "<Scalar_ULong_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_ULong_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Short(Scalar):
     """
@@ -404,8 +382,7 @@ class Scalar_Short_RO(Scalar_Short):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_Short_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Short_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_Short_RW(Scalar_Short):
     """
@@ -416,8 +393,7 @@ class Scalar_Short_RW(Scalar_Short):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Scalar_Short_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_Short_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_State(Scalar):
     """
@@ -436,8 +412,7 @@ class Scalar_State_RO(Scalar_State):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_State_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_State_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_State_RW(Scalar_State):
     """
@@ -448,8 +423,7 @@ class Scalar_State_RW(Scalar_State):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Scalar_State_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_State_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_String(Scalar):
     """
@@ -468,8 +442,7 @@ class Scalar_String_RO(Scalar_String):
     __table_args__ = {'extend_existing': True}
 
     def __repr__(self):
-        return "<Scalar_String_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Scalar_String_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Scalar_String_RW(Scalar_String):
     """
@@ -480,8 +453,7 @@ class Scalar_String_RW(Scalar_String):
     value_w = Column(String)
 
     def __repr__(self):
-        return "<Scalar_String_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',value_r='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.value_r,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Scalar_String_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',value_r='{self.value_r}',value_w='{self.value_w}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array(Base):
     """
@@ -518,8 +490,7 @@ class Array_Boolean_RO(Array_Boolean):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Boolean_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Boolean_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Boolean_RW(Array_Boolean):
     """
@@ -532,8 +503,7 @@ class Array_Boolean_RW(Array_Boolean):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Array_Boolean_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Boolean_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_UChar(Array):
     """
@@ -552,8 +522,7 @@ class Array_UChar_RO(Array_UChar):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_UChar_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_UChar_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_UChar_RW(Array_Boolean):
     """
@@ -566,8 +535,7 @@ class Array_UChar_RW(Array_Boolean):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Array_UChar_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_UChar_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Double(Array):
     """
@@ -586,8 +554,7 @@ class Array_Double_RO(Array_Double):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Double_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Double_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Double_RW(Array_Double):
     """
@@ -600,8 +567,7 @@ class Array_Double_RW(Array_Double):
     value_w = Column(DOUBLE)
 
     def __repr__(self):
-        return "<Array_Double_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Double_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Encoded(Array):
     """
@@ -620,8 +586,7 @@ class Array_Encoded_RO(Array_Encoded):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Encoded_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Encoded_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Encoded_RW(Array_Encoded):
     """
@@ -634,8 +599,7 @@ class Array_Encoded_RW(Array_Encoded):
     value_w = Column(BLOB)
 
     def __repr__(self):
-        return "<Array_Encoded_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Encoded_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Enum(Array):
     """
@@ -654,8 +618,7 @@ class Array_Enum_RO(Array_Enum):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Enum_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Enum_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Enum_RW(Array_Enum):
     """
@@ -668,8 +631,7 @@ class Array_Enum_RW(Array_Enum):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Array_Enum_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Enum_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Float(Array):
     """
@@ -688,8 +650,7 @@ class Array_Float_RO(Array_Float):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Float_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Float_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Float_RW(Array_Float):
     """
@@ -702,8 +663,7 @@ class Array_Float_RW(Array_Float):
     value_w = Column(FLOAT)
 
     def __repr__(self):
-        return "<Array_Float_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Float_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Long64(Array):
     """
@@ -722,8 +682,7 @@ class Array_Long64_RO(Array_Long64):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Long64_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Long64_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Long64_RW(Array_Long64):
     """
@@ -736,8 +695,7 @@ class Array_Long64_RW(Array_Long64):
     value_w = Column(BIGINT)
 
     def __repr__(self):
-        return "<Array_Long64_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Long64_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_ULong64(Array):
     """
@@ -756,8 +714,7 @@ class Array_ULong64_RO(Array_ULong64):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_ULong64_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_ULong64_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_ULong64_RW(Array_ULong64):
     """
@@ -770,8 +727,7 @@ class Array_ULong64_RW(Array_ULong64):
     value_w = Column(INTEGER)
 
     def __repr__(self):
-        return "<Array_ULong64_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_ULong64_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 
 class Array_Long(Array):
@@ -791,8 +747,7 @@ class Array_Long_RO(Array_Long):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Long_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Long_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Long_RW(Array_Long):
     """
@@ -805,8 +760,7 @@ class Array_Long_RW(Array_Long):
     value_w = Column(INTEGER)
 
     def __repr__(self):
-        return "<Array_Long_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Long_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_ULong(Array):
     """
@@ -825,8 +779,7 @@ class Array_ULong_RO(Array_ULong):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_ULong_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_ULong_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_ULong_RW(Array_ULong):
     """
@@ -839,8 +792,7 @@ class Array_ULong_RW(Array_ULong):
     value_w = Column(INTEGER)
 
     def __repr__(self):
-        return "<Array_ULong_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_ULong_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Short(Array):
     """
@@ -859,8 +811,7 @@ class Array_Short_RO(Array_Short):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_Short_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_Short_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_Short_RW(Array_Short):
     """
@@ -873,8 +824,7 @@ class Array_Short_RW(Array_Short):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Array_Short_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_Short_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_State(Array):
     """
@@ -893,8 +843,7 @@ class Array_State_RO(Array_State):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_State_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_State_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_State_RW(Array_State):
     """
@@ -907,8 +856,7 @@ class Array_State_RW(Array_State):
     value_w = Column(Integer)
 
     def __repr__(self):
-        return "<Array_State_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_State_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_String(Array):
     """
@@ -927,8 +875,7 @@ class Array_String_RO(Array_String):
     __table_args__ = {'extend_existing': True}
     
     def __repr__(self):
-        return "<Array_String_RO(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.quality,self.att_error_desc_id)
+        return f"<Array_String_RO(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 class Array_String_RW(Array_String):
     """
@@ -941,8 +888,7 @@ class Array_String_RW(Array_String):
     value_w = Column(String)
 
     def __repr__(self):
-        return "<Array_String_RW(att_conf_id='%s',data_time='%s',recv_time='%s',insert_time='%s',idx='%s',dim_x_r='%s',dim_y_r='%s',value_r='%s',dim_x_w='%s',dim_y_w='%s',value_w='%s',quality='%s',att_error_desc_id='%s')>" \
-                % (self.att_conf_id,self.data_time,self.recv_time,self.insert_time,self.idx,self.dim_x_r,self.dim_y_r,self.value_r,self.dim_x_w,self.dim_y_w,self.value_w,self.quality,self.att_error_desc_id)
+        return f"<Array_String_RW(att_conf_id='{self.att_conf_id}',data_time='{self.data_time}',recv_time='{self.recv_time}',insert_time='{self.insert_time}',idx='{self.idx}',dim_x_r='{self.dim_x_r}',dim_y_r='{self.dim_y_r}',value_r='{self.value_r}',dim_x_w='{self.dim_x_w}',dim_y_w='{self.dim_y_w}',value_w='%{self.value_w},quality='{self.quality}',att_error_desc_id='{self.att_error_desc_id}')>"
 
 def get_class_by_tablename(tablename: str):
     """
diff --git a/tangostationcontrol/tangostationcontrol/toolkit/udp_simulator.py b/tangostationcontrol/tangostationcontrol/toolkit/udp_simulator.py
index 9720cff969f4db0a1f406359512036357b224076..32dc156e27e7816a805d430f6fe5730f90bd0c3e 100644
--- a/tangostationcontrol/tangostationcontrol/toolkit/udp_simulator.py
+++ b/tangostationcontrol/tangostationcontrol/toolkit/udp_simulator.py
@@ -7,8 +7,8 @@ UDP_IP = "127.0.0.1"
 UDP_PORT = 5001
 MESSAGE = "{}".format(i)
 
-print("UDP target IP: %s" % UDP_IP)
-print("UDP target port: %s" % UDP_PORT)
+print(f"UDP target IP: {UDP_IP}")
+print(f"UDP target port: {UDP_PORT}")
 
 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # create UDP socket