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

Improve weather service #1822

Closed
wants to merge 3 commits into from
Closed
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
99 changes: 29 additions & 70 deletions src/components/ble/weather/WeatherService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ namespace Pinetime {
CleanUpQcbor(&decodeContext);
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}

// Do not add already expired events
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
if (static_cast<uint64_t>(tmpTimestamp + tmpExpires) < currentTimestamp) {
CleanUpQcbor(&decodeContext);
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}

int64_t tmpEventType = 0;
QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", &tmpEventType);
if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS || tmpEventType < 0 ||
Expand All @@ -74,6 +82,8 @@ namespace Pinetime {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}

TidyTimeline();

switch (static_cast<WeatherData::eventtype>(tmpEventType)) {
case WeatherData::eventtype::AirQuality: {
std::unique_ptr<WeatherData::AirQuality> airquality = std::make_unique<WeatherData::AirQuality>();
Expand Down Expand Up @@ -363,9 +373,9 @@ namespace Pinetime {
}
}

std::sort(std::begin(timeline), std::end(timeline), CompareTimelineEvents);

QCBORDecode_ExitMap(&decodeContext);
GetTimelineLength();
TidyTimeline();

if (QCBORDecode_Finish(&decodeContext) != QCBOR_SUCCESS) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
Expand Down Expand Up @@ -401,103 +411,52 @@ namespace Pinetime {
return 0;
}

std::unique_ptr<WeatherData::Clouds>& WeatherService::GetCurrentClouds() {
template <class T>
std::unique_ptr<T>& WeatherService::GetEventOfType(WeatherData::eventtype eventType) {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Clouds && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(header);
if (header->eventType == eventType && IsEventStillValid(header, currentTimestamp)) {
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
return reinterpret_cast<std::unique_ptr<T>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(*this->nullHeader);
return reinterpret_cast<std::unique_ptr<T>&>(*this->nullHeader);
}

std::unique_ptr<WeatherData::Obscuration>& WeatherService::GetCurrentObscuration() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Obscuration && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(header);
}
}
std::unique_ptr<WeatherData::Clouds>& WeatherService::GetCurrentClouds() {
return GetEventOfType<WeatherData::Clouds>(WeatherData::eventtype::Clouds);
}

return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(*this->nullHeader);
std::unique_ptr<WeatherData::Obscuration>& WeatherService::GetCurrentObscuration() {
return GetEventOfType<WeatherData::Obscuration>(WeatherData::eventtype::Obscuration);
}

std::unique_ptr<WeatherData::Precipitation>& WeatherService::GetCurrentPrecipitation() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Precipitation && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Precipitation>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Precipitation>&>(*this->nullHeader);
return GetEventOfType<WeatherData::Precipitation>(WeatherData::eventtype::Precipitation);
}

std::unique_ptr<WeatherData::Wind>& WeatherService::GetCurrentWind() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Wind && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Wind>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Wind>&>(*this->nullHeader);
return GetEventOfType<WeatherData::Wind>(WeatherData::eventtype::Wind);
}

std::unique_ptr<WeatherData::Temperature>& WeatherService::GetCurrentTemperature() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Temperature>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Temperature>&>(*this->nullHeader);
return GetEventOfType<WeatherData::Temperature>(WeatherData::eventtype::Temperature);
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
}

std::unique_ptr<WeatherData::Humidity>& WeatherService::GetCurrentHumidity() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Humidity && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Humidity>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Humidity>&>(*this->nullHeader);
return GetEventOfType<WeatherData::Humidity>(WeatherData::eventtype::Humidity);
}

std::unique_ptr<WeatherData::Pressure>& WeatherService::GetCurrentPressure() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Pressure && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Pressure>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Pressure>&>(*this->nullHeader);
return GetEventOfType<WeatherData::Pressure>(WeatherData::eventtype::Pressure);
}

std::unique_ptr<WeatherData::Location>& WeatherService::GetCurrentLocation() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Location && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::Location>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::Location>&>(*this->nullHeader);
return GetEventOfType<WeatherData::Location>(WeatherData::eventtype::Location);
}

std::unique_ptr<WeatherData::AirQuality>& WeatherService::GetCurrentQuality() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::AirQuality && IsEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<std::unique_ptr<WeatherData::AirQuality>&>(header);
}
}

return reinterpret_cast<std::unique_ptr<WeatherData::AirQuality>&>(*this->nullHeader);
return GetEventOfType<WeatherData::AirQuality>(WeatherData::eventtype::AirQuality);
}

