diff --git a/Dockerfile b/Dockerfile
index 4df32f8fed937557c50fac4a586ece9d8b489dce..9d6727da7a843f83de6c3aa2ac2b7674245a4d68 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM python:3.8 AS builder
+FROM python:3.5 AS builder
 
 ARG TWINE_USERNAME
 ARG TWINE_PASSWORD
@@ -12,7 +12,7 @@ RUN pip install --no-cache-dir twine
 
 ADD . /usr/src/app
 
-RUN cd /usr/src/app/gen && \
+RUN cd /usr/src/app/lib && \
     ./publish.sh
 
 
diff --git a/Dockerfile-Patchset-Txt4 b/Dockerfile-Patchset-Txt4
new file mode 100644
index 0000000000000000000000000000000000000000..f458393e1b7b8e6d0380a5819d1e301687ba2bb9
--- /dev/null
+++ b/Dockerfile-Patchset-Txt4
@@ -0,0 +1,13 @@
+FROM python:3.9.16
+
+ENV IP_ADDRESS="192.168.6.225"
+
+WORKDIR /usr/src/app
+
+RUN pip3 install --no-cache-dir twine fabric decorator
+
+ADD patchset/txt4/docker-entrypoint.sh /docker-entrypoint.sh
+ADD . /usr/src/app
+
+CMD /docker-entrypoint.sh
+    
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 48411e30bcc7c72d2a5602843023ba901a2da7c0..0000000000000000000000000000000000000000
--- a/VERSION
+++ /dev/null
@@ -1,8 +0,0 @@
-MAJOR=6
-MINOR=0
-PATCH=11
-COMMITS_AHEAD=
-COMMIT_HASH=885a135
-VERSION_NUM=6.0.11
-DEV_VERSION_NUM=6.0.11.
-FULL_VERSION_NUM=6.0.11.-885a135
diff --git a/createVersionNr.sh b/createVersionNr.sh
index 13370915dd755c2876ad4152422be85bfaaee966..0dea5a0ba337da9efee1e321268248b21abafc3a 100755
--- a/createVersionNr.sh
+++ b/createVersionNr.sh
@@ -41,15 +41,15 @@ DEV_VERSION_NUM=$dev_version_num
 FULL_VERSION_NUM=$full_version_num
 EOM
 
-cat $(pwd)/gen/setup.py | sed "/version=/ s/=.*/='${version_num}',/" > $(pwd)/gen/setup.new
-mv $(pwd)/gen/setup.new $(pwd)/gen/setup.py
+cat $(pwd)/lib/setup.py | sed "/version=/ s/=.*/='${version_num}',/" > $(pwd)/lib/setup.new
+mv $(pwd)/lib/setup.new $(pwd)/lib/setup.py
 
-cat $(pwd)/gen/fischertechnik/__init__.py | sed "/__version__ =/ s/= .*/= '${version_num}'/" > $(pwd)/gen/fischertechnik/__init__.new
-mv $(pwd)/gen/fischertechnik/__init__.new $(pwd)/gen/fischertechnik/__init__.py
+cat $(pwd)/lib/fischertechnik/__init__.py | sed "/__version__ =/ s/= .*/= '${version_num}'/" > $(pwd)/lib/fischertechnik/__init__.new
+mv $(pwd)/lib/fischertechnik/__init__.new $(pwd)/lib/fischertechnik/__init__.py
 
 if [[ -z "$pre_release" ]]; then
 	echo "Commit main release to stable branch with jenkins user"
-	git add $(pwd)/gen/setup.py $(pwd)/gen/fischertechnik/__init__.py $(pwd)/VERSION
+	git add $(pwd)/lib/setup.py $(pwd)/lib/fischertechnik/__init__.py $(pwd)/VERSION
 	git commit -am "release $version_num"
 	git push --force origin HEAD:stable
 fi
