diff --git a/biscuit/apps/untis/api.py b/biscuit/apps/untis/api.py
index 44ecd32cb11a5833822b197897e28222e2ce87ce..e706287c7b2be7ec5b225f197407ebfe5ed6b955 100755
--- a/biscuit/apps/untis/api.py
+++ b/biscuit/apps/untis/api.py
@@ -10,6 +10,7 @@ TYPE_CLASS = 2
 
 from datetime import date
 
+
 def run_all(obj, filter_term=True):
     return run_default_filter(run_using(obj).all(), filter_term=filter_term)
 
@@ -74,6 +75,13 @@ class Teacher(object):
         else:
             return "Unbekannt"
 
+    def __eq__(self, other):
+        if not isinstance(other, Teacher):
+            # don't attempt to compare against unrelated types
+            return NotImplemented
+
+        return self.id == other.id
+
     def create(self, db_obj):
         self.filled = True
         self.id = db_obj.teacher_id
@@ -116,6 +124,13 @@ class Class(object):
         else:
             return "Unbekannt"
 
+    def __eq__(self, other):
+        if not isinstance(other, Class):
+            # don't attempt to compare against unrelated types
+            return NotImplemented
+
+        return self.id == other.id
+
     def create(self, db_obj):
         self.filled = True
         self.id = db_obj.class_id
@@ -187,6 +202,13 @@ class Room(object):
         else:
             return "Unbekannt"
 
+    def __eq__(self, other):
+        if not isinstance(other, Room):
+            # don't attempt to compare against unrelated types
+            return NotImplemented
+
+        return self.id == other.id
+
     def create(self, db_obj):
         self.filled = True
         self.id = db_obj.room_id
@@ -219,6 +241,13 @@ class Corridor(object):
         else:
             return "Unbekannt"
 
+    def __eq__(self, other):
+        if not isinstance(other, Corridor):
+            # don't attempt to compare against unrelated types
+            return NotImplemented
+
+        return self.id == other.id
+
     def create(self, db_obj):
         self.filled = True
         self.id = db_obj.corridor_id
@@ -248,6 +277,19 @@ class Subject(object):
         self.color = None
         self.hex_color = None
 
+    def __str__(self):
+        if self.filled:
+            return self.shortcode or "Unbekannt"
+        else:
+            return "Unbekannt"
+
+    def __eq__(self, other):
+        if not isinstance(other, Teacher):
+            # don't attempt to compare against unrelated types
+            return NotImplemented
+
+        return self.id == other.id
+
     def create(self, db_obj):
         self.filled = True
         self.id = db_obj.subject_id
@@ -382,7 +424,8 @@ def get_all_events_by_date(date):
 # LESSON #
 ##########
 def get_raw_lessons():
-    return run_all(models.Lesson.objects)
+    return run_all(models.Lesson.objects.filter(deleted=0))
+
 
 ###########
 # HOLIDAY #
@@ -408,7 +451,7 @@ class Holiday(object):
 
 
 def get_today_holidays(date):
-    #db_holidays = row_by_row(models.Holiday, Holiday)
+    # db_holidays = row_by_row(models.Holiday, Holiday)
     d_i = int(date_to_untis_date(date))
     db_rows = run_all(models.Holiday.objects.filter(dateto__gte=d_i, datefrom__lte=d_i), filter_term=False)
-    return row_by_row_helper(db_rows, Holiday)
\ No newline at end of file
+    return row_by_row_helper(db_rows, Holiday)
diff --git a/biscuit/apps/untis/drive.py b/biscuit/apps/untis/drive.py
index 8a47aa060bc309cc329b29bd2c3025c87490fb73..a57627807bfa1b2d9a4c4920606bdc0176abc8ad 100644
--- a/biscuit/apps/untis/drive.py
+++ b/biscuit/apps/untis/drive.py
@@ -1,6 +1,12 @@
+from dashboard.caches import DRIVE_CACHE, Cache
 from .api import *
 