size_t WeatherService::GetTimelineLength() const {
Expand Down
7 changes: 7 additions & 0 deletions src/components/ble/weather/WeatherService.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ namespace Pinetime {
*/
bool HasTimelineEventOfType(WeatherData::eventtype type) const;

const std::vector<std::unique_ptr<WeatherData::TimelineHeader>>& GetEventTimeline() const {
return timeline;
}

private:
// 00040000-78fc-48fe-8e23-433b3a1942d0
static constexpr ble_uuid128_t BaseUuid() {
Expand Down Expand Up @@ -146,6 +150,9 @@ namespace Pinetime {
static bool CompareTimelineEvents(const std::unique_ptr<WeatherData::TimelineHeader>& first,
const std::unique_ptr<WeatherData::TimelineHeader>& second);

template <class T>
std::unique_ptr<T>& GetEventOfType(WeatherData::eventtype eventType);
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns current UNIX timestamp
*/
Expand Down
1 change: 1 addition & 0 deletions src/displayapp/Apps.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace Pinetime {
SettingChimes,
SettingShakeThreshold,
SettingBluetooth,
Weather,
Error
};
}
Expand Down
3 changes: 1 addition & 2 deletions src/displayapp/DisplayApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,11 +540,10 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
case Apps::Metronome:
currentScreen = std::make_unique<Screens::Metronome>(motorController, *systemTask);
break;
/* Weather debug app
/* Weather debug app*/
case Apps::Weather:
currentScreen = std::make_unique<Screens::Weather>(this, systemTask->nimble().weather());
break;
*/
case Apps::Steps:
currentScreen = std::make_unique<Screens::Steps>(motionController, settingsController);
break;
Expand Down
2 changes: 1 addition & 1 deletion src/displayapp/screens/ApplicationList.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ namespace Pinetime {
{"2", Apps::Twos},
{Symbols::drum, Apps::Metronome},
{Symbols::map, Apps::Navigation},
{Symbols::none, Apps::None},
{"W", Apps::Weather},

// {"M", Apps::Motion},
}};
Expand Down
76 changes: 76 additions & 0 deletions src/displayapp/screens/Weather.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers:
screens {app,
0,
{[this]() -> std::unique_ptr<Screen> {
return CreateTimelineStatsPage();
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreenTemperature();
},
[this]() -> std::unique_ptr<Screen> {
Expand Down Expand Up @@ -67,6 +70,79 @@ bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}

std::unique_ptr<Screen> Weather::CreateTimelineStatsPage() {
static constexpr uint8_t maxTimelineCount = 8;

const auto& timeline = weatherService.GetEventTimeline();

lv_obj_t* count_label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_fmt(count_label, "Size: %u, Cap: %u", timeline.size(), timeline.capacity());

lv_obj_t* timelineTable = lv_table_create(lv_scr_act(), nullptr);
lv_obj_align(timelineTable, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 25);
lv_table_set_col_cnt(timelineTable, 3);
lv_table_set_row_cnt(timelineTable, maxTimelineCount + 1);
lv_obj_set_style_local_pad_all(timelineTable, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_border_color(timelineTable, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));

lv_table_set_cell_value(timelineTable, 0, 0, "#");
lv_table_set_col_width(timelineTable, 0, 30);
lv_table_set_cell_value(timelineTable, 0, 1, "Type"); // State
lv_table_set_col_width(timelineTable, 1, 50);
lv_table_set_cell_value(timelineTable, 0, 2, "Expires");
lv_table_set_col_width(timelineTable, 2, 150);

for (uint8_t i = 0; i < timeline.size() && i < maxTimelineCount; i++) {
char buffer[12] = {0};

sprintf(buffer, "%u", i);
lv_table_set_cell_value(timelineTable, i + 1, 0, buffer);

auto& header = timeline[i];
switch (header->eventType) {
case Controllers::WeatherData::eventtype::Obscuration:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Obsc");
break;
case Controllers::WeatherData::eventtype::Precipitation:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Prec");
break;
case Controllers::WeatherData::eventtype::Wind:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Wind");
break;
case Controllers::WeatherData::eventtype::Temperature:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Temp");
break;
case Controllers::WeatherData::eventtype::AirQuality:
lv_table_set_cell_value(timelineTable, i + 1, 1, "AirQ");
break;
case Controllers::WeatherData::eventtype::Special:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Spec");
break;
case Controllers::WeatherData::eventtype::Pressure:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Press");
break;
case Controllers::WeatherData::eventtype::Location:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Loc");
break;
case Controllers::WeatherData::eventtype::Clouds:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Cloud");
break;
case Controllers::WeatherData::eventtype::Humidity:
lv_table_set_cell_value(timelineTable, i + 1, 1, "Humi");
break;
default:
lv_table_set_cell_value(timelineTable, i + 1, 1, "????");
break;
}
memset(buffer, 0, sizeof(buffer));
uint64_t expired_at = header->timestamp + header->expires;
sprintf(buffer, "%lu", static_cast<uint32_t>(expired_at));
lv_table_set_cell_value(timelineTable, i + 1, 2, buffer);
}

return std::make_unique<Screens::Label>(3, 5, timelineTable);
}

std::unique_ptr<Screen> Weather::CreateScreenTemperature() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
Expand Down
4 changes: 3 additions & 1 deletion src/displayapp/screens/Weather.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ namespace Pinetime {

Controllers::WeatherService& weatherService;

ScreenList<5> screens;
ScreenList<6> screens;

std::unique_ptr<Screen> CreateTimelineStatsPage();

std::unique_ptr<Screen> CreateScreenTemperature();

Expand Down