diff --git a/fabric/txt/deploy/colorized_output.py b/fabric/txt/deploy/colorized_output.py
deleted file mode 100755
index cb1305c65172553a34aa9ad4539158cfaf027e88..0000000000000000000000000000000000000000
--- a/fabric/txt/deploy/colorized_output.py
+++ /dev/null
@@ -1,27 +0,0 @@
-class Color:
-    HEADER = '\033[95m'
-    OKBLUE = '\033[94m'
-    OKGREEN = '\033[92m'
-    WARNING = '\033[93m'
-    FAIL = '\033[91m'
-    ENDC = '\033[0m'
-    BOLD = '\033[1m'
-    UNDERLINE = '\033[4m'
-
-def print_colored(string, color):
-    print(color + string + Color.ENDC)
-
-def print_bold(string):
-    print_colored(string, Color.BOLD)
-
-def print_warning(string):
-    print_colored(string, Color.WARNING)
-
-def print_success(string):
-    print_colored(string, Color.OKGREEN)
-
-def print_info(string):
-    print_colored(string, Color.OKBLUE)
-
-def print_error(string):
-    print_colored(string, Color.FAIL)
\ No newline at end of file
diff --git a/fabric/txt/deploy/deployment.py b/fabric/txt/deploy/deployment.py
deleted file mode 100644
index 7a65e23f8cd1a6711026b9a0fc5726b80af146f2..0000000000000000000000000000000000000000
--- a/fabric/txt/deploy/deployment.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import os
-
-from deploy import colorized_output as co
-from deploy.mounts import Mounts
-from deploy.python_environment import PythonEnvironment
-from deploy.repository import Repository
-
-from fabric import Connection
-
-USER = 'ftc'
-ROOT = 'root'
-
-
-class Deployment:
-    def __init__(self, host):
-        self.host = host
-        self.con = Connection(host = host, user = USER)
-
-    def copy_ssh_key(self):
-        co.print_warning('Copying SSH credentials (scp)...')
-        os.system("scp $HOME/.ssh/id_rsa.pub {0}@{1}:/tmp/credentials.pub".format(ROOT, self.host))
-        co.print_warning('Establishing SSH connection (mkdir, chmod, mv)...')
-        os.system("ssh {0}@{1} 'mkdir -p /home/ftc/.ssh && chmod 755 /tmp/credentials.pub &&"
-                  "mv /tmp/credentials.pub /home/ftc/.ssh/authorized_keys'".format(ROOT, self.host))
-
-    def check_mounts(self):
-        mnts = Mounts(self.con)
-        mnts.check_mounts()
-
-    def check_pip_and_libraries(self):
-        pyenv = PythonEnvironment(self.con)
-        pyenv.check_pip()
-        pyenv.check_pip_libraries()
-        pyenv.add_ftc_path()
-
-    def run_tests(self):
-        repo = Repository(self.con)
-        repo.uploadFolder('../../tests')
-        co.print_info("Starting tests...")
-        self.con.run("python3 /home/ftc/tests/txt/main.py")
diff --git a/fabric/txt/deploy/mounts.py b/fabric/txt/deploy/mounts.py
deleted file mode 100755
index 0b962939a384a545635f928336984f06a9eea378..0000000000000000000000000000000000000000
--- a/fabric/txt/deploy/mounts.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from deploy import colorized_output as co
-
-class Mounts:
-    MOUNTED_SUDO = '/home/ftc/mounts/usr/bin/sudo'
-
-    def __init__(self, connection):
-        self.connection = connection
-        self.mounts = self.connection.run('cat /etc/mtab').stdout.strip().split()
-
-    def create_mounts(self):
-        co.print_info('Copying files to local mount folders')
-        self.copy_folder_to_mounts('/usr/lib/python3.7/.', '~/mounts/python3.7')
-        self.copy_folder_to_mounts('/usr/bin', '~/mounts/usr')
-        self.chown_mounted_sudo()
-
-    def copy_folder_to_mounts(self, src, dst):
-        self.connection.run("mkdir -p {0}".format(dst))
-        self.connection.run("cp -r {0} {1}".format(src, dst))
-
-    def chown_mounted_sudo(self):
-        self.connection.sudo("chown root:root {0}".format(Mounts.MOUNTED_SUDO))
-        self.connection.sudo("chmod 4755 {0}".format(Mounts.MOUNTED_SUDO))
-
-    def check_mounts(self):
-        if not self.connection.run('ls mounts', warn=True):
-            self.create_mounts()
-        self.check_mount('/usr/lib/python3.7', '/home/ftc/mounts/python3.7')
-        self.check_mount('/usr/bin', '/home/ftc/mounts/usr/bin')
-
-    def check_mount(self, mnt, mnt_dir):
-        co.print_info("Checking mount {0}".format(mnt))
-        if mnt in self.mounts:
-            co.print_success("--> Already mounted")
-        else:
-            co.print_warning("--> Not mounted. Please authorize sudo on txt to mount it")
-            self.connection.sudo("mount {0} {1}".format(mnt_dir, mnt))
-            co.print_success("--> Sucessfully mounted")
\ No newline at end of file
diff --git a/fabric/txt/deploy/python_environment.py b/fabric/txt/deploy/python_environment.py
deleted file mode 100755
index a7fc54212e1df4ba6d24b6326aaa98ad133b653f..0000000000000000000000000000000000000000
--- a/fabric/txt/deploy/python_environment.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from deploy import colorized_output as co
-import os
-
-class PythonEnvironment:
-    def __init__(self, connection):
-        self.connection = connection
-
-    def add_ftc_path(self):
-        co.print_info('Add /opt/ftc to PYTHONPATH')
-        self.connection.run('echo "export PYTHONPATH=/opt/ftc" > /home/ftc/.profile', warn=True)
-        co.print_success('--> Important for ui applications')
-
-    def check_pip(self):
-        co.print_info("Checking pip-installation")
-        if self.connection.run('ls /usr/bin | grep pip3.7', warn=True):
-            co.print_success('--> Already installed')
-        else:
-            co.print_warning('--> Not installed. Starting installation of pip')
-            self.install_pip('~/tmp')
-            co.print_success('--> Successfully installed pip')
-
-    def install_pip(self, tmp_dir):
-        self.connection.run("mkdir -p {0}".format(tmp_dir))
-        self.connection.run("wget https://bootstrap.pypa.io/get-pip.py -O/home/ftc/tmp/get-pip.py".format(tmp_dir))
-        self.connection.run("python {0}/get-pip.py".format(tmp_dir))
-        self.connection.run("rm -rf {0}".format(tmp_dir))
-
-    def check_pip_libraries(self):
-        co.print_info('Checking pip libraries')
-        requirements = self.get_requirements()
-        pip_list = self.get_pip_list()
-        for requirement in requirements:
-            search = requirement.strip().replace(' ', '')
-            self.check_pip_library(pip_list, search)
-
-    def check_pip_library(self, dependencies, dependency):
-        co.print_info("Checking {0}:".format(dependency))
-        if dependency in dependencies:
-            co.print_success("--> Already installed")
-        else:
-            co.print_warning("--> Not installed. Starting installation")
-            if dependency.find('ft-') == -1 and dependency.find('ftrobopy') == -1:
-                self.connection.run("pip install {0}".format(dependency))
-            else:
-                if dependency.find('ftrobopy') != -1:
-                    co.print_warning("--> Removing preinstalled ftrobopy.")
-                    self.connection.run("rm -rf /usr/lib/python3.7/ftrobopy /usr/lib/python3.7/ftrobopy-1.80-py3.7.egg-info /usr/lib/python3.7/ftrobopy.pyc")
-                co.print_info("Downloading from custom repository")
-                co.print_info("Enter credentials if needed")
-                self.connection.run("pip install --index-url https://{0}:{1}@update.fischertechnik-cloud.com/repository/ft-txt-lib/simple/ --no-deps {2}".format(os.getenv('FT_USERNAME'), os.getenv('FT_PASSWORD'), dependency))
-            co.print_success("--> Successfully installed")
-
-    def get_pip_list(self):
-        return self.connection.run('pip list --format=freeze').stdout.strip().split()
-
-    def get_requirements(self):
-        fd = open('requirements.txt', 'r')
-        return fd.readlines()
diff --git a/fabric/txt/deploy/repository.py b/fabric/txt/deploy/repository.py
deleted file mode 100755
index 632c2e8bfb47745bbf7af39bb5bf9f5fadbfc791..0000000000000000000000000000000000000000
--- a/fabric/txt/deploy/repository.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import os
-from deploy import colorized_output as co
-
-class Repository:
-    def __init__(self, connection):
-        self.connection = connection
-
-    def uploadFolder(self, folder):
-        tar_folder = "{0}.tar".format(folder.split('/')[-1])
-        os.system("tar -cf {0} {1}/".format(tar_folder, folder))
-        self.connection.put("{0}".format(tar_folder))
-        self.connection.run("tar -xf {0}".format(tar_folder))
-        self.connection.run("rm {0}".format(tar_folder))
-        os.system("rm {0}".format(tar_folder))
-
-    def uploadAppFolder(self, folder):
-        self.uploadFolder(folder)
-        co.print_info('UploadAppFolder ' + folder)
-        self.connection.run("mkdir -p apps", warn=True)
-        self.connection.run("rm -rf apps/{0}/".format(folder), warn=True)
-        self.connection.run("mv -f {0} apps/".format(folder))
-        self.connection.run("chmod +x apps/{0}/start.py".format(folder))
-        self.connection.run("python apps/{0}/refresh.py".format(folder))
-
-    def replace_ip(self, ip):
-        self.connection.run("cd txtapi/txtapi/openapi && sed -i 's/^host:.*$/host: \"{0}:8080\"/g' openapi.yaml".format(ip))
-
-    def replace_env(self, env_file):
-        self.connection.run("mv txtapi/txtapi/environment/{0} txtapi/txtapi/environment/environment.py".format(env_file))
\ No newline at end of file
diff --git a/fabric/txt/fabfile.py b/fabric/txt/fabfile.py
deleted file mode 100644
index 06df762e1bb83c8bb74464f1d51dbc2443e471b0..0000000000000000000000000000000000000000
--- a/fabric/txt/fabfile.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import os
-
-from deploy import colorized_output as co
-from deploy.deployment import Deployment
-
-from invoke import task
-
-
-def set_ctx(ctx, host):
-    deployment = Deployment(host)
-    ctx.update({'deploy': deployment})
-
-
-@task(help={'host': "IP of the txt-controller"})
-def copy_ssh_key(ctx, host):
-    """
-    copy the own ssh-key to the txt-controller
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.copy_ssh_key()
-
-
-@task(help={'host': "IP of the txt-controller"})
-def mount(ctx, host):
-    """
-    mounts the needed directories on the txt-controller
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.check_mounts()
-
-
-@task(help={'host': "IP of the txt-controller"})
-def install_python(ctx, host):
-    """
-    installs pip and dependencies on the txt-controller
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.check_pip_and_libraries()
-
-
-@task(help={'host': "IP of the txt-controller"})
-def run_tests(ctx, host):
-    """
-    Runs the tests
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.run_tests()
-
-
-@task(help={'host': "IP of the txt-controller"})
-def deploySSH(ctx, host):
-    """
-    Deploy ssh credentials
-    """
-    set_ctx(ctx, host)
-    co.print_info("Step 1/1 >> Copying SSH-Key to TXT")
-    copy_ssh_key(ctx, host)
-    co.print_success('Deployment successfully finished!')
-
-
-@task(help={'host': "IP of the txt-controller"})
-def deploy(ctx, host):
-    """
-    Setup and deploy controllerlib
-    """
-    set_ctx(ctx, host)
-    co.print_info("Step 1/3 >> Creating mounts")
-    mount(ctx, host)
-    co.print_info("Step 2/3 >> Installing pip and dependencies")
-    install_python(ctx, host)
-    co.print_success('Deployment successfully finished!')
-    set_ctx(ctx, host)
-    co.print_info("Step 3/3 >> Copying 'tests' folder...")
-    run_tests(ctx, host)
diff --git a/fabric/txt/requirements.txt b/fabric/txt/requirements.txt
deleted file mode 100644
index cb98873f5f63163d438f863579e2c66969bba86e..0000000000000000000000000000000000000000
--- a/fabric/txt/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ft-controllerlib==1.0.37.5.sschulze
-ftrobopy==1.92
-imutils==0.5.3
-bme680==1.0.5
diff --git a/fabric/txt4/deploy/colorized_output.py b/fabric/txt4/deploy/colorized_output.py
deleted file mode 100755
index cb1305c65172553a34aa9ad4539158cfaf027e88..0000000000000000000000000000000000000000
--- a/fabric/txt4/deploy/colorized_output.py
+++ /dev/null
@@ -1,27 +0,0 @@
-class Color:
-    HEADER = '\033[95m'
-    OKBLUE = '\033[94m'
-    OKGREEN = '\033[92m'
-    WARNING = '\033[93m'
-    FAIL = '\033[91m'
-    ENDC = '\033[0m'
-    BOLD = '\033[1m'
-    UNDERLINE = '\033[4m'
-
-def print_colored(string, color):
-    print(color + string + Color.ENDC)
-
-def print_bold(string):
-    print_colored(string, Color.BOLD)
-
-def print_warning(string):
-    print_colored(string, Color.WARNING)
-
-def print_success(string):
-    print_colored(string, Color.OKGREEN)
-
-def print_info(string):
-    print_colored(string, Color.OKBLUE)
-
-def print_error(string):
-    print_colored(string, Color.FAIL)
\ No newline at end of file
diff --git a/fabric/txt4/deploy/deployment.py b/fabric/txt4/deploy/deployment.py
deleted file mode 100644
index 08e8e702854d37ab425d2dce31606fb9d128239c..0000000000000000000000000000000000000000
--- a/fabric/txt4/deploy/deployment.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import os
-
-from deploy import colorized_output as co
-from fabric import Connection
-from invoke import env
-
-USER = 'root'
-PASSWORD = 'root'
-
-
-class Deployment:
-    def __init__(self, host):
-        self.host = host
-        env.key_filename = "~/.ssh/id_rsa"
-        self.connection = Connection(host=host, user=USER, connect_kwargs={
-            "password": PASSWORD
-        })
-
-    def clean_up(self):
-        self.connection.run("rm -rf /tests")
-        os.system("cd ../../gen && rm -rf dist build ft_git ft-controllerlib.egg-info")
-
-    def build_package(self):
-        os.system('cd ../../gen && ./build.sh')
-
-    def upload_package(self):
-        os.system(
-            "scp ../../gen/dist/ft-controllerlib-*.tar.gz {0}@{1}:/ft-controllerlib.tar.gz".format(USER, self.host))
-
-    def install_package(self):
-        self.connection.run("pip3 install -I /ft-controllerlib.tar.gz")
-
-    def upload_tests(self, folder):
-        os.system("scp -r {0} {1}@{2}:/tests".format(folder, USER, self.host))
-
-    def run_tests(self):
-        co.print_info("Starting tests...")
-        self.connection.run("cd /tests/txt4 && python3 -m unittest discover -p '*Test.py' -v")
diff --git a/fabric/txt4/fabfile.py b/fabric/txt4/fabfile.py
deleted file mode 100644
index eb7300173ff0999fe2aa16b4152e1b877b4693b1..0000000000000000000000000000000000000000
--- a/fabric/txt4/fabfile.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from deploy import colorized_output as co
-from deploy.deployment import Deployment
-from invoke import task
-
-
-def set_ctx(ctx, host):
-    deployment = Deployment(host)
-    ctx.update({'deploy': deployment})
-
-@task(help={'host': "IP of the txt-controller"})
-def build_package(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.build_package()
-
-
-@task(help={'host': "IP of the txt-controller"})
-def upload_package(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.upload_package()
-
-@task(help={'host': "IP of the txt-controller"})
-def install_package(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.install_package()
-
-@task(help={'host': "IP of the txt-controller"})
-def upload_tests(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.upload_tests("../../tests")
-
-@task(help={'host': "IP of the txt-controller"})
-def run_tests(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.run_tests()
-
-@task(help={'host': "IP of the txt-controller"})
-def clean_up(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.clean_up()
-
-
-@task(help={'host': "IP of the txt-controller"})
-def deploy(ctx, host):
-
-    """
-    Setup and deploy controllerlib
-    """
-    set_ctx(ctx, host)
-    set_ctx(ctx, host)
-    co.print_info("Step 1/6 >> Clean up")
-    clean_up(ctx, host)
-    co.print_info("Step 2/6 >> Build Package")
-    build_package(ctx, host)
-    co.print_info("Step 3/6 >> Upload Package")
-    upload_package(ctx, host)
-    co.print_info("Step 4/6 >> Install Package")
-    install_package(ctx, host)
-    co.print_info("Step 5/6 >> Upload Tests")
-    upload_tests(ctx, host)
-    co.print_info("Step 6/6 >> Run Tests")
-    run_tests(ctx, host)
diff --git a/gen/test_combined_sensor.py b/gen/test_combined_sensor.py
deleted file mode 100644
index 3648061456ea75ee227971972e8d9e49025e1ca1..0000000000000000000000000000000000000000
--- a/gen/test_combined_sensor.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from fischertechnik.factories import controller_factory, input_factory, i2c_factory
-import os
-from time import sleep
-
-controller = controller_factory.create_graphical_controller()
-combined_sensor = i2c_factory.create_combined_sensor(controller, 0)
-
-filehandle = open('data.csv', 'w')
-filehandle.truncate(0)
-filehandle.close
-
-i = 0
-while i < 500:
-    x_acceleration = combined_sensor.get_acceleration_x()
-    y_acceleration = combined_sensor.get_acceleration_y()
-    z_acceleration = combined_sensor.get_acceleration_z()
-
-    x_rotation = combined_sensor.get_rotation_x()
-    y_rotation = combined_sensor.get_rotation_y()
-    z_rotation = combined_sensor.get_rotation_z()
-
-    magnetic_field_x = combined_sensor.get_magnetic_field_x()
-    magnetic_field_y = combined_sensor.get_magnetic_field_y()
-    magnetic_field_z = combined_sensor.get_magnetic_field_z()
-
-    print('X acceleration:', x_acceleration)
-    print('Y acceleration:', y_acceleration)
-    print('Z acceleration:', z_acceleration)
-    print()
-    print('X rotation:', x_rotation)
-    print('Y rotation:', y_rotation)
-    print('Z rotation:', z_rotation)
-    print()
-    print('Magnetic field in X direction:', magnetic_field_x)
-    print('Magnetic field in Y direction:', magnetic_field_y)
-    print('Magnetic field in Z direction:', magnetic_field_z)
-
-    with open('data.csv', 'a') as filehandle:
-        filehandle.write('{},{},{},{},{},{},{},{},{}\n'.format(x_acceleration, y_acceleration, z_acceleration, x_rotation, y_rotation, z_rotation, magnetic_field_x, magnetic_field_y, magnetic_field_z))
-
-    sleep(1)
-    os.system('clear')
-    i += 1
diff --git a/gen/test_environment_sensor.py b/gen/test_environment_sensor.py
deleted file mode 100644
index 54797e4d0c914551b860b06012941ddc41b4b2da..0000000000000000000000000000000000000000
--- a/gen/test_environment_sensor.py
+++ /dev/null
@@ -1,60 +0,0 @@
-from fischertechnik.factories import controller_factory, input_factory, i2c_factory
-import os
-from time import sleep
-
-controller = controller_factory.create_graphical_controller()
-environment_sensor = i2c_factory.create_environment_sensor(controller, 0)
-
-# test needs_calibration()
-needs_calibration = environment_sensor.needs_calibration()
-
-if needs_calibration:
-    print('Sensor needs calibration.')
-else:
-    print('Sensor is calibrated')
-
-assert needs_calibration == True, 'Expected EnvironmentSensor.needs_calibration() to be True after initialization, but was {}'.format(needs_calibration)
-
-# test get_accuracy()
-accuracy = environment_sensor.get_accuracy()
-print('Accuracy: {}'.format(accuracy))
-assert accuracy == 0, 'Expected EnvironmentSensor.get_accuracy() to be 0 after initialization, but was {}'.format(accuracy)
-
-i = 0
-while i < 500:
-    # test get_temperature()
-    print('Temperature:', environment_sensor.get_temperature(), '°C')
-    # test get_humidity()
-    print('relative Humidity:', environment_sensor.get_humidity(), '%')
-    # test get_pressure()
-    print('Air pressure:', environment_sensor.get_pressure(), 'hPa')
-
-    # test get_indoor_air_quality_as_number()
-    air_quality = environment_sensor.get_indoor_air_quality_as_number()
-    assert air_quality >= 0 and air_quality <= 500, 'Air quality should be within range(0, 500)'
-
-    # test needs_calibration()
-    needs_calibration = environment_sensor.needs_calibration()
-
-    if needs_calibration:
-        print('Sensor needs calibration.')
-    else:
-        print('Sensor is calibrated')
-
-    assert needs_calibration == False, 'Expected sensor to be automatically calibrated after calling get_indoor_air_quality() for the first time, but it wasn\'t.'
-
-    # test get_accuracy()
-    accuracy = environment_sensor.get_accuracy()
-    print('Accuracy: {}'.format(accuracy))
-    assert accuracy == 3, 'Expected accuracy to be 3 (calibrated) after having called get_indoor_air_quality_*'
-
-    # test get_indoor_air_quality_as_text()
-    air_quality_text = environment_sensor.get_indoor_air_quality_as_text()
-    assert air_quality_text in ('Good', 'Moderate', 'Not so good', 'Bad', 'Worse than Bad', 'Very bad')
-    assert air_quality_text != 'Unknown'
-
-    print('The air quality is', air_quality,  'which is', air_quality_text)
-
-    sleep(1)
-    os.system('clear')
-    i += 1
diff --git a/gen/tests/ColorSensorTest.py b/gen/tests/ColorSensorTest.py
deleted file mode 100644
index 8bc6fa649f32aa0c6d9fc2003c4f8d60ae80657c..0000000000000000000000000000000000000000
--- a/gen/tests/ColorSensorTest.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.input_factory.create_color_sensor(c,8)
-
-while True:
-    color = b.get_color()
-    print("Color", color)
-    time.sleep(1)
-
diff --git a/gen/tests/DiscoveryTest.py b/gen/tests/DiscoveryTest.py
deleted file mode 100644
index 2121b5e01f6252092a7f01637d1720ac9da34b4b..0000000000000000000000000000000000000000
--- a/gen/tests/DiscoveryTest.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import fischertechnik.factories as f
-
-c = f.controller_factory.create_graphical_controller()
-list = f.controller_factory.get_controller_info_list(c)
-
-for b in list:
-    print("Controller :", b.get_name())
-
-if len(list) <= 1:
-    exit()
-
-print("Check remote controller")
-
-c2 = f.controller_factory.create_graphical_controller_from_info(c, list[1])
-
-print("Remote controller access is OK")
-
diff --git a/gen/tests/EncodermotorSync2Test.py b/gen/tests/EncodermotorSync2Test.py
deleted file mode 100644
index 3cb62d74672138e480957a4a1c81d4818e194105..0000000000000000000000000000000000000000
--- a/gen/tests/EncodermotorSync2Test.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import time
-import fischertechnik.factories as f
-
-c = f.controller_factory.create_graphical_controller()
-b1 = f.motor_factory.create_encodermotor(c,1)
-b2 = f.motor_factory.create_encodermotor(c,2)
-
-b1.stop()
-b2.stop()
-
-b1.set_speed(100)
-b2.set_speed(100)
-
-b1.set_distance(100, b2)
-while b1.is_running():
-  print("Speed", b1.get_speed())
-  print("Distance", b1.get_distance())
-  time.sleep(0.1)
-
-b1.set_speed(-100)
-b2.set_speed(-100)
-
-b1.set_distance(100, b2)
-while b1.is_running():
-  print("Speed", b1.get_speed())
-  print("Distance", b1.get_distance())
-  time.sleep(0.1)
diff --git a/gen/tests/EncodermotorSync4Test.py b/gen/tests/EncodermotorSync4Test.py
deleted file mode 100644
index deea344bb270c724668955d1bd6cf49b1a21429b..0000000000000000000000000000000000000000
--- a/gen/tests/EncodermotorSync4Test.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import time
-import fischertechnik.factories as f
-
-c = f.controller_factory.create_graphical_controller()
-b1 = f.motor_factory.create_encodermotor(c,1)
-b2 = f.motor_factory.create_encodermotor(c,2)
-b3 = f.motor_factory.create_encodermotor(c,3)
-b4 = f.motor_factory.create_encodermotor(c,4)
-
-b1.stop()
-b2.stop()
-b3.stop()
-b4.stop()
-
-b1.set_speed(100)
-b2.set_speed(100)
-b3.set_speed(100)
-b4.set_speed(100)
-
-b1.set_distance(100, b2, b3, b4)
-while b1.is_running():
-  print("Speed", b1.get_speed())
-  print("Distance", b1.get_distance())
-  time.sleep(0.1)
-
-b1.set_speed(-100)
-b2.set_speed(-100)
-b3.set_speed(-100)
-b4.set_speed(-100)
-
-b1.set_distance(100, b2, b3, b4)
-while b1.is_running():
-  print("Speed", b1.get_speed())
-  print("Distance", b1.get_distance())
-  time.sleep(0.1)
diff --git a/gen/tests/EncodermotorTest.py b/gen/tests/EncodermotorTest.py
deleted file mode 100644
index 39c7f1b357ee4ae08069aac14ea22cd05f570599..0000000000000000000000000000000000000000
--- a/gen/tests/EncodermotorTest.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.motor_factory.create_encodermotor(c,1)
-
-b.stop()
-print("Stop speed", b.get_speed())
-
-# Use one direction
-b.set_speed(100)
-b.set_distance(100)
-b.start_sync()
-
-while b.is_running():
-  print("Speed", b.get_speed())
-  print("Distance", b.get_distance())
-  time.sleep(0.1)
-
-print("Distance", b.get_distance())
-
-b.stop()
-b.set_speed(-100)
-b.set_distance(100)
-b.start_sync()
-
-while b.is_running():
-  print("Speed", b.get_speed())
-  print("Distance", b.get_distance())
-  time.sleep(0.1)
-
-print("Distance", b.get_distance())
-
diff --git a/gen/tests/LampTest.py b/gen/tests/LampTest.py
deleted file mode 100644
index d64ff62194be1c6ec62986f6198d55de45b0898b..0000000000000000000000000000000000000000
--- a/gen/tests/LampTest.py
+++ /dev/null
@@ -1,16 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.output_factory.create_lamp(c,7)
-
-b.set_brightness(0)
-
-while True:
-  if b.is_on():
-     print("Lamp is on")
-  if b.is_off():
-     print("Lamp is off")
-  b.set_brightness(b.get_brightness() ^ 512)
-  time.sleep(1)
-
diff --git a/gen/tests/MagneticValveTest.py b/gen/tests/MagneticValveTest.py
deleted file mode 100644
index d0f2e295028fcd60cef5716cf4237811d14353bc..0000000000000000000000000000000000000000
--- a/gen/tests/MagneticValveTest.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.output_factory.create_magnetic_valve(c,7)
-
-b.off()
-
-while True:
-  if b.is_on():
-     print("MV is on")
-  if b.is_off():
-     print("MV is off")
-     b.on()
-  else:
-     b.off()
-  time.sleep(1)
-
diff --git a/gen/tests/MiniSwitchTest.py b/gen/tests/MiniSwitchTest.py
deleted file mode 100644
index 320dc9eb8f62049c2d7e373604a5448b744e0de1..0000000000000000000000000000000000000000
--- a/gen/tests/MiniSwitchTest.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import fischertechnik.factories as f
-
-c = f.controller_factory.create_graphical_controller()
-b = f.input_factory.create_mini_switch(c,8)
-
-while True:
-    if b.get_state() == 1:
-        print("Button gedrueckt")
\ No newline at end of file
diff --git a/gen/tests/MotorCounterTest.py b/gen/tests/MotorCounterTest.py
deleted file mode 100644
index ce1f69ec33bce000678555eeb1367bea22e2c252..0000000000000000000000000000000000000000
--- a/gen/tests/MotorCounterTest.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.motor_factory.create_encodermotor(c,1)
-d = f.counter_factory.create_encodermotor_counter(c,1)
-d.set_motor(b)
-
-b.stop()
-print("Stop speed", b.get_speed())
-
-# Use one direction
-b.set_speed(100)
-b.set_distance(100)
-
-while b.is_running():
-  print("Speed", b.get_speed())
-  print("Distance", d.get_distance())
-  time.sleep(0.1)
-
-print("Distance", d.get_distance())
-
-b.stop()
-b.set_speed(-100)
-b.set_distance(100)
-
-while b.is_running():
-  print("Speed", b.get_speed())
-  print("Distance", d.get_distance())
-  time.sleep(0.1)
-
-print("Distance", d.get_distance())
-
diff --git a/gen/tests/MotorTest.py b/gen/tests/MotorTest.py
deleted file mode 100644
index 256e27b5db8a56aad573cad11143e51f1e82e226..0000000000000000000000000000000000000000
--- a/gen/tests/MotorTest.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.motor_factory.create_motor(c,1)
-
-b.stop()
-print("Stop speed", b.get_speed(), b.is_running())
-
-# Use one direction
-b.set_speed(100)
-print("Speed100", b.get_speed(), b.is_running())
-time.sleep(1)
-b.set_speed(0)
-print("Speed0", b.get_speed(), b.is_running())
-time.sleep(1)
-b.set_speed(-100)
-print("Speed-100", b.get_speed(), b.is_running())
-time.sleep(1)
-b.stop()
-
-
diff --git a/gen/tests/NTCResistorTest.py b/gen/tests/NTCResistorTest.py
deleted file mode 100644
index 3142897031f89f8fde360daed861d2c180d3ab37..0000000000000000000000000000000000000000
--- a/gen/tests/NTCResistorTest.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.input_factory.create_ntc_resistor(c, 1)
-
-while True:
-    print(b.get_temperature())
-    time.sleep(1)
-
diff --git a/gen/tests/PhotoResistorTest.py b/gen/tests/PhotoResistorTest.py
deleted file mode 100644
index 2c6ced27b4d3f582a53e1d5fddba36119ff745cb..0000000000000000000000000000000000000000
--- a/gen/tests/PhotoResistorTest.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.input_factory.create_photo_resistor(c, 2)
-
-print(b.get_resistance())
-time.sleep(1)
-print(b.get_resistance())
-time.sleep(1)
-print(b.get_resistance())
-
diff --git a/gen/tests/PhotoTransistorTest.py b/gen/tests/PhotoTransistorTest.py
deleted file mode 100644
index d8e635d1a4acd1603dfdecb85dc96d3a7c99fdde..0000000000000000000000000000000000000000
--- a/gen/tests/PhotoTransistorTest.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import fischertechnik.factories as f
-
-c = f.controller_factory.create_graphical_controller()
-b = f.input_factory.create_photo_transistor(c,8)
-
-while True:
-    if b.get_state() == 1:
-        print("Sensor on" )
-    else:
-        print("Sensor off" )
\ No newline at end of file
diff --git a/gen/tests/README b/gen/tests/README
deleted file mode 100644
index 36006e22220683aae0f4c0da704402f2faf40ee4..0000000000000000000000000000000000000000
--- a/gen/tests/README
+++ /dev/null
@@ -1,11 +0,0 @@
-These tests can be used both for current and already installed package verification.
-
-For new sources Run tests from the directory above (gen) with the -m option, for example:
-
-python3 -m tests.DiscoveryTest
-
-Run immediately in the tests directory to verify the installed package, for example:
-
-cd tests
-python3 DiscoveryTest.py
-
diff --git a/gen/tests/TrailFollowerTest.py b/gen/tests/TrailFollowerTest.py
deleted file mode 100644
index ba80cfdb553e8ea18855a02ed2028618141d90aa..0000000000000000000000000000000000000000
--- a/gen/tests/TrailFollowerTest.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-l = f.input_factory.create_trail_follower(c,3)
-r = f.input_factory.create_trail_follower(c,8)
-
-while True:
-  print(l.get_state(),r.get_state())
-  time.sleep(0.2)
-
diff --git a/gen/tests/UltrasonicDistanceMeterTest.py b/gen/tests/UltrasonicDistanceMeterTest.py
deleted file mode 100644
index 9472a2493fd3b8b8af5fcbb0f0f711b5fb6f7920..0000000000000000000000000000000000000000
--- a/gen/tests/UltrasonicDistanceMeterTest.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import fischertechnik.factories as f
-import time
-
-c = f.controller_factory.create_graphical_controller()
-b = f.input_factory.create_ultrasonic_distance_meter(c,3)
-
-while True:
-  print("Dustance", b.get_distance())
-  time.sleep(0.2)
-
diff --git a/gen/build.sh b/lib/build.sh
similarity index 100%
rename from gen/build.sh
rename to lib/build.sh
diff --git a/gen/fischertechnik/__init__.py b/lib/fischertechnik/__init__.py
similarity index 70%
rename from gen/fischertechnik/__init__.py
rename to lib/fischertechnik/__init__.py
index 7750e2ab606f288a0dd5c55163488b057b149755..72eb915c3c1a1f56380032c097cf076b34c9b195 100644
--- a/gen/fischertechnik/__init__.py
+++ b/lib/fischertechnik/__init__.py
@@ -1,3 +1,3 @@
-__version__ = '6.0.11'
+__version__ = '0.0.0'
 __author__ = 'beemo GmbH'
 __email__ = 'info@beemo.eu'
diff --git a/gen/fischertechnik/camera/BallDetector.py b/lib/fischertechnik/camera/BallDetector.py
similarity index 100%
rename from gen/fischertechnik/camera/BallDetector.py
rename to lib/fischertechnik/camera/BallDetector.py
diff --git a/gen/fischertechnik/camera/CameraFactory.py b/lib/fischertechnik/camera/CameraFactory.py
similarity index 100%
rename from gen/fischertechnik/camera/CameraFactory.py
rename to lib/fischertechnik/camera/CameraFactory.py
diff --git a/gen/fischertechnik/camera/ColorDetector.py b/lib/fischertechnik/camera/ColorDetector.py
similarity index 100%
rename from gen/fischertechnik/camera/ColorDetector.py
rename to lib/fischertechnik/camera/ColorDetector.py
diff --git a/gen/fischertechnik/camera/Detector.py b/lib/fischertechnik/camera/Detector.py
similarity index 100%
rename from gen/fischertechnik/camera/Detector.py
rename to lib/fischertechnik/camera/Detector.py
diff --git a/gen/fischertechnik/camera/DetectorResult.py b/lib/fischertechnik/camera/DetectorResult.py
similarity index 100%
rename from gen/fischertechnik/camera/DetectorResult.py
rename to lib/fischertechnik/camera/DetectorResult.py
diff --git a/gen/fischertechnik/camera/LineDetector.py b/lib/fischertechnik/camera/LineDetector.py
similarity index 100%
rename from gen/fischertechnik/camera/LineDetector.py
rename to lib/fischertechnik/camera/LineDetector.py
diff --git a/gen/fischertechnik/camera/MotionDetector.py b/lib/fischertechnik/camera/MotionDetector.py
similarity index 100%
rename from gen/fischertechnik/camera/MotionDetector.py
rename to lib/fischertechnik/camera/MotionDetector.py
diff --git a/gen/fischertechnik/camera/VideoStream.py b/lib/fischertechnik/camera/VideoStream.py
similarity index 100%
rename from gen/fischertechnik/camera/VideoStream.py
rename to lib/fischertechnik/camera/VideoStream.py
diff --git a/gen/fischertechnik/camera/__init__.py b/lib/fischertechnik/camera/__init__.py
similarity index 100%
rename from gen/fischertechnik/camera/__init__.py
rename to lib/fischertechnik/camera/__init__.py
diff --git a/lib/fischertechnik/control/RemoteControl.py b/lib/fischertechnik/control/RemoteControl.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d34ec3a1586f5a3d91d274e28398e716e7c492f
--- /dev/null
+++ b/lib/fischertechnik/control/RemoteControl.py
@@ -0,0 +1,160 @@
+import socket
+import threading
+import json
+import time
+
+class RemoteControl():
+
+    BUFFERSIZE = 1024 * 4
+    HOST = "0.0.0.0"
+    IN_PORT = 10010
+    OUT_PORT = 10011
+
+    def __init__(self):
+
+        self._stack = []
+        self._listeners = []
+        self._in_lock = threading.Lock()
+        self._out_lock = threading.Lock()
+
+        self._in_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self._in_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self._in_socket.bind((RemoteControl.HOST, RemoteControl.IN_PORT))
+        self._in_socket.listen(1) 
+
+        self._out_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self._out_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self._out_socket.bind((RemoteControl.HOST, RemoteControl.OUT_PORT))
+        self._out_socket.listen(1) 
+
+        self._running = True
+        self._in_thread = threading.Thread(target=self._recv, args=(), daemon=True)
+        self._in_thread.start()
+
+        self._out_thread = threading.Thread(target=self._send, args=(), daemon=True)
+        self._out_thread.start()
+
+
+    def __del__(self):
+        
+        self._running = False
+
+        try:     
+            if self._in_socket is not None:
+                self._in_socket.shutdown()
+                self._in_socket.close()
+        except Exception as e:
+            pass
+        finally:
+            self._in_socket = None
+
+        try:     
+            if self._out_socket is not None:
+                self._out_socket.shutdown()
+                self._out_socket.close()
+        except Exception as e:
+            pass
+        finally:
+            self._out_socket = None
+
+        try:
+            if self._in_thread is not None:
+                self._in_thread.join()
+        except Exception as e:
+            pass
+        finally:
+            self._in_thread = None
+
+        try:
+            if self._out_thread is not None:
+                self._out_thread.join()
+        except Exception as e:
+            pass
+        finally:
+            self._out_thread = None
+
+
+    def set_attr(self, id, name, value):
+        with self._out_lock:
+            message = {"id": id, "attributes": [{"name": name, "value": value}]}
+            self._stack.append(message)
+
+
+    def add_listener(self, id, callback):
+        with self._in_lock:
+            listener = self._get_listener(id, callback)
+            if listener is not None:
+                return 
+            self._listeners.append({
+                "id": id,
+                "callback": callback
+            })
+
+
+    def remove_listener(self, id, callback):
+        with self._in_lock:   
+            listener = self._get_listener(id, callback)
+            if listener is None:
+                return
+            self._listeners.remove(listener)
+
+
+    def _get_listener(self, id, callback):
+        for listener in self._listeners:
+            if listener["id"] == id and listener["callback"] == callback:
+                return listener
+        return None
+
+
+    def _recv(self):
+
+        while self._running:
+
+             # keep accepting connections from clients
+            conn, _ = self._in_socket.accept() 
+
+            try:    
+
+                full_msg = ''
+                while True:
+                    data = conn.recv(RemoteControl.BUFFERSIZE)
+                    if len(data) <= 0:
+                        break
+                    full_msg += data.decode("utf-8")
+
+                if len(full_msg) > 0:
+
+                    message = json.loads(full_msg)
+                
+                    with self._in_lock:
+                        for listener in self._listeners:
+                            if listener["id"] == message["id"]:
+                                # parse array of attributers to dictionary
+                                attributes = {}
+                                for attr in message["attributes"]:
+                                    attributes[attr["name"]] = attr["value"]
+                                listener["callback"](attributes)
+
+            except Exception as e:
+                self._running = False
+            finally:
+                conn.close()
+
+    def _send(self):
+
+        # keep accepting connections from clients
+        conn, _ = self._out_socket.accept() 
+
+        while self._running:
+
+            try:    
+
+                with self._out_lock:
+                    message = json.dumps(self._stack)
+                    conn.send(message.encode('utf-8'))
+                    self._stack = []
+
+                time.sleep(1)
+
+            except Exception as e:
+                conn, _ = self._out_socket.accept() 
diff --git a/gen/fischertechnik/control/VoiceControl.py b/lib/fischertechnik/control/VoiceControl.py
similarity index 100%
rename from gen/fischertechnik/control/VoiceControl.py
rename to lib/fischertechnik/control/VoiceControl.py
diff --git a/gen/fischertechnik/control/__init__.py b/lib/fischertechnik/control/__init__.py
similarity index 100%
rename from gen/fischertechnik/control/__init__.py
rename to lib/fischertechnik/control/__init__.py
diff --git a/gen/fischertechnik/controller/BaseController.py b/lib/fischertechnik/controller/BaseController.py
similarity index 100%
rename from gen/fischertechnik/controller/BaseController.py
rename to lib/fischertechnik/controller/BaseController.py
diff --git a/gen/fischertechnik/controller/Camera.py b/lib/fischertechnik/controller/Camera.py
similarity index 100%
rename from gen/fischertechnik/controller/Camera.py
rename to lib/fischertechnik/controller/Camera.py
diff --git a/gen/fischertechnik/controller/ColorSensor.py b/lib/fischertechnik/controller/ColorSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/ColorSensor.py
rename to lib/fischertechnik/controller/ColorSensor.py
diff --git a/gen/fischertechnik/controller/CombinedSensor.py b/lib/fischertechnik/controller/CombinedSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/CombinedSensor.py
rename to lib/fischertechnik/controller/CombinedSensor.py
diff --git a/gen/fischertechnik/controller/Compressor.py b/lib/fischertechnik/controller/Compressor.py
similarity index 100%
rename from gen/fischertechnik/controller/Compressor.py
rename to lib/fischertechnik/controller/Compressor.py
diff --git a/gen/fischertechnik/controller/ControllerFactory.py b/lib/fischertechnik/controller/ControllerFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/ControllerFactory.py
rename to lib/fischertechnik/controller/ControllerFactory.py
diff --git a/gen/fischertechnik/controller/ControllerInfo.py b/lib/fischertechnik/controller/ControllerInfo.py
similarity index 100%
rename from gen/fischertechnik/controller/ControllerInfo.py
rename to lib/fischertechnik/controller/ControllerInfo.py
diff --git a/gen/fischertechnik/controller/Counter.py b/lib/fischertechnik/controller/Counter.py
similarity index 100%
rename from gen/fischertechnik/controller/Counter.py
rename to lib/fischertechnik/controller/Counter.py
diff --git a/gen/fischertechnik/controller/CounterFactory.py b/lib/fischertechnik/controller/CounterFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/CounterFactory.py
rename to lib/fischertechnik/controller/CounterFactory.py
diff --git a/gen/fischertechnik/controller/Encodermotor.py b/lib/fischertechnik/controller/Encodermotor.py
similarity index 100%
rename from gen/fischertechnik/controller/Encodermotor.py
rename to lib/fischertechnik/controller/Encodermotor.py
diff --git a/gen/fischertechnik/controller/EnvironmentSensor.py b/lib/fischertechnik/controller/EnvironmentSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/EnvironmentSensor.py
rename to lib/fischertechnik/controller/EnvironmentSensor.py
diff --git a/gen/fischertechnik/controller/GestureSensor.py b/lib/fischertechnik/controller/GestureSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/GestureSensor.py
rename to lib/fischertechnik/controller/GestureSensor.py
diff --git a/gen/fischertechnik/controller/GraphicalInputOutputController.py b/lib/fischertechnik/controller/GraphicalInputOutputController.py
similarity index 100%
rename from gen/fischertechnik/controller/GraphicalInputOutputController.py
rename to lib/fischertechnik/controller/GraphicalInputOutputController.py
diff --git a/gen/fischertechnik/controller/I2C.py b/lib/fischertechnik/controller/I2C.py
similarity index 100%
rename from gen/fischertechnik/controller/I2C.py
rename to lib/fischertechnik/controller/I2C.py
diff --git a/gen/fischertechnik/controller/I2CFactory.py b/lib/fischertechnik/controller/I2CFactory.py
similarity index 77%
rename from gen/fischertechnik/controller/I2CFactory.py
rename to lib/fischertechnik/controller/I2CFactory.py
index 8da1c331082032c3ed3d60ef0ed1714f84d07f41..b5d8d782909a331d3eb2867e0e386d39b151a8d8 100644
--- a/gen/fischertechnik/controller/I2CFactory.py
+++ b/lib/fischertechnik/controller/I2CFactory.py
@@ -11,6 +11,12 @@ class I2CFactory(object):
         @ReturnType fischertechnik.controller.CombinedSensor"""
         pass
 
+    def create_combined_sensor_6pin(self, controller, identifier):
+        """@ParamType controller fischertechnik.controller.GraphicalInputOutputController
+        @ParamType identifier int
+        @ReturnType fischertechnik.controller.CombinedSensor"""
+        pass
+
     def create_environment_sensor(self, controller, identifier):
         """@ParamType controller fischertechnik.controller.GraphicalInputOutputController
         @ParamType identifier int
diff --git a/gen/fischertechnik/controller/IOUnit.py b/lib/fischertechnik/controller/IOUnit.py
similarity index 100%
rename from gen/fischertechnik/controller/IOUnit.py
rename to lib/fischertechnik/controller/IOUnit.py
diff --git a/gen/fischertechnik/controller/IR.py b/lib/fischertechnik/controller/IR.py
similarity index 100%
rename from gen/fischertechnik/controller/IR.py
rename to lib/fischertechnik/controller/IR.py
diff --git a/gen/fischertechnik/controller/Input.py b/lib/fischertechnik/controller/Input.py
similarity index 100%
rename from gen/fischertechnik/controller/Input.py
rename to lib/fischertechnik/controller/Input.py
diff --git a/gen/fischertechnik/controller/InputFactory.py b/lib/fischertechnik/controller/InputFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/InputFactory.py
rename to lib/fischertechnik/controller/InputFactory.py
diff --git a/gen/fischertechnik/controller/InputOutputController.py b/lib/fischertechnik/controller/InputOutputController.py
similarity index 100%
rename from gen/fischertechnik/controller/InputOutputController.py
rename to lib/fischertechnik/controller/InputOutputController.py
diff --git a/gen/fischertechnik/controller/LightSource.py b/lib/fischertechnik/controller/LightSource.py
similarity index 100%
rename from gen/fischertechnik/controller/LightSource.py
rename to lib/fischertechnik/controller/LightSource.py
diff --git a/gen/fischertechnik/controller/Loudspeaker.py b/lib/fischertechnik/controller/Loudspeaker.py
similarity index 100%
rename from gen/fischertechnik/controller/Loudspeaker.py
rename to lib/fischertechnik/controller/Loudspeaker.py
diff --git a/gen/fischertechnik/controller/MagneticValve.py b/lib/fischertechnik/controller/MagneticValve.py
similarity index 100%
rename from gen/fischertechnik/controller/MagneticValve.py
rename to lib/fischertechnik/controller/MagneticValve.py
diff --git a/gen/fischertechnik/controller/Microphone.py b/lib/fischertechnik/controller/Microphone.py
similarity index 100%
rename from gen/fischertechnik/controller/Microphone.py
rename to lib/fischertechnik/controller/Microphone.py
diff --git a/gen/fischertechnik/controller/MiniSwitch.py b/lib/fischertechnik/controller/MiniSwitch.py
similarity index 100%
rename from gen/fischertechnik/controller/MiniSwitch.py
rename to lib/fischertechnik/controller/MiniSwitch.py
diff --git a/gen/fischertechnik/controller/Motor.py b/lib/fischertechnik/controller/Motor.py
similarity index 100%
rename from gen/fischertechnik/controller/Motor.py
rename to lib/fischertechnik/controller/Motor.py
diff --git a/gen/fischertechnik/controller/MotorFactory.py b/lib/fischertechnik/controller/MotorFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/MotorFactory.py
rename to lib/fischertechnik/controller/MotorFactory.py
diff --git a/gen/fischertechnik/controller/NTCResistor.py b/lib/fischertechnik/controller/NTCResistor.py
similarity index 100%
rename from gen/fischertechnik/controller/NTCResistor.py
rename to lib/fischertechnik/controller/NTCResistor.py
diff --git a/gen/fischertechnik/controller/Output.py b/lib/fischertechnik/controller/Output.py
similarity index 100%
rename from gen/fischertechnik/controller/Output.py
rename to lib/fischertechnik/controller/Output.py
diff --git a/gen/fischertechnik/controller/OutputFactory.py b/lib/fischertechnik/controller/OutputFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/OutputFactory.py
rename to lib/fischertechnik/controller/OutputFactory.py
diff --git a/gen/fischertechnik/controller/PhotoTransistor.py b/lib/fischertechnik/controller/PhotoTransistor.py
similarity index 100%
rename from gen/fischertechnik/controller/PhotoTransistor.py
rename to lib/fischertechnik/controller/PhotoTransistor.py
diff --git a/gen/fischertechnik/controller/Resistor.py b/lib/fischertechnik/controller/Resistor.py
similarity index 100%
rename from gen/fischertechnik/controller/Resistor.py
rename to lib/fischertechnik/controller/Resistor.py
diff --git a/gen/fischertechnik/controller/Servomotor.py b/lib/fischertechnik/controller/Servomotor.py
similarity index 100%
rename from gen/fischertechnik/controller/Servomotor.py
rename to lib/fischertechnik/controller/Servomotor.py
diff --git a/gen/fischertechnik/controller/ServomotorFactory.py b/lib/fischertechnik/controller/ServomotorFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/ServomotorFactory.py
rename to lib/fischertechnik/controller/ServomotorFactory.py
diff --git a/gen/fischertechnik/controller/TrailFollower.py b/lib/fischertechnik/controller/TrailFollower.py
similarity index 100%
rename from gen/fischertechnik/controller/TrailFollower.py
rename to lib/fischertechnik/controller/TrailFollower.py
diff --git a/gen/fischertechnik/controller/USB.py b/lib/fischertechnik/controller/USB.py
similarity index 100%
rename from gen/fischertechnik/controller/USB.py
rename to lib/fischertechnik/controller/USB.py
diff --git a/gen/fischertechnik/controller/USBFactory.py b/lib/fischertechnik/controller/USBFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/USBFactory.py
rename to lib/fischertechnik/controller/USBFactory.py
diff --git a/gen/fischertechnik/controller/UltrasonicDistanceMeter.py b/lib/fischertechnik/controller/UltrasonicDistanceMeter.py
similarity index 100%
rename from gen/fischertechnik/controller/UltrasonicDistanceMeter.py
rename to lib/fischertechnik/controller/UltrasonicDistanceMeter.py
diff --git a/gen/fischertechnik/controller/UnidirectionalMotor.py b/lib/fischertechnik/controller/UnidirectionalMotor.py
similarity index 100%
rename from gen/fischertechnik/controller/UnidirectionalMotor.py
rename to lib/fischertechnik/controller/UnidirectionalMotor.py
diff --git a/gen/fischertechnik/controller/Voltmeter.py b/lib/fischertechnik/controller/Voltmeter.py
similarity index 100%
rename from gen/fischertechnik/controller/Voltmeter.py
rename to lib/fischertechnik/controller/Voltmeter.py
diff --git a/gen/fischertechnik/controller/Window.py b/lib/fischertechnik/controller/Window.py
similarity index 100%
rename from gen/fischertechnik/controller/Window.py
rename to lib/fischertechnik/controller/Window.py
diff --git a/gen/fischertechnik/controller/__init__.py b/lib/fischertechnik/controller/__init__.py
similarity index 100%
rename from gen/fischertechnik/controller/__init__.py
rename to lib/fischertechnik/controller/__init__.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Camera.py b/lib/fischertechnik/controller/txt4/Txt4Camera.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Camera.py
rename to lib/fischertechnik/controller/txt4/Txt4Camera.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4ColorSensor.py b/lib/fischertechnik/controller/txt4/Txt4ColorSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4ColorSensor.py
rename to lib/fischertechnik/controller/txt4/Txt4ColorSensor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4CombinedSensor.py b/lib/fischertechnik/controller/txt4/Txt4CombinedSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4CombinedSensor.py
rename to lib/fischertechnik/controller/txt4/Txt4CombinedSensor.py
diff --git a/lib/fischertechnik/controller/txt4/Txt4CombinedSensor6Pin.py b/lib/fischertechnik/controller/txt4/Txt4CombinedSensor6Pin.py
new file mode 100644
index 0000000000000000000000000000000000000000..1186fdfd488d5ad15911647d2aa01b8b5da57ee5
--- /dev/null
+++ b/lib/fischertechnik/controller/txt4/Txt4CombinedSensor6Pin.py
@@ -0,0 +1,357 @@
+import smbus2
+from ..CombinedSensor import CombinedSensor
+
+class ICM_42670_P(object):
+    GYRO_ACC_ADDR = 0x68
+
+    GYRO_ACC_PWR_MGMT0_ADDR = 0x1F
+    GYRO_ACC_PWR_MGMT0_BITMASK = 0b00001111
+    PowerMode = {
+        'Sleep': 0b0000,  # Gyroscope: OFF, Accelerometer: OFF
+        'Standby': 0b0100,  # Gyroscope: DRIVE ON, Accelerometer: OFF
+        'AccelLowPower': 0b0010,  # Gyroscope: OFF, Accelerometer: DUTY - CYCLED
+        'AccelLowNoise': 0b0011,  # Gyroscope: OFF, Accelerometer: ON
+        'GyroLowNoise': 0b1100,  # Gyroscope: ON, Accelerometer: OFF
+        'SixAxisLowNoise': 0b1111  # Gyroscope: ON, Accelerometer: ON
+    }
+
+    GYRO_CONFIG0_ADDR = 0x20
+    ACC_CONFIG0_ADDR = 0x21
+
+    GYRO_CONFIG0_RANGE_BITMASK = 0b01100000
+    GYRO_CONFIG0_ODR_BITMASK = 0b00001111
+    GYRO_CONFIG0_BITMASK = GYRO_CONFIG0_RANGE_BITMASK | GYRO_CONFIG0_ODR_BITMASK
+
+    ACC_CONFIG0_RANGE_BITMASK = 0b01100000
+    ACC_CONFIG0_ODR_BITMASK = 0b00001111
+    ACC_CONFIG0_BITMASK = ACC_CONFIG0_RANGE_BITMASK | ACC_CONFIG0_ODR_BITMASK
+
+    GYRO_CONFIG1_ADDR = 0x23
+    ACC_CONFIG1_ADDR = 0x24
+
+    GYRO_CONFIG1_BITMASK = 0b00000111
+
+    ACC_CONFIG1_AVG_FILTER_BITMASK = 0b01110000
+    ACC_CONFIG1_LOWPASS_FILTER_BITMASK = 0b00000111
+    ACC_CONFIG1_BITMASK = ACC_CONFIG1_AVG_FILTER_BITMASK | ACC_CONFIG1_LOWPASS_FILTER_BITMASK
+
+    GYRO_X_MSB = 0x11
+    GYRO_X_LSB = 0x12
+    GYRO_Y_MSB = 0x13
+    GYRO_Y_LSB = 0x14
+    GYRO_Z_MSB = 0x15
+    GYRO_Z_LSB = 0x16
+
+    ACC_X_MSB = 0x0B
+    ACC_X_LSB = 0x0C
+    ACC_Y_MSB = 0x0D
+    ACC_Y_LSB = 0x0E
+    ACC_Z_MSB = 0x0F
+    ACC_Z_LSB = 0x0E
+
+    GyroRange = {
+        250: 131.0,
+        500: 65.5,
+        1000: 32.8,
+        2000: 16.4
+    }
+
+    GyroRangeBits = {
+        250: 0b01100000,
+        500: 0b01000000,
+        1000: 0b00100000,
+        2000: 0b00000000
+    }
+
+    AccRange = {
+        2: 16384.0,
+        4: 8192.0,
+        8: 4096.0,
+        16: 2048.0
+    }
+
+    AccRangeBits = {
+        2: 0b01100000,
+        4: 0b01000000,
+        8: 0b00100000,
+        16: 0b00000000
+    }
+
+    AccOdrBits = {
+        1600: 0b0101,
+        800: 0b0110,
+        400: 0b0111,
+        200: 0b1000,
+        100: 0b1001,
+        50: 0b1010,
+        25: 0b1011,
+        12.5: 0b1100,
+        6.25: 0b1101,
+        3.125: 0b1110,
+        1.5625: 0b1111
+    }
+
+    GyroOdrBits = {
+        1600: 0b0101,
+        800: 0b0110,
+        400: 0b0111,
+        200: 0b1000,
+        100: 0b1001,
+        50: 0b1010,
+        25: 0b1011,
+        12.5: 0b1100,
+    }
+
+    GyroLowPassFilterBits = {
+        0: 0b0000,
+        180: 0b0001,
+        121: 0b0010,
+        73: 0b0011,
+        53: 0b0100,
+        34: 0b0101,
+        25: 0b0110,
+        16: 0b0111
+    }
+
+    AccLowPassFilterBits = {
+        0: 0b0000,
+        180: 0b0001,
+        121: 0b0010,
+        73: 0b0011,
+        53: 0b0100,
+        34: 0b0101,
+        25: 0b0110,
+        16: 0b0111
+    }
+
+    AccAverageFilterBits = {
+        2: 0b0000,
+        4: 0b0001,
+        8: 0b0010,
+        16: 0b0011,
+        32: 0b0100,
+        64: 0b0101,
+    }
+
+class MMC5603NJ(object):
+    MAGNETOMETER_ADDRESS = 0x30
+
+    MMC56X3_PRODUCT_ID = 0x39
+    MMC56X3_CTRL0_REG = 0x1B
+    MMC56X3_CTRL1_REG = 0x1C
+    MMC56X3_CTRL2_REG = 0x1D
+    MMC56X3_STATUS_REG = 0x18
+    MMC56X3_OUT_TEMP = 0x09
+    MMC56X3_OUT_X_L = 0x00
+    MMC5603_ODR_REG = 0x1A
+
+    MAG_Xout_0 = 0x00
+    MAG_Xout_1 = 0x01
+    MAG_Yout_0 = 0x02
+    MAG_Yout_1 = 0x03
+    MAG_Zout_0 = 0x04
+    MAG_Zout_1 = 0x05
+    MAG_Xout_2 = 0x06
+    MAG_Yout_2 = 0x07
+    MAG_Zout_2 = 0x08
+
+
+class Txt4CombinedSensor6Pin(CombinedSensor):
+    def __init__(self, controller, identifier):
+        CombinedSensor.__init__(self, controller, identifier)
+        self.__gyro_resolution = 0
+        self.__acc_resolution = 0
+        self.__i2c = smbus2.SMBus(3)
+        self.__is_accelerometer_initialized = False
+        self.__is_magnetometer_initialized = False
+        self.__is_gyrometer_initialized = False
+        self.set_power_mode(ICM_42670_P.PowerMode['SixAxisLowNoise'])
+
+    def set_power_mode(self, mode=ICM_42670_P.PowerMode['SixAxisLowNoise']):
+        self.update_reg(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.GYRO_ACC_PWR_MGMT0_ADDR,
+                        mode,
+                        ICM_42670_P.GYRO_ACC_PWR_MGMT0_BITMASK)
+
+    def read_power_mode(self):
+        result = self.__i2c.read_byte_data(ICM_42670_P.GYRO_ACC_ADDR,
+                                           ICM_42670_P.GYRO_ACC_PWR_MGMT0_ADDR) & ICM_42670_P.GYRO_ACC_PWR_MGMT0_BITMASK
+        return [k for k, v in ICM_42670_P.PowerMode.items() if v == result][0]
+
+    def init_accelerometer(self, acc_range=16, odr=800):
+        self.__acc_resolution = 1 / ICM_42670_P.AccRange[acc_range]
+        self.update_reg(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.ACC_CONFIG0_ADDR,
+                        ICM_42670_P.AccRangeBits[acc_range] | ICM_42670_P.AccOdrBits[odr],
+                        ICM_42670_P.ACC_CONFIG0_BITMASK)
+        self.__is_accelerometer_initialized = True
+
+    def init_gyrometer(self, gyro_range=2000, odr=800):
+        self.__gyro_resolution = 1 / ICM_42670_P.GyroRange[gyro_range]
+        self.update_reg(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.GYRO_CONFIG0_ADDR,
+                        ICM_42670_P.GyroRangeBits[gyro_range] | ICM_42670_P.GyroOdrBits[odr],
+                        ICM_42670_P.GYRO_CONFIG0_BITMASK)
+        self.__is_gyrometer_initialized = True
+
+    def init_magnetometer(self, odr=255):
+        if not ((odr == 1000) or (0 <= odr <= 255)):
+            raise ValueError('Data rate must be 0-255 or 1000 Hz!')
+        mag_ctrl2_cache = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MMC56X3_CTRL2_REG)
+        if odr == 1000:
+            self.__i2c.write_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MMC5603_ODR_REG, 255)
+            mag_ctrl2_cache |= 0x80
+        else:
+            self.__i2c.write_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MMC5603_ODR_REG, odr)
+            mag_ctrl2_cache &= ~0x80
+        self.__i2c.write_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MMC56X3_CTRL2_REG, mag_ctrl2_cache)
+        self.__is_magnetometer_initialized = True
+
+    def get_acceleration_x(self) -> float:
+        """
+        Returns the current acceleration in X direction in g. 1g = 9.81m/s^2.
+        @returns {float} acceleration in X direction in g
+        """
+        if self.__is_accelerometer_initialized:
+            """
+            On reading multiple bytes from i2c the register will be incremented.
+            Therefore the lower register value will be read which is the MSB.
+            The returned value is the most significant byte (MSB) and least significant byte (LSB) in reverse order.
+            """
+            result = self.__i2c.read_word_data(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.ACC_X_MSB)
+            result = result.from_bytes(result.to_bytes(2, byteorder='big'), byteorder='little', signed='True')
+            return result * self.__acc_resolution
+        return None
+
+    def get_acceleration_y(self) -> float:
+        """
+        Returns the current acceleration in X direction in g. 1g = 9.81m/s^2.
+        @returns {float} acceleration in X direction in g
+        """
+        if self.__is_accelerometer_initialized:
+            """
+            On reading multiple bytes from i2c the register will be incremented.
+            Therefore the lower register value will be read which is the MSB.
+            The returned value is the most significant byte (MSB) and least significant byte (LSB) in reverse order.
+            """
+            result = self.__i2c.read_word_data(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.ACC_Y_MSB)
+            result = result.from_bytes(result.to_bytes(2, byteorder='big'), byteorder='little', signed='True')
+            return result * self.__acc_resolution
+        return None
+
+    def get_acceleration_z(self) -> float:
+        """
+        Returns the current acceleration in X direction in g. 1g = 9.81m/s^2.
+        @returns {float} acceleration in X direction in g
+        """
+        if self.__is_accelerometer_initialized:
+            """
+            On reading multiple bytes from i2c the register will be incremented.
+            Therefore the lower register value will be read which is the MSB.
+            The returned value is the most significant byte (MSB) and least significant byte (LSB) in reverse order.
+            """
+            result = self.__i2c.read_word_data(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.ACC_Z_MSB)
+            result = result.from_bytes(result.to_bytes(2, byteorder='big'), byteorder='little', signed='True')
+            return result * self.__acc_resolution
+        return None
+
+    def get_rotation_x(self) -> float:
+        """
+        Returns the rotation speed around the X axis in degrees per second.
+        @returns {float} rotation speed around the X axis in degrees per second
+        """
+        if self.__is_gyrometer_initialized:
+            """
+            On reading multiple bytes from i2c the register will be incremented.
+            Therefore the lower register value will be read which is the MSB.
+            The returned value is the most significant byte (MSB) and least significant byte (LSB) in reverse order.
+            """
+            result = self.__i2c.read_word_data(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.GYRO_X_MSB)
+            result = result.from_bytes(result.to_bytes(2, byteorder='big'), byteorder='little', signed='True')
+            return result * self.__gyro_resolution
+        return None
+
+    def get_rotation_y(self) -> float:
+        """
+        Returns the rotation speed around the X axis in degrees per second.
+        @returns {float} rotation speed around the X axis in degrees per second
+        """
+        if self.__is_gyrometer_initialized:
+            """
+            On reading multiple bytes from i2c the register will be incremented.
+            Therefore the lower register value will be read which is the MSB.
+            The returned value is the most significant byte (MSB) and least significant byte (LSB) in reverse order.
+            """
+            result = self.__i2c.read_word_data(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.GYRO_Y_MSB)
+            result = result.from_bytes(result.to_bytes(2, byteorder='big'), byteorder='little', signed='True')
+            return result * self.__gyro_resolution
+        return None
+
+    def get_rotation_z(self) -> float:
+        """
+        Returns the rotation speed around the X axis in degrees per second.
+        @returns {float} rotation speed around the X axis in degrees per second
+        """
+        if self.__is_gyrometer_initialized:
+            """
+            On reading multiple bytes from i2c the register will be incremented.
+            Therefore the lower register value will be read which is the MSB.
+            The returned value is the most significant byte (MSB) and least significant byte (LSB) in reverse order.
+            """
+            result = self.__i2c.read_word_data(ICM_42670_P.GYRO_ACC_ADDR, ICM_42670_P.GYRO_Z_MSB)
+            result = result.from_bytes(result.to_bytes(2, byteorder='big'), byteorder='little', signed='True')
+            return result * self.__gyro_resolution
+        return None
+
+    def get_magnetic_field_x(self) -> float:
+        """
+        Returns the current magnetic flux density in X direction in microtesla.
+        @returns {float} mangnetic flux density in X direction in microtesla
+        """
+        if self.__is_magnetometer_initialized:
+            Xout0 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Xout_0) << 12
+            Xout1 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Xout_1) << 4
+            Xout2 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Xout_2) >> 4
+            x = Xout0 | Xout1 | Xout2
+            x -= 1 << 19
+            x *= 0.00625
+            # trigger next conversion
+            self.__i2c.write_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, 0x1B, 0x21)
+            return x
+        return None
+
+    def get_magnetic_field_y(self) -> float:
+        """
+        Returns the current magnetic flux density in y direction in microtesla.
+        @returns {float} mangnetic flux density in y direction in microtesla
+        """
+        if self.__is_magnetometer_initialized:
+            Yout0 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Yout_0) << 12
+            Yout1 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Yout_1) << 4
+            Yout2 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Yout_2) >> 4
+            y = Yout0 | Yout1 | Yout2
+            y -= 1 << 19
+            y *= 0.00625
+            # trigger next conversion
+            self.__i2c.write_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, 0x1B, 0x21)
+            return y
+        return None
+
+    def get_magnetic_field_z(self) -> float:
+        """
+        Returns the current magnetic flux density in z direction in microtesla.
+        @returns {float} mangnetic flux density in z direction in microtesla
+        """
+        if self.__is_magnetometer_initialized:
+            Zout0 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Zout_0) << 12
+            Zout1 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Zout_1) << 4
+            Zout2 = self.__i2c.read_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, MMC5603NJ.MAG_Zout_2) >> 4
+            z = Zout0 | Zout1 | Zout2
+            z -= 1 << 19
+            z *= 0.00625
+            # trigger next conversion
+            self.__i2c.write_byte_data(MMC5603NJ.MAGNETOMETER_ADDRESS, 0x1B, 0x21)
+            return z
+        return None
+
+    def update_reg(self, address, register, value, mask):
+        current = self.__i2c.read_word_data(address, register)
+        val = (current & ~mask) | (value & mask)
+        self.__i2c.write_byte_data(address, register, val)
diff --git a/gen/fischertechnik/controller/txt4/Txt4Compressor.py b/lib/fischertechnik/controller/txt4/Txt4Compressor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Compressor.py
rename to lib/fischertechnik/controller/txt4/Txt4Compressor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Controller.py b/lib/fischertechnik/controller/txt4/Txt4Controller.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Controller.py
rename to lib/fischertechnik/controller/txt4/Txt4Controller.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4ControllerFactory.py b/lib/fischertechnik/controller/txt4/Txt4ControllerFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4ControllerFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4ControllerFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4ControllerInfo.py b/lib/fischertechnik/controller/txt4/Txt4ControllerInfo.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4ControllerInfo.py
rename to lib/fischertechnik/controller/txt4/Txt4ControllerInfo.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Counter.py b/lib/fischertechnik/controller/txt4/Txt4Counter.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Counter.py
rename to lib/fischertechnik/controller/txt4/Txt4Counter.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4CounterFactory.py b/lib/fischertechnik/controller/txt4/Txt4CounterFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4CounterFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4CounterFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4DigitalCounter.py b/lib/fischertechnik/controller/txt4/Txt4DigitalCounter.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4DigitalCounter.py
rename to lib/fischertechnik/controller/txt4/Txt4DigitalCounter.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Encodermotor.py b/lib/fischertechnik/controller/txt4/Txt4Encodermotor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Encodermotor.py
rename to lib/fischertechnik/controller/txt4/Txt4Encodermotor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4EncodermotorCounter.py b/lib/fischertechnik/controller/txt4/Txt4EncodermotorCounter.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4EncodermotorCounter.py
rename to lib/fischertechnik/controller/txt4/Txt4EncodermotorCounter.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4EnvironmentSensor.py b/lib/fischertechnik/controller/txt4/Txt4EnvironmentSensor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4EnvironmentSensor.py
rename to lib/fischertechnik/controller/txt4/Txt4EnvironmentSensor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4GestureSensor.py b/lib/fischertechnik/controller/txt4/Txt4GestureSensor.py
similarity index 89%
rename from gen/fischertechnik/controller/txt4/Txt4GestureSensor.py
rename to lib/fischertechnik/controller/txt4/Txt4GestureSensor.py
index 9f16d2d9faf92eca0432dc4b0f0809d1b4ac8c08..0bad92b9cefc3efff64f46d174dd7eab1e80d6da 100644
--- a/gen/fischertechnik/controller/txt4/Txt4GestureSensor.py
+++ b/lib/fischertechnik/controller/txt4/Txt4GestureSensor.py
@@ -3,6 +3,7 @@ from apds9960 import APDS9960
 from smbus import SMBus
 
 import threading
