Skip to content

Commit 04b8bc8

Browse files
committed
SimpleWeatherService: Add sunrise and sunset data
1 parent 7b39d81 commit 04b8bc8

10 files changed

+73
-17
lines changed

doc/SimpleWeatherService.md

+9-5
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,8 @@ The byte array must contain the following data:
4345
- 6 = Thunderstorm
4446
- 7 = Snow
4547
- 8 = Mist, smog
48+
- [49, 50] : Sunrise (16 bits, number of minutes elapsed since midnight)
49+
- [51, 52] : Sunset (16 bits, number of minutes elapsed since midnight)
4650

4751
### Forecast
4852

src/components/ble/SimpleWeatherService.cpp

+34-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ namespace {
3333
(static_cast<uint64_t>(data[5]) << 40) + (static_cast<uint64_t>(data[6]) << 48) + (static_cast<uint64_t>(data[7]) << 56);
3434
}
3535

36+
uint16_t ToUInt16(const uint8_t* data) {
37+
return data[0] + (data[1] << 8);
38+
}
39+
3640
int16_t ToInt16(const uint8_t* data) {
3741
return data[0] + (data[1] << 8);
3842
}
@@ -41,12 +45,20 @@ namespace {
4145
SimpleWeatherService::Location cityName;
4246
std::memcpy(cityName.data(), &dataBuffer[16], 32);
4347
cityName[32] = '\0';
48+
uint16_t sunrise = 0;
49+
uint16_t sunset = 0;
50+
if (dataBuffer[1] > 0) {
51+
sunrise = ToUInt16(&dataBuffer[49]);
52+
sunset = ToUInt16(&dataBuffer[51]);
53+
}
4454
return SimpleWeatherService::CurrentWeather(ToUInt64(&dataBuffer[2]),
4555
SimpleWeatherService::Temperature(ToInt16(&dataBuffer[10])),
4656
SimpleWeatherService::Temperature(ToInt16(&dataBuffer[12])),
4757
SimpleWeatherService::Temperature(ToInt16(&dataBuffer[14])),
4858
SimpleWeatherService::Icons {dataBuffer[16 + 32]},
49-
std::move(cityName));
59+
std::move(cityName),
60+
sunrise,
61+
sunset);
5062
}
5163

