diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..131d9b6cc8e86bfbe3b9e8199a1d2823df569bde
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+**/env
+**/__pycache__
+**/*.pyc
diff --git a/README.md b/README.md
index fa336c344a5eb3393c7f466c7826394cc856f7e2..afb32b2b2ad7924a923fd8cb301722bba3b9553f 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,66 @@ Python OPC-UA server to control the I2C devices in the LTS.
 
 + opcuserv.py: OPC-UA server that expose (visible) variables and methods.
 
-# LTS structure:
+# Prerequisites
+
+## Requirements
+
+This Python3 code uses other Python3 modules:
+
+- opcua
+- pyyaml
+- numpy
+
+We recommend to install a virtual environment and then install the dependencies there.  For convenience we have added the relevant modules to the file `requirements.txt` that can be used to install them with pip3: `python3 -m pip install -r requirements.txt`
+
+Below are step-by-step instructions that show how to install the dependencies neatly in a Python3 virtual environment.
+
+```bash
+# Create a Python3 virtual environment with the name "env"
+python3 -m venv env
+# Activate the virtual environment
+. env/bin/activate
+# Update the already installed modules in the virtual environment since they are usually outdated
+python3 -m pip install --upgrade pip wheel
+# Deactivate the virtual environment and start it again
+deactivate
+. env/bin/activate
+# And finally install the module dependencies
+python3 -m pip install -r requirements.txt
+```
+
+# Execute it
+
+The software can be simply executed with Python3:  `python3 opcuaserv.py`
+
+Optional parameters are explained when the `-h` or `--help` parameter is supplied:
+
+```bash
+python3 opcuaserv.py --help
+cryptography is not installed, use of crypto disabled
+cryptography is not installed, use of crypto disabled
+usage: opcuaserv.py [-h] [-s] [--no-lib-hack] [-p PORT]
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -s, --simulator       Do not connect to I2c, but simulate behaviour.
+  --no-lib-hack         Do not require a hacked opcua library. Breaks behaviour.
+  -p PORT, --port PORT  Port number to listen on [4842].
+```
+
+# LTS structure
 
 Raspberry pi (LTS_pypcc.yaml -> I2C controller on raspberry pi)
+
 > Control PCB (LTS_switch.yaml -> I2C switch)
->> RCU2 PCB   (LTS_RCUx.yaml  -> I2C devices)
->>> RCU2 Dither source (LTS_RCU2_dither.yaml -> I2C bitbang)
->>
->>> ADC (LTS_RCU2_ADC.yaml -> SPI bitbang2)
->>
->> Clock PCB (LTS_clk.yaml -> I2C device)
->>> PLL (LTS_clkPLL.yaml -> SPI bitbang1)
+>
+> > RCU2 PCB   (LTS_RCUx.yaml  -> I2C devices)
+> >
+> > > RCU2 Dither source (LTS_RCU2_dither.yaml -> I2C bitbang)
+> >
+> > > ADC (LTS_RCU2_ADC.yaml -> SPI bitbang2)
+> >
+> > Clock PCB (LTS_clk.yaml -> I2C device)
+> >
+> > > PLL (LTS_clkPLL.yaml -> SPI bitbang1)
+
diff --git a/yaml/LTS_RCU2L.yaml b/YAML/LTS_RCU2L.yaml
similarity index 100%
rename from yaml/LTS_RCU2L.yaml
rename to YAML/LTS_RCU2L.yaml
diff --git a/yaml/LTS_RCU2_ADC.yaml b/YAML/LTS_RCU2_ADC.yaml
similarity index 100%
rename from yaml/LTS_RCU2_ADC.yaml
rename to YAML/LTS_RCU2_ADC.yaml
diff --git a/yaml/LTS_RCU2_dither.yaml b/YAML/LTS_RCU2_dither.yaml
similarity index 100%
rename from yaml/LTS_RCU2_dither.yaml
rename to YAML/LTS_RCU2_dither.yaml
diff --git a/yaml/LTS_RCU2dig.yaml b/YAML/LTS_RCU2dig.yaml
similarity index 100%
rename from yaml/LTS_RCU2dig.yaml
rename to YAML/LTS_RCU2dig.yaml
diff --git a/yaml/LTS_clk.yaml b/YAML/LTS_clk.yaml
similarity index 100%
rename from yaml/LTS_clk.yaml
rename to YAML/LTS_clk.yaml
diff --git a/yaml/LTS_clkPLL.yaml b/YAML/LTS_clkPLL.yaml
similarity index 100%
rename from yaml/LTS_clkPLL.yaml
rename to YAML/LTS_clkPLL.yaml
diff --git a/yaml/LTS_pypcc.yaml b/YAML/LTS_pypcc.yaml
similarity index 100%
rename from yaml/LTS_pypcc.yaml
rename to YAML/LTS_pypcc.yaml
diff --git a/yaml/LTS_switch.yaml b/YAML/LTS_switch.yaml
similarity index 100%
rename from yaml/LTS_switch.yaml
rename to YAML/LTS_switch.yaml
diff --git a/hwdev.py b/hwdev.py
index 78305f67473abb9805771afb2237b4bdba3534a8..30362bc8e82d62e05c22321f6ce21488028948ad 100644
--- a/hwdev.py
+++ b/hwdev.py
@@ -1,7 +1,7 @@
 import yaml;
 import importlib
 import sys, inspect
-YAMLDIR='yaml/'
+YAMLDIR='YAML/'
 class hwdev:
     def __init__(self,configfile):
         print("Loading:",configfile)
@@ -36,7 +36,7 @@ class hwdev:
 
     def GetVarValue(self,name,value,I2Ccallback):
         return False
-    
+
     def SetVarValue(self,name,value,I2Ccallback):
         return False
 
@@ -58,4 +58,4 @@ def Find(L,name,value):
   for x in L:
     if x[name]==value:
         return x;
-  return False;
\ No newline at end of file
+  return False;
diff --git a/opcuaserv.py b/opcuaserv.py
index 9c243fe88f465876c92fdf1a43da0064fd1508ed..103493bdb4ef71ce63c3f437cb3cb28433047af9 100644
--- a/opcuaserv.py
+++ b/opcuaserv.py
@@ -5,17 +5,25 @@ sys.path.insert(0, "..")
 import time
 from opcua import ua, Server
 from datetime import datetime;
+import argparse
 
+parser = argparse.ArgumentParser()
+parser.add_argument("-s", "--simulator", help="Do not connect to I2c, but simulate behaviour.", action="store_true")
+parser.add_argument("--no-lib-hack", help="Do not require a hacked opcua library. Breaks behaviour.", action="store_true")
+parser.add_argument("-p", "--port", help="Port number to listen on [%(default)s].", type=int, default=4842)
+args = parser.parse_args()
 
-import pypcc;
-#import pypcc_test as pypcc;
-P1=pypcc.pypcc("LTS_pypcc.yaml")
+if args.simulator:
+    import pypcc_test as pypcc
+else:
+    import pypcc
 
+P1=pypcc.pypcc("LTS_pypcc.yaml")
 
 if True:
 # setup our server
     server = Server()
-    server.set_endpoint("opc.tcp://0.0.0.0:4842/PCC/")
+    server.set_endpoint("opc.tcp://0.0.0.0:{}/PCC/".format(args.port))
 
     idx = server.register_namespace("http://lofar.eu")
 #    uri = "http://examples.freeopcua.github.io"
@@ -77,8 +85,12 @@ class SubHandler(object):
 #        print(Vars_R,Vars_R.values())
         for vname2,myvar2,oldvalue in Vars_R.values():
             if vname2==vname:
-              res=P1.GetVarValue(vname,val)
-              print("Read callback",vname,": Result:",res,oldvalue)
+              if args.simulator:
+                res=True
+                print("Simulating fallthrough _RW->_R for",vname,": Result:",res,oldvalue)
+              else:
+                res=P1.GetVarValue(vname,val)
+                print("Read callback",vname,": Result:",res,oldvalue)
               if res:
                 myvar2.Value.Value=(val[0] if len(val)==1 else val)
                 myvar2.SourceTimestamp = datetime.utcnow()
@@ -113,7 +125,8 @@ def AddVar(name,dtype=0,RW=0,cnt=1):
         Vars_R[myvar.nodeid.Identifier]=[name,myvar.get_data_value(),varvalue2]
         ValCallback(myvar.nodeid,force=True)
 #        print(myvar.get_value())
-        server.set_attribute_callback(myvar.nodeid, ValCallback)
+        if not args.no_lib_hack:
+            server.set_attribute_callback(myvar.nodeid, ValCallback)
 #        varvalue=myvar.get_data_value().Value
 #        Vars_R[myvar.nodeid.Identifier][2]=varvalue
 #        print(varvalue2,varvalue)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a0a74090325423b55cce129fd7d729190c3cedbb
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+opcua
+pyyaml
+numpy
diff --git a/test/test_ADCs.py b/test/test_ADCs.py
index b0c18ee84b543a7cc85afa692d4a3a92dfed3f63..3be2fa979f976cb867efa14f351deaaeae88914e 100644
--- a/test/test_ADCs.py
+++ b/test/test_ADCs.py
@@ -1,5 +1,5 @@
-#import pypcc;
-import pypcc_test as pypcc;
+import pypcc;
+#import pypcc_test as pypcc;
 
 P1=pypcc.pypcc("LTS_pypcc.yaml")
 
@@ -9,8 +9,10 @@ def AddMethod(name):
 P1.GetMethodNames("",AddMethod);
 
 ##Print all the visible variables
-def AddVar(name,dtype=0,RW=0):
-    print("Var:",name,dtype,RW)
+def AddVar(name,dtype=0,RW=3,cnt=1):
+    Types={0:'int',1:'float'}
+    RWs={0:'hidden',1:'RO',2:'WO',3:'RW'}
+    print("Var:",name,Types[dtype],RWs[RW],cnt)
 P1.GetVarNames("",AddVar);
 
 a=[0]
diff --git a/test/test_clk.py b/test/test_clk.py
index 04c59107e635cc4e95178449e619eef4b614d7c4..da3e84bb7e72045d7ad03530f7438515958298eb 100644
--- a/test/test_clk.py
+++ b/test/test_clk.py
@@ -17,10 +17,11 @@ def AddMethod(name):
     print("Method:",name)
 P1.GetMethodNames("",AddMethod);
 
-def AddVar(name,dtype=0,RW=3):
+def AddVar(name,dtype=0,RW=3,cnt=1):
     Types={0:'int',1:'float'}
     RWs={0:'hidden',1:'RO',2:'WO',3:'RW'}
-    print("Var:",name,Types[dtype],RWs[RW])
+    print("Var:",name,Types[dtype],RWs[RW],cnt)
+
 P1.GetVarNames("",AddVar);
 #exit()
 #P1.CallMethod("RCU01_RCU_on",None)
diff --git a/test_ADCs.py b/test_ADCs.py
deleted file mode 100644
index 94c874699db3677108165e4fd01ef0a087fb66a3..0000000000000000000000000000000000000000
--- a/test_ADCs.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import pypcc;
-#import pypcc_test as pypcc;
-
-P1=pypcc.pypcc("LTS_pypcc.yaml")
-
-##Print all the visible methods
-def AddMethod(name):
-    print("Method:",name)
-P1.GetMethodNames("",AddMethod);
-
-##Print all the visible variables
-def AddVar(name,dtype=0,RW=0,dim=1):
-    print("Var:",name,dtype,RW,dim)
-P1.GetVarNames("",AddVar);
-
-a=[0]
-##Setup ADC RCU1
-P1.CallMethod("RCU01_RCU_off",None)
-P1.CallMethod("RCU01_RCU_on",None)
-#P1.GetVarValue("RCU01_ADC1_locked",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC1_SYNC",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC1_CML",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC1_JESD",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC2_SYNC",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC2_CML",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC2_JESD",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC3_SYNC",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC3_CML",a);print(a[0]);
-P1.GetVarValue("RCU01_ADC3_JESD",a);print(a[0]);
-#P1.GetVarValue("RCU01_ADC1_JESD_control1",a);print(a[0]);
-#P1.GetVarValue("RCU01_ADC1_CML_level",a);print(a[0]);
-#P1.GetVarValue("RCU01_ADC1_locked",a);print(a[0]);
-#P1.GetVarValue("RCU01_ADC1_locked",a);print(a[0]);
-#        - ADC1.SYNC_control: [1]  #Setup ADCs
-#        - ADC1.JESD_control1: [14]  #Setup ADCs
-#        - ADC1.CML_level: [0x7]
-#        - ADC1.Update: [1]       #Needed to update ADC registers
-
-exit()
-##Setup ADC RCU3
-P1.CallMethod("RCU01_RCU_off",None)
-P1.CallMethod("RCU03_RCU_on",None)
-P1.GetVarValue("RCU03_ADC1_locked",a);print(a[0]);
-P1.GetVarValue("RCU03_ADC2_locked",a);print(a[0]);
-P1.GetVarValue("RCU03_ADC3_locked",a);print(a[0]);