+import time
 
 from ...models.Color import Color
 from ..GestureSensor import GestureSensor
@@ -15,6 +16,7 @@ class Txt4GestureSensor(GestureSensor):
         self.__lock = threading.Lock()
         self.__thread = None
         self.__gesture = APDS9960_DIR_NONE
+        self.__last_gesture_time = time.time()
 
     def enable_light(self):
         self.__stop_read_gesture()
@@ -100,3 +102,10 @@ class Txt4GestureSensor(GestureSensor):
             if self.__apds.isGestureAvailable():
                 with self.__lock:
                     self.__gesture = self.__apds.readGesture()
+                    self.__last_gesture_time = time.time()
+            else:
+                current_time = time.time()
+                if (current_time - self.__last_gesture_time) > 0.7:
+                    with self.__lock:
+                        self.__gesture = APDS9960_DIR_NONE
+
diff --git a/gen/fischertechnik/controller/txt4/Txt4I2CFactory.py b/lib/fischertechnik/controller/txt4/Txt4I2CFactory.py
similarity index 76%
rename from gen/fischertechnik/controller/txt4/Txt4I2CFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4I2CFactory.py
index 2b92ff7b00d6116ce8c67149d9f31155ff040e7a..9e8e3a0ba640eb2c850d1da624199dd8ed684b90 100644
--- a/gen/fischertechnik/controller/txt4/Txt4I2CFactory.py
+++ b/lib/fischertechnik/controller/txt4/Txt4I2CFactory.py
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 # -*- coding: UTF-8 -*-
 from .Txt4CombinedSensor import Txt4CombinedSensor
