Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

weather: Add function for converting to units #2015

Merged
merged 3 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions src/components/ble/SimpleWeatherService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,22 @@ 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));
}

SimpleWeatherService::Forecast CreateForecast(const uint8_t* dataBuffer) {
auto timestamp = static_cast<uint64_t>(ToUInt64(&dataBuffer[2]));

std::array<SimpleWeatherService::Forecast::Day, SimpleWeatherService::MaxNbForecastDays> days;
std::array<std::optional<SimpleWeatherService::Forecast::Day>, SimpleWeatherService::MaxNbForecastDays> days;
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};
Expand Down Expand Up @@ -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());
}
Expand All @@ -112,9 +112,9 @@ 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].iconId);
forecast->days[i]->minTemperature.PreciseCelsius(),
forecast->days[i]->maxTemperature.PreciseCelsius(),
forecast->days[i]->iconId);
}
}
break;
Expand Down
51 changes: 38 additions & 13 deletions src/components/ble/SimpleWeatherService.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,42 @@ namespace Pinetime {
Unknown = 255
};

class Temperature {
public:
explicit Temperature(int16_t raw) : 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<char, 33>; // 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},
Expand All @@ -79,9 +108,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;

Expand All @@ -93,25 +122,21 @@ 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;
};

std::array<Day, MaxNbForecastDays> days;
std::array<std::optional<Day>, MaxNbForecastDays> days;

bool operator==(const Forecast& other) const;
};

std::optional<CurrentWeather> Current() const;
std::optional<Forecast> 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() {
Expand Down
6 changes: 3 additions & 3 deletions src/displayapp/screens/WatchFaceDigital.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <lvgl/lvgl.h>
#include <cstdio>

#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/WeatherSymbols.h"
Expand Down Expand Up @@ -174,13 +175,12 @@ void WatchFaceDigital::Refresh() {
if (currentWeather.IsUpdated()) {
auto optCurrentWeather = currentWeather.Get();
if (optCurrentWeather) {
int16_t temp = optCurrentWeather->temperature;
int16_t temp = optCurrentWeather->temperature.Celsius();
char tempUnit = 'C';
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
temp = optCurrentWeather->temperature.Fahrenheit();
tempUnit = 'F';
}
temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
} else {
Expand Down
7 changes: 3 additions & 4 deletions src/displayapp/screens/WatchFacePineTimeStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "displayapp/screens/WatchFacePineTimeStyle.h"
#include <lvgl/lvgl.h>
#include <cstdio>
#include <displayapp/Colors.h>
#include "displayapp/Colors.h"
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/BleIcon.h"
#include "displayapp/screens/NotificationIcon.h"
Expand Down Expand Up @@ -543,11 +543,10 @@ void WatchFacePineTimeStyle::Refresh() {
if (currentWeather.IsUpdated()) {
auto optCurrentWeather = currentWeather.Get();
if (optCurrentWeather) {
int16_t temp = optCurrentWeather->temperature;
int16_t temp = optCurrentWeather->temperature.Celsius();
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
temp = optCurrentWeather->temperature.Fahrenheit();
}
temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
lv_label_set_text_fmt(temperature, "%d°", temp);
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
} else {
Expand Down
63 changes: 31 additions & 32 deletions src/displayapp/screens/Weather.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "displayapp/screens/Weather.h"

#include <lvgl/lvgl.h>

#include "components/ble/SimpleWeatherService.h"
#include "components/datetime/DateTimeController.h"
#include "components/settings/Settings.h"
Expand All @@ -10,31 +12,27 @@
using namespace Pinetime::Applications::Screens;

namespace {
lv_color_t TemperatureColor(int16_t temperature) {
if (temperature <= 0) { // freezing
lv_color_t TemperatureColor(Pinetime::Controllers::SimpleWeatherService::Temperature temp) {
if (temp.Celsius() <= 0) { // freezing
return Colors::blue;
} else if (temperature <= 400) { // ice
} else if (temp.Celsius() <= 4) { // ice
return LV_COLOR_CYAN;
} else if (temperature >= 2700) { // hot
} else if (temp.Celsius() >= 27) { // hot
return Colors::deepOrange;
}
return Colors::orange; // normal
}

uint8_t TemperatureStyle(int16_t temperature) {
if (temperature <= 0) { // freezing
uint8_t TemperatureStyle(Pinetime::Controllers::SimpleWeatherService::Temperature temp) {
if (temp.Celsius() <= 0) { // freezing
return LV_TABLE_PART_CELL3;
} else if (temperature <= 400) { // ice
} else if (temp.Celsius() <= 4) { // ice
return LV_TABLE_PART_CELL4;
} else if (temperature >= 2700) { // hot
} else if (temp.Celsius() >= 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)
Expand Down Expand Up @@ -120,22 +118,25 @@ 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;
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 = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
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", 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, 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, "");
Expand All @@ -152,24 +153,22 @@ void Weather::Refresh() {
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));
for (int i = 0; i < optCurrentForecast->nbDays; i++) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be correct to use nbDays rather than MaxNbForecastDays here, but we should test it before merging.

int16_t minTemp = optCurrentForecast->days[i]->maxTemperature.Celsius();
int16_t maxTemp = optCurrentForecast->days[i]->minTemperature.Celsius();
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
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;
}
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));
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] = " ";
Expand Down
Loading