Skip to content

Commit d8a93a5

Browse files
authored
Merge branch 'main' into pawn
2 parents 5c4d580 + 0fabfe9 commit d8a93a5

15 files changed

Lines changed: 267 additions & 87 deletions

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
cmake_minimum_required(VERSION 3.10)
22

33
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
4+
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
45

5-
project(pinetime VERSION 1.15.0 LANGUAGES C CXX ASM)
6+
project(pinetime VERSION 1.16.0 LANGUAGES C CXX ASM)
67

78
set(CMAKE_C_STANDARD 99)
89
set(CMAKE_CXX_STANDARD 20)

doc/SimpleWeatherService.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,25 @@ The host uses this characteristic to update the current weather information and
1717

1818
This characteristics accepts a byte array with the following 2-Bytes header:
1919

20-
- [0] Message Type :
20+
- [0] Message Type :
2121
- `0` : Current weather
2222
- `1` : Forecast
23-
- [1] Message Version : Version `0` is currently supported. Other versions might be added in future releases
23+
- [1] Message Version :
24+
- `0` : Currently supported
25+
- `1` : Adds support for sunrise and sunset
2426

25-
### Current Weather
27+
### Current Weather
2628

2729
The byte array must contain the following data:
2830

2931
- [0] : Message type = `0`
30-
- [1] : Message version = `0`
32+
- [1] : Message version = `1`
3133
- [2][3][4][5][6][7][8][9] : Timestamp (64 bits UNIX timestamp, number of seconds elapsed since 1 JAN 1970) in local time (the same timezone as the one used to set the time)
3234
- [10, 11] : Current temperature (°C * 100)
3335
- [12, 13] : Minimum temperature (°C * 100)
3436
- [14, 15] : Maximum temperature (°C * 100)
3537
- [16]..[47] : location (string, unused characters should be set to `0`)
36-
- [48] : icon ID
38+
- [48] : icon ID
3739
- 0 = Sun, clear sky
3840
- 1 = Few clouds
3941
- 2 = Clouds
@@ -43,6 +45,13 @@ The byte array must contain the following data:
4345
- 6 = Thunderstorm
4446
- 7 = Snow
4547
- 8 = Mist, smog
48+
- [49, 50] : Sunrise (number of minutes elapsed since midnight)
49+
- `0` sun already up when day starts
50+
- `-1` unknown
51+
- `-2` no sunrise (e.g. polar night)
52+
- [51, 52] : Sunset (number of minutes elapsed since midnight)
53+
- `-1` unknown
54+
- `-2` no sunset (e.g. polar day)
4655

4756
### Forecast
4857

src/components/ble/SimpleWeatherService.cpp

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,48 @@ namespace {
4141
SimpleWeatherService::Location cityName;
4242
std::memcpy(cityName.data(), &dataBuffer[16], 32);
4343
cityName[32] = '\0';
44+
int16_t sunrise = -1;
45+
int16_t sunset = -1;
46+
if (dataBuffer[1] > 0) {
47+
int16_t bufferSunrise = ToInt16(&dataBuffer[49]);
48+
int16_t bufferSunset = ToInt16(&dataBuffer[51]);
49+
50+
// Sunrise/sunset format
51+
52+
// Assume sun is down at minute 0 / midnight
53+
54+
// 0<=x<1440 sunrise happens this many minutes into the day
55+
// (0 day starts with sun up)
56+
// -1 unknown
57+
// -2 sun not rising today
58+
59+
// 0<x<1440 sunset happens this many minutes into the day
60+
// -1 unknown
61+
// -2 sun not setting today
62+
63+
// Check if the weather data is well formed
64+
// Disable boolean simplification suggestion, as simplifying it makes it unreadable
65+
if (!( // NOLINT(readability-simplify-boolean-expr)
66+
// Fail if either unknown
67+
(bufferSunrise == -1 || bufferSunset == -1)
68+
// Cannot be out of range
69+
|| (bufferSunrise < -2 || bufferSunrise > 1439 || bufferSunset < -2 || bufferSunset > 1439)
70+
// Cannot have sunset without sunrise
71+
|| (bufferSunrise == -2 && bufferSunset != -2)
72+
// Cannot have sunset before sunrise
73+
|| (bufferSunrise >= bufferSunset && bufferSunrise >= 0 && bufferSunset >= 0))) {
74+
sunrise = bufferSunrise;
75+
sunset = bufferSunset;
76+
}
77+
}
4478
return SimpleWeatherService::CurrentWeather(ToUInt64(&dataBuffer[2]),
4579
SimpleWeatherService::Temperature(ToInt16(&dataBuffer[10])),
4680
SimpleWeatherService::Temperature(ToInt16(&dataBuffer[12])),
4781
SimpleWeatherService::Temperature(ToInt16(&dataBuffer[14])),
4882
SimpleWeatherService::Icons {dataBuffer[16 + 32]},
49-
std::move(cityName));
83+
std::move(cityName),
84+
sunrise,
85+
sunset);
5086
}
5187