+from .Txt4CombinedSensor6Pin import Txt4CombinedSensor6Pin
 from .Txt4EnvironmentSensor import Txt4EnvironmentSensor
 from .Txt4GestureSensor import Txt4GestureSensor
 from ..I2CFactory import I2CFactory
@@ -19,6 +20,12 @@ class Txt4I2CFactory(I2CFactory):
         @ReturnType fischertechnik.controller.CombinedSensor"""
         return Txt4CombinedSensor(controller, identifier)
 
+    def create_combined_sensor_6pin(self, controller, identifier):
+        """@ParamType controller fischertechnik.controller.GraphicalInputOutputController
+        @ParamType identifier int
+        @ReturnType fischertechnik.controller.CombinedSensor"""
+        return Txt4CombinedSensor6Pin(controller, identifier)
+
     def create_gesture_sensor(self, controller, identifier):
         """@ParamType controller fischertechnik.controller.GraphicalInputOutputController
         @ParamType identifier int
diff --git a/gen/fischertechnik/controller/txt4/Txt4InputFactory.py b/lib/fischertechnik/controller/txt4/Txt4InputFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4InputFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4InputFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4LightSource.py b/lib/fischertechnik/controller/txt4/Txt4LightSource.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4LightSource.py
rename to lib/fischertechnik/controller/txt4/Txt4LightSource.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Loudspeaker.py b/lib/fischertechnik/controller/txt4/Txt4Loudspeaker.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Loudspeaker.py
rename to lib/fischertechnik/controller/txt4/Txt4Loudspeaker.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4MagneticValve.py b/lib/fischertechnik/controller/txt4/Txt4MagneticValve.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4MagneticValve.py
rename to lib/fischertechnik/controller/txt4/Txt4MagneticValve.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Microphone.py b/lib/fischertechnik/controller/txt4/Txt4Microphone.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Microphone.py
rename to lib/fischertechnik/controller/txt4/Txt4Microphone.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4MiniSwitch.py b/lib/fischertechnik/controller/txt4/Txt4MiniSwitch.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4MiniSwitch.py
rename to lib/fischertechnik/controller/txt4/Txt4MiniSwitch.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4MiniSwitchCounter.py b/lib/fischertechnik/controller/txt4/Txt4MiniSwitchCounter.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4MiniSwitchCounter.py
rename to lib/fischertechnik/controller/txt4/Txt4MiniSwitchCounter.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Motor.py b/lib/fischertechnik/controller/txt4/Txt4Motor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Motor.py
rename to lib/fischertechnik/controller/txt4/Txt4Motor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4MotorFactory.py b/lib/fischertechnik/controller/txt4/Txt4MotorFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4MotorFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4MotorFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4NTCResistor.py b/lib/fischertechnik/controller/txt4/Txt4NTCResistor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4NTCResistor.py
rename to lib/fischertechnik/controller/txt4/Txt4NTCResistor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4OutputFactory.py b/lib/fischertechnik/controller/txt4/Txt4OutputFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4OutputFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4OutputFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4PhotoTransistor.py b/lib/fischertechnik/controller/txt4/Txt4PhotoTransistor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4PhotoTransistor.py
rename to lib/fischertechnik/controller/txt4/Txt4PhotoTransistor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4PhotoTransistorCounter.py b/lib/fischertechnik/controller/txt4/Txt4PhotoTransistorCounter.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4PhotoTransistorCounter.py
rename to lib/fischertechnik/controller/txt4/Txt4PhotoTransistorCounter.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Resistor.py b/lib/fischertechnik/controller/txt4/Txt4Resistor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Resistor.py
rename to lib/fischertechnik/controller/txt4/Txt4Resistor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4Servomotor.py b/lib/fischertechnik/controller/txt4/Txt4Servomotor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4Servomotor.py
rename to lib/fischertechnik/controller/txt4/Txt4Servomotor.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4ServomotorFactory.py b/lib/fischertechnik/controller/txt4/Txt4ServomotorFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4ServomotorFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4ServomotorFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4TrailFollower.py b/lib/fischertechnik/controller/txt4/Txt4TrailFollower.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4TrailFollower.py
rename to lib/fischertechnik/controller/txt4/Txt4TrailFollower.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4USBFactory.py b/lib/fischertechnik/controller/txt4/Txt4USBFactory.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4USBFactory.py
rename to lib/fischertechnik/controller/txt4/Txt4USBFactory.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4UltrasonicDistanceMeter.py b/lib/fischertechnik/controller/txt4/Txt4UltrasonicDistanceMeter.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4UltrasonicDistanceMeter.py
rename to lib/fischertechnik/controller/txt4/Txt4UltrasonicDistanceMeter.py
diff --git a/gen/fischertechnik/controller/txt4/Txt4UnidirectionalMotor.py b/lib/fischertechnik/controller/txt4/Txt4UnidirectionalMotor.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/Txt4UnidirectionalMotor.py
rename to lib/fischertechnik/controller/txt4/Txt4UnidirectionalMotor.py
diff --git a/gen/fischertechnik/controller/txt4/__init__.py b/lib/fischertechnik/controller/txt4/__init__.py
similarity index 100%
rename from gen/fischertechnik/controller/txt4/__init__.py
rename to lib/fischertechnik/controller/txt4/__init__.py
diff --git a/gen/fischertechnik/events/Event.py b/lib/fischertechnik/events/Event.py
similarity index 100%
rename from gen/fischertechnik/events/Event.py
rename to lib/fischertechnik/events/Event.py
diff --git a/gen/fischertechnik/events/EventLoop.py b/lib/fischertechnik/events/EventLoop.py
similarity index 100%
rename from gen/fischertechnik/events/EventLoop.py
rename to lib/fischertechnik/events/EventLoop.py
diff --git a/gen/fischertechnik/events/EventWorker.py b/lib/fischertechnik/events/EventWorker.py
similarity index 100%
rename from gen/fischertechnik/events/EventWorker.py
rename to lib/fischertechnik/events/EventWorker.py
diff --git a/gen/fischertechnik/events/__init__.py b/lib/fischertechnik/events/__init__.py
similarity index 100%
rename from gen/fischertechnik/events/__init__.py
rename to lib/fischertechnik/events/__init__.py
diff --git a/gen/fischertechnik/factories/__init__.py b/lib/fischertechnik/factories/__init__.py
similarity index 100%
rename from gen/fischertechnik/factories/__init__.py
rename to lib/fischertechnik/factories/__init__.py
diff --git a/lib/fischertechnik/http/HttpRequests.py b/lib/fischertechnik/http/HttpRequests.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3496735ae4b4d40472dd1227700bcbcc6d0a72e
--- /dev/null
+++ b/lib/fischertechnik/http/HttpRequests.py
@@ -0,0 +1,73 @@
+import requests
+import json
+
+
+class HttpRequests:
+
+    @staticmethod
+    def __http_request(url, headers, data, method):
+        try:
+            # The required format is: {"Header1": "Header1"}.
+            # The input value of headers is expected as string,
+            # the json.load operation removes the first quotation marks.
+            _headers = json.loads(headers)
+            _data = data
+            # Timeout-Tuple = (connect, read)
+            _timeout = (3, 20)
+
+            if method == "get":
+                r = requests.get(url, headers=_headers, timeout=_timeout)
+            elif method == "post":
+                r = requests.post(url, headers=_headers, data=_data, timeout=_timeout)
+            elif method == "put":
+                r = requests.put(url, headers=_headers, data=_data, timeout=_timeout)
+            elif method == "patch":
+                r = requests.patch(url, data=_data, headers=_headers, timeout=_timeout)
+            elif method == "delete":
+                r = requests.delete(url, headers=_headers, data=_data, timeout=_timeout)
+            else:
+                raise ValueError("Illegal Argument: Unknown HTTP-Method")
+
+            if r.status_code == 200:
+                return json.dumps(r.json())
+            else:
+                return json.dumps(r.status_code)
+
+        except Exception as exc:
+            raise ValueError("Something went wrong, please check your input values!") from exc
+
+    @staticmethod
+    def get_request(url, headers):
+        try:
+            return HttpRequests.__http_request(url, headers, None, "get")
+        except ValueError as ve:
+            return ve
+
+    @staticmethod
+    def post_request(url, headers, data):
+        try:
+            return HttpRequests.__http_request(url, headers, data, "post")
+        except ValueError as ve:
+            return ve
+
+    @staticmethod
+    def put_request(url, headers, data):
+        try:
+            return HttpRequests.__http_request(url, headers, data, "put")
+        except ValueError as ve:
+            return ve
+
+    @staticmethod
+    def patch_request(url, header, data):
+        try:
+            return HttpRequests.__http_request(url, header, data, "patch")
+        except ValueError as ve:
+            return ve
+
+    @staticmethod
+    def delete_request(url, header, data):
+        try:
+            return HttpRequests.__http_request(url, header, data, "delete")
+        except ValueError as ve:
+            return ve
+
diff --git a/gen/fischertechnik/machine_learning/__init__.py b/lib/fischertechnik/http/__init__.py
similarity index 100%
rename from gen/fischertechnik/machine_learning/__init__.py
rename to lib/fischertechnik/http/__init__.py
diff --git a/gen/fischertechnik/machine_learning/Detector.py b/lib/fischertechnik/machine_learning/Detector.py
similarity index 83%
rename from gen/fischertechnik/machine_learning/Detector.py
rename to lib/fischertechnik/machine_learning/Detector.py
index 1e4de7bb668e69c23e0e91c9a5c427db0f891eac..a254724d4e3ae523da10b1bfe2c00884af493e99 100644
--- a/gen/fischertechnik/machine_learning/Detector.py
+++ b/lib/fischertechnik/machine_learning/Detector.py
@@ -1,4 +1,5 @@
 import base64
