diff --git a/static_src/timer.js b/static_src/timer.js
index 7a51484ede93ff7e92d811e9bb7af06069c63e59..4729748c509bcc8f4d4ca21678b0872de3279792 100644
--- a/static_src/timer.js
+++ b/static_src/timer.js
@@ -1,11 +1,23 @@
 import $ from "jquery"
 import Timer from "easytimer.js"
 
+import alertify from "alertifyjs";
+import "alertifyjs/build/css/alertify.css";
+
+const updateTimeText = (timer) => {
+    const timeValues = timer.getTimeValues()
+
+    const hours = String(timeValues.minutes + timeValues.hours * 60 + timeValues.days * 1440).padStart(2, '0')
+    const seconds = String(timeValues.seconds).padStart(2, '0')
+
+    $('#timer .timer-values').html(`${hours}:${seconds}`)
+}
+
 const assignEventListeners = (timer) => {
     timer.addEventListener(
         'secondsUpdated',
         (event) => {
-            $('#timer .timer-values').html(timer.getTimeValues().toString(['minutes', 'seconds']))
+            updateTimeText(timer)
         }
     )
 
@@ -17,7 +29,7 @@ const assignEventListeners = (timer) => {
         }
     )
 
-    $('#timer .timer-values').html(timer.getTimeValues().toString(['minutes', 'seconds']))
+    updateTimeText(timer)
 }
 
 $(window).ready(
@@ -32,59 +44,79 @@ $(window).ready(
             }
         })
 
