From be5a916e7399955f83e6ee76de944d692df2cfc6 Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Tue, 20 Feb 2024 11:25:02 +0100 Subject: [PATCH 1/2] weather: Refactor temperature type for type safety There is now a Temperature struct in the weather service, which holds the internal representation. There is also a temperature struct in the Applications namespace, which holds the temperature in either Celsius or Fahrenheit. --- src/CMakeLists.txt | 2 + src/components/ble/SimpleWeatherService.cpp | 17 +++--- src/components/ble/SimpleWeatherService.h | 24 ++++---- src/displayapp/Weather.cpp | 13 +++++ src/displayapp/Weather.h | 17 ++++++ src/displayapp/screens/WatchFaceDigital.cpp | 8 +-- .../screens/WatchFacePineTimeStyle.cpp | 9 +-- src/displayapp/screens/Weather.cpp | 56 ++++++++----------- 8 files changed, 84 insertions(+), 62 deletions(-) create mode 100644 src/displayapp/Weather.cpp create mode 100644 src/displayapp/Weather.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a97a015..d69c1d6b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -398,6 +398,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Styles.cpp displayapp/screens/WeatherSymbols.cpp displayapp/Colors.cpp + displayapp/Weather.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp displayapp/widgets/DotIndicator.cpp @@ -606,6 +607,7 @@ set(INCLUDE_FILES displayapp/screens/ApplicationList.h displayapp/screens/CheckboxList.h displayapp/Apps.h + displayapp/Weather.h displayapp/screens/Notifications.h displayapp/screens/HeartRate.h displayapp/screens/Metronome.h diff --git a/src/components/ble/SimpleWeatherService.cpp b/src/components/ble/SimpleWeatherService.cpp index 504cad14..a1f0439e 100644 --- a/src/components/ble/SimpleWeatherService.cpp +++ b/src/components/ble/SimpleWeatherService.cpp @@ -42,9 +42,9 @@ namespace { std::memcpy(cityName.data(), &dataBuffer[16], 32); cityName[32] = '\0'; return SimpleWeatherService::CurrentWeather(ToUInt64(&dataBuffer[2]), - ToInt16(&dataBuffer[10]), - ToInt16(&dataBuffer[12]), - ToInt16(&dataBuffer[14]), + SimpleWeatherService::Temperature {ToInt16(&dataBuffer[10])}, + SimpleWeatherService::Temperature {ToInt16(&dataBuffer[12])}, + SimpleWeatherService::Temperature {ToInt16(&dataBuffer[14])}, SimpleWeatherService::Icons {dataBuffer[16 + 32]}, std::move(cityName)); } @@ -56,8 +56,8 @@ namespace { const uint8_t nbDaysInBuffer = dataBuffer[10]; const uint8_t nbDays = std::min(SimpleWeatherService::MaxNbForecastDays, nbDaysInBuffer); for (int i = 0; i < nbDays; i++) { - days[i] = SimpleWeatherService::Forecast::Day {ToInt16(&dataBuffer[11 + (i * 5)]), - ToInt16(&dataBuffer[13 + (i * 5)]), + days[i] = SimpleWeatherService::Forecast::Day {SimpleWeatherService::Temperature {ToInt16(&dataBuffer[11 + (i * 5)])}, + SimpleWeatherService::Temperature {ToInt16(&dataBuffer[13 + (i * 5)])}, SimpleWeatherService::Icons {dataBuffer[15 + (i * 5)]}}; } return SimpleWeatherService::Forecast {timestamp, nbDays, days}; @@ -154,13 +154,14 @@ std::optional SimpleWeatherService::GetForecast( } bool SimpleWeatherService::CurrentWeather::operator==(const SimpleWeatherService::CurrentWeather& other) const { - return this->iconId == other.iconId && this->temperature == other.temperature && this->timestamp == other.timestamp && - this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature && + return this->iconId == other.iconId && this->temperature.temp == other.temperature.temp && this->timestamp == other.timestamp && + this->maxTemperature.temp == other.maxTemperature.temp && this->minTemperature.temp == other.maxTemperature.temp && std::strcmp(this->location.data(), other.location.data()) == 0; } bool SimpleWeatherService::Forecast::Day::operator==(const SimpleWeatherService::Forecast::Day& other) const { - return this->iconId == other.iconId && this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature; + return this->iconId == other.iconId && this->maxTemperature.temp == other.maxTemperature.temp && + this->minTemperature.temp == other.maxTemperature.temp; } bool SimpleWeatherService::Forecast::operator==(const SimpleWeatherService::Forecast& other) const { diff --git a/src/components/ble/SimpleWeatherService.h b/src/components/ble/SimpleWeatherService.h index 03d2f6ff..ef55f03c 100644 --- a/src/components/ble/SimpleWeatherService.h +++ b/src/components/ble/SimpleWeatherService.h @@ -61,13 +61,17 @@ namespace Pinetime { Unknown = 255 }; + struct Temperature { + int16_t temp; + }; + using Location = std::array; // 32 char + \0 (end of string) struct CurrentWeather { CurrentWeather(uint64_t timestamp, - int16_t temperature, - int16_t minTemperature, - int16_t maxTemperature, + Temperature temperature, + Temperature minTemperature, + Temperature maxTemperature, Icons iconId, Location&& location) : timestamp {timestamp}, @@ -79,9 +83,9 @@ namespace Pinetime { } uint64_t timestamp; - int16_t temperature; - int16_t minTemperature; - int16_t maxTemperature; + Temperature temperature; + Temperature minTemperature; + Temperature maxTemperature; Icons iconId; Location location; @@ -93,8 +97,8 @@ namespace Pinetime { uint8_t nbDays; struct Day { - int16_t minTemperature; - int16_t maxTemperature; + Temperature minTemperature; + Temperature maxTemperature; Icons iconId; bool operator==(const Day& other) const; @@ -108,10 +112,6 @@ namespace Pinetime { std::optional Current() const; std::optional GetForecast() const; - static int16_t CelsiusToFahrenheit(int16_t celsius) { - return celsius * 9 / 5 + 3200; - } - private: // 00050000-78fc-48fe-8e23-433b3a1942d0 static constexpr ble_uuid128_t BaseUuid() { diff --git a/src/displayapp/Weather.cpp b/src/displayapp/Weather.cpp new file mode 100644 index 00000000..a0f0a281 --- /dev/null +++ b/src/displayapp/Weather.cpp @@ -0,0 +1,13 @@ +#include "displayapp/Weather.h" + +using namespace Pinetime::Applications; + +Temperature Pinetime::Applications::Convert(Controllers::SimpleWeatherService::Temperature temp, + Controllers::Settings::WeatherFormat format) { + Temperature t = {temp.temp}; + if (format == Controllers::Settings::WeatherFormat::Imperial) { + t.temp = t.temp * 9 / 5 + 3200; + } + t.temp = t.temp / 100 + (t.temp % 100 >= 50 ? 1 : 0); + return t; +} diff --git a/src/displayapp/Weather.h b/src/displayapp/Weather.h new file mode 100644 index 00000000..0dd17fce --- /dev/null +++ b/src/displayapp/Weather.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "components/ble/SimpleWeatherService.h" +#include "components/settings/Settings.h" + +namespace Pinetime { + namespace Applications { + struct Temperature { + int16_t temp; + }; + + Temperature Convert(Controllers::SimpleWeatherService::Temperature temp, Controllers::Settings::WeatherFormat format); + } +} diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 2e00ee98..b6c4caa1 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -2,6 +2,8 @@ #include #include + +#include "displayapp/Weather.h" #include "displayapp/screens/NotificationIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/WeatherSymbols.h" @@ -174,14 +176,12 @@ void WatchFaceDigital::Refresh() { if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { - int16_t temp = optCurrentWeather->temperature; char tempUnit = 'C'; if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { - temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); tempUnit = 'F'; } - temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); - lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat()); + lv_label_set_text_fmt(temperature, "%d°%c", temp.temp, tempUnit); lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); } else { lv_label_set_text_static(temperature, ""); diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.cpp b/src/displayapp/screens/WatchFacePineTimeStyle.cpp index e56031f7..c5946111 100644 --- a/src/displayapp/screens/WatchFacePineTimeStyle.cpp +++ b/src/displayapp/screens/WatchFacePineTimeStyle.cpp @@ -22,7 +22,8 @@ #include "displayapp/screens/WatchFacePineTimeStyle.h" #include #include -#include +#include "displayapp/Colors.h" +#include "displayapp/Weather.h" #include "displayapp/screens/BatteryIcon.h" #include "displayapp/screens/BleIcon.h" #include "displayapp/screens/NotificationIcon.h" @@ -543,11 +544,7 @@ void WatchFacePineTimeStyle::Refresh() { if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { - int16_t temp = optCurrentWeather->temperature; - if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { - temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); - } - temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat()); lv_label_set_text_fmt(temperature, "%d°", temp); lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); } else { diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 5321b7cc..1bdad983 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -1,8 +1,11 @@ #include "displayapp/screens/Weather.h" + #include + #include "components/ble/SimpleWeatherService.h" #include "components/datetime/DateTimeController.h" #include "components/settings/Settings.h" +#include "displayapp/Weather.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/WeatherSymbols.h" #include "displayapp/InfiniTimeTheme.h" @@ -10,31 +13,27 @@ using namespace Pinetime::Applications::Screens; namespace { - lv_color_t TemperatureColor(int16_t temperature) { - if (temperature <= 0) { // freezing + lv_color_t TemperatureColor(Pinetime::Applications::Temperature temp) { + if (temp.temp <= 0) { // freezing return Colors::blue; - } else if (temperature <= 400) { // ice + } else if (temp.temp <= 4) { // ice return LV_COLOR_CYAN; - } else if (temperature >= 2700) { // hot + } else if (temp.temp >= 27) { // hot return Colors::deepOrange; } return Colors::orange; // normal } - uint8_t TemperatureStyle(int16_t temperature) { - if (temperature <= 0) { // freezing + uint8_t TemperatureStyle(Pinetime::Applications::Temperature temp) { + if (temp.temp <= 0) { // freezing return LV_TABLE_PART_CELL3; - } else if (temperature <= 400) { // ice + } else if (temp.temp <= 4) { // ice return LV_TABLE_PART_CELL4; - } else if (temperature >= 2700) { // hot + } else if (temp.temp >= 27) { // 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) @@ -120,22 +119,19 @@ void Weather::Refresh() { if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { - int16_t temp = optCurrentWeather->temperature; - int16_t minTemp = optCurrentWeather->minTemperature; - int16_t maxTemp = optCurrentWeather->maxTemperature; + Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat()); + Applications::Temperature minTemp = Applications::Convert(optCurrentWeather->minTemperature, settingsController.GetWeatherFormat()); + Applications::Temperature maxTemp = Applications::Convert(optCurrentWeather->maxTemperature, settingsController.GetWeatherFormat()); 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)); + lv_label_set_text_fmt(temperature, "%d°%c", temp.temp, tempUnit); + lv_label_set_text_fmt(minTemperature, "%d°", minTemp.temp); + lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp.temp); } else { lv_label_set_text(icon, ""); lv_label_set_text(condition, ""); @@ -153,27 +149,23 @@ void Weather::Refresh() { std::tm localTime = *std::localtime(reinterpret_cast(&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; + Applications::Temperature maxTemp = + Applications::Convert(optCurrentForecast->days[i].maxTemperature, settingsController.GetWeatherFormat()); + Applications::Temperature minTemp = + Applications::Convert(optCurrentForecast->days[i].minTemperature, settingsController.GetWeatherFormat()); 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(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); + int diff = snprintf(nullptr, 0, "%d", maxTemp.temp) - snprintf(nullptr, 0, "%d", minTemp.temp); if (diff <= 0) { maxPadding[-diff] = '\0'; minPadding[0] = '\0'; @@ -181,8 +173,8 @@ void Weather::Refresh() { 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); + lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp.temp); + lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp.temp); } } else { for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { From 24626966a0167d8085560d105ab677e07790e197 Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Wed, 2 Oct 2024 11:58:32 +0200 Subject: [PATCH 2/2] Switch to simpler temperature interface --- src/CMakeLists.txt | 2 - src/components/ble/SimpleWeatherService.cpp | 27 +++++---- src/components/ble/SimpleWeatherService.h | 29 +++++++++- src/displayapp/Weather.cpp | 13 ----- src/displayapp/Weather.h | 17 ------ src/displayapp/screens/WatchFaceDigital.cpp | 6 +- .../screens/WatchFacePineTimeStyle.cpp | 6 +- src/displayapp/screens/Weather.cpp | 57 +++++++++++-------- 8 files changed, 79 insertions(+), 78 deletions(-) delete mode 100644 src/displayapp/Weather.cpp delete mode 100644 src/displayapp/Weather.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d69c1d6b..0a97a015 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -398,7 +398,6 @@ list(APPEND SOURCE_FILES displayapp/screens/Styles.cpp displayapp/screens/WeatherSymbols.cpp displayapp/Colors.cpp - displayapp/Weather.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp displayapp/widgets/DotIndicator.cpp @@ -607,7 +606,6 @@ set(INCLUDE_FILES displayapp/screens/ApplicationList.h displayapp/screens/CheckboxList.h displayapp/Apps.h - displayapp/Weather.h displayapp/screens/Notifications.h displayapp/screens/HeartRate.h displayapp/screens/Metronome.h diff --git a/src/components/ble/SimpleWeatherService.cpp b/src/components/ble/SimpleWeatherService.cpp index a1f0439e..a58c3a76 100644 --- a/src/components/ble/SimpleWeatherService.cpp +++ b/src/components/ble/SimpleWeatherService.cpp @@ -42,9 +42,9 @@ namespace { std::memcpy(cityName.data(), &dataBuffer[16], 32); cityName[32] = '\0'; return SimpleWeatherService::CurrentWeather(ToUInt64(&dataBuffer[2]), - SimpleWeatherService::Temperature {ToInt16(&dataBuffer[10])}, - SimpleWeatherService::Temperature {ToInt16(&dataBuffer[12])}, - SimpleWeatherService::Temperature {ToInt16(&dataBuffer[14])}, + SimpleWeatherService::Temperature(ToInt16(&dataBuffer[10])), + SimpleWeatherService::Temperature(ToInt16(&dataBuffer[12])), + SimpleWeatherService::Temperature(ToInt16(&dataBuffer[14])), SimpleWeatherService::Icons {dataBuffer[16 + 32]}, std::move(cityName)); } @@ -56,8 +56,8 @@ namespace { const uint8_t nbDaysInBuffer = dataBuffer[10]; const uint8_t nbDays = std::min(SimpleWeatherService::MaxNbForecastDays, nbDaysInBuffer); for (int i = 0; i < nbDays; i++) { - days[i] = SimpleWeatherService::Forecast::Day {SimpleWeatherService::Temperature {ToInt16(&dataBuffer[11 + (i * 5)])}, - SimpleWeatherService::Temperature {ToInt16(&dataBuffer[13 + (i * 5)])}, + days[i] = SimpleWeatherService::Forecast::Day {SimpleWeatherService::Temperature(ToInt16(&dataBuffer[11 + (i * 5)])), + SimpleWeatherService::Temperature(ToInt16(&dataBuffer[13 + (i * 5)])), SimpleWeatherService::Icons {dataBuffer[15 + (i * 5)]}}; } return SimpleWeatherService::Forecast {timestamp, nbDays, days}; @@ -98,9 +98,9 @@ int SimpleWeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { currentWeather = CreateCurrentWeather(dataBuffer); NRF_LOG_INFO("Current weather :\n\tTimestamp : %d\n\tTemperature:%d\n\tMin:%d\n\tMax:%d\n\tIcon:%d\n\tLocation:%s", currentWeather->timestamp, - currentWeather->temperature, - currentWeather->minTemperature, - currentWeather->maxTemperature, + currentWeather->temperature.PreciseCelsius(), + currentWeather->minTemperature.PreciseCelsius(), + currentWeather->maxTemperature.PreciseCelsius(), currentWeather->iconId, currentWeather->location.data()); } @@ -112,8 +112,8 @@ int SimpleWeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { for (int i = 0; i < 5; i++) { NRF_LOG_INFO("\t[%d] Min: %d - Max : %d - Icon : %d", i, - forecast->days[i].minTemperature, - forecast->days[i].maxTemperature, + forecast->days[i].minTemperature.PreciseCelsius(), + forecast->days[i].maxTemperature.PreciseCelsius(), forecast->days[i].iconId); } } @@ -154,14 +154,13 @@ std::optional SimpleWeatherService::GetForecast( } bool SimpleWeatherService::CurrentWeather::operator==(const SimpleWeatherService::CurrentWeather& other) const { - return this->iconId == other.iconId && this->temperature.temp == other.temperature.temp && this->timestamp == other.timestamp && - this->maxTemperature.temp == other.maxTemperature.temp && this->minTemperature.temp == other.maxTemperature.temp && + return this->iconId == other.iconId && this->temperature == other.temperature && this->timestamp == other.timestamp && + this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature && std::strcmp(this->location.data(), other.location.data()) == 0; } bool SimpleWeatherService::Forecast::Day::operator==(const SimpleWeatherService::Forecast::Day& other) const { - return this->iconId == other.iconId && this->maxTemperature.temp == other.maxTemperature.temp && - this->minTemperature.temp == other.maxTemperature.temp; + return this->iconId == other.iconId && this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature; } bool SimpleWeatherService::Forecast::operator==(const SimpleWeatherService::Forecast& other) const { diff --git a/src/components/ble/SimpleWeatherService.h b/src/components/ble/SimpleWeatherService.h index ef55f03c..6dc0bb1b 100644 --- a/src/components/ble/SimpleWeatherService.h +++ b/src/components/ble/SimpleWeatherService.h @@ -61,8 +61,33 @@ namespace Pinetime { Unknown = 255 }; - struct Temperature { - int16_t temp; + class Temperature { + public: + explicit Temperature(int16_t raw = 0) : raw {raw} { + } + + [[nodiscard]] int16_t PreciseCelsius() const { + return raw; + } + + [[nodiscard]] int16_t PreciseFahrenheit() const { + return raw * 9 / 5 + 3200; + } + + [[nodiscard]] int16_t Celsius() const { + return (PreciseCelsius() + 50) / 100; + } + + [[nodiscard]] int16_t Fahrenheit() const { + return (PreciseFahrenheit() + 50) / 100; + } + + bool operator==(const Temperature& other) const { + return raw == other.raw; + } + + private: + int16_t raw; }; using Location = std::array; // 32 char + \0 (end of string) diff --git a/src/displayapp/Weather.cpp b/src/displayapp/Weather.cpp deleted file mode 100644 index a0f0a281..00000000 --- a/src/displayapp/Weather.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "displayapp/Weather.h" - -using namespace Pinetime::Applications; - -Temperature Pinetime::Applications::Convert(Controllers::SimpleWeatherService::Temperature temp, - Controllers::Settings::WeatherFormat format) { - Temperature t = {temp.temp}; - if (format == Controllers::Settings::WeatherFormat::Imperial) { - t.temp = t.temp * 9 / 5 + 3200; - } - t.temp = t.temp / 100 + (t.temp % 100 >= 50 ? 1 : 0); - return t; -} diff --git a/src/displayapp/Weather.h b/src/displayapp/Weather.h deleted file mode 100644 index 0dd17fce..00000000 --- a/src/displayapp/Weather.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include - -#include "components/ble/SimpleWeatherService.h" -#include "components/settings/Settings.h" - -namespace Pinetime { - namespace Applications { - struct Temperature { - int16_t temp; - }; - - Temperature Convert(Controllers::SimpleWeatherService::Temperature temp, Controllers::Settings::WeatherFormat format); - } -} diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index b6c4caa1..d944117d 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -3,7 +3,6 @@ #include #include -#include "displayapp/Weather.h" #include "displayapp/screens/NotificationIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/WeatherSymbols.h" @@ -176,12 +175,13 @@ void WatchFaceDigital::Refresh() { if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature.Celsius(); char tempUnit = 'C'; if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = optCurrentWeather->temperature.Fahrenheit(); tempUnit = 'F'; } - Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat()); - lv_label_set_text_fmt(temperature, "%d°%c", temp.temp, tempUnit); + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); } else { lv_label_set_text_static(temperature, ""); diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.cpp b/src/displayapp/screens/WatchFacePineTimeStyle.cpp index c5946111..22ccefc7 100644 --- a/src/displayapp/screens/WatchFacePineTimeStyle.cpp +++ b/src/displayapp/screens/WatchFacePineTimeStyle.cpp @@ -23,7 +23,6 @@ #include #include #include "displayapp/Colors.h" -#include "displayapp/Weather.h" #include "displayapp/screens/BatteryIcon.h" #include "displayapp/screens/BleIcon.h" #include "displayapp/screens/NotificationIcon.h" @@ -544,7 +543,10 @@ void WatchFacePineTimeStyle::Refresh() { if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { - Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat()); + int16_t temp = optCurrentWeather->temperature.Celsius(); + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = optCurrentWeather->temperature.Fahrenheit(); + } lv_label_set_text_fmt(temperature, "%d°", temp); lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); } else { diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 1bdad983..275153e9 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -5,7 +5,6 @@ #include "components/ble/SimpleWeatherService.h" #include "components/datetime/DateTimeController.h" #include "components/settings/Settings.h" -#include "displayapp/Weather.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/WeatherSymbols.h" #include "displayapp/InfiniTimeTheme.h" @@ -13,23 +12,23 @@ using namespace Pinetime::Applications::Screens; namespace { - lv_color_t TemperatureColor(Pinetime::Applications::Temperature temp) { - if (temp.temp <= 0) { // freezing + lv_color_t TemperatureColor(Pinetime::Controllers::SimpleWeatherService::Temperature temp) { + if (temp.Celsius() <= 0) { // freezing return Colors::blue; - } else if (temp.temp <= 4) { // ice + } else if (temp.Celsius() <= 4) { // ice return LV_COLOR_CYAN; - } else if (temp.temp >= 27) { // hot + } else if (temp.Celsius() >= 27) { // hot return Colors::deepOrange; } return Colors::orange; // normal } - uint8_t TemperatureStyle(Pinetime::Applications::Temperature temp) { - if (temp.temp <= 0) { // freezing + uint8_t TemperatureStyle(Pinetime::Controllers::SimpleWeatherService::Temperature temp) { + if (temp.Celsius() <= 0) { // freezing return LV_TABLE_PART_CELL3; - } else if (temp.temp <= 4) { // ice + } else if (temp.Celsius() <= 4) { // ice return LV_TABLE_PART_CELL4; - } else if (temp.temp >= 27) { // hot + } else if (temp.Celsius() >= 27) { // hot return LV_TABLE_PART_CELL6; } return LV_TABLE_PART_CELL5; // normal @@ -119,19 +118,25 @@ void Weather::Refresh() { if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { - Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat()); - Applications::Temperature minTemp = Applications::Convert(optCurrentWeather->minTemperature, settingsController.GetWeatherFormat()); - Applications::Temperature maxTemp = Applications::Convert(optCurrentWeather->maxTemperature, settingsController.GetWeatherFormat()); - lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, TemperatureColor(temp)); + int16_t temp = optCurrentWeather->temperature.Celsius(); + int16_t minTemp = optCurrentWeather->minTemperature.Celsius(); + int16_t maxTemp = optCurrentWeather->maxTemperature.Celsius(); char tempUnit = 'C'; if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = optCurrentWeather->temperature.Fahrenheit(); + minTemp = optCurrentWeather->minTemperature.Fahrenheit(); + maxTemp = optCurrentWeather->maxTemperature.Fahrenheit(); tempUnit = 'F'; } + lv_obj_set_style_local_text_color(temperature, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + TemperatureColor(optCurrentWeather->temperature)); 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", temp.temp, tempUnit); - lv_label_set_text_fmt(minTemperature, "%d°", minTemp.temp); - lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp.temp); + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_label_set_text_fmt(minTemperature, "%d°", minTemp); + lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); } else { lv_label_set_text(icon, ""); lv_label_set_text(condition, ""); @@ -149,12 +154,14 @@ void Weather::Refresh() { std::tm localTime = *std::localtime(reinterpret_cast(&optCurrentForecast->timestamp)); for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { - Applications::Temperature maxTemp = - Applications::Convert(optCurrentForecast->days[i].maxTemperature, settingsController.GetWeatherFormat()); - Applications::Temperature minTemp = - Applications::Convert(optCurrentForecast->days[i].minTemperature, settingsController.GetWeatherFormat()); - lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(maxTemp)); - lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(minTemp)); + int16_t minTemp = optCurrentForecast->days[i].maxTemperature.Celsius(); + int16_t maxTemp = optCurrentForecast->days[i].minTemperature.Celsius(); + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + minTemp = optCurrentForecast->days[i].maxTemperature.Fahrenheit(); + maxTemp = optCurrentForecast->days[i].minTemperature.Fahrenheit(); + } + lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(optCurrentForecast->days[i].maxTemperature)); + lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(optCurrentForecast->days[i].minTemperature)); uint8_t wday = localTime.tm_wday + i + 1; if (wday > 7) { wday -= 7; @@ -165,7 +172,7 @@ void Weather::Refresh() { // 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.temp) - snprintf(nullptr, 0, "%d", minTemp.temp); + int diff = snprintf(nullptr, 0, "%d", maxTemp) - snprintf(nullptr, 0, "%d", minTemp); if (diff <= 0) { maxPadding[-diff] = '\0'; minPadding[0] = '\0'; @@ -173,8 +180,8 @@ void Weather::Refresh() { maxPadding[0] = '\0'; minPadding[diff] = '\0'; } - lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp.temp); - lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp.temp); + 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++) {