+import multiprocessing
 
 import cv2
 import numpy as np
@@ -26,7 +27,8 @@ class Detector(object):
 
     def load_model(self, model_path):
         r"""Load TFLite model, returns a Interpreter instance."""
-        interpreter = tflite.Interpreter(model_path=model_path)
+        core_count = multiprocessing.cpu_count()
+        interpreter = tflite.Interpreter(model_path=model_path, num_threads=core_count)
         interpreter.allocate_tensors()
         return interpreter
 
@@ -34,7 +36,7 @@ class Detector(object):
         pass
 
 
-    def process_base64_image(self, encoded_image, k=3):
+    def process_base64_image(self, encoded_image):
         decoded_data = base64.b64decode(encoded_image)
         np_array = np.frombuffer(decoded_data, np.uint8)
         image = cv2.imdecode(np_array, cv2.IMREAD_UNCHANGED)
diff --git a/gen/fischertechnik/machine_learning/ImageClassifier.py b/lib/fischertechnik/machine_learning/ImageClassifier.py
similarity index 57%
rename from gen/fischertechnik/machine_learning/ImageClassifier.py
rename to lib/fischertechnik/machine_learning/ImageClassifier.py
index 8c2c1a4a949982a07bfbd3de78c16874f735358c..890b043d228e9a56698a62bf0cc048d2df9d9e8e 100644
--- a/gen/fischertechnik/machine_learning/ImageClassifier.py
+++ b/lib/fischertechnik/machine_learning/ImageClassifier.py
@@ -6,33 +6,41 @@ from .Detector import Detector
 
 class ImageClassifier(Detector):
 
