diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
index 3b77d9ffa47d6c66481f764b8bbceae45e9d4ab2..855db2bfaf6574ef5619898098ffc103c3d50e46 100644
--- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
@@ -58,12 +58,12 @@ public class Learner {
   }
 
   private void activityDataAnalyser(String activity_csv_url) {
-    VersatileDataSource a_souce;
+    VersatileDataSource a_source;
     String csv_url_activity;
     csv_url_activity = activity_csv_url;
     this.csv_file = new File(csv_url_activity);
-    a_souce = new CSVDataSource(csv_file, true, CSVFormat.DECIMAL_POINT);
-    a_data = new VersatileMLDataSet(a_souce);
+    a_source = new CSVDataSource(csv_file, true, CSVFormat.DECIMAL_POINT);
+    a_data = new VersatileMLDataSet(a_source);
     String[] activity_inputs = {"m_accel_x", "m_accel_y", "m_accel_z",
         "m_rotation_x", "m_rotation_y", "m_rotation_z",
         "w_accel_x", "w_accel_y", "w_accel_z",
@@ -142,8 +142,10 @@ public class Learner {
     result[0] = activity_predictor(activity_data);
     preference_data[0] = result[0];
     preference_data[1] = new_data[12];
-    result[1] = preference_predictor(preference_data)[0];
-    result[2] = preference_predictor(preference_data)[1];
+    // FIXME should be done with array copy
+    String[] tmp = preference_predictor(preference_data);
+    result[1] = tmp[0];
+    result[2] = tmp[1];
     Encog.getInstance().shutdown();
     return result;
   }
@@ -174,8 +176,8 @@ public class Learner {
     preference_result[0] = preference_helper.denormalizeOutputVectorToString(output)[0];
     preference_result[1] = preference_helper.denormalizeOutputVectorToString(output)[1];
     Encog.getInstance().shutdown();
-    logger.debug("Preference Predictor result is, Color:  {}", Math.round(Float.valueOf(preference_result[0])));
-    logger.debug("Preference Predictor result is, Brightness: {} ", Math.round(Float.valueOf(preference_result[1])));
+    logger.debug("Preference Predictor result, Color: {}, brightness: {}",
+        Math.round(Float.parseFloat(preference_result[0])), Math.round(Float.parseFloat(preference_result[1])));
     return preference_result;
   }
 
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
index 65005d8ba485026c2771cca1df0f02e1920a14ce..0155d93a697e7833573040ff5de2b6542af980fe 100644
--- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
@@ -1,8 +1,5 @@
 package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
 
-
-//import com.sun.javafx.tools.packager.Log;
-
 import de.tudresden.inf.st.eraser.jastadd.model.*;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -11,7 +8,6 @@ import java.time.Instant;
 import java.util.*;
 import java.util.stream.Collectors;
 
-
 public class MachineLearningImpl implements MachineLearningDecoder, MachineLearningEncoder {
 
   public static final int GOAL_ACTIVITY_PHONE_AND_WATCH = 1;
@@ -29,7 +25,7 @@ public class MachineLearningImpl implements MachineLearningDecoder, MachineLearn
   private String[] p_new_data = new String[2];
 
   private int a_length = 0;
-  boolean empty;
+  private boolean empty;
 
   private Root root;
   private String activity_result;
@@ -123,33 +119,30 @@ public class MachineLearningImpl implements MachineLearningDecoder, MachineLearn
         for (String value : a_new_data){
           if(value == null){
             empty = true;
+            break;
           }
         }
         if(!empty){
           this.activity_result = learner.activity_predictor(a_new_data);
         }
         a_length = 0;
-        for (int j=0; j < this.a_new_data.length; j++){
-          this.a_new_data[j] = null;
-        }
+        Arrays.fill(this.a_new_data, null);
       }
 
     } else if (this.goal == GOAL_PREFERENCE_BRIGHTNESS_IRIS) {
       for (Item item : changedItems) {
         if (root.getSmartHomeEntityModel().getActivityItem().equals(item)) {
           String test = item.getStateAsString();
-          int index = Math.round(Float.valueOf(test));
+          int index = Math.round(Float.parseFloat(test));
           this.p_new_data[0] = root.getMachineLearningRoot().getActivity(index).getLabel();
         }
         if (item.getID().equals("w_brightness")) {
           this.p_new_data[1] = item.getStateAsString();
         }
       }
-      logger.info("debug_preference_new_data");
-      logger.info(Arrays.toString(this.p_new_data));
+      logger.debug("debug_preference_new_data: {}", Arrays.toString(this.p_new_data));
       this.preference_result = learner.preference_predictor(this.p_new_data);
-      logger.info("debug for p");
-      logger.info(Arrays.toString(this.preference_result));
+      logger.debug("preference for {} is {}", Arrays.toString(this.p_new_data), this.preference_result);
     }
   }
 