-def build_drive():
+
+def build_drive(force_update=False):
+    cached = DRIVE_CACHE.get()
+    if cached is not False and not force_update:
+        print("Drive come from cache")
+        return cached
     odrive = {
         "teachers": get_all_teachers(),
         "rooms": get_all_rooms(),
@@ -16,7 +22,8 @@ def build_drive():
             id = el.id
             drive[key][id] = el
 
+    DRIVE_CACHE.update(drive)
     return drive
 
 
-drive = build_drive()
\ No newline at end of file
+drive = build_drive()
diff --git a/biscuit/apps/untis/parse.py b/biscuit/apps/untis/parse.py
index f615f59e88ca11136634aaea10add8c38a2b9964..630f1844c7c56c783020637c670b566694a3dfca 100755
--- a/biscuit/apps/untis/parse.py
+++ b/biscuit/apps/untis/parse.py
@@ -1,3 +1,11 @@
+from dashboard import caches
+
+from .api import *
+from .api_helper import untis_split_third
+
+from .drive import drive
+
+
 class Lesson(object):
     def __init__(self):
         self.filled = False
@@ -108,24 +116,19 @@ class LessonTime(object):
         self.rooms = rooms
 
 
-from .api import *
-from .api_helper import untis_split_third
-
-from .drive import drive
-
-drive = drive
-
-
-def parse():
+def parse(force_update=False):
     global drive
+
+    cached = caches.PARSED_LESSONS_CACHE.get()
+    if cached is not False and not force_update:
+        # print("Lessons come from cache")
+        return cached
     lessons = []
+
+    # Load lessons from Django ORM
     raw_lessons = get_raw_lessons()
 
     for raw_lesson in raw_lessons:
-        # print("[RAW LESSON]")
-        # print("LESSON_ID      | ", raw_lesson.lesson_id)
-        # print("LessonElement1 | ", raw_lesson.lessonelement1)
-        # print("Lesson_TT      | ", raw_lesson.lesson_tt)
 
         if raw_lesson.lesson_tt and raw_lesson.lessonelement1:
             # Create object
@@ -134,6 +137,9 @@ def parse():
 
             lessons.append(lesson_obj)
 
+    # print("Lesson cache was refreshed")
+    caches.PARSED_LESSONS_CACHE.update(lessons)
+
     return lessons
 
 
@@ -146,8 +152,6 @@ def get_lesson_by_id(id):
 
 
 def get_lesson_element_by_id_and_teacher(lesson_id, teacher, hour=None, weekday=None):
-    # print(lesson_id)
-    # print(hour, "LEWE", weekday)
     try:
         lesson = get_lesson_by_id(lesson_id)
     except Exception:
diff --git a/biscuit/apps/untis/plan.py b/biscuit/apps/untis/plan.py
index a295d791901eabf27277787785e091a32078ab62..4c58ae1b31edeffd73495f172a48a0e5f35ae2de 100644
--- a/biscuit/apps/untis/plan.py
+++ b/biscuit/apps/untis/plan.py
@@ -2,6 +2,7 @@ import datetime
 
 from django.utils import timezone
 
+from dashboard import caches, plan_caches
 from schoolapps import settings
 from schoolapps.settings import LESSONS
 from untisconnect.api import format_classes, TYPE_CLASS, TYPE_TEACHER, TYPE_ROOM
@@ -63,8 +64,16 @@ def parse_lesson_times():
     return times
 
 
-def get_plan(type, id, smart=False, monday_of_week=None):
-    """ Generates a plan for type (TYPE_TEACHE, TYPE_CLASS, TYPE_ROOM) and a id of the teacher (class, room)"""
+def get_plan(type, id, smart=False, monday_of_week=None, force_update=False):
+    """ Generates a plan for type (TYPE_TEACHER, TYPE_CLASS, TYPE_ROOM) and a id of the teacher (class, room)"""
+    # Check cache
+    cache = plan_caches.get_cache_for_plan(type, id, smart, monday_of_week)
+
+    cached = cache.get()
+    # print(cached)
+    if cached is not False and not force_update:
+        # print("Plan come from cache", cache.id)
+        return cached
 
     # Get parsed lessons
     lessons = parse()
@@ -81,8 +90,7 @@ def get_plan(type, id, smart=False, monday_of_week=None):
 
             hols = get_today_holidays(week_day)
             hols_for_weekdays.append(hols)
-            # print(subs)
-            # print(len(subs))
+
 
     # Init plan array
     plan = []
@@ -236,4 +244,5 @@ def get_plan(type, id, smart=False, monday_of_week=None):
                     for j in range(event.event.from_lesson - 1, event.event.to_lesson):
                         plan[j][0][i].append(element_container)
 
+    cache.update((plan, hols_for_weekdays))
     return plan, hols_for_weekdays
diff --git a/biscuit/apps/untis/sub.py b/biscuit/apps/untis/sub.py
index a51afdc1c00d586055b82666e218666f5817ce0d..d116a4d598186ff555bfb95882ff3aedfd39485f 100644
--- a/biscuit/apps/untis/sub.py
+++ b/biscuit/apps/untis/sub.py
@@ -1,11 +1,12 @@
 from django.utils import timezone
+from django.db.models import Q
 
 from untisconnect import models
 from untisconnect.api import run_default_filter, row_by_row_helper, format_classes, get_all_absences_by_date, \
     TYPE_TEACHER
 from untisconnect.api_helper import run_using, untis_split_first, untis_date_to_date, date_to_untis_date
 from untisconnect.parse import get_lesson_element_by_id_and_teacher
-from untisconnect.drive import build_drive
+from untisconnect.drive import drive
 
 TYPE_SUBSTITUTION = 0
 TYPE_CANCELLATION = 1
@@ -28,10 +29,6 @@ def parse_type_of_untis_flags(flags):
     return type_
 
 
-# Build cache
-drive = build_drive()
-
-
 class Substitution(object):
     def __init__(self):
         self.filled = False
@@ -316,7 +313,10 @@ def get_header_information(subs, date, events=[]):
 def get_substitutions_by_date(date):
     subs_raw = run_default_filter(
         run_using(models.Substitution.objects.filter(date=date_to_untis_date(date), deleted=0).exclude(
-            flags__contains="N").order_by("classids", "lesson")),
+            Q(flags__contains="N") |
+            Q(flags__contains="b") |
+            Q(flags__contains="F") |
+            Q(flags__exact="g")).order_by("classids", "lesson")),
         filter_term=False)
 
     subs = row_by_row_helper(subs_raw, Substitution)