-    def process_image(self, image, k=0):
-        r"""Process an image, Return top K result in a list of 2-Tuple(confidence_score, _id)"""
-        result = dict()
+    def process_image(self, image):
+        
+        result = []
         if image is None:
-            for label in self.labels:
-                result[self.labels[label]] = 0
-            return dict()
+            return result
+        
+        orig_width = image.shape[1]
+        orig_height = image.shape[0]
+
         input_details = self.interpreter.get_input_details()
         input_shape = input_details[0]['shape']
         height = input_shape[1]
         width = input_shape[2]
+
         image = cv2.resize(image, (width, height))
         input_data = np.expand_dims(image, axis=0)  # expand to 4-dim
 
-        # Process
+        # analyse image
         self.interpreter.set_tensor(self.interpreter.get_input_details()[0]['index'], input_data)
         self.interpreter.invoke()
 
-        # Get outputs
+        # result of the analysis
         output_details = self.interpreter.get_output_details()
         output_data = self.interpreter.get_tensor(output_details[0]['index'])
         output_data = np.squeeze(output_data)
 
-        # Get top K result
-        top_k = output_data.argsort()[-k:][::-1]  # Top_k index
-        for _id in top_k:
+        k = 1 # only the first result is relevant
+        sorted_output = output_data.argsort()[-k:][::-1]
+        for _id in sorted_output:
             score = float(output_data[_id] / 255.0)
-            result[self.labels[_id]] = score
+            if score > 0.5:
+                result.append({
+                    'label': self.labels[_id],
+                    'position': [0, 0, orig_width, orig_height],
+                    'probability': score
+                })
 
         return result
diff --git a/gen/fischertechnik/machine_learning/ObjectDetector.py b/lib/fischertechnik/machine_learning/ObjectDetector.py
similarity index 56%
rename from gen/fischertechnik/machine_learning/ObjectDetector.py
rename to lib/fischertechnik/machine_learning/ObjectDetector.py
index 014bdc8d3d4a6b4a85fb67c0ba601e285d03f9aa..d4f1e6a68424aef025935c6782ff22bed1be3d08 100644
--- a/gen/fischertechnik/machine_learning/ObjectDetector.py
+++ b/lib/fischertechnik/machine_learning/ObjectDetector.py
@@ -1,31 +1,34 @@
 import cv2
 import numpy as np
 
-from ..camera.VideoStream import VideoStream
 from .Detector import Detector
 
 
 class ObjectDetector(Detector):
 
     def process_image(self, image):
-        r"""Process an image, Return a list of detected class ids and positions"""
-        result = dict()
+        
+        result = []
         if image is None:
-            for label in self.labels:
-                result[self.labels[label]] = 0
-            return dict()
+            return result
+        
+        orig_width = image.shape[1]
+        orig_height = image.shape[0]
+
         input_details = self.interpreter.get_input_details()
         input_shape = input_details[0]['shape']
         height = input_shape[1]
         width = input_shape[2]
+        
         image = cv2.resize(image, (width, height))
+        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
         input_data = np.expand_dims(image, axis=0)  # expand to 4-dim
 
-        # Process
+        # analyse image
         self.interpreter.set_tensor(self.interpreter.get_input_details()[0]['index'], input_data)
         self.interpreter.invoke()
 
-        # Get outputs
+        # result of the analysis
         output_details = self.interpreter.get_output_details()
         # output_details[0] - position
         # output_details[1] - class id
@@ -37,11 +40,16 @@ class ObjectDetector(Detector):
         scores = np.squeeze(self.interpreter.get_tensor(output_details[2]['index']))
 
         for idx, score in enumerate(scores):
-            positions[idx][1] = int(max(0, positions[idx][1] * VideoStream.getInstance().get_width()))
-            positions[idx][3] = int(min(width, positions[idx][3] * VideoStream.getInstance().get_width()))
-            positions[idx][0] = int(max(0, positions[idx][0] * VideoStream.getInstance().get_height()))
-            positions[idx][2] = int(min(height, positions[idx][2] * VideoStream.getInstance().get_height()))
-            result[self.labels[int(classes[idx])]] = {'position': positions[idx], 'probability': score}
-
-        return result
+            if score > 0.5:
+                x1 = int(max(0, positions[idx][1] * orig_width))
+                x2 = int(min(positions[idx][3] * orig_width, orig_width))
+                y1 = int(max(0, positions[idx][0] * orig_height))
+                y2 = int(min(positions[idx][2] * orig_height, orig_height))
+                result.append({
+                    'label': self.labels[int(classes[idx])],
+                    'position': [x1, y1, x2, y2],
+                    'probability': score
+                })
+
+        return sorted(result, key=lambda i: i['probability'], reverse=True)
 
diff --git a/gen/fischertechnik/models/__init__.py b/lib/fischertechnik/machine_learning/__init__.py
similarity index 100%
rename from gen/fischertechnik/models/__init__.py
rename to lib/fischertechnik/machine_learning/__init__.py
diff --git a/gen/fischertechnik/models/Ball.py b/lib/fischertechnik/models/Ball.py
similarity index 100%
rename from gen/fischertechnik/models/Ball.py
rename to lib/fischertechnik/models/Ball.py
diff --git a/gen/fischertechnik/models/Color.py b/lib/fischertechnik/models/Color.py
similarity index 100%
rename from gen/fischertechnik/models/Color.py
rename to lib/fischertechnik/models/Color.py
diff --git a/gen/fischertechnik/models/Line.py b/lib/fischertechnik/models/Line.py
similarity index 100%
rename from gen/fischertechnik/models/Line.py
rename to lib/fischertechnik/models/Line.py
diff --git a/gen/fischertechnik/models/Rectangle.py b/lib/fischertechnik/models/Rectangle.py
similarity index 100%
rename from gen/fischertechnik/models/Rectangle.py
rename to lib/fischertechnik/models/Rectangle.py
diff --git a/gen/fischertechnik/mqtt/__init__.py b/lib/fischertechnik/models/__init__.py
similarity index 100%
rename from gen/fischertechnik/mqtt/__init__.py
rename to lib/fischertechnik/models/__init__.py
diff --git a/gen/fischertechnik/mqtt/Client.py b/lib/fischertechnik/mqtt/Client.py
similarity index 57%
rename from gen/fischertechnik/mqtt/Client.py
rename to lib/fischertechnik/mqtt/Client.py
index 429d1c405aff490111544974cacbd6d52b00a9e0..1400e094faf9ad5e7a7f93f92567a6fe18cb1b60 100644
--- a/gen/fischertechnik/mqtt/Client.py
+++ b/lib/fischertechnik/mqtt/Client.py
@@ -6,10 +6,11 @@ import paho.mqtt.client as mqtt
 
 class Client:
 
+    KEEP_ALIVE = 60
+
     def __init__(self, client_id="", clean_session=True, userdata=None, protocol=mqtt.MQTTv311, transport="tcp",
                  path="/"):
-        self.callbacks = {}
-        self.subscribe_qos = 0
+        self.handler = {}
         self.connected = False
         self.paho_client = mqtt.Client(client_id, clean_session, userdata, protocol, transport)
         if transport == 'websockets':
@@ -23,11 +24,14 @@ class Client:
 
     def connect(self, host, port, keepalive, bind_address, user, password):
         if 'beemo.eu' in host or 'fischertechnik-cloud.com' in host:
-            context = ssl.create_default_context()
-            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            context.wrap_socket(s, server_hostname="*.beemo.eu")
-            self.paho_client.tls_set_context(context)
-        if user:
+            try:
+                context = ssl.create_default_context()
+                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                context.wrap_socket(s, server_hostname="*.beemo.eu")
+                self.paho_client.tls_set_context(context)
+            except:
+                pass
+        if user and password:
             self.paho_client.username_pw_set(user, password)
         self.paho_client.connect(host, port, keepalive, bind_address)
         self.paho_client.loop_start()
@@ -40,13 +44,16 @@ class Client:
         return self.connected
 
     def subscribe(self, topic, callback, qos=0):
-        self.subscribe_qos = qos
-        self.__add_callback(topic, callback)
+        self.handler[topic] = {"callback": callback, "qos": qos}
+        if self.connected == True:
+            self.paho_client.subscribe(topic, qos)
 
-    def unsubscribe(self, topic, callback):
-        self.__remove_callback(topic, callback)
+    def unsubscribe(self, topic):
+        del self.handler[topic]
+        if self.connected == True:
+            self.paho_client.unsubscribe(topic)
 
-    def publish(self, topic, payload, qos, retain):
+    def publish(self, topic, payload=None, qos=0, retain=True):
         return self.paho_client.publish(topic, payload, qos, retain)
 
     def will_set(self, topic, payload=None, qos=0, retain=False):
@@ -56,8 +63,8 @@ class Client:
         if rc != 0:
             print("Unexpected connection.")
         else:
-            for topic in self.callbacks:
-                self.paho_client.subscribe(topic, self.subscribe_qos)
+            for topic in self.handler:
+                self.paho_client.subscribe(topic, self.handler[topic]["qos"])
             self.connected = True
 
     def __on_disconnect(self, client, userdata, rc):
@@ -67,22 +74,6 @@ class Client:
             self.connected = False
 
     def __on_message(self, client, userdata, msg):
-        for topic in self.callbacks:
+        for topic in self.handler:
             if mqtt.topic_matches_sub(topic, msg.topic):
-                for callback in self.callbacks[topic]:
-                    callback(msg)
-
-    def __add_callback(self, topic, callback):
-        if not self.__has_callback(topic, callback):
-            if topic not in self.callbacks:
-                self.callbacks[topic] = []
-            self.callbacks[topic].append(callback)
-
-    def __remove_callback(self, topic, callback):
-        if self.__has_callback(topic, callback):
-            self.callbacks[topic].remove(callback)
-            if len(self.callbacks[topic]) == 0:
-                del self.callbacks[topic]
-
-    def __has_callback(self, topic, callback):
-        return topic in self.callbacks and callback in self.callbacks[topic]
+                self.handler[topic]["callback"](msg)
diff --git a/gen/fischertechnik/mqtt/Constants.py b/lib/fischertechnik/mqtt/Constants.py
similarity index 80%
rename from gen/fischertechnik/mqtt/Constants.py
rename to lib/fischertechnik/mqtt/Constants.py
index 03d9cee1c832f437e2c587306c9d6d94ff2f0ef1..00177bcbf0c3dc55adda4d2c3c693b720b8a2012 100644
--- a/gen/fischertechnik/mqtt/Constants.py
+++ b/lib/fischertechnik/mqtt/Constants.py
@@ -5,10 +5,7 @@ def read_out(a, b):
     configFilePath = r'/opt/ft/config/Fischertechnik/TXT_4.0_Menu.conf'
     configParser.read(configFilePath)
     value = configParser.get(a, b)
-    if value != "":
-        return value
-    else:
-        raise Exception('No value given for ' + b)
+    return value
 
 MQTT_USER = read_out('FischertechnikCloud', 'ft_mqtt_user')
 MQTT_PASSWORD = read_out('FischertechnikCloud', 'ft_mqtt_password')
diff --git a/gen/fischertechnik/mqtt/FTCloudClient.py b/lib/fischertechnik/mqtt/FTCloudClient.py
similarity index 85%
rename from gen/fischertechnik/mqtt/FTCloudClient.py
rename to lib/fischertechnik/mqtt/FTCloudClient.py
index 301c29fea02e9c59015f29fbfd7886f3f59e2000..2bbacfc0fe6ad6ee91d19c97b68a0369147aec85 100644
--- a/gen/fischertechnik/mqtt/FTCloudClient.py
+++ b/lib/fischertechnik/mqtt/FTCloudClient.py
@@ -6,7 +6,6 @@ class FTCloudClient(Client):
 
     HOST = "rabbitmq-data-live.beemo.eu"
     PORT = 443
-    KEEP_ALIVE = 60
 
     __instance = None
 
@@ -28,8 +27,7 @@ class FTCloudClient(Client):
     def __del__(self):
         Client.__del__(self)
 
-    def connect(self, host=HOST, port=PORT, keepalive=KEEP_ALIVE, bind_address="", user=MQTT_USER,
-                password=MQTT_PASSWORD):
+    def connect(self, host=HOST, port=PORT, keepalive=Client.KEEP_ALIVE, bind_address="", user=MQTT_USER, password=MQTT_PASSWORD):
         Client.connect(self, host, port, keepalive, bind_address, user, password)
 
     def publish(self, topic, payload=None, qos=2, retain=True):
diff --git a/gen/fischertechnik/mqtt/MqttClient.py b/lib/fischertechnik/mqtt/MqttClient.py
similarity index 59%
rename from gen/fischertechnik/mqtt/MqttClient.py
rename to lib/fischertechnik/mqtt/MqttClient.py
index fa5afa71608ffc4fd09dc8931db3d7ef85a9cfb0..96029657140a967ed65c18cc3f1367fc54c22410 100644
--- a/gen/fischertechnik/mqtt/MqttClient.py
+++ b/lib/fischertechnik/mqtt/MqttClient.py
@@ -1,7 +1,6 @@
 import paho.mqtt.client as mqtt
 
 from ..mqtt.Client import Client
-from ..mqtt.Constants import MQTT_USER, MQTT_PASSWORD
 
 
 class MqttClient(Client):
@@ -13,8 +12,5 @@ class MqttClient(Client):
     def __del__(self):
         Client.__del__(self)
 
-    def connect(self, host, port, keepalive=60, bind_address="", user=MQTT_USER, password=MQTT_PASSWORD):
-        Client.connect(self, host, port, keepalive, bind_address, user, password)
-
-    def publish(self, topic, payload=None, qos=0, retain=False):
-        return Client.publish(self, topic, payload, qos, retain)
+    def connect(self, host, port, keepalive=Client.KEEP_ALIVE, bind_address="", user="", password=""):
+        Client.connect(self, host, port, keepalive, bind_address, user, password)
\ No newline at end of file
diff --git a/gen/fischertechnik/utility/__init__.py b/lib/fischertechnik/mqtt/__init__.py
similarity index 100%
rename from gen/fischertechnik/utility/__init__.py
rename to lib/fischertechnik/mqtt/__init__.py
diff --git a/lib/fischertechnik/utility/__init__.py b/lib/fischertechnik/utility/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/gen/fischertechnik/utility/math.py b/lib/fischertechnik/utility/math.py
similarity index 100%
rename from gen/fischertechnik/utility/math.py
rename to lib/fischertechnik/utility/math.py
diff --git a/gen/fischertechnik/utility/txt_state.py b/lib/fischertechnik/utility/txt_state.py
similarity index 100%
rename from gen/fischertechnik/utility/txt_state.py
rename to lib/fischertechnik/utility/txt_state.py
diff --git a/gen/publish.sh b/lib/publish.sh
similarity index 100%
rename from gen/publish.sh
rename to lib/publish.sh
diff --git a/gen/setup.py b/lib/setup.py
similarity index 67%
rename from gen/setup.py
rename to lib/setup.py
index 2988f2c398c12f680aebcc1b1ec2b15888b381de..5470d5955b92f558476147304662fc02c51aceb3 100644
--- a/gen/setup.py
+++ b/lib/setup.py
@@ -1,14 +1,22 @@
 import setuptools
 
+REQUIRES = [
+    "setuptools==41.4.0",
+    "imutils==0.5.3",
+    "smbus2>=0.2.1",
+    "bme680==1.0.5",
+    "apds9960==0.2"
+]
+
 setuptools.setup(
     name='ft-controllerlib',
+    install_requires=REQUIRES,
     packages=setuptools.find_packages(),
     description='A Library for the fischertechnik controller',
-    version='6.0.11',
+    version='0.0.0',
     author='beemo GmbH',
     author_email='info@beemo.eu',
     url="https://www.fischertechnik-cloud.com",
     keywords=['txt', 'fischertechnik', 'controller', 'lib'],
     python_requires='>=3.5'
 )
