diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8d0b792cbd..fd8ece62a6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -379,6 +379,7 @@ list(APPEND SOURCE_FILES
         displayapp/screens/Navigation.cpp
         displayapp/screens/Metronome.cpp
         displayapp/screens/Motion.cpp
+        displayapp/screens/Weather.cpp
         displayapp/screens/FirmwareValidation.cpp
         displayapp/screens/ApplicationList.cpp
         displayapp/screens/Notifications.cpp
diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp
index 8d4a834e06..f0ccb5e579 100644
--- a/src/components/datetime/DateTimeController.cpp
+++ b/src/components/datetime/DateTimeController.cpp
@@ -115,8 +115,8 @@ const char* DateTime::MonthShortToStringLow(Months month) {
   return MonthsStringLow[static_cast<uint8_t>(month)];
 }
 
-const char* DateTime::DayOfWeekShortToStringLow() const {
-  return DaysStringShortLow[static_cast<uint8_t>(DayOfWeek())];
+const char* DateTime::DayOfWeekShortToStringLow(Days day) {
+  return DaysStringShortLow[static_cast<uint8_t>(day)];
 }
 
 void DateTime::Register(Pinetime::System::SystemTask* systemTask) {
diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h
index 0bf6ac2a06..f719df7d52 100644
--- a/src/components/datetime/DateTimeController.h
+++ b/src/components/datetime/DateTimeController.h
@@ -122,7 +122,7 @@ namespace Pinetime {
       const char* MonthShortToString() const;
       const char* DayOfWeekShortToString() const;
       static const char* MonthShortToStringLow(Months month);
-      const char* DayOfWeekShortToStringLow() const;
+      static const char* DayOfWeekShortToStringLow(Days day);
 
       std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
         return currentDateTime;
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index e5329b2d9d..f3f0bd934b 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -27,6 +27,7 @@
 #include "displayapp/screens/BatteryInfo.h"
 #include "displayapp/screens/Steps.h"
 #include "displayapp/screens/Dice.h"
+#include "displayapp/screens/Weather.h"
 #include "displayapp/screens/PassKey.h"
 #include "displayapp/screens/Error.h"
 
diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in
index 77d3b366f3..2104a267c0 100644
--- a/src/displayapp/apps/Apps.h.in
+++ b/src/displayapp/apps/Apps.h.in
@@ -28,6 +28,7 @@ namespace Pinetime {
       Motion,
       Steps,
       Dice,
+      Weather,
       PassKey,
       QuickSettings,
       Settings,
@@ -41,8 +42,7 @@ namespace Pinetime {
       SettingChimes,
       SettingShakeThreshold,
       SettingBluetooth,
-      Error,
-      Weather
+      Error
     };
 
     enum class WatchFace : uint8_t {
diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt
index 51c08595d1..d78587609e 100644
--- a/src/displayapp/apps/CMakeLists.txt
+++ b/src/displayapp/apps/CMakeLists.txt
@@ -13,7 +13,7 @@ else ()
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
-    #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
+    set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
     #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion")
     set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")
 endif ()
diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json
index a3132504bc..41c383c0d4 100644
--- a/src/displayapp/fonts/fonts.json
+++ b/src/displayapp/fonts/fonts.json
@@ -18,7 +18,7 @@
       "sources": [
          {
             "file": "JetBrainsMono-Regular.ttf",
-            "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74"
+            "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x43, 0x46, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74, 0xb0"
          }
       ],
       "bpp": 1,
@@ -28,7 +28,7 @@
       "sources": [
          {
             "file": "JetBrainsMono-Light.ttf",
-            "range": "0x25, 0x2D, 0x2F, 0x30-0x3a"
+            "range": "0x25, 0x2D, 0x2F, 0x30-0x3a, 0x43, 0x46, 0xb0"
          }
       ],
       "bpp": 1,
diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp
index 3308303dcc..c643f3bd79 100644
--- a/src/displayapp/screens/WatchFaceInfineat.cpp
+++ b/src/displayapp/screens/WatchFaceInfineat.cpp
@@ -426,7 +426,8 @@ void WatchFaceInfineat::Refresh() {
     currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
     if (currentDate.IsUpdated()) {
       uint8_t day = dateTimeController.Day();
-      lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(), day);
+      Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek();
+      lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(dayOfWeek), day);
       lv_obj_realign(labelDate);
     }
   }
diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp
new file mode 100644
index 0000000000..5321b7cc29
--- /dev/null
+++ b/src/displayapp/screens/Weather.cpp
@@ -0,0 +1,198 @@
+#include "displayapp/screens/Weather.h"
+#include <lvgl/lvgl.h>
+#include "components/ble/SimpleWeatherService.h"
+#include "components/datetime/DateTimeController.h"
+#include "components/settings/Settings.h"
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/WeatherSymbols.h"
+#include "displayapp/InfiniTimeTheme.h"
+
+using namespace Pinetime::Applications::Screens;
+
+namespace {
+  lv_color_t TemperatureColor(int16_t temperature) {
+    if (temperature <= 0) { // freezing
+      return Colors::blue;
+    } else if (temperature <= 400) { // ice
+      return LV_COLOR_CYAN;
+    } else if (temperature >= 2700) { // hot
+      return Colors::deepOrange;
+    }
+    return Colors::orange; // normal
+  }
+
+  uint8_t TemperatureStyle(int16_t temperature) {
+    if (temperature <= 0) { // freezing
+      return LV_TABLE_PART_CELL3;
+    } else if (temperature <= 400) { // ice
+      return LV_TABLE_PART_CELL4;
+    } else if (temperature >= 2700) { // hot
+      return LV_TABLE_PART_CELL6;
+    }
+    return LV_TABLE_PART_CELL5; // normal
+  }
+
+  int16_t RoundTemperature(int16_t temp) {
+    return temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
+  }
+}
+
+Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService)
+  : settingsController {settingsController}, weatherService {weatherService} {
+
+  temperature = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+  lv_obj_set_style_local_text_font(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
+  lv_label_set_text(temperature, "---");
+  lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, 0, -30);
+  lv_obj_set_auto_realign(temperature, true);
+
+  minTemperature = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg);
+  lv_label_set_text(minTemperature, "");
+  lv_obj_align(minTemperature, temperature, LV_ALIGN_OUT_LEFT_MID, -10, 0);
+  lv_obj_set_auto_realign(minTemperature, true);
+
+  maxTemperature = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_set_style_local_text_color(maxTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg);
+  lv_label_set_text(maxTemperature, "");
+  lv_obj_align(maxTemperature, temperature, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
+  lv_obj_set_auto_realign(maxTemperature, true);
+
+  condition = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_set_style_local_text_color(condition, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
+  lv_label_set_text(condition, "");
+  lv_obj_align(condition, temperature, LV_ALIGN_OUT_TOP_MID, 0, -10);
+  lv_obj_set_auto_realign(condition, true);
+
+  icon = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+  lv_obj_set_style_local_text_font(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons);
+  lv_label_set_text(icon, "");
+  lv_obj_align(icon, condition, LV_ALIGN_OUT_TOP_MID, 0, 0);
+  lv_obj_set_auto_realign(icon, true);
+
+  forecast = lv_table_create(lv_scr_act(), nullptr);
+  lv_table_set_col_cnt(forecast, Controllers::SimpleWeatherService::MaxNbForecastDays);
+  lv_table_set_row_cnt(forecast, 4);
+  // LV_TABLE_PART_CELL1: Default table style
+  lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+  lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, Colors::lightGray);
+  // LV_TABLE_PART_CELL2: Condition icon
+  lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+  lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+  lv_obj_set_style_local_text_font(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, &fontawesome_weathericons);
+  // LV_TABLE_PART_CELL3: Freezing
+  lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+  lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, Colors::blue);
+  // LV_TABLE_PART_CELL4: Ice
+  lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+  lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_CYAN);
+  // LV_TABLE_PART_CELL5: Normal
+  lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+  lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, Colors::orange);
+  // LV_TABLE_PART_CELL6: Hot
+  lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, LV_COLOR_BLACK);
+  lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, Colors::deepOrange);
+
+  lv_obj_align(forecast, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
+
+  for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
+    lv_table_set_col_width(forecast, i, 48);
+    lv_table_set_cell_type(forecast, 1, i, LV_TABLE_PART_CELL2);
+    lv_table_set_cell_align(forecast, 0, i, LV_LABEL_ALIGN_CENTER);
+    lv_table_set_cell_align(forecast, 1, i, LV_LABEL_ALIGN_CENTER);
+    lv_table_set_cell_align(forecast, 2, i, LV_LABEL_ALIGN_CENTER);
+    lv_table_set_cell_align(forecast, 3, i, LV_LABEL_ALIGN_CENTER);
+  }
+
+  taskRefresh = lv_task_create(RefreshTaskCallback, 1000, LV_TASK_PRIO_MID, this);
+  Refresh();
+}
+
+Weather::~Weather() {
+  lv_task_del(taskRefresh);
+  lv_obj_clean(lv_scr_act());
+}
+
+void Weather::Refresh() {
+  currentWeather = weatherService.Current();
+  if (currentWeather.IsUpdated()) {
+    auto optCurrentWeather = currentWeather.Get();
+    if (optCurrentWeather) {
+      int16_t temp = optCurrentWeather->temperature;
+      int16_t minTemp = optCurrentWeather->minTemperature;
+      int16_t maxTemp = optCurrentWeather->maxTemperature;
+      lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, TemperatureColor(temp));
+      char tempUnit = 'C';
+      if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
+        temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
+        minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
+        maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
+        tempUnit = 'F';
+      }
+      lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId));
+      lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId));
+      lv_label_set_text_fmt(temperature, "%d°%c", RoundTemperature(temp), tempUnit);
+      lv_label_set_text_fmt(minTemperature, "%d°", RoundTemperature(minTemp));
+      lv_label_set_text_fmt(maxTemperature, "%d°", RoundTemperature(maxTemp));
+    } else {
+      lv_label_set_text(icon, "");
+      lv_label_set_text(condition, "");
+      lv_label_set_text(temperature, "---");
+      lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
+      lv_label_set_text(minTemperature, "");
+      lv_label_set_text(maxTemperature, "");
+    }
+  }
+
+  currentForecast = weatherService.GetForecast();
+  if (currentForecast.IsUpdated()) {
+    auto optCurrentForecast = currentForecast.Get();
+    if (optCurrentForecast) {
+      std::tm localTime = *std::localtime(reinterpret_cast<const time_t*>(&optCurrentForecast->timestamp));
+
+      for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
+        int16_t maxTemp = optCurrentForecast->days[i].maxTemperature;
+        int16_t minTemp = optCurrentForecast->days[i].minTemperature;
+        lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(maxTemp));
+        lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(minTemp));
+        if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
+          maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
+          minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
+        }
+        uint8_t wday = localTime.tm_wday + i + 1;
+        if (wday > 7) {
+          wday -= 7;
+        }
+        maxTemp = RoundTemperature(maxTemp);
+        minTemp = RoundTemperature(minTemp);
+        const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast<Controllers::DateTime::Days>(wday));
+        lv_table_set_cell_value(forecast, 0, i, dayOfWeek);
+        lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i].iconId));
+        // Pad cells based on the largest number of digits on each column
+        char maxPadding[3] = "  ";
+        char minPadding[3] = "  ";
+        int diff = snprintf(nullptr, 0, "%d", maxTemp) - snprintf(nullptr, 0, "%d", minTemp);
+        if (diff <= 0) {
+          maxPadding[-diff] = '\0';
+          minPadding[0] = '\0';
+        } else {
+          maxPadding[0] = '\0';
+          minPadding[diff] = '\0';
+        }
+        lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp);
+        lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp);
+      }
+    } else {
+      for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
+        lv_table_set_cell_value(forecast, 0, i, "");
+        lv_table_set_cell_value(forecast, 1, i, "");
+        lv_table_set_cell_value(forecast, 2, i, "");
+        lv_table_set_cell_value(forecast, 3, i, "");
+        lv_table_set_cell_type(forecast, 2, i, LV_TABLE_PART_CELL1);
+        lv_table_set_cell_type(forecast, 3, i, LV_TABLE_PART_CELL1);
+      }
+    }
+  }
+}
diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h
new file mode 100644
index 0000000000..6975311e06
--- /dev/null
+++ b/src/displayapp/screens/Weather.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include "displayapp/screens/Screen.h"
+#include "components/ble/SimpleWeatherService.h"
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "Symbols.h"
+#include "utility/DirtyValue.h"
+
+namespace Pinetime {
+
+  namespace Controllers {
+    class Settings;
+  }
+
+  namespace Applications {
+    namespace Screens {
+
+      class Weather : public Screen {
+      public:
+        Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService);
+        ~Weather() override;
+
+        void Refresh() override;
+
+      private:
+        Controllers::Settings& settingsController;
+        Controllers::SimpleWeatherService& weatherService;
+
+        Utility::DirtyValue<std::optional<Controllers::SimpleWeatherService::CurrentWeather>> currentWeather {};
+        Utility::DirtyValue<std::optional<Controllers::SimpleWeatherService::Forecast>> currentForecast {};
+
+        lv_obj_t* icon;
+        lv_obj_t* condition;
+        lv_obj_t* temperature;
+        lv_obj_t* minTemperature;
+        lv_obj_t* maxTemperature;
+        lv_obj_t* forecast;
+
+        lv_task_t* taskRefresh;
+      };
+    }
+
+    template <>
+    struct AppTraits<Apps::Weather> {
+      static constexpr Apps app = Apps::Weather;
+      static constexpr const char* icon = Screens::Symbols::cloudSunRain;
+
+      static Screens::Screen* Create(AppControllers& controllers) {
+        return new Screens::Weather(controllers.settingsController, *controllers.weatherController);
+      };
+    };
+  }
+}
diff --git a/src/displayapp/screens/WeatherSymbols.cpp b/src/displayapp/screens/WeatherSymbols.cpp
index a7749541c3..de66312f90 100644
--- a/src/displayapp/screens/WeatherSymbols.cpp
+++ b/src/displayapp/screens/WeatherSymbols.cpp
@@ -34,3 +34,28 @@ const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime::
       break;
   }
 }