@@ -198,8 +191,8 @@ public class MachineLearningImpl implements MachineLearningDecoder, MachineLearn
         int color = 0;
         int brightness = 0;
         if (preference_result != null) {
-          color = Math.round(Float.valueOf(preference_result[0]));
-          brightness = Math.round(Float.valueOf(preference_result[1]));
+          color = Math.round(Float.parseFloat(preference_result[0]));
+          brightness = Math.round(Float.parseFloat(preference_result[1]));
         }
         result.addItemUpdate(new ItemUpdateColor(iris1, TupleHSB.of(color, 100, brightness)));
         return result;
@@ -209,12 +202,13 @@ public class MachineLearningImpl implements MachineLearningDecoder, MachineLearn
     }
   }
 
-  public void initActivities(String filenameOfCsv) {
-    logger.debug(filenameOfCsv);
+  void initActivities(String filenameOfCsv) {
+    logger.debug("init activities with {}", filenameOfCsv);
     learner.activity_train(filenameOfCsv);
   }
 
-  public void initPreferences(String filenameOfCsv) {
+  void initPreferences(String filenameOfCsv) {
+    logger.debug("init preferences with {}", filenameOfCsv);
     learner.preference_train(filenameOfCsv);
   }
 
diff --git a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTest.java b/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTest.java
index 896f402cf36597c4fbb62167000e9d49184e79e5..62786140f4b0e6f2fda61a2954e479efc28d1545 100644
--- a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTest.java
+++ b/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop/learner_backup/LearnerTest.java
@@ -2,9 +2,10 @@ package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
 
 import com.opencsv.CSVReader;
 import de.tudresden.inf.st.eraser.jastadd.model.*;
+import de.tudresden.inf.st.eraser.jastadd.model.MachineLearningHandlerFactory.MachineLearningHandlerFactoryTarget;
 import de.tudresden.inf.st.eraser.util.ParserUtils;
 import org.apache.logging.log4j.LogManager;
-import org.hamcrest.Matchers;
+import org.apache.logging.log4j.Logger;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -15,9 +16,18 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Collections;
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
+import static de.tudresden.inf.st.eraser.jastadd.model.MachineLearningHandlerFactory.MachineLearningHandlerFactoryTarget.ACTIVITY_RECOGNITION;
+import static de.tudresden.inf.st.eraser.jastadd.model.MachineLearningHandlerFactory.MachineLearningHandlerFactoryTarget.PREFERENCE_LEARNING;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.junit.Assert.*;
 
@@ -28,13 +38,17 @@ import static org.junit.Assert.*;
  */
 public class LearnerTest {
 
-  private static final double MIN_ACCURACY = 0.95;
+  private static final double MIN_ACCURACY = 0.94;
+  private static final Logger logger = LogManager.getLogger(LearnerTest.class);
 
   private static URL ACTIVITY_DATA;
+  private static URL PREFERENCE_DATA;
   private MachineLearningEncoder encoder;
   private MachineLearningDecoder decoder;
-  private String[] itemNames = new String[]{"m_accel_x", "m_accel_y", "m_accel_z", "m_rotation_x", "m_rotation_y",
+  private String[] activityInputItemNames = new String[]{"m_accel_x", "m_accel_y", "m_accel_z", "m_rotation_x", "m_rotation_y",
       "m_rotation_z", "w_accel_x", "w_accel_y", "w_accel_z", "w_rotation_x", "w_rotation_y", "w_rotation_z"};
+  private String[] preferenceInputItemNames = new String[]{"activity", "w_brightness"};
+  private final String preferenceOutputItemName = "iris1_item";
   private String[] activityNames = new String[]{"working",
       "walking",
       "dancing",
@@ -42,10 +56,13 @@ public class LearnerTest {
       "getting up",
       "reading"};
   private Root root;
+  private MachineLearningHandlerFactoryImpl factory;
 
   @BeforeClass
-  public static void setActivityData() throws MalformedURLException {
-    ACTIVITY_DATA = Paths.get("src", "test", "resources", "activity_data.csv").toUri().toURL();
+  public static void setData() throws MalformedURLException {
+    Path base = Paths.get("src", "test", "resources");
+    ACTIVITY_DATA = base.resolve("activity_data.csv").toUri().toURL();
+    PREFERENCE_DATA = base.resolve("preference_data.csv").toUri().toURL();
   }
 
   private Root createKnowledgeBase() {
@@ -53,12 +70,23 @@ public class LearnerTest {
     Group group = new Group();
     result.getSmartHomeEntityModel().addGroup(group);
     // init items
-    for (String itemName : itemNames) {
-      NumberItem item = new NumberItem();
-      item.setID(itemName);
-      ParserUtils.createMqttTopic(item, itemName, result);
-      group.addItem(item);
-    }
+    Stream.concat(Arrays.stream(activityInputItemNames),
+        Stream.concat(Arrays.stream(preferenceInputItemNames), Stream.of(preferenceOutputItemName)))
+        .distinct().forEach(
+        itemName -> {
+          if (itemName.equals("activity")) return;
+          Item item;
+          switch(itemName) {
+            case preferenceOutputItemName: item = new ColorItem(); break;
+            case "w_brightness": item = new StringItem(); break;
+            default:
+              item = new NumberItem();
+          };
+          item.setID(itemName);
+          ParserUtils.createMqttTopic(item, itemName, result);
+          group.addItem(item);
+        }
+    );
     // init activities
     for (int i = 0; i < activityNames.length; i++) {
       result.getMachineLearningRoot().addActivity(new Activity(i, activityNames[i]));
@@ -69,45 +97,65 @@ public class LearnerTest {
   @Before
   public void initLearner() {
     root = createKnowledgeBase();
-    MachineLearningHandlerFactoryImpl factory = new MachineLearningHandlerFactoryImpl();
+    factory = new MachineLearningHandlerFactoryImpl();
     factory.setKnowledgeBaseRoot(root);
-    factory.initializeFor(MachineLearningHandlerFactory.MachineLearningHandlerFactoryTarget.ACTIVITY_RECOGNITION,
-        ACTIVITY_DATA);
+  }
+
+  private void testLearner(URL inputCsvFileName,
+                           String[] inputItemNames,
+                           Function<String[], String> expectedOutput,
+                           Map<String, BiConsumer<Item, String>> specialInputHandler,
+                           Supplier<Item> outputItemProvider,
+                           Function<Item, String> stateOfOutputItem,
+                           MachineLearningHandlerFactoryTarget factoryTarget,
+                           boolean singleUpdateList) {
+    factory.initializeFor(factoryTarget, inputCsvFileName);
     encoder = factory.createEncoder();
     decoder = factory.createDecoder();
     // maybe use factory.createModel() here instead
-  }
-
-  @Test
-  public void testActivities() {
     // go through same csv as for training and test some of the values
     int correct = 0, wrong = 0;
-    try(InputStream is = ACTIVITY_DATA.openStream();
+    try(InputStream is = inputCsvFileName.openStream();
         Reader reader = new InputStreamReader(is);
         CSVReader csvreader = new CSVReader(reader)) {
       int index = 0;
       for (String[] line : csvreader) {
         if (++index % 10 == 0) {
           // only check every 10th line, push an update for every 12 input columns
-          for (int i = 0; i < itemNames.length; i++) {
-            int finalI = i;
-            Item item = root.getSmartHomeEntityModel().resolveItem(itemNames[i])
-                .orElseThrow(() -> new AssertionError("Item " + itemNames[finalI] + " not found"));
-            item.setStateFromString(line[i]);
-            encoder.newData(Collections.singletonList(item));
+          List<Item> itemsToUpdate = new ArrayList<>(inputItemNames.length);
+          for (int i = 0; i < inputItemNames.length; i++) {
+            String itemName = inputItemNames[i];
+            Item item = root.getSmartHomeEntityModel().resolveItem(itemName)
+                .orElseThrow(() -> new AssertionError("Item " + itemName + " not found"));
+            if (specialInputHandler.containsKey(itemName)) {
+              specialInputHandler.get(itemName).accept(item, line[i]);
+            } else {
+              item.setStateFromString(line[i]);
+            }
+            if (singleUpdateList) {
+              itemsToUpdate.add(item);
+            } else {
+              encoder.newData(Collections.singletonList(item));
+            }
+          }
+          if (singleUpdateList) {
+            encoder.newData(itemsToUpdate);
           }
           MachineLearningResult result = decoder.classify();
           // check if only one item is to be updated
           assertEquals("Not one item update", 1, result.getNumItemUpdate());
           ItemUpdate update = result.getItemUpdate(0);
-          // check that the activity item is to be updated
-          assertEquals("activity not updated", root.getSmartHomeEntityModel().getActivityItem(), update.getItem());
+          // check that the output item is to be updated
+          assertEquals("output item not updated", outputItemProvider.get(), update.getItem());
           update.apply();
-          // check if the correct activity was set
-          if (line[12].equals(root.currentActivityName())) {
+          // check if the correct new state was set
+          String expected = expectedOutput.apply(line);
+          String actual = stateOfOutputItem.apply(update.getItem());
+          if (expected.equals(actual)) {
             correct++;
           } else {
             wrong++;
+            logger.debug("Result not equal, expected '{}' but was '{}'", expected, actual);
           }
         }
       }
@@ -117,7 +165,62 @@ public class LearnerTest {
     }
     assertThat(correct + wrong, greaterThan(0));
     double accuracy = correct * 1.0 / (correct + wrong);
+    logger.info("Accuracy: {}", accuracy);
     assertThat(accuracy, greaterThan(MIN_ACCURACY));
-    LogManager.getLogger(LearnerTest.class).info("Accuracy: {}", accuracy);
   }
+
+  @Test
+  public void testActivities() {
+    testLearner(ACTIVITY_DATA, activityInputItemNames, line -> line[12], Collections.emptyMap(),
+        () -> root.getSmartHomeEntityModel().getActivityItem(),
+        item -> root.currentActivityName(), ACTIVITY_RECOGNITION, false);
+  }
+
+  @Test
+  public void testPreferences() {
+    Map<String, BiConsumer<Item, String>> specialHandler = new HashMap<>();
+    specialHandler.put("activity", (item, value) -> item.setStateFromLong(
+        root.resolveActivity(value)
+            .orElseThrow(() -> new AssertionError("Activity " + value + " not found"))
+            .getIdentifier()));
+//    specialHandler.put("w_brightness", (item, value) -> {
+//      int target;
+//      switch (value) {
+//        case "medium":
+//          target = 50;
+//          break;
+//        case "bright":
+//          target = 100;
+//          break;
+//        case "dimmer":
+//          target = 20;
+//          break;
+//        case "dark":
+//          target = 0;
+//          break;
+//        default:
+//          throw new IllegalArgumentException("Unknown value for brightness:" + value);
+//      }
+//      item.setStateFromLong(target);
+//    });
+    testLearner(PREFERENCE_DATA, preferenceInputItemNames, this::decodeOutput, specialHandler,
+        () -> root.getSmartHomeEntityModel().resolveItem(preferenceOutputItemName)
+            .orElseThrow(() -> new AssertionError("Item " + preferenceOutputItemName + " not found")),
+        Item::getStateAsString, PREFERENCE_LEARNING, true);
+  }
+
+  private String decodeOutput(String[] line) {
+    int color = Integer.parseInt(line[2]);
+    int brightness = Integer.parseInt(line[3]);
+    return TupleHSB.of(color, 100, brightness).toString();
+  }
+
+  public static <K, V> Map.Entry<K, V> entry(K key, V value) {
+    return new AbstractMap.SimpleEntry<>(key, value);
+  }
+
+  public static <K, U> Collector<Map.Entry<K, U>, ?, Map<K, U>> entriesToMap() {
+    return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
+  }
+
 }