Skip to content

Commit 29ad09f

Browse files
FintasticManJF002
authored andcommitted
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.
1 parent afeded0 commit 29ad09f

8 files changed

Lines changed: 84 additions & 62 deletions

File tree

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ list(APPEND SOURCE_FILES
398398
displayapp/screens/Styles.cpp
399399
displayapp/screens/WeatherSymbols.cpp
400400
displayapp/Colors.cpp
401+
displayapp/Weather.cpp
401402
displayapp/widgets/Counter.cpp
402403
displayapp/widgets/PageIndicator.cpp
403404
displayapp/widgets/DotIndicator.cpp
@@ -606,6 +607,7 @@ set(INCLUDE_FILES
606607
displayapp/screens/ApplicationList.h
607608
displayapp/screens/CheckboxList.h
608609
displayapp/Apps.h
610+
displayapp/Weather.h
609611
displayapp/screens/Notifications.h
610612
displayapp/screens/HeartRate.h
611613
displayapp/screens/Metronome.h

src/components/ble/SimpleWeatherService.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ namespace {
4242
std::memcpy(cityName.data(), &dataBuffer[16], 32);
4343
cityName[32] = '\0';
4444
return SimpleWeatherService::CurrentWeather(ToUInt64(&dataBuffer[2]),
45-
ToInt16(&dataBuffer[10]),
46-
ToInt16(&dataBuffer[12]),
47-
ToInt16(&dataBuffer[14]),
45+
SimpleWeatherService::Temperature {ToInt16(&dataBuffer[10])},
46+
SimpleWeatherService::Temperature {ToInt16(&dataBuffer[12])},
47+
SimpleWeatherService::Temperature {ToInt16(&dataBuffer[14])},
4848
SimpleWeatherService::Icons {dataBuffer[16 + 32]},
4949
std::move(cityName));
5050
}
@@ -56,8 +56,8 @@ namespace {
5656
const uint8_t nbDaysInBuffer = dataBuffer[10];
5757
const uint8_t nbDays = std::min(SimpleWeatherService::MaxNbForecastDays, nbDaysInBuffer);
5858
for (int i = 0; i < nbDays; i++) {
59-
days[i] = SimpleWeatherService::Forecast::Day {ToInt16(&dataBuffer[11 + (i * 5)]),
60-
ToInt16(&dataBuffer[13 + (i * 5)]),
59+
days[i] = SimpleWeatherService::Forecast::Day {SimpleWeatherService::Temperature {ToInt16(&dataBuffer[11 + (i * 5)])},
60+
SimpleWeatherService::Temperature {ToInt16(&dataBuffer[13 + (i * 5)])},
6161
SimpleWeatherService::Icons {dataBuffer[15 + (i * 5)]}};
6262
}
6363
return SimpleWeatherService::Forecast {timestamp, nbDays, days};
@@ -154,13 +154,14 @@ std::optional<SimpleWeatherService::Forecast> SimpleWeatherService::GetForecast(
154154
}
155155

156156
bool SimpleWeatherService::CurrentWeather::operator==(const SimpleWeatherService::CurrentWeather& other) const {
157-
return this->iconId == other.iconId && this->temperature == other.temperature && this->timestamp == other.timestamp &&
158-
this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature &&
157+
return this->iconId == other.iconId && this->temperature.temp == other.temperature.temp && this->timestamp == other.timestamp &&
158+
this->maxTemperature.temp == other.maxTemperature.temp && this->minTemperature.temp == other.maxTemperature.temp &&
159159
std::strcmp(this->location.data(), other.location.data()) == 0;
160160
}
161161

162162
bool SimpleWeatherService::Forecast::Day::operator==(const SimpleWeatherService::Forecast::Day& other) const {
163-
return this->iconId == other.iconId && this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature;
163+
return this->iconId == other.iconId && this->maxTemperature.temp == other.maxTemperature.temp &&
164+
this->minTemperature.temp == other.maxTemperature.temp;
164165
}
165166

166167
bool SimpleWeatherService::Forecast::operator==(const SimpleWeatherService::Forecast& other) const {

src/components/ble/SimpleWeatherService.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,17 @@ namespace Pinetime {
6161
Unknown = 255
6262
};
6363

64+
struct Temperature {
65+
int16_t temp;
66+
};
67+
6468
using Location = std::array<char, 33>; // 32 char + \0 (end of string)
6569

6670
struct CurrentWeather {
6771
CurrentWeather(uint64_t timestamp,
68-
int16_t temperature,
69-
int16_t minTemperature,
70-
int16_t maxTemperature,
72+
Temperature temperature,
73+
Temperature minTemperature,
74+
Temperature maxTemperature,
7175
Icons iconId,
7276
Location&& location)
7377
: timestamp {timestamp},
@@ -79,9 +83,9 @@ namespace Pinetime {
7983
}
8084

8185
uint64_t timestamp;
82-
int16_t temperature;
83-
int16_t minTemperature;
84-
int16_t maxTemperature;
86+
Temperature temperature;
87+
Temperature minTemperature;
88+
Temperature maxTemperature;
8589
Icons iconId;
8690
Location location;
8791

@@ -93,8 +97,8 @@ namespace Pinetime {
9397
uint8_t nbDays;
9498

9599
struct Day {
96-
int16_t minTemperature;
97-
int16_t maxTemperature;
100+
Temperature minTemperature;
101+
Temperature maxTemperature;
98102
Icons iconId;
99103

100104
bool operator==(const Day& other) const;
@@ -108,10 +112,6 @@ namespace Pinetime {
108112
std::optional<CurrentWeather> Current() const;
109113
std::optional<Forecast> GetForecast() const;
110114

111-
static int16_t CelsiusToFahrenheit(int16_t celsius) {
112-
return celsius * 9 / 5 + 3200;
113-
}
114-
115115
private:
116116
// 00050000-78fc-48fe-8e23-433b3a1942d0
117117
static constexpr ble_uuid128_t BaseUuid() {

src/displayapp/Weather.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "displayapp/Weather.h"
2+
3+
using namespace Pinetime::Applications;
4+
5+
Temperature Pinetime::Applications::Convert(Controllers::SimpleWeatherService::Temperature temp,
6+
Controllers::Settings::WeatherFormat format) {
7+
Temperature t = {temp.temp};
8+
if (format == Controllers::Settings::WeatherFormat::Imperial) {
9+
t.temp = t.temp * 9 / 5 + 3200;
10+
}
11+
t.temp = t.temp / 100 + (t.temp % 100 >= 50 ? 1 : 0);
12+
return t;
13+
}

src/displayapp/Weather.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <variant>
5+
6+
#include "components/ble/SimpleWeatherService.h"
7+
#include "components/settings/Settings.h"
8+
9+
namespace Pinetime {
10+
namespace Applications {
11+
struct Temperature {
12+
int16_t temp;
13+
};
14+
15+
Temperature Convert(Controllers::SimpleWeatherService::Temperature temp, Controllers::Settings::WeatherFormat format);
16+
}
17+
}

src/displayapp/screens/WatchFaceDigital.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <lvgl/lvgl.h>
44
#include <cstdio>
5+
6+
#include "displayapp/Weather.h"
57
#include "displayapp/screens/NotificationIcon.h"
68
#include "displayapp/screens/Symbols.h"
79
#include "displayapp/screens/WeatherSymbols.h"
@@ -174,14 +176,12 @@ void WatchFaceDigital::Refresh() {
174176
if (currentWeather.IsUpdated()) {
175177
auto optCurrentWeather = currentWeather.Get();
176178
if (optCurrentWeather) {
177-
int16_t temp = optCurrentWeather->temperature;
178179
char tempUnit = 'C';
179180
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
180-
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
181181
tempUnit = 'F';
182182
}
183-
temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
184-
lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
183+
Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat());
184+
lv_label_set_text_fmt(temperature, "%d°%c", temp.temp, tempUnit);
185185
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
186186
} else {
187187
lv_label_set_text_static(temperature, "");

src/displayapp/screens/WatchFacePineTimeStyle.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
#include "displayapp/screens/WatchFacePineTimeStyle.h"
2323
#include <lvgl/lvgl.h>
2424
#include <cstdio>
25-
#include <displayapp/Colors.h>
25+
#include "displayapp/Colors.h"
26+
#include "displayapp/Weather.h"
2627
#include "displayapp/screens/BatteryIcon.h"
2728
#include "displayapp/screens/BleIcon.h"
2829
#include "displayapp/screens/NotificationIcon.h"
@@ -543,11 +544,7 @@ void WatchFacePineTimeStyle::Refresh() {
543544
if (currentWeather.IsUpdated()) {
544545
auto optCurrentWeather = currentWeather.Get();
545546
if (optCurrentWeather) {
546-
int16_t temp = optCurrentWeather->temperature;
547-
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
548-
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
549-
}
550-
temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
547+
Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat());
551548
lv_label_set_text_fmt(temperature, "%d°", temp);
552549
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
553550
} else {

src/displayapp/screens/Weather.cpp

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,39 @@
11
#include "displayapp/screens/Weather.h"
2+
23
#include <lvgl/lvgl.h>
4+
35
#include "components/ble/SimpleWeatherService.h"
46
#include "components/datetime/DateTimeController.h"
57
#include "components/settings/Settings.h"
8+
#include "displayapp/Weather.h"
69
#include "displayapp/DisplayApp.h"
710
#include "displayapp/screens/WeatherSymbols.h"
811
#include "displayapp/InfiniTimeTheme.h"
912

1013
using namespace Pinetime::Applications::Screens;
1114

1215
namespace {
13-
lv_color_t TemperatureColor(int16_t temperature) {
14-
if (temperature <= 0) { // freezing
16+
lv_color_t TemperatureColor(Pinetime::Applications::Temperature temp) {
17+
if (temp.temp <= 0) { // freezing
1518
return Colors::blue;
16-
} else if (temperature <= 400) { // ice
19+
} else if (temp.temp <= 4) { // ice
1720
return LV_COLOR_CYAN;
18-
} else if (temperature >= 2700) { // hot
21+
} else if (temp.temp >= 27) { // hot
1922
return Colors::deepOrange;
2023
}
2124
return Colors::orange; // normal
2225
}
2326

24-
uint8_t TemperatureStyle(int16_t temperature) {
25-
if (temperature <= 0) { // freezing
27+
uint8_t TemperatureStyle(Pinetime::Applications::Temperature temp) {
28+
if (temp.temp <= 0) { // freezing
2629
return LV_TABLE_PART_CELL3;
27-
} else if (temperature <= 400) { // ice
30+
} else if (temp.temp <= 4) { // ice
2831
return LV_TABLE_PART_CELL4;
29-
} else if (temperature >= 2700) { // hot
32+
} else if (temp.temp >= 27) { // hot
3033
return LV_TABLE_PART_CELL6;
3134
}
3235
return LV_TABLE_PART_CELL5; // normal
3336
}
34-
35-
int16_t RoundTemperature(int16_t temp) {
36-
return temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
37-
}
3837
}
3938

4039
Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService)
@@ -120,22 +119,19 @@ void Weather::Refresh() {
120119
if (currentWeather.IsUpdated()) {
121120
auto optCurrentWeather = currentWeather.Get();
122121
if (optCurrentWeather) {
123-
int16_t temp = optCurrentWeather->temperature;
124-
int16_t minTemp = optCurrentWeather->minTemperature;
125-
int16_t maxTemp = optCurrentWeather->maxTemperature;
122+
Applications::Temperature temp = Applications::Convert(optCurrentWeather->temperature, settingsController.GetWeatherFormat());
123+
Applications::Temperature minTemp = Applications::Convert(optCurrentWeather->minTemperature, settingsController.GetWeatherFormat());
124+
Applications::Temperature maxTemp = Applications::Convert(optCurrentWeather->maxTemperature, settingsController.GetWeatherFormat());
126125
lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, TemperatureColor(temp));
127126
char tempUnit = 'C';
128127
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
129-
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
130-
minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
131-
maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
132128
tempUnit = 'F';
133129
}
134130
lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId));
135131
lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId));
136-
lv_label_set_text_fmt(temperature, "%d°%c", RoundTemperature(temp), tempUnit);
137-
lv_label_set_text_fmt(minTemperature, "%d°", RoundTemperature(minTemp));
138-
lv_label_set_text_fmt(maxTemperature, "%d°", RoundTemperature(maxTemp));
132+
lv_label_set_text_fmt(temperature, "%d°%c", temp.temp, tempUnit);
133+
lv_label_set_text_fmt(minTemperature, "%d°", minTemp.temp);
134+
lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp.temp);
139135
} else {
140136
lv_label_set_text(icon, "");
141137
lv_label_set_text(condition, "");
@@ -153,36 +149,32 @@ void Weather::Refresh() {
153149
std::tm localTime = *std::localtime(reinterpret_cast<const time_t*>(&optCurrentForecast->timestamp));
154150

155151
for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
156-
int16_t maxTemp = optCurrentForecast->days[i].maxTemperature;
157-
int16_t minTemp = optCurrentForecast->days[i].minTemperature;
152+
Applications::Temperature maxTemp =
153+
Applications::Convert(optCurrentForecast->days[i].maxTemperature, settingsController.GetWeatherFormat());
154+
Applications::Temperature minTemp =
155+
Applications::Convert(optCurrentForecast->days[i].minTemperature, settingsController.GetWeatherFormat());
158156
lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(maxTemp));
159157
lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(minTemp));
160-
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
161-
maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
162-
minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
163-
}
164158
uint8_t wday = localTime.tm_wday + i + 1;
165159
if (wday > 7) {
166160
wday -= 7;
167161
}
168-
maxTemp = RoundTemperature(maxTemp);
169-
minTemp = RoundTemperature(minTemp);
170162
const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast<Controllers::DateTime::Days>(wday));
171163
lv_table_set_cell_value(forecast, 0, i, dayOfWeek);
172164
lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i].iconId));
173165
// Pad cells based on the largest number of digits on each column
174166
char maxPadding[3] = " ";
175167
char minPadding[3] = " ";
176-
int diff = snprintf(nullptr, 0, "%d", maxTemp) - snprintf(nullptr, 0, "%d", minTemp);
168+
int diff = snprintf(nullptr, 0, "%d", maxTemp.temp) - snprintf(nullptr, 0, "%d", minTemp.temp);
177169
if (diff <= 0) {
178170
maxPadding[-diff] = '\0';
179171
minPadding[0] = '\0';
180172
} else {
181173
maxPadding[0] = '\0';
182174
minPadding[diff] = '\0';
183175
}
184-
lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp);
185-
lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp);
176+
lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp.temp);
177+
lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp.temp);
186178
}
187179
} else {
188180
for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {

0 commit comments

Comments
 (0)