Bunch of bugs fixed, improved error handling, debug UI addition

This commit is contained in:
Avamander 2021-12-01 00:45:28 +02:00
parent 48beb7c3b1
commit c870f8ed30
5 changed files with 194 additions and 141 deletions

View file

@ -28,6 +28,7 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController) WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController)
: system(system), dateTimeController(dateTimeController) { : system(system), dateTimeController(dateTimeController) {
nullHeader = &nullTimelineheader;
} }
void WeatherService::Init() { void WeatherService::Init() {
@ -42,7 +43,7 @@ namespace Pinetime {
int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) { int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) {
// TODO: Detect control messages // TODO: Detect control messages
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om);
if (packetLen <= 0) { if (packetLen <= 0) {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
} }
@ -56,30 +57,28 @@ namespace Pinetime {
// Always encodes to the smallest number of bytes based on the value // Always encodes to the smallest number of bytes based on the value
int64_t tmpTimestamp = 0; int64_t tmpTimestamp = 0;
QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp); QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp);
if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS) { uint8_t err = QCBORDecode_GetError(&decodeContext);
if (err != QCBOR_SUCCESS) {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
} }
int64_t tmpExpires = 0; int64_t tmpExpires = 0;
QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires); QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires);
if (tmpExpires < 0 || tmpExpires > 4294967295) { if (tmpExpires < 0 || tmpExpires > 4294967295) {
// TODO: Return better error?
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
} }
int64_t tmpEventType = 0; int64_t tmpEventType = 0;
QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", &tmpEventType); QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", &tmpEventType);
if (tmpEventType < 0 || tmpEventType > static_cast<int64_t>(WeatherData::eventtype::Length)) { if (tmpEventType < 0 || tmpEventType > static_cast<int64_t>(WeatherData::eventtype::Length)) {
// TODO: Return better error?
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
} }
switch (static_cast<WeatherData::eventtype>(tmpEventType)) { switch (static_cast<WeatherData::eventtype>(tmpEventType)) {
// TODO: Populate
case WeatherData::eventtype::AirQuality: { case WeatherData::eventtype::AirQuality: {
std::unique_ptr<WeatherData::AirQuality> airquality = std::make_unique<WeatherData::AirQuality>(); std::unique_ptr<WeatherData::AirQuality> airquality = std::make_unique<WeatherData::AirQuality>();
airquality->timestamp = tmpTimestamp; airquality->timestamp = tmpTimestamp;
airquality->eventType = static_cast<WeatherData::eventtype>(tmpEventType); airquality->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
airquality->expires = tmpExpires; airquality->expires = tmpExpires;
UsefulBufC String; UsefulBufC String; // TODO: Everything ok with lifecycle here?
QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &String); QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &String);
if (UsefulBuf_IsNULLOrEmptyC(String) != 0) { if (UsefulBuf_IsNULLOrEmptyC(String) != 0) {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
@ -172,10 +171,9 @@ namespace Pinetime {
} }
} }
GetCurrentPressure();
TidyTimeline();
GetTimelineLength();
QCBORDecode_ExitMap(&decodeContext); QCBORDecode_ExitMap(&decodeContext);
GetTimelineLength();
TidyTimeline();
if (QCBORDecode_Finish(&decodeContext) != QCBOR_SUCCESS) { if (QCBORDecode_Finish(&decodeContext) != QCBOR_SUCCESS) {
return BLE_ATT_ERR_INSUFFICIENT_RES; return BLE_ATT_ERR_INSUFFICIENT_RES;
@ -205,94 +203,103 @@ namespace Pinetime {
return 0; return 0;
} }
WeatherData::Clouds WeatherService::GetCurrentClouds() const { std::unique_ptr<WeatherData::Clouds>& WeatherService::GetCurrentClouds() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Clouds && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Clouds && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Clouds&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(this->nullHeader);
} }
WeatherData::Obscuration WeatherService::GetCurrentObscuration() const { std::unique_ptr<WeatherData::Obscuration>& WeatherService::GetCurrentObscuration() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Obscuration && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Obscuration && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Obscuration&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(this->nullHeader);
} }
WeatherData::Precipitation WeatherService::GetCurrentPrecipitation() const { std::unique_ptr<WeatherData::Precipitation>& WeatherService::GetCurrentPrecipitation() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Precipitation && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Precipitation && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Precipitation&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Precipitation>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Precipitation>&>(this->nullHeader);
} }
WeatherData::Wind WeatherService::GetCurrentWind() const { std::unique_ptr<WeatherData::Wind>& WeatherService::GetCurrentWind() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Wind && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Wind && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Wind&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Wind>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Wind>&>(this->nullHeader);
} }
WeatherData::Temperature WeatherService::GetCurrentTemperature() const { std::unique_ptr<WeatherData::Temperature>& WeatherService::GetCurrentTemperature() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Temperature && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Temperature&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Temperature>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Temperature>&>(this->nullHeader);
} }
WeatherData::Humidity WeatherService::GetCurrentHumidity() const { std::unique_ptr<WeatherData::Humidity>& WeatherService::GetCurrentHumidity() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Humidity && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Humidity && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Humidity&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Humidity>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Humidity>&>(this->nullHeader);
} }
WeatherData::Pressure WeatherService::GetCurrentPressure() const { std::unique_ptr<WeatherData::Pressure>& WeatherService::GetCurrentPressure() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Pressure && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Pressure && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Pressure&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Pressure>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Pressure>&>(this->nullHeader);
} }
WeatherData::Location WeatherService::GetCurrentLocation() const { std::unique_ptr<WeatherData::Location>& WeatherService::GetCurrentLocation() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::Location && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::Location && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::Location&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::Location>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::Location>&>(this->nullHeader);
} }
WeatherData::AirQuality WeatherService::GetCurrentQuality() const { std::unique_ptr<WeatherData::AirQuality>& WeatherService::GetCurrentQuality() {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : this->timeline) {
if (header->eventType == WeatherData::eventtype::AirQuality && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == WeatherData::eventtype::AirQuality && isEventStillValid(header, currentTimestamp)) {
return reinterpret_cast<const WeatherData::AirQuality&>(header); return reinterpret_cast<std::unique_ptr<WeatherData::AirQuality>&>(header);
} }
} }
return {};
return reinterpret_cast<std::unique_ptr<WeatherData::AirQuality>&>(this->nullHeader);
} }
size_t WeatherService::GetTimelineLength() const { size_t WeatherService::GetTimelineLength() const {
@ -311,8 +318,7 @@ namespace Pinetime {
bool WeatherService::HasTimelineEventOfType(const WeatherData::eventtype type) const { bool WeatherService::HasTimelineEventOfType(const WeatherData::eventtype type) const {
uint64_t currentTimestamp = GetCurrentUnixTimestamp(); uint64_t currentTimestamp = GetCurrentUnixTimestamp();
for (auto&& header : timeline) { for (auto&& header : timeline) {
if (header->eventType == type && header->timestamp + header->expires <= currentTimestamp) { if (header->eventType == type && isEventStillValid(header, currentTimestamp)) {
// TODO: Check if its currently valid
return true; return true;
} }
} }
@ -320,11 +326,11 @@ namespace Pinetime {
} }
void WeatherService::TidyTimeline() { void WeatherService::TidyTimeline() {
uint64_t timeCurrent = 0; uint64_t timeCurrent = GetCurrentUnixTimestamp();
timeline.erase(std::remove_if(std::begin(timeline), timeline.erase(std::remove_if(std::begin(timeline),
std::end(timeline), std::end(timeline),
[&](std::unique_ptr<WeatherData::TimelineHeader> const& header) { [&](std::unique_ptr<WeatherData::TimelineHeader> const& header) {
return header->timestamp + header->expires > timeCurrent; return isEventStillValid(header, timeCurrent);
}), }),
std::end(timeline)); std::end(timeline));
@ -336,6 +342,11 @@ namespace Pinetime {
return first->timestamp > second->timestamp; return first->timestamp > second->timestamp;
} }
bool WeatherService::isEventStillValid(const std::unique_ptr<WeatherData::TimelineHeader>& header, const uint64_t currentTimestamp) {
// Not getting timestamp in isEventStillValid for more speed
return header->timestamp + header->expires <= currentTimestamp;
}
uint64_t WeatherService::GetCurrentUnixTimestamp() const { uint64_t WeatherService::GetCurrentUnixTimestamp() const {
return std::chrono::duration_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime().time_since_epoch()).count(); return std::chrono::duration_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime().time_since_epoch()).count();
} }

View file

@ -51,15 +51,15 @@ namespace Pinetime {
/* /*
* Helper functions for quick access to currently valid data * Helper functions for quick access to currently valid data
*/ */
WeatherData::Location GetCurrentLocation() const; std::unique_ptr<WeatherData::Location>& GetCurrentLocation();
WeatherData::Clouds GetCurrentClouds() const; std::unique_ptr<WeatherData::Clouds>& GetCurrentClouds();
WeatherData::Obscuration GetCurrentObscuration() const; std::unique_ptr<WeatherData::Obscuration>& GetCurrentObscuration();
WeatherData::Precipitation GetCurrentPrecipitation() const; std::unique_ptr<WeatherData::Precipitation>& GetCurrentPrecipitation();
WeatherData::Wind GetCurrentWind() const; std::unique_ptr<WeatherData::Wind>& GetCurrentWind();
WeatherData::Temperature GetCurrentTemperature() const; std::unique_ptr<WeatherData::Temperature>& GetCurrentTemperature();
WeatherData::Humidity GetCurrentHumidity() const; std::unique_ptr<WeatherData::Humidity>& GetCurrentHumidity();
WeatherData::Pressure GetCurrentPressure() const; std::unique_ptr<WeatherData::Pressure>& GetCurrentPressure();
WeatherData::AirQuality GetCurrentQuality() const; std::unique_ptr<WeatherData::AirQuality>& GetCurrentQuality();
/* /*
* Management functions * Management functions
@ -123,7 +123,6 @@ namespace Pinetime {
/** /**
* Cleans up the timeline of expired events * Cleans up the timeline of expired events
* @return result code
*/ */
void TidyTimeline(); void TidyTimeline();
@ -137,6 +136,18 @@ namespace Pinetime {
* Returns current UNIX timestamp * Returns current UNIX timestamp
*/ */
uint64_t GetCurrentUnixTimestamp() const; uint64_t GetCurrentUnixTimestamp() const;
/**
* Checks if the event hasn't gone past and expired
*
* @param header timeline event to check
* @param currentTimestamp what's the time right now
* @return if the event is valid
*/
static bool isEventStillValid(const std::unique_ptr<WeatherData::TimelineHeader>& uniquePtr, const uint64_t timestamp);
std::unique_ptr<WeatherData::TimelineHeader> nullTimelineheader = std::make_unique<WeatherData::TimelineHeader>();
std::unique_ptr<WeatherData::TimelineHeader>* nullHeader;
}; };
} }
} }