-
diff --git a/modelling/Fischertechnik.vpp b/modelling/Fischertechnik.vpp
deleted file mode 100644
index 72b11daedb1f6f75fd8814f39d5d6c6d9eb4ddca..0000000000000000000000000000000000000000
Binary files a/modelling/Fischertechnik.vpp and /dev/null differ
diff --git a/modelling/Fischertechnik.vux b/modelling/Fischertechnik.vux
deleted file mode 100644
index 6ba285c459ace90d444d7a98a7b39307f68d37bd..0000000000000000000000000000000000000000
Binary files a/modelling/Fischertechnik.vux and /dev/null differ
diff --git a/patchset/txt/deploy/colorized_output.py b/patchset/txt/deploy/colorized_output.py
deleted file mode 100755
index cb1305c65172553a34aa9ad4539158cfaf027e88..0000000000000000000000000000000000000000
--- a/patchset/txt/deploy/colorized_output.py
+++ /dev/null
@@ -1,27 +0,0 @@
-class Color:
-    HEADER = '\033[95m'
-    OKBLUE = '\033[94m'
-    OKGREEN = '\033[92m'
-    WARNING = '\033[93m'
-    FAIL = '\033[91m'
-    ENDC = '\033[0m'
-    BOLD = '\033[1m'
-    UNDERLINE = '\033[4m'
-
-def print_colored(string, color):
-    print(color + string + Color.ENDC)
-
-def print_bold(string):
-    print_colored(string, Color.BOLD)
-
-def print_warning(string):
-    print_colored(string, Color.WARNING)
-
-def print_success(string):
-    print_colored(string, Color.OKGREEN)
-
-def print_info(string):
-    print_colored(string, Color.OKBLUE)
-
-def print_error(string):
-    print_colored(string, Color.FAIL)
\ No newline at end of file
diff --git a/patchset/txt/deploy/deployment.py b/patchset/txt/deploy/deployment.py
deleted file mode 100644
index 01bdb36b5836efe942690e9b61cdefb336d3ac9b..0000000000000000000000000000000000000000
--- a/patchset/txt/deploy/deployment.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import os
-
-from deploy import colorized_output as co
-from deploy.mounts import Mounts
-from deploy.python_environment import PythonEnvironment
-from deploy.repository import Repository
-
-from fabric import Connection
-
-USER = 'ftc'
-ROOT = 'root'
-
-class Deployment:
-    def __init__(self, host):
-        self.host = host
-        self.connection = Connection(host = host, user = USER)
-
-    def check_mounts(self):
-        mnts = Mounts(self.connection)
-        mnts.check_mounts()
-
-    def check_pip_and_libraries(self):
-        pyenv = PythonEnvironment(self.connection)
-        pyenv.check_pip()
-        pyenv.check_pip_libraries()
-        pyenv.add_ftc_path()
-
-    def run_tests(self):
-        repo = Repository(self.connection)
-        repo.uploadFolder('../../tests')
-        co.print_info("Starting tests...")
-        self.connection.run("python3 /home/ftc/tests/txt/main.py")
-
-    def build_package(self):
-        os.system('cd ../../gen && ./build.sh')
-        os.system('mv ../../gen/dist/ft-controllerlib-*.tar.gz ../../gen/dist/ft-controllerlib.tar.gz')
-
-    def upload_package(self):
-        repo = Repository(self.connection)
-        repo.uploadFolder('../../gen/dist')
-
-    def install_package(self):
-        self.connection.run("pip3 install -I /home/ftc/gen/dist/ft-controllerlib.tar.gz")
-
-    def clean_up(self):
-        self.connection.run("rm -rf /tests")
-        os.system("cd ../../gen && rm -rf dist build ft_git ft-controllerlib.egg-info")
-
-
diff --git a/patchset/txt/deploy/mounts.py b/patchset/txt/deploy/mounts.py
deleted file mode 100755
index 0b962939a384a545635f928336984f06a9eea378..0000000000000000000000000000000000000000
--- a/patchset/txt/deploy/mounts.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from deploy import colorized_output as co
-
-class Mounts:
-    MOUNTED_SUDO = '/home/ftc/mounts/usr/bin/sudo'
-
-    def __init__(self, connection):
-        self.connection = connection
-        self.mounts = self.connection.run('cat /etc/mtab').stdout.strip().split()
-
-    def create_mounts(self):
-        co.print_info('Copying files to local mount folders')
-        self.copy_folder_to_mounts('/usr/lib/python3.7/.', '~/mounts/python3.7')
-        self.copy_folder_to_mounts('/usr/bin', '~/mounts/usr')
-        self.chown_mounted_sudo()
-
-    def copy_folder_to_mounts(self, src, dst):
-        self.connection.run("mkdir -p {0}".format(dst))
-        self.connection.run("cp -r {0} {1}".format(src, dst))
-
-    def chown_mounted_sudo(self):
-        self.connection.sudo("chown root:root {0}".format(Mounts.MOUNTED_SUDO))
-        self.connection.sudo("chmod 4755 {0}".format(Mounts.MOUNTED_SUDO))
-
-    def check_mounts(self):
-        if not self.connection.run('ls mounts', warn=True):
-            self.create_mounts()
-        self.check_mount('/usr/lib/python3.7', '/home/ftc/mounts/python3.7')
-        self.check_mount('/usr/bin', '/home/ftc/mounts/usr/bin')
-
-    def check_mount(self, mnt, mnt_dir):
-        co.print_info("Checking mount {0}".format(mnt))
-        if mnt in self.mounts:
-            co.print_success("--> Already mounted")
-        else:
-            co.print_warning("--> Not mounted. Please authorize sudo on txt to mount it")
-            self.connection.sudo("mount {0} {1}".format(mnt_dir, mnt))
-            co.print_success("--> Sucessfully mounted")
\ No newline at end of file
diff --git a/patchset/txt/deploy/python_environment.py b/patchset/txt/deploy/python_environment.py
deleted file mode 100755
index a7fc54212e1df4ba6d24b6326aaa98ad133b653f..0000000000000000000000000000000000000000
--- a/patchset/txt/deploy/python_environment.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from deploy import colorized_output as co
-import os
-
-class PythonEnvironment:
-    def __init__(self, connection):
-        self.connection = connection
-
-    def add_ftc_path(self):
-        co.print_info('Add /opt/ftc to PYTHONPATH')
-        self.connection.run('echo "export PYTHONPATH=/opt/ftc" > /home/ftc/.profile', warn=True)
-        co.print_success('--> Important for ui applications')
-
-    def check_pip(self):
-        co.print_info("Checking pip-installation")
-        if self.connection.run('ls /usr/bin | grep pip3.7', warn=True):
-            co.print_success('--> Already installed')
-        else:
-            co.print_warning('--> Not installed. Starting installation of pip')
-            self.install_pip('~/tmp')
-            co.print_success('--> Successfully installed pip')
-
-    def install_pip(self, tmp_dir):
-        self.connection.run("mkdir -p {0}".format(tmp_dir))
-        self.connection.run("wget https://bootstrap.pypa.io/get-pip.py -O/home/ftc/tmp/get-pip.py".format(tmp_dir))
-        self.connection.run("python {0}/get-pip.py".format(tmp_dir))
-        self.connection.run("rm -rf {0}".format(tmp_dir))
-
-    def check_pip_libraries(self):
-        co.print_info('Checking pip libraries')
-        requirements = self.get_requirements()
-        pip_list = self.get_pip_list()
-        for requirement in requirements:
-            search = requirement.strip().replace(' ', '')
-            self.check_pip_library(pip_list, search)
-
-    def check_pip_library(self, dependencies, dependency):
-        co.print_info("Checking {0}:".format(dependency))
-        if dependency in dependencies:
-            co.print_success("--> Already installed")
-        else:
-            co.print_warning("--> Not installed. Starting installation")
-            if dependency.find('ft-') == -1 and dependency.find('ftrobopy') == -1:
-                self.connection.run("pip install {0}".format(dependency))
-            else:
-                if dependency.find('ftrobopy') != -1:
-                    co.print_warning("--> Removing preinstalled ftrobopy.")
-                    self.connection.run("rm -rf /usr/lib/python3.7/ftrobopy /usr/lib/python3.7/ftrobopy-1.80-py3.7.egg-info /usr/lib/python3.7/ftrobopy.pyc")
-                co.print_info("Downloading from custom repository")
-                co.print_info("Enter credentials if needed")
-                self.connection.run("pip install --index-url https://{0}:{1}@update.fischertechnik-cloud.com/repository/ft-txt-lib/simple/ --no-deps {2}".format(os.getenv('FT_USERNAME'), os.getenv('FT_PASSWORD'), dependency))
-            co.print_success("--> Successfully installed")
-
-    def get_pip_list(self):
-        return self.connection.run('pip list --format=freeze').stdout.strip().split()
-
-    def get_requirements(self):
-        fd = open('requirements.txt', 'r')
-        return fd.readlines()
diff --git a/patchset/txt/deploy/repository.py b/patchset/txt/deploy/repository.py
deleted file mode 100755
index 632c2e8bfb47745bbf7af39bb5bf9f5fadbfc791..0000000000000000000000000000000000000000
--- a/patchset/txt/deploy/repository.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import os
-from deploy import colorized_output as co
-
-class Repository:
-    def __init__(self, connection):
-        self.connection = connection
-
-    def uploadFolder(self, folder):
-        tar_folder = "{0}.tar".format(folder.split('/')[-1])
-        os.system("tar -cf {0} {1}/".format(tar_folder, folder))
-        self.connection.put("{0}".format(tar_folder))
-        self.connection.run("tar -xf {0}".format(tar_folder))
-        self.connection.run("rm {0}".format(tar_folder))
-        os.system("rm {0}".format(tar_folder))
-
-    def uploadAppFolder(self, folder):
-        self.uploadFolder(folder)
-        co.print_info('UploadAppFolder ' + folder)
-        self.connection.run("mkdir -p apps", warn=True)
-        self.connection.run("rm -rf apps/{0}/".format(folder), warn=True)
-        self.connection.run("mv -f {0} apps/".format(folder))
-        self.connection.run("chmod +x apps/{0}/start.py".format(folder))
-        self.connection.run("python apps/{0}/refresh.py".format(folder))
-
-    def replace_ip(self, ip):
-        self.connection.run("cd txtapi/txtapi/openapi && sed -i 's/^host:.*$/host: \"{0}:8080\"/g' openapi.yaml".format(ip))
-
-    def replace_env(self, env_file):
-        self.connection.run("mv txtapi/txtapi/environment/{0} txtapi/txtapi/environment/environment.py".format(env_file))
\ No newline at end of file
diff --git a/patchset/txt/fabfile.py b/patchset/txt/fabfile.py
deleted file mode 100644
index 471029b8bc95a159d4cf603e992ddf8b4683556f..0000000000000000000000000000000000000000
--- a/patchset/txt/fabfile.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import os
-
-from deploy import colorized_output as co
-from deploy.deployment import Deployment
-
-from invoke import task
-
-
-def set_ctx(ctx, host):
-    deployment = Deployment(host)
-    ctx.update({'deploy': deployment})
-
-@task(help={'host': "IP of the txt-controller"})
-def mount(ctx, host):
-    """
-    mounts the needed directories on the txt-controller
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.check_mounts()
-
-@task(help={'host': "IP of the txt-controller"})
-def install_python(ctx, host):
-    """
-    installs pip and dependencies on the txt-controller
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.check_pip_and_libraries()
-
-@task(help={'host': "IP of the txt-controller"})
-def run_tests(ctx, host):
-    """
-    Runs the tests
-    """
-    set_ctx(ctx, host)
-    ctx.deploy.run_tests()
-
-@task(help={'host': "IP of the txt-controller"})
-def clean_up(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.clean_up()
-
-@task(help={'host': "IP of the txt-controller"})
-def build_package(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.build_package()
-
-@task(help={'host': "IP of the txt-controller"})
-def upload_package(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.upload_package()
-
-@task(help={'host': "IP of the txt-controller"})
-def install_package(ctx, host):
-    set_ctx(ctx, host)
-    ctx.deploy.install_package()
-
-@task(help={'host': "IP of the txt-controller"})
-def deploy(ctx, host):
-    """
-    Setup and deploy controllerlib
-    """
-    set_ctx(ctx, host)
-    co.print_info("Step 1/7 >> Creating mounts")
-    mount(ctx, host)
-    co.print_info("Step 2/7 >> Installing pip and dependencies")
-    install_python(ctx, host)
-    co.print_info("Step 3/7 >> Clean up")
-    clean_up(ctx, host)
-    co.print_info("Step 4/7 >> Build Package")
-    build_package(ctx, host)
-    co.print_info("Step 5/7 >> Upload Package")
-    upload_package(ctx, host)
-    co.print_info("Step 6/7 >> Install Package")
-    install_package(ctx, host)
-    co.print_info("Step 7/7 >> Run Tests")
-    run_tests(ctx, host)
diff --git a/patchset/txt/requirements.txt b/patchset/txt/requirements.txt
deleted file mode 100644
index 1c21ac96baecd7b14996cbac55df74110a9632f1..0000000000000000000000000000000000000000
--- a/patchset/txt/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ftrobopy==1.92
-bme680==1.0.5
-apds9960==0.2
diff --git a/patchset/txt4/deploy/deployment.py b/patchset/txt4/deploy/deployment.py
index 078025e1a99bfee66767988e8d4238c3fec283dc..d4899302e72ab883f131afa4d2bc688fc3b7419a 100644
--- a/patchset/txt4/deploy/deployment.py
+++ b/patchset/txt4/deploy/deployment.py
@@ -26,17 +26,17 @@ class Deployment:
 
     def clean_up(self):
         self.connection.run("rm -rf /tests")
-        os.system("cd ../../gen && rm -rf dist build ft_git ft-controllerlib.egg-info")
+        os.system("cd ../../lib && rm -rf dist build ft_git ft-controllerlib.egg-info")
 
     def build_package(self):
-        os.system('cd ../../gen && ./build.sh')
+        os.system('cd ../../lib && ./build.sh')
 
     def upload_package(self):
         os.system(
-            "scp ../../gen/dist/ft-controllerlib-*.tar.gz {0}@{1}:/ft-controllerlib.tar.gz".format(USER, self.host))
+            "scp ../../lib/dist/ft-controllerlib-*.tar.gz {0}@{1}:/ft-controllerlib.tar.gz".format(USER, self.host))
 
     def install_package(self):
-        self.connection.run("pip3 install -I /ft-controllerlib.tar.gz")
+        self.connection.run("export LC_ALL='en_US.UTF-8' && pip3 install -I /ft-controllerlib.tar.gz")
 
     def upload_tests(self, folder):
         os.system("scp -r {0} {1}@{2}:/tests".format(folder, USER, self.host))
diff --git a/patchset/txt4/docker-entrypoint.sh b/patchset/txt4/docker-entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c4bfe9be352d3de67f012c98f9221222334caf10
--- /dev/null
+++ b/patchset/txt4/docker-entrypoint.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+
+mkdir -p ~/.ssh
+ssh-keyscan -t rsa -H $IP_ADDRESS >> ~/.ssh/known_hosts
+
+cd /usr/src/app/patchset/txt4
+fab deploy -h $IP_ADDRESS
\ No newline at end of file
diff --git a/patchset/txt4/requirements.txt b/patchset/txt4/requirements.txt
index e4c1983c6042e2b3131b19e03afd7ab9eb24de2b..4beadc4f39936c6eea3693c4f2c51ee6f62c4adf 100644
--- a/patchset/txt4/requirements.txt
+++ b/patchset/txt4/requirements.txt
@@ -1,2 +1,5 @@
 bme680==1.0.5
 apds9960==0.2
+setuptools==41.4.0
+imutils==0.5.3
+smbus2>=0.2.1
diff --git a/tests/txt/inputs/mini_switch_test.py b/tests/txt/inputs/mini_switch_test.py
deleted file mode 100644
index 1af8ee727818befa58a403dbb47e1e4a4449c5af..0000000000000000000000000000000000000000
--- a/tests/txt/inputs/mini_switch_test.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import fischertechnik.factories as txtFactory
-import time
-
-
-class MiniSwitchTest:
-    description = "Tests, if a push button pressed by a motor is working as intended."
-    brief = "Checks, if a push button works."
-
-    def __init__(self, txt):
-        txtFactory.init_input_factory()
-        self.mini_switch = txtFactory.input_factory.create_mini_switch(txt, 1)
-
-    def does_pass(self):
-        return self.mini_switch.is_open())
diff --git a/tests/txt/lamps/lamp_test.py b/tests/txt/lamps/lamp_test.py
deleted file mode 100644
index 94e741768f466483fd3048abf2f1d521d5e5d56f..0000000000000000000000000000000000000000
--- a/tests/txt/lamps/lamp_test.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import fischertechnik.factories as txtFactory
-import time
-
-
-class SimpleLampTest:
-    description = "Tests, if the LED is working."
-    brief = "Checks LED."
-
-    def __init__(self, txt):
-        txtFactory.init_output_factory()
-        self.lamp = txtFactory.output_factory.create_led(txt, 3)
-
-    def does_pass(self):
-        # Actual code
-        self.lamp.set_brightness(255)
-        time.sleep(1)
-        self.lamp.set_brightness(0)
-        return True
-
diff --git a/tests/txt/main.py b/tests/txt/main.py
deleted file mode 100644
index c5da63041ce4fe8f5d98b1015dad0701b52d168c..0000000000000000000000000000000000000000
--- a/tests/txt/main.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import fischertechnik.factories as txtFactory
-from motors.encodermotor_test import EncodermotorTest
-from inputs.mini_switch_test import MiniSwitchTest
-from lamps.lamp_test import SimpleLampTest
-from sensors.photo_transistor_test import PhotoTransistorTest
-from sensors.environmental_sensor_test import EnvironmentSensorTest
-
-success = '\033[94m'
-failure = '\033[91m'
-info = '\033[93m'
-reset = '\033[0m'
-txtFactory.init_controller_factory()
-txt = txtFactory.controller_factory.create_graphical_controller()
-tests = []
-
-# Add tests
-tests.append(EncodermotorTest(txt))
-tests.append(MiniSwitchTest(txt))
-tests.append(SimpleLampTest(txt))
-tests.append(PhotoTransistorTest(txt))
-tests.append(EnvironmentSensorTest(txt))
-
-
-print(info + "--> Having a total of " + str(len(tests)) + " tasks.\n" + reset)
-for i in range(len(tests)):
-    print(info + "Executing task " + str(i + 1) + "/" + str(len(tests)) + reset + "\n Info: " + tests[i].brief +
-          " ... ", end="", flush=True)
-    if not tests[i].does_pass():
-        print(failure + "failed!\nDescription: " + tests[i].description + reset)
-        print(failure + "\nTests were not successful." + reset)
-        exit(1)
-        break
-    else:
-        print(success + "success." + reset, flush=True)
-print(success + "\nTests were successful." + reset)
-exit(0)
-
diff --git a/tests/txt/motors/encodermotor_test.py b/tests/txt/motors/encodermotor_test.py
deleted file mode 100644
index 5ddffc8cc196ffe55f7c9fc9ab279f2af6702065..0000000000000000000000000000000000000000
--- a/tests/txt/motors/encodermotor_test.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import fischertechnik.factories as txtFactory
-import time
-
-
-class EncodermotorTest:
-    description = "Rotate an encoder motor at 50% and expect a constant rotational speed."
-    brief = "Checks rotational speed of an encoder motor."
-
-    def __init__(self, txt):
-        txtFactory.init_motor_factory()
-        txtFactory.init_counter_factory()
-        self.encodermotor = txtFactory.motor_factory.create_encodermotor(txt, 1)
-        self.counter = txtFactory.counter_factory.create_encodermotor_counter(txt, 1)
-        self.counter.set_motor(self.encodermotor)
-
-    def does_pass(self):
-        self.encodermotor.set_speed(255)
-        time.sleep(2)
-        start_value = self.counter.get_count()
-        step_count = 0
-        last_steps = 0
-        millis = time.time() * 1000
-        last_millis = millis
-        for i in range(10):
-            # Accurately sleep for 1s
-            while (millis + 1000) > last_millis:
-                last_millis = time.time() * 1000
-            tmp = self.counter.get_count()
-            steps = tmp - start_value - step_count
-            if last_steps is not 0:
-                if abs(steps - last_steps) > 20:
-                    return False
-            step_count += steps
-            last_steps = steps
-            millis = time.time() * 1000
-        self.encodermotor.stop()
-        end_value = self.counter.get_count()
-        if end_value - start_value < 10:
-            return False
-        else:
-            return True
diff --git a/tests/txt/sensors/environmental_sensor_test.py b/tests/txt/sensors/environmental_sensor_test.py
deleted file mode 100644
index 6288d6d28e448905988a91230c8846b07c6c13a0..0000000000000000000000000000000000000000
--- a/tests/txt/sensors/environmental_sensor_test.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import fischertechnik.factories as txtFactory
-import time
-
-
-class EnvironmentSensorTest:
-    description = "Checks, if the environment sensor is working correctly with its values not fluctuating too much."
-    brief = "Checks environment sensor for reasonable values."
-
-    def __init__(self, txt):
-        txtFactory.init_i2c_factory()
-        self.env_sensor = txtFactory.i2c_factory.create_environment_sensor(txt, 0)
-
-    def does_pass(self):
-        temperature = self.env_sensor.get_temperature()
-        humidity = self.env_sensor.get_humidity()
-        pressure = self.env_sensor.get_pressure()
-        for i in range(10):
-            time.sleep(1)
-            temperature_temp = self.env_sensor.get_temperature()
-            humidity_temp = self.env_sensor.get_humidity()
-            pressure_temp = self.env_sensor.get_pressure()
-            if abs(temperature_temp - temperature) > 1 or abs(humidity_temp - humidity) > 5 or abs(pressure_temp - pressure) > 5:
-                return False
-            else:
-                temperature = temperature_temp
-                humidity = humidity_temp
-                pressure = pressure_temp
-        return True
diff --git a/tests/txt/sensors/photo_transistor_test.py b/tests/txt/sensors/photo_transistor_test.py
deleted file mode 100644
index c0abab5db7e30a8e3f1a1a9f61cbc5e2a50bfc0d..0000000000000000000000000000000000000000
--- a/tests/txt/sensors/photo_transistor_test.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import fischertechnik.factories as txtFactory
-import time
-
-
-class PhotoTransistorTest:
-    description = "Checks, if a light sensor is working correctly."
-    brief = "Checks a light sensor."
-
-    def __init__(self, txt):
-        txtFactory.init_input_factory()
-        txtFactory.init_output_factory()
-        self.photo_transistor = txtFactory.input_factory.create_photo_transistor(txt, 2)
-        self.led = txtFactory.output_factory.create_led(txt, 3)
-
-    def does_pass(self):
-        self.led.set_brightness(255)
-        time.sleep(1)
-        state = self.photo_transistor.get_state()
-        if state == 0:
-            return False
-        else:
-            return True