-        const timerSocket = new WebSocket(
-            (
-                (window.location.protocol === "https:") ?
-                "wss://" : "ws://"
+        let timerSocket = null
+        let isInitialConnect = true
+
+        const connectToSocket = () => {
+            timerSocket = new WebSocket(
+                (
+                    (window.location.protocol === "https:") ?
+                    "wss://" : "ws://"
+                )
+                + window.location.host
+                + "/ws/timer/"
             )
-            + window.location.host
-            + "/ws/timer/"
-        )
 
-        timerSocket.onmessage = (event) => {
-            const data = JSON.parse(event.data)
+            if (!isInitialConnect) {
+                alertify.success("Obnovování spojení.")
+            }
 
-            if ("status" in data) {
-                if (data["status"] === "playing") {
-                    // Reset if we are playing again.
-                    const remainingTime = timer.getTimeValues()
+            isInitialConnect = false
 
-                    if (remainingTime.seconds === 0 && remainingTime.minutes === 0) {
-                        timer = new Timer({
-                            countdown: true,
-                            startValues: {
-                                minutes: window.startingTime.minutes,
-                                seconds: window.startingTime.seconds,
-                            }
-                        })
+            timerSocket.onmessage = (event) => {
+                console.log("Received timer message:", event.data)
 
-                        assignEventListeners(timer)
-                    }
+                const data = JSON.parse(event.data)
+
+                if ("status" in data) {
+                    if (data["status"] === "playing") {
+                        // Reset if we are playing again.
+                        const remainingTime = timer.getTimeValues()
+
+                        if (remainingTime.seconds === 0 && remainingTime.minutes === 0) {
+                            timer = new Timer({
+                                countdown: true,
+                                startValues: {
+                                    minutes: window.startingTime.minutes,
+                                    seconds: window.startingTime.seconds,
+                                }
+                            })
 
-                    timer.start()
-                } else if (data["status"] === "paused") {
+                            assignEventListeners(timer)
+                        }
+
+                        timer.start()
+                    } else if (data["status"] === "paused") {
+                        timer.pause()
+                    }
+                } else if ("time" in data) {
                     timer.pause()
-                }
-            } else if ("time" in data) {
-                timer.pause()
 
-                window.startingTime = {
-                    minutes: data["time"]["minutes"],
-                    seconds: data["time"]["seconds"]
+                    window.startingTime = {
+                        minutes: data["time"]["minutes"],
+                        seconds: data["time"]["seconds"]
+                    }
+
+                    timer = new Timer({
+                        countdown: true,
+                        startValues: {
+                            minutes: window.startingTime.minutes,
+                            seconds: window.startingTime.seconds,
+                        }
+                    })
+
+                    assignEventListeners(timer)
                 }
+            }
 
-                timer = new Timer({
-                    countdown: true,
-                    startValues: {
-                        minutes: window.startingTime.minutes,
-                        seconds: window.startingTime.seconds,
-                    }
-                })
+            timerSocket.onclose = (event) => {
+                alertify.error("Ztráta spojení, pokoušíme se o zpětné připojení.")
 
-                assignEventListeners(timer)
+                setTimeout(connectToSocket, 5000)
             }
         }
 
+        connectToSocket()
         assignEventListeners(timer)
 
         // --- END Timer ---
@@ -120,10 +152,13 @@ $(window).ready(
         $("#update-time").on(
             "click",
             (event) => {
+                let minutes = Number($("#minutes").val())
+                let seconds = Number($("#seconds").val())
+
                 timerSocket.send(JSON.stringify({
                     "time": {
-                        "minutes": Number($("#minutes").val()),
-                        "seconds": Number($("#seconds").val())
+                        "minutes": minutes,
+                        "seconds": seconds
                     }
                 }))
 
diff --git a/timer/consumers.py b/timer/consumers.py
index 4cdf054f097fa0f5e8c1c6d19b2a125ee9c4e275..e0a9be6c697311c5a1c5cc8521b4531b61238f10 100644
--- a/timer/consumers.py
+++ b/timer/consumers.py
@@ -1,43 +1,90 @@
+import datetime
 import json
 
 from asgiref.sync import async_to_sync
-from channels.generic.websocket import WebsocketConsumer
+from channels.generic.websocket import AsyncWebsocketConsumer
+import time
 
 
-class TimerConsumer(WebsocketConsumer):
-    def connect(self):
-        async_to_sync(self.channel_layer.group_add)("timer", self.channel_name)
+class TimerConsumer(AsyncWebsocketConsumer):
+    timer_is_running = False
 
-        self.accept()
+    async def connect(self) -> None:
+        await self.channel_layer.group_add("timer", self.channel_name)
+        await self.accept()
 
-    def disconnect(self, close_code):
-        pass
+    async def disconnect(self, close_code) -> None:
+        await self.channel_layer.group_discard("timer", self.channel_name)
 
-    def receive(self, text_data):
+    async def run_timer(self, minutes: int, seconds: int) -> None:
+        total_seconds = (minutes * 60) + seconds
+        first_run = True
+
+        print("running timer")
+
+        for second in range(total_seconds + 1):
+            if not first_run:
+                while not self.timer_is_running:
+                    time.sleep(0.05)
+
+            # Do on the first run, then every 5 seconds
+            if first_run or total_seconds % 5 == 0:
+                new_seconds = total_seconds % 60
+                new_minutes = round((total_seconds - new_seconds) / 60)
+
+                print("sending")
+
+                await self.channel_layer.group_send(
+                    "timer",
+                    {
+                        "type": "timer_message",
+                        "text": json.dumps({
+                            "time": {
+                                "minutes": new_minutes,
+                                "seconds": new_seconds
+                            }
+                        })
+                    }
+                )
+
+            if not first_run:
+                total_seconds -= 1
+                time.sleep(1)
+
+            first_run = False
+
+    async def receive(self, text_data: str) -> None:
         json_data = json.loads(text_data)
 
         response = None
+        time_updated = False
 
         if "status" in json_data:
             if json_data["status"] == "playing":
                 response = {"status": "playing"}
+                self.timer_is_running = True
             elif json_data["status"] == "paused":
                 response = {"status": "paused"}
+                self.timer_is_running = False
 
         if "time" in json_data:
+            minutes = json_data["time"]["minutes"]
+            seconds = json_data["time"]["seconds"]
+
             response = {
                 "time": {
-                    "minutes": json_data["time"]["minutes"],
-                    "seconds": json_data["time"]["seconds"],
+                    "minutes": minutes,
+                    "seconds": seconds,
                 }
             }
 
+            time_updated = True
+
         if response is not None:
-            async_to_sync(self.channel_layer.group_send)(
-                "timer", {"type": "timer_message", "text": json.dumps(response)}
-            )
+            if time_updated:
+                await self.run_timer(minutes, seconds)
 
-        self.send(text_data=json.dumps({}))
+        await self.send(text_data=json.dumps({}))
 
-    def timer_message(self, event):
-        self.send(text_data=event["text"])
+    async def timer_message(self, event: dict) -> None:
+        await self.send(text_data=event["text"])
diff --git a/timer/templates/timer/edit_timer.html b/timer/templates/timer/edit_timer.html
index 7e9811af2fa729389ecde962cdcf37d1abe33281..370a72097240343f8caf448e4159434126e0fd13 100644
--- a/timer/templates/timer/edit_timer.html
+++ b/timer/templates/timer/edit_timer.html
@@ -59,6 +59,8 @@
                     type="number"
                     id="minutes"
                     name="minutes"
+                    min="0"
+                    max="60"
                     placeholder="Minuty"
                     autocomplete="off"
                 >
@@ -67,6 +69,8 @@
                     type="number"
                     id="seconds"
                     name="seconds"
+                    min="0"
+                    max="60"
                     placeholder="Sekundy"
                     autocomplete="off"
                 >
diff --git a/webpack.config.js b/webpack.config.js
index 6e3af748fb555b9e8a168d13c4d8a731a4862f46..ce84878402ff4474e3758b8f9ef44a1e2b6c21da 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -33,7 +33,7 @@ module.exports = {
   },
   output: {
     path: path.resolve(__dirname, "shared", "static", "shared"),
-    filename: "[name]-[fullhash].js",
+    filename: "[name].js",
   },
   module: {
     rules: [