View file

@ -25,6 +25,7 @@ namespace Pinetime {
Metronome, Metronome,
Motion, Motion,
Steps, Steps,
Weather,
QuickSettings, QuickSettings,
Settings, Settings,
SettingWatchFace, SettingWatchFace,

View file

@ -35,16 +35,16 @@ Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers:
return CreateScreenTemperature(); return CreateScreenTemperature();
}, },
[this]() -> std::unique_ptr<Screen> { [this]() -> std::unique_ptr<Screen> {
return CreateScreen2(); return CreateScreenAir();
}, },
[this]() -> std::unique_ptr<Screen> { [this]() -> std::unique_ptr<Screen> {
return CreateScreen3(); return CreateScreenClouds();
}, },
[this]() -> std::unique_ptr<Screen> { [this]() -> std::unique_ptr<Screen> {
return CreateScreen4(); return CreateScreenPrecipitation();
}, },
[this]() -> std::unique_ptr<Screen> { [this]() -> std::unique_ptr<Screen> {
return CreateScreen5(); return CreateScreenHumidity();
}}, }},
Screens::ScreenListModes::UpDown} { Screens::ScreenListModes::UpDown} {
} }
@ -71,78 +71,108 @@ bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
std::unique_ptr<Screen> Weather::CreateScreenTemperature() { std::unique_ptr<Screen> Weather::CreateScreenTemperature() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true); lv_label_set_recolor(label, true);
Controllers::WeatherData::Temperature current = weatherService.GetCurrentTemperature(); std::unique_ptr<Controllers::WeatherData::Temperature>& current = weatherService.GetCurrentTemperature();
lv_label_set_text_fmt(label, if (current->timestamp == 0) {
"#FFFF00 Temperature#\n\n" // Do not use the data, it's invalid
"#444444 %hd%%#°C \n\n" } else {
"#444444 %hd#\n" lv_label_set_text_fmt(label,
"%llu\n" "#FFFF00 Temperature#\n\n"
"%lu\n", "#444444 %hd%%#°C \n\n"
current.temperature, "#444444 %hd#\n\n"
current.dewPoint, "%llu\n"
current.timestamp, "%lu\n",
current.expires); current->temperature,
current->dewPoint,
current->timestamp,
current->expires);
}
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label)); return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
} }
std::unique_ptr<Screen> Weather::CreateScreen2() { std::unique_ptr<Screen> Weather::CreateScreenAir() {
// uptime
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true); lv_label_set_recolor(label, true);
lv_label_set_text_fmt(label, "#444444 Date# %02d\n", dateTimeController.Day()); std::unique_ptr<Controllers::WeatherData::AirQuality>& current = weatherService.GetCurrentQuality();
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); if (current->timestamp == 0) {
return std::unique_ptr<Screen>(new Screens::Label(1, 4, app, label)); // Do not use the data, it's invalid
} } else {
lv_label_set_text_fmt(label,
std::unique_ptr<Screen> Weather::CreateScreen3() { "#FFFF00 Air quality#\n\n"
lv_mem_monitor_t mon; "#444444 %s#\n"
lv_mem_monitor(&mon); "#444444 %lu#\n\n"
"%llu\n"
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); "%lu\n",
lv_label_set_recolor(label, true); current->polluter.c_str(),
lv_label_set_text_fmt(label, current->amount,
" #444444 frag# %d%%\n" current->timestamp,
" #444444 free# %d", current->expires);
mon.used_pct, }
mon.frag_pct);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(2, 5, app, label));
}
bool sortById(const TaskStatus_t& lhs, const TaskStatus_t& rhs) {
return lhs.xTaskNumber < rhs.xTaskNumber;
}
std::unique_ptr<Screen> Weather::CreateScreen4() {
lv_obj_t* infoTask = lv_table_create(lv_scr_act(), nullptr);
lv_table_set_col_cnt(infoTask, 3);
lv_table_set_row_cnt(infoTask, 8);
lv_obj_set_pos(infoTask, 10, 10);
lv_table_set_cell_value(infoTask, 0, 0, "#");
lv_table_set_col_width(infoTask, 0, 50);
lv_table_set_cell_value(infoTask, 0, 1, "Task");
lv_table_set_col_width(infoTask, 1, 80);
lv_table_set_cell_value(infoTask, 0, 2, "Free");
lv_table_set_col_width(infoTask, 2, 90);
return std::unique_ptr<Screen>(new Screens::Label(3, 5, app, infoTask));
}
std::unique_ptr<Screen> Weather::CreateScreen5() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
lv_label_set_text_static(label,
"Software Licensed\n"
"under the terms of\n"
"the GNU General\n"
"Public License v3\n"
"#444444 Source code#\n"
"#FFFF00 https://github.com/#\n"
"#FFFF00 JF002/InfiniTime#");
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(4, 5, app, label)); return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
}
std::unique_ptr<Screen> Weather::CreateScreenClouds() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
std::unique_ptr<Controllers::WeatherData::Clouds>& current = weatherService.GetCurrentClouds();
if (current->timestamp == 0) {
// Do not use the data, it's invalid
} else {
lv_label_set_text_fmt(label,
"#FFFF00 Clouds#\n\n"
"#444444 %hhu%%#\n\n"
"%llu\n"
"%lu\n",
current->amount,
current->timestamp,
current->expires);
}
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
}
std::unique_ptr<Screen> Weather::CreateScreenPrecipitation() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
std::unique_ptr<Controllers::WeatherData::Precipitation>& current = weatherService.GetCurrentPrecipitation();
if (current->timestamp == 0) {
// Do not use the data, it's invalid
} else {
lv_label_set_text_fmt(label,
"#FFFF00 Precipitation#\n\n"
"#444444 %hhu%%#\n\n"
"%llu\n"
"%lu\n",
current->amount,
current->timestamp,
current->expires);
}
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
}
std::unique_ptr<Screen> Weather::CreateScreenHumidity() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
std::unique_ptr<Controllers::WeatherData::Humidity>& current = weatherService.GetCurrentHumidity();
if (current->timestamp == 0) {
// Do not use the data, it's invalid
} else {
lv_label_set_text_fmt(label,
"#FFFF00 Humidity#\n\n"
"#444444 %hhu%%#\n\n"
"%llu\n"
"%lu\n",
current->humidity,
current->timestamp,
current->expires);
}
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::unique_ptr<Screen>(new Screens::Label(0, 5, app, label));
} }

View file

@ -32,13 +32,13 @@ namespace Pinetime {
std::unique_ptr<Screen> CreateScreenTemperature(); std::unique_ptr<Screen> CreateScreenTemperature();
std::unique_ptr<Screen> CreateScreen2(); std::unique_ptr<Screen> CreateScreenAir();
std::unique_ptr<Screen> CreateScreen3(); std::unique_ptr<Screen> CreateScreenClouds();
std::unique_ptr<Screen> CreateScreen4(); std::unique_ptr<Screen> CreateScreenPrecipitation();
std::unique_ptr<Screen> CreateScreen5(); std::unique_ptr<Screen> CreateScreenHumidity();
}; };
} }
} }