5288
SimpleWeatherService::Forecast CreateForecast(const uint8_t* dataBuffer) {
@@ -94,7 +130,7 @@ int SimpleWeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) {
94130

95131
switch (GetMessageType(dataBuffer)) {
96132
case MessageType::CurrentWeather:
97-
if (GetVersion(dataBuffer) == 0) {
133+
if (GetVersion(dataBuffer) <= 1) {
98134
currentWeather = CreateCurrentWeather(dataBuffer);
99135
NRF_LOG_INFO("Current weather :\n\tTimestamp : %d\n\tTemperature:%d\n\tMin:%d\n\tMax:%d\n\tIcon:%d\n\tLocation:%s",
100136
currentWeather->timestamp,
@@ -103,6 +139,9 @@ int SimpleWeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) {
103139
currentWeather->maxTemperature.PreciseCelsius(),
104140
currentWeather->iconId,
105141
currentWeather->location.data());
142+
if (GetVersion(dataBuffer) == 1) {
143+
NRF_LOG_INFO("Sunrise: %d\n\tSunset: %d", currentWeather->sunrise, currentWeather->sunset);
144+
}
106145
}
107146
break;
108147
case MessageType::Forecast:
@@ -153,10 +192,36 @@ std::optional<SimpleWeatherService::Forecast> SimpleWeatherService::GetForecast(
153192
return {};
154193
}
155194

195+
bool SimpleWeatherService::IsNight() const {
196+
if (currentWeather && currentWeather->sunrise != -1 && currentWeather->sunset != -1) {
197+
auto currentTime = dateTimeController.CurrentDateTime().time_since_epoch();
198+
199+
// Get timestamp for last midnight
200+
auto midnight = std::chrono::floor<std::chrono::days>(currentTime);
201+
202+
// Calculate minutes since midnight
203+
auto currentMinutes = std::chrono::duration_cast<std::chrono::minutes>(currentTime - midnight).count();
204+
205+
// Sun not rising today => night all hours
206+
if (currentWeather->sunrise == -2) {
207+
return true;
208+
}
209+
// Sun not setting today => check before sunrise
210+
if (currentWeather->sunset == -2) {
211+
return currentMinutes < currentWeather->sunrise;
212+
}
213+
214+
// Before sunrise or after sunset
215+
return currentMinutes < currentWeather->sunrise || currentMinutes >= currentWeather->sunset;
216+
}
217+
218+
return false;
219+
}
220+
156221
bool SimpleWeatherService::CurrentWeather::operator==(const SimpleWeatherService::CurrentWeather& other) const {
157222
return this->iconId == other.iconId && this->temperature == other.temperature && this->timestamp == other.timestamp &&
158223
this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature &&
159-
std::strcmp(this->location.data(), other.location.data()) == 0;
224+
std::strcmp(this->location.data(), other.location.data()) == 0 && this->sunrise == other.sunrise && this->sunset == other.sunset;
160225
}
161226

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

src/components/ble/SimpleWeatherService.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,17 @@ namespace Pinetime {
113113
Temperature minTemperature,
114114
Temperature maxTemperature,
115115
Icons iconId,
116-
Location&& location)
116+
Location&& location,
117+
int16_t sunrise,
118+
int16_t sunset)
117119
: timestamp {timestamp},
118120
temperature {temperature},
119121
minTemperature {minTemperature},
120122
maxTemperature {maxTemperature},
121123
iconId {iconId},
122-
location {std::move(location)} {
124+
location {std::move(location)},
125+
sunrise {sunrise},
126+
sunset {sunset} {
123127
}
124128

125129
uint64_t timestamp;
@@ -128,6 +132,8 @@ namespace Pinetime {
128132
Temperature maxTemperature;
129133
Icons iconId;
130134
Location location;
135+
int16_t sunrise;
136+
int16_t sunset;
131137

132138
bool operator==(const CurrentWeather& other) const;
133139
};
@@ -152,6 +158,8 @@ namespace Pinetime {
152158
std::optional<CurrentWeather> Current() const;
153159
std::optional<Forecast> GetForecast() const;
154160

161+
[[nodiscard]] bool IsNight() const;
162+
155163
private:
156164
// 00050000-78fc-48fe-8e23-433b3a1942d0
157165
static constexpr ble_uuid128_t BaseUuid() {

src/displayapp/InfiniTimeTheme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace Colors {
88
static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0);
99
static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff);
1010
static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0);
11+
static constexpr lv_color_t gray = LV_COLOR_MAKE(0x50, 0x50, 0x50);
1112

1213
static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e);
1314
static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38);

src/displayapp/fonts/fonts.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"sources": [
6969
{
7070
"file": "FontAwesome5-Solid+Brands+Regular.woff",
71-
"range": "0xf185, 0xf6c4, 0xf743, 0xf740, 0xf75f, 0xf0c2, 0xf05e, 0xf73b, 0xf0e7, 0xf2dc"
71+
"range": "0xf185, 0xf186, 0xf6c3, 0xf6c4, 0xf73c, 0xf743, 0xf740, 0xf75f, 0xf0c2, 0xf05e, 0xf73b, 0xf0e7, 0xf2dc"
7272
}
7373
],
7474
"bpp": 1,

src/displayapp/screens/BatteryIcon.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
#include "displayapp/screens/BatteryIcon.h"
21
#include <cstdint>
2+
#include <cmath>
3+
#include "displayapp/screens/BatteryIcon.h"
34
#include "displayapp/screens/Symbols.h"
45
#include "displayapp/icons/battery/batteryicon.c"
56
#include "displayapp/InfiniTimeTheme.h"
7+
#include <lvgl/src/lv_misc/lv_color.h>
68

79
using namespace Pinetime::Applications::Screens;
810

@@ -51,3 +53,14 @@ const char* BatteryIcon::GetPlugIcon(bool isCharging) {
5153
else
5254
return "";
5355
}
56+
57+
lv_color_t BatteryIcon::ColorFromPercentage(int batteryPercent) {
58+
// HSV color model has red at 0° and green at 120°.
59+
// We lock saturation and brightness at 100% and traverse the cylinder
60+
// between red and green, thus avoiding the darker RGB on medium battery
61+
// charges and giving us a much nicer color range.
62+
const float normalizedPercent = batteryPercent / 100.0f;
63+
// Follow -e^{-4x} + 1 curve: begins going yellow around 25%, yellow around 15%, red around 5%
64+
const uint8_t hue = (-std::exp(-4.0f * normalizedPercent) + 1.0f) * 120.0f;
65+
return lv_color_hsv_to_rgb(hue, 100, 100);
66+
}

src/displayapp/screens/BatteryIcon.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Pinetime {
1616

1717
static const char* GetUnknownIcon();
1818
static const char* GetPlugIcon(bool isCharging);
19+
static lv_color_t ColorFromPercentage(int batteryPercent);
1920

2021
private:
2122
lv_obj_t* batteryImg;

src/displayapp/screens/Symbols.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ namespace Pinetime {
4545

4646
// fontawesome_weathericons.c
4747
// static constexpr const char* sun = "\xEF\x86\x85";
48+
static constexpr const char* moon = "\xEF\x86\x86"; // 0xf186
4849
static constexpr const char* cloudSun = "\xEF\x9B\x84";
50+
static constexpr const char* cloudMoon = "\xEF\x9B\x83"; // 0xf6c3
4951
static constexpr const char* cloudSunRain = "\xEF\x9D\x83";
52+
static constexpr const char* cloudMoonRain = "\xEF\x9C\xBC"; // 0xf73c
5053
static constexpr const char* cloudShowersHeavy = "\xEF\x9D\x80";
5154
static constexpr const char* smog = "\xEF\x9D\x9F";
5255
static constexpr const char* cloud = "\xEF\x83\x82";

src/displayapp/screens/WatchFacePineTimeStyle.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ void WatchFacePineTimeStyle::Refresh() {
548548
temp = optCurrentWeather->temperature.Fahrenheit();
549549
}
550550
lv_label_set_text_fmt(temperature, "%d°", temp);
551-
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
551+
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId, weatherService.IsNight()));
552552
} else {
553553
lv_label_set_text(temperature, "--");
554554
lv_label_set_text(weatherIcon, Symbols::ban);

0 commit comments

Comments
 (0)