5264
SimpleWeatherService::Forecast CreateForecast(const uint8_t* dataBuffer) {
@@ -94,7 +106,7 @@ int SimpleWeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) {
94106

95107
switch (GetMessageType(dataBuffer)) {
96108
case MessageType::CurrentWeather:
97-
if (GetVersion(dataBuffer) == 0) {
109+
if (GetVersion(dataBuffer) <= 1) {
98110
currentWeather = CreateCurrentWeather(dataBuffer);
99111
NRF_LOG_INFO("Current weather :\n\tTimestamp : %d\n\tTemperature:%d\n\tMin:%d\n\tMax:%d\n\tIcon:%d\n\tLocation:%s",
100112
currentWeather->timestamp,
@@ -103,6 +115,9 @@ int SimpleWeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) {
103115
currentWeather->maxTemperature.PreciseCelsius(),
104116
currentWeather->iconId,
105117
currentWeather->location.data());
118+
if (GetVersion(dataBuffer) == 1) {
119+
NRF_LOG_INFO("Sunrise: %d\n\tSunset: %d", currentWeather->sunrise, currentWeather->sunset);
120+
}
106121
}
107122
break;
108123
case MessageType::Forecast:
@@ -153,10 +168,26 @@ std::optional<SimpleWeatherService::Forecast> SimpleWeatherService::GetForecast(
153168
return {};
154169
}
155170

171+
bool SimpleWeatherService::IsNight() const {
172+
if (currentWeather && currentWeather->sunrise > 0 && currentWeather->sunset > 0) {
173+
auto currentTime = dateTimeController.CurrentDateTime().time_since_epoch();
174+
175+
// Get timestamp for last midnight
176+
auto midnight = std::chrono::floor<std::chrono::days>(currentTime);
177+
178+
// Calculate minutes since midnight
179+
auto currentMinutes = std::chrono::duration_cast<std::chrono::minutes>(currentTime - midnight).count();
180+
181+
return currentMinutes < currentWeather->sunrise || currentMinutes > currentWeather->sunset;
182+
}
183+
184+
return false;
185+
}
186+
156187
bool SimpleWeatherService::CurrentWeather::operator==(const SimpleWeatherService::CurrentWeather& other) const {
157188
return this->iconId == other.iconId && this->temperature == other.temperature && this->timestamp == other.timestamp &&
158189
this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature &&
159-
std::strcmp(this->location.data(), other.location.data()) == 0;
190+
std::strcmp(this->location.data(), other.location.data()) == 0 && this->sunrise == other.sunrise && this->sunset == other.sunset;
160191
}
161192

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

src/components/ble/SimpleWeatherService.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,17 @@ namespace Pinetime {
9898
Temperature minTemperature,
9999
Temperature maxTemperature,
100100
Icons iconId,
101-
Location&& location)
101+
Location&& location,
102+
uint16_t sunrise,
103+
uint16_t sunset)
102104
: timestamp {timestamp},
103105
temperature {temperature},
104106
minTemperature {minTemperature},
105107
maxTemperature {maxTemperature},
106108
iconId {iconId},
107-
location {std::move(location)} {
109+
location {std::move(location)},
110+
sunrise {sunrise},
111+
sunset {sunset} {
108112
}
109113

110114
uint64_t timestamp;
@@ -113,6 +117,8 @@ namespace Pinetime {
113117
Temperature maxTemperature;
114118
Icons iconId;
115119
Location location;
120+
uint16_t sunrise;
121+
uint16_t sunset;
116122

117123
bool operator==(const CurrentWeather& other) const;
118124
};
@@ -137,6 +143,8 @@ namespace Pinetime {
137143
std::optional<CurrentWeather> Current() const;
138144
std::optional<Forecast> GetForecast() const;
139145

146+
bool IsNight() const;
147+
140148
private:
141149
// 00050000-78fc-48fe-8e23-433b3a1942d0
142150
static constexpr ble_uuid128_t BaseUuid() {

src/displayapp/fonts/fonts.json

+1-1
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/Symbols.h

+3
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ namespace Pinetime {
4242

4343
// fontawesome_weathericons.c
4444
// static constexpr const char* sun = "\xEF\x86\x85";
45+
static constexpr const char* moon = "\xEF\x86\x86"; // 0xf186
4546
static constexpr const char* cloudSun = "\xEF\x9B\x84";
47+
static constexpr const char* cloudMoon = "\xEF\x9B\x83"; // 0xf6c3
4648
static constexpr const char* cloudSunRain = "\xEF\x9D\x83";
49+
static constexpr const char* cloudMoonRain = "\xEF\x9C\xBC"; // 0xf73c
4750
static constexpr const char* cloudShowersHeavy = "\xEF\x9D\x80";
4851
static constexpr const char* smog = "\xEF\x9D\x9F";
4952
static constexpr const char* cloud = "\xEF\x83\x82";

src/displayapp/screens/WatchFaceDigital.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ void WatchFaceDigital::Refresh() {
183183
tempUnit = 'F';
184184
}
185185
lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
186-
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId));
186+
lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId, weatherService.IsNight()));
187187
} else {
188188
lv_label_set_text_static(temperature, "");
189189
lv_label_set_text(weatherIcon, "");

src/displayapp/screens/WatchFacePineTimeStyle.cpp

+1-1
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);

src/displayapp/screens/Weather.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ void Weather::Refresh() {
132132
LV_LABEL_PART_MAIN,
133133
LV_STATE_DEFAULT,
134134
TemperatureColor(optCurrentWeather->temperature));
135-
lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId));
135+
lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId, weatherService.IsNight()));
136136
lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId));
137137
lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit);
138138
lv_label_set_text_fmt(minTemperature, "%d°", minTemp);
@@ -168,7 +168,7 @@ void Weather::Refresh() {
168168
}
169169
const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast<Controllers::DateTime::Days>(wday));
170170
lv_table_set_cell_value(forecast, 0, i, dayOfWeek);
171-
lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i]->iconId));
171+
lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i]->iconId, false));
172172
// Pad cells based on the largest number of digits on each column
173173
char maxPadding[3] = " ";
174174
char minPadding[3] = " ";

src/displayapp/screens/WeatherSymbols.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
#include "displayapp/screens/WeatherSymbols.h"
22

3-
const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon) {
3+
const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon,
4+
const bool isNight) {
45
switch (icon) {
56
case Pinetime::Controllers::SimpleWeatherService::Icons::Sun:
7+
if (isNight) {
8+
return Symbols::moon;
9+
}
610
return Symbols::sun;
711
break;
812
case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun:
13+
if (isNight) {
14+
return Symbols::cloudMoon;
15+
}
916
return Symbols::cloudSun;
1017
break;
1118
case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds:
@@ -24,6 +31,9 @@ const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime::
2431
return Symbols::cloudShowersHeavy;
2532
break;
2633
case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain:
34+
if (isNight) {
35+
return Symbols::cloudMoonRain;
36+
}
2737
return Symbols::cloudSunRain;
2838
break;
2939
case Pinetime::Controllers::SimpleWeatherService::Icons::Smog:

src/displayapp/screens/WeatherSymbols.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Pinetime {
66
namespace Applications {
77
namespace Screens {
88
namespace Symbols {
9-
const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
9+
const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon, const bool isNight);
1010
const char* GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon);
1111
}
1212
}

0 commit comments

Comments
 (0)