summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Bini <michele.bini@gmail.com>2022-03-24 04:51:16 (GMT)
committerMichele Bini <michele.bini@gmail.com>2022-03-24 10:48:25 (GMT)
commit3c29183dd22d33928ac62c65a378922d49fa06e9 (patch)
treec05c85bb5b2cf079e1547a572cd75c72e0d42d15
parentb729db093ddb903fc55b5010fa1fe17da5217ae4 (diff)
Remove weather service
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/components/ble/NimbleController.h4
-rw-r--r--src/components/ble/weather/WeatherData.h385
-rw-r--r--src/components/ble/weather/WeatherService.cpp604
-rw-r--r--src/components/ble/weather/WeatherService.h172
-rw-r--r--src/displayapp/screens/Weather.cpp222
-rw-r--r--src/displayapp/screens/Weather.h45
7 files changed, 0 insertions, 1433 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7032f0d..8e505d6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -654,7 +654,6 @@ set(INCLUDE_FILES
components/ble/BleClient.h
components/ble/HeartRateService.h
components/ble/MotionService.h
- components/ble/weather/WeatherService.h
components/settings/Settings.h
components/timer/TimerController.h
components/alarm/AlarmController.h
diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h
index 87d44aa..fecc665 100644
--- a/src/components/ble/NimbleController.h
+++ b/src/components/ble/NimbleController.h
@@ -19,7 +19,6 @@
#include "components/ble/ImmediateAlertService.h"
#include "components/ble/ServiceDiscovery.h"
#include "components/ble/MotionService.h"
-#include "components/ble/weather/WeatherService.h"
#include "components/fs/FS.h"
namespace Pinetime {
@@ -56,9 +55,6 @@ namespace Pinetime {
Pinetime::Controllers::AlertNotificationService& alertService() {
return anService;
};
- Pinetime::Controllers::WeatherService& weather() {
- return weatherService;
- };
uint16_t connHandle();
void NotifyBatteryLevel(uint8_t level);
diff --git a/src/components/ble/weather/WeatherData.h b/src/components/ble/weather/WeatherData.h
deleted file mode 100644
index 613d5ac..0000000
--- a/src/components/ble/weather/WeatherData.h
+++ /dev/null
@@ -1,385 +0,0 @@
-/* Copyright (C) 2021 Avamander
-
- This file is part of InfiniTime.
-
- InfiniTime is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- InfiniTime is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-#pragma once
-
-/**
- * Different weather events, weather data structures used by {@link WeatherService.h}
- *
- * How to upload events to the timeline?
- *
- * All timeline write payloads are simply CBOR-encoded payloads of the structs described below.
- *
- * All payloads have a mandatory header part and the dynamic part that
- * depends on the event type specified in the header. If you don't,
- * you'll get an error returned. Data is relatively well-validated,
- * so keep in the bounds of the data types given.
- *
- * Write all struct members (CamelCase keys) into a single finite-sized map, and write it to the characteristic.
- * Mind the MTU.
- *
- * How to debug?
- *
- * There's a Screen that you can compile into your firmware that shows currently valid events.
- * You can adapt that to display something else. That part right now is very much work in progress
- * because the exact requirements are not yet known.
- *
- *
- * Implemented based on and other material:
- * https://en.wikipedia.org/wiki/METAR
- * https://www.weather.gov/jetstream/obscurationtypes
- * http://www.faraim.org/aim/aim-4-03-14-493.html
- */
-
-namespace Pinetime {
- namespace Controllers {
- class WeatherData {
- public:
- /**
- * Visibility obscuration types
- */
- enum class obscurationtype {
- /** No obscuration */
- None = 0,
- /** Water particles suspended in the air; low visibility; does not fall */
- Fog = 1,
- /** Tiny, dry particles in the air; invisible to the eye; opalescent */
- Haze = 2,
- /** Small fire-created particles suspended in the air */
- Smoke = 3,
- /** Fine rock powder, from for example volcanoes */
- Ash = 4,
- /** Fine particles of earth suspended in the air by the wind */
- Dust = 5,
- /** Fine particles of sand suspended in the air by the wind */
- Sand = 6,
- /** Water particles suspended in the air; low-ish visibility; temperature is near dewpoint */
- Mist = 7,
- /** This is SPECIAL in the sense that the thing raining down is doing the obscuration */
- Precipitation = 8,
- Length
- };
-
- /**
- * Types of precipitation
- */
- enum class precipitationtype {
- /**
- * No precipitation
- *
- * Theoretically we could just _not_ send the event, but then
- * how do we differentiate between no precipitation and
- * no information about precipitation
- */
- None = 0,
- /** Drops larger than a drizzle; also widely separated drizzle */
- Rain = 1,
- /** Fairly uniform rain consisting of fine drops */
- Drizzle = 2,
- /** Rain that freezes upon contact with objects and ground */
- FreezingRain = 3,
- /** Rain + hail; ice pellets; small translucent frozen raindrops */
- Sleet = 4,
- /** Larger ice pellets; falling separately or in irregular clumps */
- Hail = 5,
- /** Hail with smaller grains of ice; mini-snowballs */
- SmallHail = 6,
- /** Snow... */
- Snow = 7,
- /** Frozen drizzle; very small snow crystals */
- SnowGrains = 8,
- /** Needles; columns or plates of ice. Sometimes described as "diamond dust". In very cold regions */
- IceCrystals = 9,
- /** It's raining down ash, e.g. from a volcano */
- Ash = 10,
- Length
- };
-
- /**
- * These are special events that can "enhance" the "experience" of existing weather events
- */
- enum class specialtype {
- /** Strong wind with a sudden onset that lasts at least a minute */
- Squall = 0,
- /** Series of waves in a water body caused by the displacement of a large volume of water */
- Tsunami = 1,
- /** Violent; rotating column of air */
- Tornado = 2,
- /** Unplanned; unwanted; uncontrolled fire in an area */
- Fire = 3,
- /** Thunder and/or lightning */
- Thunder = 4,
- Length
- };
-
- /**
- * These are used for weather timeline manipulation
- * that isn't just adding to the stack of weather events
- */
- enum class controlcodes {
- /** How much is stored already */
- GetLength = 0,
- /** This wipes the entire timeline */
- DelTimeline = 1,
- /** There's a currently valid timeline event with the given type */
- HasValidEvent = 3,
- Length
- };
-
- /**
- * Events have types
- * then they're easier to parse after sending them over the air
- */
- enum class eventtype : uint8_t {
- /** @see obscuration */
- Obscuration = 0,
- /** @see precipitation */
- Precipitation = 1,
- /** @see wind */
- Wind = 2,
- /** @see temperature */
- Temperature = 3,
- /** @see airquality */
- AirQuality = 4,
- /** @see special */
- Special = 5,
- /** @see pressure */
- Pressure = 6,
- /** @see location */
- Location = 7,
- /** @see cloud */
- Clouds = 8,
- /** @see humidity */
- Humidity = 9,
- Length
- };
-
- /**
- * Valid event query
- *
- * NOTE: Not currently available, until needs are better known
- */
- class ValidEventQuery {
- public:
- static constexpr controlcodes code = controlcodes::HasValidEvent;
- eventtype eventType;
- };
-
- /** The header used for further parsing */
- class TimelineHeader {
- public:
- /**
- * UNIX timestamp
- * TODO: This is currently WITH A TIMEZONE OFFSET!
- * Please send events with the timestamp offset by the timezone.
- **/
- uint64_t timestamp;
- /**
- * Time in seconds until the event expires
- *
- * 32 bits ought to be enough for everyone
- *
- * If there's a newer event of the same type then it overrides this one, even if it hasn't expired
- */
- uint32_t expires;
- /**
- * What type of weather-related event
- */
- eventtype eventType;
- };
-
- /** Specifies how cloudiness is stored */
- class Clouds : public TimelineHeader {
- public:
- /** Cloud coverage in percentage, 0-100% */
- uint8_t amount;
- };
-
- /** Specifies how obscuration is stored */
- class Obscuration : public TimelineHeader {
- public:
- /** Type of precipitation */
- obscurationtype type;
- /**
- * Visibility distance in meters
- * 65535 is reserved for unspecified
- */
- uint16_t amount;
- };
-
- /** Specifies how precipitation is stored */
- class Precipitation : public TimelineHeader {
- public:
- /** Type of precipitation */
- precipitationtype type;
- /**
- * How much is it going to rain? In millimeters
- * 255 is reserved for unspecified
- **/
- uint8_t amount;
- };
-
- /**
- * How wind speed is stored
- *
- * In order to represent bursts of wind instead of constant wind,
- * you have minimum and maximum speeds.
- *
- * As direction can fluctuate wildly and some watchfaces might wish to display it nicely,
- * we're following the aerospace industry weather report option of specifying a range.
- */
- class Wind : public TimelineHeader {
- public:
- /** Meters per second */
- uint8_t speedMin;
- /** Meters per second */
- uint8_t speedMax;
- /** Unitless direction between 0-255; approximately 1 unit per 0.71 degrees */
- uint8_t directionMin;
- /** Unitless direction between 0-255; approximately 1 unit per 0.71 degrees */
- uint8_t directionMax;
- };
-
- /**
- * How temperature is stored
- *
- * As it's annoying to figure out the dewpoint on the watch,
- * please send it from the companion
- *
- * We don't do floats, picodegrees are not useful. Make sure to multiply.
- */
- class Temperature : public TimelineHeader {
- public:
- /**
- * Temperature °C but multiplied by 100 (e.g. -12.50°C becomes -1250)
- * -32768 is reserved for "no data"
- */
- int16_t temperature;
- /**
- * Dewpoint °C but multiplied by 100 (e.g. -12.50°C becomes -1250)
- * -32768 is reserved for "no data"
- */
- int16_t dewPoint;
- };
-
- /**
- * How location info is stored
- *
- * This can be mostly static with long expiration,
- * as it usually is, but it could change during a trip for ex.
- * so we allow changing it dynamically.
- *
- * Location info can be for some kind of map watchface
- * or daylight calculations, should those be required.
- *
- */
- class Location : public TimelineHeader {
- public:
- /** Location name */
- std::string location;
- /** Altitude relative to sea level in meters */
- int16_t altitude;
- /** Latitude, EPSG:3857 (Google Maps, Openstreetmaps datum) */
- int32_t latitude;
- /** Longitude, EPSG:3857 (Google Maps, Openstreetmaps datum) */
- int32_t longitude;
- };
-
- /**
- * How humidity is stored
- */
- class Humidity : public TimelineHeader {
- public:
- /** Relative humidity, 0-100% */
- uint8_t humidity;
- };
-
- /**
- * How air pressure is stored
- */
- class Pressure : public TimelineHeader {
- public:
- /** Air pressure in hectopascals (hPa) */
- int16_t pressure;
- };
-
- /**
- * How special events are stored
- */
- class Special : public TimelineHeader {
- public:
- /** Special event's type */
- specialtype type;
- };
-
- /**
- * How air quality is stored
- *
- * These events are a bit more complex because the topic is not simple,
- * the intention is to heavy-lift the annoying preprocessing from the watch
- * this allows watchface or watchapp makers to generate accurate alerts and graphics
- *
- * If this needs further enforced standardization, pull requests are welcome
- */
- class AirQuality : public TimelineHeader {
- public:
- /**
- * The name of the pollution
- *
- * for the sake of better compatibility with watchapps
- * that might want to use this data for say visuals
- * don't localize the name.
- *
- * Ideally watchapp itself localizes the name, if it's at all needed.
- *
- * E.g.
- * For generic ones use "PM0.1", "PM5", "PM10"
- * For chemical compounds use the molecular formula e.g. "NO2", "CO2", "O3"
- * For pollen use the genus, e.g. "Betula" for birch or "Alternaria" for that mold's spores
- */
- std::string polluter;
- /**
- * Amount of the pollution in SI units,
- * otherwise it's going to be difficult to create UI, alerts
- * and so on and for.
- *
- * See more:
- * https://ec.europa.eu/environment/air/quality/standards.htm
- * http://www.ourair.org/wp-content/uploads/2012-aaqs2.pdf
- *
- * Example units:
- * count/m³ for pollen
- * µgC/m³ for micrograms of organic carbon
- * µg/m³ sulfates, PM0.1, PM1, PM2, PM10 and so on, dust
- * mg/m³ CO2, CO
- * ng/m³ for heavy metals
- *
- * List is not comprehensive, should be improved.
- * The current ones are what watchapps assume!
- *
- * Note: ppb and ppm to concentration should be calculated on the companion, using
- * the correct formula (taking into account temperature and air pressure)
- *
- * Note2: The amount is off by times 100, for two decimal places of precision.
- * E.g. 54.32µg/m³ is 5432
- *
- */
- uint32_t amount;
- };
- };
- }
-}
diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp
deleted file mode 100644
index 23f53b7..0000000
--- a/src/components/ble/weather/WeatherService.cpp
+++ /dev/null
@@ -1,604 +0,0 @@
-/* Copyright (C) 2021 Avamander
-
- This file is part of InfiniTime.
-
- InfiniTime is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- InfiniTime is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-#include <qcbor/qcbor_spiffy_decode.h>
-#include "WeatherService.h"
-#include "libs/QCBOR/inc/qcbor/qcbor.h"
-#include "systemtask/SystemTask.h"
-
-int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
- return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(connHandle, attrHandle, ctxt);
-}
-
-namespace Pinetime {
- namespace Controllers {
- WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController)
- : system(system), dateTimeController(dateTimeController) {
- nullHeader = &nullTimelineheader;
- nullTimelineheader->timestamp = 0;
- }
-
- void WeatherService::Init() {
- uint8_t res = 0;
- res = ble_gatts_count_cfg(serviceDefinition);
- ASSERT(res == 0);
-
- res = ble_gatts_add_svcs(serviceDefinition);
- ASSERT(res == 0);
- }
-
- int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) {
- if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
- const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- if (packetLen <= 0) {
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- // Decode
- QCBORDecodeContext decodeContext;
- UsefulBufC encodedCbor = {ctxt->om->om_data, OS_MBUF_PKTLEN(ctxt->om)}; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-
- QCBORDecode_Init(&decodeContext, encodedCbor, QCBOR_DECODE_MODE_NORMAL);
- // KINDLY provide us a fixed-length map
- QCBORDecode_EnterMap(&decodeContext, nullptr);
- // Always encodes to the smallest number of bytes based on the value
- int64_t tmpTimestamp = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", &tmpTimestamp);
- if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- int64_t tmpExpires = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", &tmpExpires);
- if (QCBORDecode_GetError(&decodeContext) != QCBOR_SUCCESS || tmpExpires < 0 || tmpExpires > 4294967295) {
- 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 ||
- tmpEventType >= static_cast<int64_t>(WeatherData::eventtype::Length)) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
-
- switch (static_cast<WeatherData::eventtype>(tmpEventType)) {
- case WeatherData::eventtype::AirQuality: {
- std::unique_ptr<WeatherData::AirQuality> airquality = std::make_unique<WeatherData::AirQuality>();
- airquality->timestamp = tmpTimestamp;
- airquality->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- airquality->expires = tmpExpires;
-
- UsefulBufC stringBuf; // TODO: Everything ok with lifecycle here?
- QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Polluter", &stringBuf);
- if (UsefulBuf_IsNULLOrEmptyC(stringBuf) != 0) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- airquality->polluter = std::string(static_cast<const char*>(stringBuf.ptr), stringBuf.len);
-
- int64_t tmpAmount = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount);
- if (tmpAmount < 0 || tmpAmount > 4294967295) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- airquality->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- if (!AddEventToTimeline(std::move(airquality))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Obscuration: {
- std::unique_ptr<WeatherData::Obscuration> obscuration = std::make_unique<WeatherData::Obscuration>();
- obscuration->timestamp = tmpTimestamp;
- obscuration->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- obscuration->expires = tmpExpires;
-
- int64_t tmpType = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType);
- if (tmpType < 0 || tmpType >= static_cast<int64_t>(WeatherData::obscurationtype::Length)) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- obscuration->type = static_cast<WeatherData::obscurationtype>(tmpType);
-
- int64_t tmpAmount = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount);
- if (tmpAmount < 0 || tmpAmount > 65535) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- obscuration->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- if (!AddEventToTimeline(std::move(obscuration))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Precipitation: {
- std::unique_ptr<WeatherData::Precipitation> precipitation = std::make_unique<WeatherData::Precipitation>();
- precipitation->timestamp = tmpTimestamp;
- precipitation->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- precipitation->expires = tmpExpires;
-
- int64_t tmpType = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType);
- if (tmpType < 0 || tmpType >= static_cast<int64_t>(WeatherData::precipitationtype::Length)) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- precipitation->type = static_cast<WeatherData::precipitationtype>(tmpType);
-
- int64_t tmpAmount = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount);
- if (tmpAmount < 0 || tmpAmount > 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- precipitation->amount = tmpAmount; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- if (!AddEventToTimeline(std::move(precipitation))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Wind: {
- std::unique_ptr<WeatherData::Wind> wind = std::make_unique<WeatherData::Wind>();
- wind->timestamp = tmpTimestamp;
- wind->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- wind->expires = tmpExpires;
-
- int64_t tmpMin = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "SpeedMin", &tmpMin);
- if (tmpMin < 0 || tmpMin > 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- wind->speedMin = tmpMin; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- int64_t tmpMax = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "SpeedMin", &tmpMax);
- if (tmpMax < 0 || tmpMax > 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- wind->speedMax = tmpMax; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- int64_t tmpDMin = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "DirectionMin", &tmpDMin);
- if (tmpDMin < 0 || tmpDMin > 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- wind->directionMin = tmpDMin; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- int64_t tmpDMax = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "DirectionMax", &tmpDMax);
- if (tmpDMax < 0 || tmpDMax > 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- wind->directionMax = tmpDMax; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- if (!AddEventToTimeline(std::move(wind))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Temperature: {
- std::unique_ptr<WeatherData::Temperature> temperature = std::make_unique<WeatherData::Temperature>();
- temperature->timestamp = tmpTimestamp;
- temperature->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- temperature->expires = tmpExpires;
-
- int64_t tmpTemperature = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Temperature", &tmpTemperature);
- if (tmpTemperature < -32768 || tmpTemperature > 32767) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- temperature->temperature =
- static_cast<int16_t>(tmpTemperature); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- int64_t tmpDewPoint = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "DewPoint", &tmpDewPoint);
- if (tmpDewPoint < -32768 || tmpDewPoint > 32767) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- temperature->dewPoint =
- static_cast<int16_t>(tmpDewPoint); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- if (!AddEventToTimeline(std::move(temperature))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Special: {
- std::unique_ptr<WeatherData::Special> special = std::make_unique<WeatherData::Special>();
- special->timestamp = tmpTimestamp;
- special->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- special->expires = tmpExpires;
-
- int64_t tmpType = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Type", &tmpType);
- if (tmpType < 0 || tmpType >= static_cast<int64_t>(WeatherData::specialtype::Length)) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- special->type = static_cast<WeatherData::specialtype>(tmpType);
-
- if (!AddEventToTimeline(std::move(special))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Pressure: {
- std::unique_ptr<WeatherData::Pressure> pressure = std::make_unique<WeatherData::Pressure>();
- pressure->timestamp = tmpTimestamp;
- pressure->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- pressure->expires = tmpExpires;
-
- int64_t tmpPressure = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Pressure", &tmpPressure);
- if (tmpPressure < 0 || tmpPressure >= 65535) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- pressure->pressure = tmpPressure; // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-
- if (!AddEventToTimeline(std::move(pressure))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Location: {
- std::unique_ptr<WeatherData::Location> location = std::make_unique<WeatherData::Location>();
- location->timestamp = tmpTimestamp;
- location->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- location->expires = tmpExpires;
-
- UsefulBufC stringBuf; // TODO: Everything ok with lifecycle here?
- QCBORDecode_GetTextStringInMapSZ(&decodeContext, "Location", &stringBuf);
- if (UsefulBuf_IsNULLOrEmptyC(stringBuf) != 0) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- location->location = std::string(static_cast<const char*>(stringBuf.ptr), stringBuf.len);
-
- int64_t tmpAltitude = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Altitude", &tmpAltitude);
- if (tmpAltitude < -32768 || tmpAltitude >= 32767) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- location->altitude = static_cast<int16_t>(tmpAltitude);
-
- int64_t tmpLatitude = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Latitude", &tmpLatitude);
- if (tmpLatitude < -2147483648 || tmpLatitude >= 2147483647) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- location->latitude = static_cast<int32_t>(tmpLatitude);
-
- int64_t tmpLongitude = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Longitude", &tmpLongitude);
- if (tmpLongitude < -2147483648 || tmpLongitude >= 2147483647) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- location->latitude = static_cast<int32_t>(tmpLongitude);
-
- if (!AddEventToTimeline(std::move(location))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Clouds: {
- std::unique_ptr<WeatherData::Clouds> clouds = std::make_unique<WeatherData::Clouds>();
- clouds->timestamp = tmpTimestamp;
- clouds->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- clouds->expires = tmpExpires;
-
- int64_t tmpAmount = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Amount", &tmpAmount);
- if (tmpAmount < 0 || tmpAmount > 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- clouds->amount = static_cast<uint8_t>(tmpAmount);
-
- if (!AddEventToTimeline(std::move(clouds))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- case WeatherData::eventtype::Humidity: {
- std::unique_ptr<WeatherData::Humidity> humidity = std::make_unique<WeatherData::Humidity>();
- humidity->timestamp = tmpTimestamp;
- humidity->eventType = static_cast<WeatherData::eventtype>(tmpEventType);
- humidity->expires = tmpExpires;
-
- int64_t tmpType = 0;
- QCBORDecode_GetInt64InMapSZ(&decodeContext, "Humidity", &tmpType);
- if (tmpType < 0 || tmpType >= 255) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- humidity->humidity = static_cast<uint8_t>(tmpType);
-
- if (!AddEventToTimeline(std::move(humidity))) {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- break;
- }
- default: {
- CleanUpQcbor(&decodeContext);
- return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
- }
- }
-
- QCBORDecode_ExitMap(&decodeContext);
- GetTimelineLength();
- TidyTimeline();
-
- if (QCBORDecode_Finish(&decodeContext) != QCBOR_SUCCESS) {
- return BLE_ATT_ERR_INSUFFICIENT_RES;
- }
- } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
- // Encode
- uint8_t buffer[64];
- QCBOREncodeContext encodeContext;
- /* TODO: This is very much still a test endpoint
- * it needs a characteristic UUID check
- * and actual implementations that show
- * what actually has to be read.
- * WARN: Consider commands not part of the API for now!
- */
- QCBOREncode_Init(&encodeContext, UsefulBuf_FROM_BYTE_ARRAY(buffer));
- QCBOREncode_OpenMap(&encodeContext);
- QCBOREncode_AddTextToMap(&encodeContext, "test", UsefulBuf_FROM_SZ_LITERAL("test"));
- QCBOREncode_AddInt64ToMap(&encodeContext, "test", 1ul);
- QCBOREncode_CloseMap(&encodeContext);
-
- UsefulBufC encodedEvent;
- auto uErr = QCBOREncode_Finish(&encodeContext, &encodedEvent);
- if (uErr != 0) {
- return BLE_ATT_ERR_INSUFFICIENT_RES;
- }
- auto res = os_mbuf_append(ctxt->om, &buffer, sizeof(buffer));
- if (res == 0) {
- return BLE_ATT_ERR_INSUFFICIENT_RES;
- }
-
- return 0;
- }
- return 0;
- }
-
- std::unique_ptr<WeatherData::Clouds>& WeatherService::GetCurrentClouds() {
- 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);
- }
- }
-
- return reinterpret_cast<std::unique_ptr<WeatherData::Clouds>&>(*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);
- }
- }
-
- return reinterpret_cast<std::unique_ptr<WeatherData::Obscuration>&>(*this->nullHeader);
- }
-
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
- size_t WeatherService::GetTimelineLength() const {
- return timeline.size();
- }
-
- bool WeatherService::AddEventToTimeline(std::unique_ptr<WeatherData::TimelineHeader> event) {
- if (timeline.size() == timeline.max_size()) {
- return false;
- }
-
- timeline.push_back(std::move(event));
- return true;
- }
-
- bool WeatherService::HasTimelineEventOfType(const WeatherData::eventtype type) const {
- uint64_t currentTimestamp = GetCurrentUnixTimestamp();
- for (auto&& header : timeline) {
- if (header->eventType == type && IsEventStillValid(header, currentTimestamp)) {
- return true;
- }
- }
- return false;
- }
-
- void WeatherService::TidyTimeline() {
- uint64_t timeCurrent = GetCurrentUnixTimestamp();
- timeline.erase(std::remove_if(std::begin(timeline),
- std::end(timeline),
- [&](std::unique_ptr<WeatherData::TimelineHeader> const& header) {
- return !IsEventStillValid(header, timeCurrent);
- }),
- std::end(timeline));
-
- std::sort(std::begin(timeline), std::end(timeline), CompareTimelineEvents);
- }
-
- bool WeatherService::CompareTimelineEvents(const std::unique_ptr<WeatherData::TimelineHeader>& first,
- const std::unique_ptr<WeatherData::TimelineHeader>& second) {
- return first->timestamp > second->timestamp;
- }
-
- bool WeatherService::IsEventStillValid(const std::unique_ptr<WeatherData::TimelineHeader>& uniquePtr, const uint64_t timestamp) {
- // Not getting timestamp in isEventStillValid for more speed
- return uniquePtr->timestamp + uniquePtr->expires >= timestamp;
- }
-
- uint64_t WeatherService::GetCurrentUnixTimestamp() const {
- return std::chrono::duration_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime().time_since_epoch()).count();
- }
-
- int16_t WeatherService::GetTodayMinTemp() const {
- uint64_t currentTimestamp = GetCurrentUnixTimestamp();
- uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) -
- ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds());
- int16_t result = -32768;
- for (auto&& header : this->timeline) {
- if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) &&
- header->timestamp < currentDayEnd &&
- reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) {
- int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature;
- if (result == -32768) {
- result = temperature;
- } else if (result > temperature) {
- result = temperature;
- } else {
- // The temperature in this item is higher than the lowest we've found
- }
- }
- }
-
- return result;
- }
-
- int16_t WeatherService::GetTodayMaxTemp() const {
- uint64_t currentTimestamp = GetCurrentUnixTimestamp();
- uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) -
- ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds());
- int16_t result = -32768;
- for (auto&& header : this->timeline) {
- if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) &&
- header->timestamp < currentDayEnd &&
- reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) {
- int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature;
- if (result == -32768) {
- result = temperature;
- } else if (result < temperature) {
- result = temperature;
- } else {
- // The temperature in this item is lower than the highest we've found
- }
- }
- }
-
- return result;
- }
-
- void WeatherService::CleanUpQcbor(QCBORDecodeContext* decodeContext) {
- QCBORDecode_ExitMap(decodeContext);
- QCBORDecode_Finish(decodeContext);
- }
- }
-}
diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h
deleted file mode 100644
index eca70cb..0000000
--- a/src/components/ble/weather/WeatherService.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* Copyright (C) 2021 Avamander
-
- This file is part of InfiniTime.
-
- InfiniTime is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- InfiniTime is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-#pragma once
-
-#include <cstdint>
-#include <string>
-#include <vector>
-#include <memory>
-
-#define min // workaround: nimble's min/max macros conflict with libstdc++
-#define max
-#include <host/ble_gap.h>
-#include <host/ble_uuid.h>
-#undef max
-#undef min
-
-#include "WeatherData.h"
-#include "libs/QCBOR/inc/qcbor/qcbor.h"
-#include "components/datetime/DateTimeController.h"
-
-int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg);
-
-namespace Pinetime {
- namespace System {
- class SystemTask;
- }
- namespace Controllers {
-
- class WeatherService {
- public:
- explicit WeatherService(System::SystemTask& system, DateTime& dateTimeController);
-
- void Init();
-
- int OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt);
-
- /*
- * Helper functions for quick access to currently valid data
- */
- std::unique_ptr<WeatherData::Location>& GetCurrentLocation();
- std::unique_ptr<WeatherData::Clouds>& GetCurrentClouds();
- std::unique_ptr<WeatherData::Obscuration>& GetCurrentObscuration();
- std::unique_ptr<WeatherData::Precipitation>& GetCurrentPrecipitation();
- std::unique_ptr<WeatherData::Wind>& GetCurrentWind();
- std::unique_ptr<WeatherData::Temperature>& GetCurrentTemperature();
- std::unique_ptr<WeatherData::Humidity>& GetCurrentHumidity();
- std::unique_ptr<WeatherData::Pressure>& GetCurrentPressure();
- std::unique_ptr<WeatherData::AirQuality>& GetCurrentQuality();
-
- /**
- * Searches for the current day's maximum temperature
- * @return -32768 if there's no data, degrees Celsius times 100 otherwise
- */
- int16_t GetTodayMaxTemp() const;
- /**
- * Searches for the current day's minimum temperature
- * @return -32768 if there's no data, degrees Celsius times 100 otherwise
- */
- int16_t GetTodayMinTemp() const;
-
- /*
- * Management functions
- */
- /**
- * Adds an event to the timeline
- * @return
- */
- bool AddEventToTimeline(std::unique_ptr<WeatherData::TimelineHeader> event);
- /**
- * Gets the current timeline length
- */
- size_t GetTimelineLength() const;
- /**
- * Checks if an event of a certain type exists in the timeline
- */
- bool HasTimelineEventOfType(WeatherData::eventtype type) const;
-
- private:
- // 00040000-78fc-48fe-8e23-433b3a1942d0
- static constexpr ble_uuid128_t BaseUuid() {
- return CharUuid(0x00, 0x00);
- }
-
- // 0004yyxx-78fc-48fe-8e23-433b3a1942d0
- static constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
- return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
- .value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, y, x, 0x04, 0x00}};
- }
-
- ble_uuid128_t weatherUuid {BaseUuid()};
-
- /**
- * Just write timeline data here.
- *
- * See {@link WeatherData.h} for more information.
- */
- ble_uuid128_t weatherDataCharUuid {CharUuid(0x00, 0x01)};
- /**
- * This doesn't take timeline data, provides some control over it.
- *
- * NOTE: Currently not supported. Companion app implementer feedback required.
- * There's very little point in solidifying an API before we know the needs.
- */
- ble_uuid128_t weatherControlCharUuid {CharUuid(0x00, 0x02)};
-
- const struct ble_gatt_chr_def characteristicDefinition[3] = {
- {.uuid = &weatherDataCharUuid.u,
- .access_cb = WeatherCallback,
- .arg = this,
- .flags = BLE_GATT_CHR_F_WRITE,
- .val_handle = &eventHandle},
- {.uuid = &weatherControlCharUuid.u, .access_cb = WeatherCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ},
- {nullptr}};
- const struct ble_gatt_svc_def serviceDefinition[2] = {
- {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &weatherUuid.u, .characteristics = characteristicDefinition}, {0}};
-
- uint16_t eventHandle {};
-
- Pinetime::System::SystemTask& system;
- Pinetime::Controllers::DateTime& dateTimeController;
-
- std::vector<std::unique_ptr<WeatherData::TimelineHeader>> timeline;
- std::unique_ptr<WeatherData::TimelineHeader> nullTimelineheader = std::make_unique<WeatherData::TimelineHeader>();
- std::unique_ptr<WeatherData::TimelineHeader>* nullHeader;
-
- /**
- * Cleans up the timeline of expired events
- */
- void TidyTimeline();
-
- /**
- * Compares two timeline events
- */
- static bool CompareTimelineEvents(const std::unique_ptr<WeatherData::TimelineHeader>& first,
- const std::unique_ptr<WeatherData::TimelineHeader>& second);
-
- /**
- * Returns current UNIX timestamp
- */
- 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);
-
- /**
- * This is a helper function that closes a QCBOR map and decoding context cleanly
- */
- void CleanUpQcbor(QCBORDecodeContext* decodeContext);
- };
- }
-}
diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp
deleted file mode 100644
index 1d0a83b..0000000
--- a/src/displayapp/screens/Weather.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/* Copyright (C) 2021 Avamander
-
- This file is part of InfiniTime.
-
- InfiniTime is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- InfiniTime is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-#include "Weather.h"
-#include <lvgl/lvgl.h>
-#include <components/ble/weather/WeatherService.h>
-#include "Label.h"
-#include "components/battery/BatteryController.h"
-#include "components/ble/BleController.h"
-#include "components/ble/weather/WeatherData.h"
-
-using namespace Pinetime::Applications::Screens;
-
-Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::WeatherService& weather)
- : Screen(app),
- dateTimeController {dateTimeController},
- weatherService(weather),
- screens {app,
- 0,
- {[this]() -> std::unique_ptr<Screen> {
- return CreateScreenTemperature();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenAir();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenClouds();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenPrecipitation();
- },
- [this]() -> std::unique_ptr<Screen> {
- return CreateScreenHumidity();
- }},
- Screens::ScreenListModes::UpDown} {
-}
-
-Weather::~Weather() {
- lv_obj_clean(lv_scr_act());
-}
-
-void Weather::Refresh() {
- if (running) {
- // screens.Refresh();
- }
-}
-
-bool Weather::OnButtonPushed() {
- running = false;
- return true;
-}
-
-bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
- return screens.OnTouchEvent(event);
-}
-
-std::unique_ptr<Screen> Weather::CreateScreenTemperature() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::Temperature>& current = weatherService.GetCurrentTemperature();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Temperature#\n\n"
- "#444444 %d#°C \n\n"
- "#444444 %d#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Temperature#\n\n"
- "#444444 %d#°C \n\n"
- "#444444 %hd#\n\n"
- "%llu\n"
- "%lu\n",
- current->temperature / 100,
- current->dewPoint,
- 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::CreateScreenAir() {
- lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
- lv_label_set_recolor(label, true);
- std::unique_ptr<Controllers::WeatherData::AirQuality>& current = weatherService.GetCurrentQuality();
- if (current->timestamp == 0) {
- // Do not use the data, it's invalid
- lv_label_set_text_fmt(label,
- "#FFFF00 Air quality#\n\n"
- "#444444 %s#\n"
- "#444444 %d#\n\n"
- "%d\n"
- "%d\n",
- "",
- 0,
- 0,
- 0);
- } else {
- lv_label_set_text_fmt(label,
- "#FFFF00 Air quality#\n\n"
- "#444444 %s#\n"
- "#444444 %lu#\n\n"
- "%llu\n"
- "%lu\n",
- current->polluter.c_str(),
- (current->amount / 100),
- 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::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
- lv_label_set_text_fmt(label,
- "#FFFF00 Clouds#\n\n"
- "#444444 %d%%#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0);
- } 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
- lv_label_set_text_fmt(label,
- "#FFFF00 Precipitation#\n\n"
- "#444444 %d%%#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0);
- } 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
- lv_label_set_text_fmt(label,
- "#FFFF00 Humidity#\n\n"
- "#444444 %d%%#\n\n"
- "%d\n"
- "%d\n",
- 0,
- 0,
- 0);
- } 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));
-}
diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h
deleted file mode 100644
index 34f95fc..0000000
--- a/src/displayapp/screens/Weather.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <memory>
-#include <components/ble/weather/WeatherService.h>
-#include "Screen.h"
-#include "ScreenList.h"
-
-namespace Pinetime {
- namespace Applications {
- class DisplayApp;
-
- namespace Screens {
- class Weather : public Screen {
- public:
- explicit Weather(DisplayApp* app, Pinetime::Controllers::WeatherService& weather);
-
- ~Weather() override;
-
- void Refresh() override;
-
- bool OnButtonPushed() override;
-
- bool OnTouchEvent(TouchEvents event) override;
-
- private:
- bool running = true;
-
- Pinetime::Controllers::DateTime& dateTimeController;
- Controllers::WeatherService& weatherService;
-
- ScreenList<5> screens;
-
- std::unique_ptr<Screen> CreateScreenTemperature();
-
- std::unique_ptr<Screen> CreateScreenAir();
-
- std::unique_ptr<Screen> CreateScreenClouds();
-
- std::unique_ptr<Screen> CreateScreenPrecipitation();
-
- std::unique_ptr<Screen> CreateScreenHumidity();
- };
- }
- }
-}