+
+const char* Pinetime::Applications::Screens::Symbols::GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon) {
+  switch (icon) {
+    case Pinetime::Controllers::SimpleWeatherService::Icons::Sun:
+      return "Clear sky";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun:
+      return "Few clouds";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds:
+      return "Scattered clouds";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds:
+      return "Broken clouds";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy:
+      return "Shower rain";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain:
+      return "Rain";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm:
+      return "Thunderstorm";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::Snow:
+      return "Snow";
+    case Pinetime::Controllers::SimpleWeatherService::Icons::Smog:
+      return "Mist";
+    default:
+      return "";
+  }
+}
diff --git a/src/displayapp/screens/WeatherSymbols.h b/src/displayapp/screens/WeatherSymbols.h
index 93453b4e9a..f3eeed5581 100644
--- a/src/displayapp/screens/WeatherSymbols.h
+++ b/src/displayapp/screens/WeatherSymbols.h
@@ -7,6 +7,7 @@ namespace Pinetime {
     namespace Screens {
       namespace Symbols {
         const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
+        const char* GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
       }
     }
   }
diff --git a/src/libs/lv_conf.h b/src/libs/lv_conf.h
index e96778ecf8..c23647f2c0 100644
--- a/src/libs/lv_conf.h
+++ b/src/libs/lv_conf.h
@@ -729,7 +729,9 @@ typedef void* lv_obj_user_data_t;
 #define LV_USE_TABLE    1
 #if LV_USE_TABLE
 #define LV_TABLE_COL_MAX    12
-#define LV_TABLE_CELL_STYLE_CNT 5
+#define LV_TABLE_CELL_STYLE_CNT 6
+#define LV_TABLE_PART_CELL5 5
+#define LV_TABLE_PART_CELL6 6
 #endif